--- /dev/null
+/** @file\r
+ UEFI Component Name(2) protocol implementation for iSCSI.\r
+\r
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "IScsiImpl.h"\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gIScsiComponentName = {\r
+ IScsiComponentNameGetDriverName,\r
+ IScsiComponentNameGetControllerName,\r
+ "eng"\r
+};\r
+\r
+//\r
+// EFI Component Name 2 Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gIScsiComponentName2 = {\r
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) IScsiComponentNameGetDriverName,\r
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) IScsiComponentNameGetControllerName,\r
+ "en"\r
+};\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mIScsiDriverNameTable[] = {\r
+ {\r
+ "eng;en",\r
+ L"iSCSI Driver"\r
+ },\r
+ {\r
+ NULL,\r
+ NULL\r
+ }\r
+};\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+ This function retrieves the user readable name of a driver in the form of a\r
+ Unicode string. If the driver specified by This has a user readable name in\r
+ the language specified by Language, then a pointer to the driver name is\r
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+ by This does not support the language specified by Language,\r
+ then EFI_UNSUPPORTED is returned.\r
+\r
+ @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param[in] Language A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified\r
+ in RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param[out] DriverName A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ driver specified by This in the language\r
+ specified by Language.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by\r
+ This and the language specified by Language was\r
+ returned in DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ )\r
+{\r
+ return LookupUnicodeString2 (\r
+ Language,\r
+ This->SupportedLanguages,\r
+ mIScsiDriverNameTable,\r
+ DriverName,\r
+ (BOOLEAN) (This == &gIScsiComponentName)\r
+ );\r
+}\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by a driver.\r
+\r
+ This function retrieves the user readable name of the controller specified by\r
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+ driver specified by This has a user readable name in the language specified by\r
+ Language, then a pointer to the controller name is returned in ControllerName,\r
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently\r
+ managing the controller specified by ControllerHandle and ChildHandle,\r
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not\r
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+ @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param[in] ControllerHandle The handle of a controller that the driver\r
+ specified by This is managing. This handle\r
+ specifies the controller whose name is to be\r
+ returned.\r
+\r
+ @param[in] ChildHandle The handle of the child controller to retrieve\r
+ the name of. This is an optional parameter that\r
+ may be NULL. It will be NULL for device\r
+ drivers. It will also be NULL for a bus drivers\r
+ that wish to retrieve the name of the bus\r
+ controller. It will not be NULL for a bus\r
+ driver that wishes to retrieve the name of a\r
+ child controller.\r
+\r
+ @param[in] Language A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified in\r
+ RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param[out] ControllerName A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ controller specified by ControllerHandle and\r
+ ChildHandle in the language specified by\r
+ Language, from the point of view of the driver\r
+ specified by This.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the user readable name in\r
+ the language specified by Language for the\r
+ driver specified by This was returned in\r
+ DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL, and it is not a valid\r
+ EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ )\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
--- /dev/null
+/** @file\r
+ Implementation for EFI_AUTHENTICATION_INFO_PROTOCOL. Currently it is a\r
+ dummy support.\r
+\r
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "IScsiImpl.h"\r
+\r
+EFI_AUTHENTICATION_INFO_PROTOCOL gIScsiAuthenticationInfo = {\r
+ IScsiGetAuthenticationInfo,\r
+ IScsiSetAuthenticationInfo\r
+};\r
+\r
+/**\r
+ Retrieves the authentication information associated with a particular controller handle.\r
+\r
+ @param[in] This Pointer to the EFI_AUTHENTICATION_INFO_PROTOCOL.\r
+ @param[in] ControllerHandle Handle to the Controller.\r
+ @param[out] Buffer Pointer to the authentication information. This function is\r
+ responsible for allocating the buffer and it is the caller's\r
+ responsibility to free buffer when the caller is finished with buffer.\r
+\r
+ @retval EFI_DEVICE_ERROR The authentication information could not be\r
+ retrieved due to a hardware error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiGetAuthenticationInfo (\r
+ IN EFI_AUTHENTICATION_INFO_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ OUT VOID **Buffer\r
+ )\r
+{\r
+ return EFI_DEVICE_ERROR;\r
+}\r
+\r
+/**\r
+ Set the authentication information for a given controller handle.\r
+\r
+ @param[in] This Pointer to the EFI_AUTHENTICATION_INFO_PROTOCOL.\r
+ @param[in] ControllerHandle Handle to the Controller.\r
+ @param[in] Buffer Pointer to the authentication information.\r
+\r
+ @retval EFI_UNSUPPORTED If the platform policies do not allow setting of\r
+ the authentication information.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiSetAuthenticationInfo (\r
+ IN EFI_AUTHENTICATION_INFO_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
--- /dev/null
+/** @file\r
+ This file is for Challenge-Handshake Authentication Protocol (CHAP) Configuration.\r
+\r
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "IScsiImpl.h"\r
+\r
+/**\r
+ Initator caculates its own expected hash value.\r
+ \r
+ @param[in] ChapIdentifier iSCSI CHAP identifier sent by authenticator.\r
+ @param[in] ChapSecret iSCSI CHAP secret of the authenticator.\r
+ @param[in] SecretLength The length of iSCSI CHAP secret.\r
+ @param[in] ChapChallenge The challenge message sent by authenticator.\r
+ @param[in] ChallengeLength The length of iSCSI CHAP challenge message.\r
+ @param[out] ChapResponse The calculation of the expected hash value.\r
+ \r
+ @retval EFI_SUCCESS The expected hash value was caculatedly successfully.\r
+ @retval EFI_PROTOCOL_ERROR The length of the secret should be at least the\r
+ length of the hash value for the hashing algorithm chosen.\r
+ @retval EFI_PROTOCOL_ERROR MD5 hash operation fail.\r
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate resource to complete MD5.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiCHAPCalculateResponse (\r
+ IN UINT32 ChapIdentifier,\r
+ IN CHAR8 *ChapSecret,\r
+ IN UINT32 SecretLength,\r
+ IN UINT8 *ChapChallenge,\r
+ IN UINT32 ChallengeLength,\r
+ OUT UINT8 *ChapResponse\r
+ )\r
+{\r
+ UINTN Md5ContextSize;\r
+ VOID *Md5Ctx;\r
+ CHAR8 IdByte[1];\r
+ EFI_STATUS Status;\r
+\r
+ if (SecretLength < ISCSI_CHAP_SECRET_MIN_LEN) {\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+\r
+ Md5ContextSize = Md5GetContextSize ();\r
+ Md5Ctx = AllocatePool (Md5ContextSize);\r
+ if (Md5Ctx == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = EFI_PROTOCOL_ERROR;\r
+\r
+ if (!Md5Init (Md5Ctx)) {\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Hash Identifier - Only calculate 1 byte data (RFC1994)\r
+ //\r
+ IdByte[0] = (CHAR8) ChapIdentifier;\r
+ if (!Md5Update (Md5Ctx, IdByte, 1)) {\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Hash Secret\r
+ //\r
+ if (!Md5Update (Md5Ctx, ChapSecret, SecretLength)) {\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Hash Challenge received from Target\r
+ //\r
+ if (!Md5Update (Md5Ctx, ChapChallenge, ChallengeLength)) {\r
+ goto Exit;\r
+ }\r
+\r
+ if (Md5Final (Md5Ctx, ChapResponse)) {\r
+ Status = EFI_SUCCESS;\r
+ }\r
+\r
+Exit:\r
+ FreePool (Md5Ctx);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ The initator checks the CHAP response replied by target against its own\r
+ calculation of the expected hash value. \r
+ \r
+ @param[in] AuthData iSCSI CHAP authentication data. \r
+ @param[in] TargetResponse The response from target. \r
+\r
+ @retval EFI_SUCCESS The response from target passed authentication.\r
+ @retval EFI_SECURITY_VIOLATION The response from target was not expected value.\r
+ @retval Others Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiCHAPAuthTarget (\r
+ IN ISCSI_CHAP_AUTH_DATA *AuthData,\r
+ IN UINT8 *TargetResponse\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 SecretSize;\r
+ UINT8 VerifyRsp[ISCSI_CHAP_RSP_LEN];\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ SecretSize = (UINT32) AsciiStrLen (AuthData->AuthConfig->ReverseCHAPSecret);\r
+ Status = IScsiCHAPCalculateResponse (\r
+ AuthData->OutIdentifier,\r
+ AuthData->AuthConfig->ReverseCHAPSecret,\r
+ SecretSize,\r
+ AuthData->OutChallenge,\r
+ AuthData->OutChallengeLength,\r
+ VerifyRsp\r
+ );\r
+\r
+ if (CompareMem (VerifyRsp, TargetResponse, ISCSI_CHAP_RSP_LEN) != 0) {\r
+ Status = EFI_SECURITY_VIOLATION;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ This function checks the received iSCSI Login Response during the security\r
+ negotiation stage.\r
+\r
+ @param[in] Conn The iSCSI connection.\r
+\r
+ @retval EFI_SUCCESS The Login Response passed the CHAP validation.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+ @retval EFI_PROTOCOL_ERROR Some kind of protocol error occurred.\r
+ @retval Others Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiCHAPOnRspReceived (\r
+ IN ISCSI_CONNECTION *Conn\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ ISCSI_SESSION *Session;\r
+ ISCSI_CHAP_AUTH_DATA *AuthData;\r
+ CHAR8 *Value;\r
+ UINT8 *Data;\r
+ UINT32 Len;\r
+ LIST_ENTRY *KeyValueList;\r
+ UINTN Algorithm;\r
+ CHAR8 *Identifier;\r
+ CHAR8 *Challenge;\r
+ CHAR8 *Name;\r
+ CHAR8 *Response;\r
+ UINT8 TargetRsp[ISCSI_CHAP_RSP_LEN];\r
+ UINT32 RspLen;\r
+ UINTN Result;\r
+\r
+ ASSERT (Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION);\r
+ ASSERT (Conn->RspQue.BufNum != 0);\r
+\r
+ Session = Conn->Session;\r
+ AuthData = &Session->AuthData.CHAP;\r
+ Len = Conn->RspQue.BufSize;\r
+ Data = AllocateZeroPool (Len);\r
+ if (Data == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // Copy the data in case the data spans over multiple PDUs.\r
+ //\r
+ NetbufQueCopy (&Conn->RspQue, 0, Len, Data);\r
+\r
+ //\r
+ // Build the key-value list from the data segment of the Login Response.\r
+ //\r
+ KeyValueList = IScsiBuildKeyValueList ((CHAR8 *) Data, Len);\r
+ if (KeyValueList == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = EFI_PROTOCOL_ERROR;\r
+\r
+ switch (Conn->AuthStep) {\r
+ case ISCSI_AUTH_INITIAL:\r
+ //\r
+ // The first Login Response.\r
+ //\r
+ Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_TARGET_PORTAL_GROUP_TAG);\r
+ if (Value == NULL) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Result = IScsiNetNtoi (Value);\r
+ if (Result > 0xFFFF) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Session->TargetPortalGroupTag = (UINT16) Result;\r
+\r
+ Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_AUTH_METHOD);\r
+ if (Value == NULL) {\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // Initiator mandates CHAP authentication but target replies without "CHAP", or\r
+ // initiator suggets "None" but target replies with some kind of auth method.\r
+ //\r
+ if (Session->AuthType == ISCSI_AUTH_TYPE_NONE) {\r
+ if (AsciiStrCmp (Value, ISCSI_KEY_VALUE_NONE) != 0) {\r
+ goto ON_EXIT;\r
+ }\r
+ } else if (Session->AuthType == ISCSI_AUTH_TYPE_CHAP) {\r
+ if (AsciiStrCmp (Value, ISCSI_AUTH_METHOD_CHAP) != 0) {\r
+ goto ON_EXIT;\r
+ }\r
+ } else {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Transit to CHAP step one.\r
+ //\r
+ Conn->AuthStep = ISCSI_CHAP_STEP_ONE;\r
+ Status = EFI_SUCCESS;\r
+ break;\r
+\r
+ case ISCSI_CHAP_STEP_TWO:\r
+ //\r
+ // The Target replies with CHAP_A=<A> CHAP_I=<I> CHAP_C=<C>\r
+ //\r
+ Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_ALGORITHM);\r
+ if (Value == NULL) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Algorithm = IScsiNetNtoi (Value);\r
+ if (Algorithm != ISCSI_CHAP_ALGORITHM_MD5) {\r
+ //\r
+ // Unsupported algorithm is chosen by target.\r
+ //\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Identifier = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_IDENTIFIER);\r
+ if (Identifier == NULL) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Challenge = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_CHALLENGE);\r
+ if (Challenge == NULL) {\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // Process the CHAP identifier and CHAP Challenge from Target.\r
+ // Calculate Response value.\r
+ // \r
+ Result = IScsiNetNtoi (Identifier);\r
+ if (Result > 0xFF) {\r
+ goto ON_EXIT;\r
+ } \r
+ \r
+ AuthData->InIdentifier = (UINT32) Result;\r
+ AuthData->InChallengeLength = ISCSI_CHAP_AUTH_MAX_LEN;\r
+ IScsiHexToBin ((UINT8 *) AuthData->InChallenge, &AuthData->InChallengeLength, Challenge);\r
+ Status = IScsiCHAPCalculateResponse (\r
+ AuthData->InIdentifier,\r
+ AuthData->AuthConfig->CHAPSecret,\r
+ (UINT32) AsciiStrLen (AuthData->AuthConfig->CHAPSecret),\r
+ AuthData->InChallenge,\r
+ AuthData->InChallengeLength,\r
+ AuthData->CHAPResponse\r
+ );\r
+\r
+ //\r
+ // Transit to next step.\r
+ //\r
+ Conn->AuthStep = ISCSI_CHAP_STEP_THREE;\r
+ break;\r
+\r
+ case ISCSI_CHAP_STEP_THREE:\r
+ //\r
+ // One way CHAP authentication and the target would like to\r
+ // authenticate us.\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ break;\r
+\r
+ case ISCSI_CHAP_STEP_FOUR:\r
+ ASSERT (AuthData->AuthConfig->CHAPType == ISCSI_CHAP_MUTUAL);\r
+ //\r
+ // The forth step, CHAP_N=<N> CHAP_R=<R> is received from Target.\r
+ //\r
+ Name = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_NAME);\r
+ if (Name == NULL) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Response = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_RESPONSE);\r
+ if (Response == NULL) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ RspLen = ISCSI_CHAP_RSP_LEN;\r
+ IScsiHexToBin (TargetRsp, &RspLen, Response);\r
+\r
+ //\r
+ // Check the CHAP Name and Response replied by Target.\r
+ //\r
+ Status = IScsiCHAPAuthTarget (AuthData, TargetRsp);\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+\r
+ON_EXIT:\r
+\r
+ if (KeyValueList != NULL) {\r
+ IScsiFreeKeyValueList (KeyValueList);\r
+ } \r
+\r
+ FreePool (Data);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ This function fills the CHAP authentication information into the login PDU\r
+ during the security negotiation stage in the iSCSI connection login.\r
+\r
+ @param[in] Conn The iSCSI connection.\r
+ @param[in, out] Pdu The PDU to send out.\r
+\r
+ @retval EFI_SUCCESS All check passed and the phase-related CHAP\r
+ authentication info is filled into the iSCSI PDU.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+ @retval EFI_PROTOCOL_ERROR Some kind of protocol error occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiCHAPToSendReq (\r
+ IN ISCSI_CONNECTION *Conn,\r
+ IN OUT NET_BUF *Pdu\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ ISCSI_SESSION *Session;\r
+ ISCSI_LOGIN_REQUEST *LoginReq;\r
+ ISCSI_CHAP_AUTH_DATA *AuthData;\r
+ CHAR8 *Value;\r
+ CHAR8 ValueStr[256];\r
+ CHAR8 *Response;\r
+ UINT32 RspLen;\r
+ CHAR8 *Challenge;\r
+ UINT32 ChallengeLen;\r
+\r
+ ASSERT (Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION);\r
+\r
+ Session = Conn->Session;\r
+ AuthData = &Session->AuthData.CHAP;\r
+ LoginReq = (ISCSI_LOGIN_REQUEST *) NetbufGetByte (Pdu, 0, 0);\r
+ Status = EFI_SUCCESS;\r
+\r
+ RspLen = 2 * ISCSI_CHAP_RSP_LEN + 3;\r
+ Response = AllocateZeroPool (RspLen);\r
+ if (Response == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ ChallengeLen = 2 * ISCSI_CHAP_RSP_LEN + 3;\r
+ Challenge = AllocateZeroPool (ChallengeLen);\r
+ if (Challenge == NULL) {\r
+ FreePool (Response);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ switch (Conn->AuthStep) {\r
+ case ISCSI_AUTH_INITIAL:\r
+ //\r
+ // It's the initial Login Request. Fill in the key=value pairs mandatory\r
+ // for the initial Login Request.\r
+ //\r
+ IScsiAddKeyValuePair (Pdu, ISCSI_KEY_INITIATOR_NAME, mPrivate->InitiatorName);\r
+ IScsiAddKeyValuePair (Pdu, ISCSI_KEY_SESSION_TYPE, "Normal");\r
+ IScsiAddKeyValuePair (\r
+ Pdu,\r
+ ISCSI_KEY_TARGET_NAME,\r
+ Session->ConfigData->SessionConfigData.TargetName\r
+ );\r
+\r
+ if (Session->AuthType == ISCSI_AUTH_TYPE_NONE) {\r
+ Value = ISCSI_KEY_VALUE_NONE;\r
+ ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);\r
+ } else {\r
+ Value = ISCSI_AUTH_METHOD_CHAP;\r
+ }\r
+\r
+ IScsiAddKeyValuePair (Pdu, ISCSI_KEY_AUTH_METHOD, Value);\r
+\r
+ break;\r
+\r
+ case ISCSI_CHAP_STEP_ONE:\r
+ //\r
+ // First step, send the Login Request with CHAP_A=<A1,A2...> key-value pair.\r
+ //\r
+ AsciiSPrint (ValueStr, sizeof (ValueStr), "%d", ISCSI_CHAP_ALGORITHM_MD5);\r
+ IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_ALGORITHM, ValueStr);\r
+\r
+ Conn->AuthStep = ISCSI_CHAP_STEP_TWO;\r
+ break;\r
+\r
+ case ISCSI_CHAP_STEP_THREE:\r
+ //\r
+ // Third step, send the Login Request with CHAP_N=<N> CHAP_R=<R> or\r
+ // CHAP_N=<N> CHAP_R=<R> CHAP_I=<I> CHAP_C=<C> if target authentication is\r
+ // required too.\r
+ //\r
+ // CHAP_N=<N>\r
+ //\r
+ IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_NAME, (CHAR8 *) &AuthData->AuthConfig->CHAPName);\r
+ //\r
+ // CHAP_R=<R>\r
+ //\r
+ IScsiBinToHex ((UINT8 *) AuthData->CHAPResponse, ISCSI_CHAP_RSP_LEN, Response, &RspLen);\r
+ IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_RESPONSE, Response);\r
+\r
+ if (AuthData->AuthConfig->CHAPType == ISCSI_CHAP_MUTUAL) {\r
+ //\r
+ // CHAP_I=<I>\r
+ //\r
+ IScsiGenRandom ((UINT8 *) &AuthData->OutIdentifier, 1);\r
+ AsciiSPrint (ValueStr, sizeof (ValueStr), "%d", AuthData->OutIdentifier);\r
+ IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_IDENTIFIER, ValueStr);\r
+ //\r
+ // CHAP_C=<C>\r
+ //\r
+ IScsiGenRandom ((UINT8 *) AuthData->OutChallenge, ISCSI_CHAP_RSP_LEN);\r
+ AuthData->OutChallengeLength = ISCSI_CHAP_RSP_LEN;\r
+ IScsiBinToHex ((UINT8 *) AuthData->OutChallenge, ISCSI_CHAP_RSP_LEN, Challenge, &ChallengeLen);\r
+ IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_CHALLENGE, Challenge);\r
+\r
+ Conn->AuthStep = ISCSI_CHAP_STEP_FOUR;\r
+ }\r
+ //\r
+ // Set the stage transition flag.\r
+ //\r
+ ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);\r
+ break;\r
+\r
+ default:\r
+ Status = EFI_PROTOCOL_ERROR;\r
+ break;\r
+ }\r
+\r
+ FreePool (Response);\r
+ FreePool (Challenge);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+ The header file of CHAP configuration.\r
+\r
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _ISCSI_CHAP_H_\r
+#define _ISCSI_CHAP_H_\r
+\r
+#define ISCSI_CHAP_AUTH_INFO_GUID \\r
+ { \\r
+ 0x786ec0ac, 0x65ae, 0x4d1b, { 0xb1, 0x37, 0xd, 0x11, 0xa, 0x48, 0x37, 0x97 }\\r
+ }\r
+\r
+#define ISCSI_AUTH_METHOD_CHAP "CHAP"\r
+\r
+#define ISCSI_KEY_CHAP_ALGORITHM "CHAP_A"\r
+#define ISCSI_KEY_CHAP_IDENTIFIER "CHAP_I"\r
+#define ISCSI_KEY_CHAP_CHALLENGE "CHAP_C"\r
+#define ISCSI_KEY_CHAP_NAME "CHAP_N"\r
+#define ISCSI_KEY_CHAP_RESPONSE "CHAP_R"\r
+\r
+#define ISCSI_CHAP_ALGORITHM_MD5 5\r
+\r
+#define ISCSI_CHAP_AUTH_MAX_LEN 1024\r
+///\r
+/// MD5_HASHSIZE\r
+///\r
+#define ISCSI_CHAP_RSP_LEN 16 \r
+\r
+#define ISCSI_CHAP_STEP_ONE 1\r
+#define ISCSI_CHAP_STEP_TWO 2\r
+#define ISCSI_CHAP_STEP_THREE 3\r
+#define ISCSI_CHAP_STEP_FOUR 4\r
+\r
+\r
+#pragma pack(1)\r
+\r
+typedef struct _ISCSI_CHAP_AUTH_CONFIG_NVDATA {\r
+ UINT8 CHAPType;\r
+ CHAR8 CHAPName[ISCSI_CHAP_NAME_STORAGE];\r
+ CHAR8 CHAPSecret[ISCSI_CHAP_SECRET_STORAGE];\r
+ CHAR8 ReverseCHAPName[ISCSI_CHAP_NAME_STORAGE];\r
+ CHAR8 ReverseCHAPSecret[ISCSI_CHAP_SECRET_STORAGE];\r
+} ISCSI_CHAP_AUTH_CONFIG_NVDATA;\r
+\r
+#pragma pack()\r
+\r
+///\r
+/// ISCSI CHAP Authentication Data\r
+///\r
+typedef struct _ISCSI_CHAP_AUTH_DATA {\r
+ ISCSI_CHAP_AUTH_CONFIG_NVDATA *AuthConfig;\r
+ UINT32 InIdentifier;\r
+ UINT8 InChallenge[ISCSI_CHAP_AUTH_MAX_LEN];\r
+ UINT32 InChallengeLength;\r
+ //\r
+ // Calculated CHAP Response (CHAP_R) value.\r
+ //\r
+ UINT8 CHAPResponse[ISCSI_CHAP_RSP_LEN];\r
+\r
+ //\r
+ // Auth-data to be sent out for mutual authentication.\r
+ //\r
+ UINT32 OutIdentifier;\r
+ UINT8 OutChallenge[ISCSI_CHAP_AUTH_MAX_LEN];\r
+ UINT32 OutChallengeLength;\r
+} ISCSI_CHAP_AUTH_DATA;\r
+\r
+/**\r
+ This function checks the received iSCSI Login Response during the security\r
+ negotiation stage.\r
+\r
+ @param[in] Conn The iSCSI connection.\r
+\r
+ @retval EFI_SUCCESS The Login Response passed the CHAP validation.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+ @retval EFI_PROTOCOL_ERROR Some kind of protocol error occurred.\r
+ @retval Others Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiCHAPOnRspReceived (\r
+ IN ISCSI_CONNECTION *Conn\r
+ );\r
+/**\r
+ This function fills the CHAP authentication information into the login PDU\r
+ during the security negotiation stage in the iSCSI connection login.\r
+\r
+ @param[in] Conn The iSCSI connection.\r
+ @param[in, out] Pdu The PDU to send out.\r
+\r
+ @retval EFI_SUCCESS All check passed and the phase-related CHAP\r
+ authentication info is filled into the iSCSI PDU.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+ @retval EFI_PROTOCOL_ERROR Some kind of protocol error occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiCHAPToSendReq (\r
+ IN ISCSI_CONNECTION *Conn,\r
+ IN OUT NET_BUF *Pdu\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+ Helper functions for configuring or getting the parameters relating to iSCSI.\r
+\r
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "IScsiImpl.h"\r
+\r
+EFI_GUID mVendorGuid = ISCSI_CONFIG_GUID;\r
+CHAR16 mVendorStorageName[] = L"ISCSI_CONFIG_IFR_NVDATA";\r
+BOOLEAN mIScsiDeviceListUpdated = FALSE;\r
+UINTN mNumberOfIScsiDevices = 0;\r
+ISCSI_FORM_CALLBACK_INFO *mCallbackInfo = NULL;\r
+\r
+HII_VENDOR_DEVICE_PATH mIScsiHiiVendorDevicePath = {\r
+ {\r
+ {\r
+ HARDWARE_DEVICE_PATH,\r
+ HW_VENDOR_DP,\r
+ {\r
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),\r
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)\r
+ }\r
+ },\r
+ //\r
+ // {49D7B73E-143D-4716-977B-C45F1CB038CC}\r
+ //\r
+ { 0x49d7b73e, 0x143d, 0x4716, { 0x97, 0x7b, 0xc4, 0x5f, 0x1c, 0xb0, 0x38, 0xcc } }\r
+ },\r
+ {\r
+ END_DEVICE_PATH_TYPE,\r
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+ { \r
+ (UINT8) (END_DEVICE_PATH_LENGTH),\r
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)\r
+ }\r
+ }\r
+};\r
+\r
+\r
+/**\r
+ Convert the IP address into a dotted string.\r
+\r
+ @param[in] Ip The IP address.\r
+ @param[in] Ipv6Flag Indicates whether the IP address is version 4 or version 6.\r
+ @param[out] Str The formatted IP string.\r
+\r
+**/\r
+VOID\r
+IScsiIpToStr (\r
+ IN EFI_IP_ADDRESS *Ip,\r
+ IN BOOLEAN Ipv6Flag,\r
+ OUT CHAR16 *Str\r
+ )\r
+{\r
+ EFI_IPv4_ADDRESS *Ip4;\r
+ EFI_IPv6_ADDRESS *Ip6;\r
+ UINTN Index;\r
+ BOOLEAN Short;\r
+ UINTN Number;\r
+ CHAR16 FormatString[8];\r
+\r
+ if (!Ipv6Flag) {\r
+ Ip4 = &Ip->v4;\r
+\r
+ UnicodeSPrint (\r
+ Str,\r
+ (UINTN) 2 * IP4_STR_MAX_SIZE,\r
+ L"%d.%d.%d.%d",\r
+ (UINTN) Ip4->Addr[0],\r
+ (UINTN) Ip4->Addr[1],\r
+ (UINTN) Ip4->Addr[2],\r
+ (UINTN) Ip4->Addr[3]\r
+ );\r
+\r
+ return ;\r
+ }\r
+\r
+ Ip6 = &Ip->v6;\r
+ Short = FALSE;\r
+\r
+ for (Index = 0; Index < 15; Index = Index + 2) {\r
+ if (!Short &&\r
+ Index % 2 == 0 &&\r
+ Ip6->Addr[Index] == 0 &&\r
+ Ip6->Addr[Index + 1] == 0\r
+ ) {\r
+ //\r
+ // Deal with the case of ::.\r
+ //\r
+ if (Index == 0) {\r
+ *Str = L':';\r
+ *(Str + 1) = L':';\r
+ Str = Str + 2;\r
+ } else {\r
+ *Str = L':';\r
+ Str = Str + 1;\r
+ }\r
+\r
+ while ((Index < 15) && (Ip6->Addr[Index] == 0) && (Ip6->Addr[Index + 1] == 0)) {\r
+ Index = Index + 2;\r
+ }\r
+\r
+ Short = TRUE;\r
+\r
+ if (Index == 16) {\r
+ //\r
+ // :: is at the end of the address.\r
+ //\r
+ *Str = L'\0';\r
+ break;\r
+ }\r
+ }\r
+\r
+ ASSERT (Index < 15);\r
+\r
+ if (Ip6->Addr[Index] == 0) {\r
+ Number = UnicodeSPrint (Str, 2 * IP_STR_MAX_SIZE, L"%x:", (UINTN) Ip6->Addr[Index + 1]);\r
+ } else {\r
+ if (Ip6->Addr[Index + 1] < 0x10) {\r
+ CopyMem (FormatString, L"%x0%x:", StrSize (L"%x0%x:"));\r
+ } else {\r
+ CopyMem (FormatString, L"%x%x:", StrSize (L"%x%x:"));\r
+ }\r
+\r
+ Number = UnicodeSPrint (\r
+ Str,\r
+ 2 * IP_STR_MAX_SIZE,\r
+ (CONST CHAR16 *) FormatString,\r
+ (UINTN) Ip6->Addr[Index],\r
+ (UINTN) Ip6->Addr[Index + 1]\r
+ );\r
+ }\r
+\r
+ Str = Str + Number;\r
+\r
+ if (Index + 2 == 16) {\r
+ *Str = L'\0';\r
+ if (*(Str - 1) == L':') {\r
+ *(Str - 1) = L'\0';\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Check whether the input IP address is valid.\r
+\r
+ @param[in] Ip The IP address.\r
+ @param[in] IpMode Indicates iSCSI running on IP4 or IP6 stack.\r
+\r
+ @retval TRUE The input IP address is valid.\r
+ @retval FALSE Otherwise\r
+\r
+**/\r
+BOOLEAN\r
+IpIsUnicast (\r
+ IN EFI_IP_ADDRESS *Ip,\r
+ IN UINT8 IpMode\r
+ )\r
+{\r
+ if (IpMode == IP_MODE_IP4) {\r
+ return NetIp4IsUnicast (NTOHL (Ip->Addr[0]), 0);\r
+ } else if (IpMode == IP_MODE_IP6) {\r
+ return NetIp6IsValidUnicast (&Ip->v6);\r
+ } else {\r
+ DEBUG ((DEBUG_ERROR, "IpMode %d is invalid when configuring the iSCSI target IP!\n", IpMode));\r
+ return FALSE;\r
+ }\r
+}\r
+\r
+/**\r
+ Parse IsId in string format and convert it to binary.\r
+\r
+ @param[in] String The buffer of the string to be parsed.\r
+ @param[in, out] IsId The buffer to store IsId.\r
+\r
+ @retval EFI_SUCCESS The operation finished successfully.\r
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiParseIsIdFromString (\r
+ IN CONST CHAR16 *String,\r
+ IN OUT UINT8 *IsId\r
+ )\r
+{\r
+ UINT8 Index;\r
+ CHAR16 *IsIdStr;\r
+ CHAR16 TempStr[3];\r
+ UINTN NodeVal;\r
+ CHAR16 PortString[ISCSI_NAME_IFR_MAX_SIZE];\r
+ EFI_INPUT_KEY Key;\r
+\r
+ if ((String == NULL) || (IsId == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ IsIdStr = (CHAR16 *) String;\r
+\r
+ if (StrLen (IsIdStr) != 6) {\r
+ UnicodeSPrint (\r
+ PortString,\r
+ (UINTN) ISCSI_NAME_IFR_MAX_SIZE,\r
+ L"Error! Input is incorrect, please input 6 hex numbers!\n"\r
+ );\r
+\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ PortString,\r
+ NULL\r
+ );\r
+\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ for (Index = 3; Index < 6; Index++) {\r
+ CopyMem (TempStr, IsIdStr, sizeof (TempStr));\r
+ TempStr[2] = L'\0';\r
+\r
+ //\r
+ // Convert the string to IsId. StrHexToUintn stops at the first character\r
+ // that is not a valid hex character, '\0' here.\r
+ //\r
+ NodeVal = StrHexToUintn (TempStr);\r
+\r
+ IsId[Index] = (UINT8) NodeVal;\r
+\r
+ IsIdStr = IsIdStr + 2;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Convert IsId from binary to string format.\r
+\r
+ @param[out] String The buffer to store the converted string.\r
+ @param[in] IsId The buffer to store IsId.\r
+\r
+ @retval EFI_SUCCESS The string converted successfully.\r
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiConvertIsIdToString (\r
+ OUT CHAR16 *String,\r
+ IN UINT8 *IsId\r
+ )\r
+{\r
+ UINT8 Index;\r
+ UINTN Number;\r
+\r
+ if ((String == NULL) || (IsId == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ for (Index = 0; Index < 6; Index++) {\r
+ if (IsId[Index] <= 0xF) {\r
+ Number = UnicodeSPrint (\r
+ String,\r
+ 2 * ISID_CONFIGURABLE_STORAGE,\r
+ L"0%X",\r
+ (UINTN) IsId[Index]\r
+ );\r
+ } else {\r
+ Number = UnicodeSPrint (\r
+ String,\r
+ 2 * ISID_CONFIGURABLE_STORAGE,\r
+ L"%X",\r
+ (UINTN) IsId[Index]\r
+ );\r
+\r
+ }\r
+\r
+ String = String + Number;\r
+ }\r
+\r
+ *String = L'\0';\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Get the attempt config data from global structure by the ConfigIndex.\r
+\r
+ @param[in] AttemptConfigIndex The unique index indicates the attempt.\r
+\r
+ @return Pointer to the attempt config data.\r
+ @retval NULL The attempt configuration data cannot be found.\r
+\r
+**/\r
+ISCSI_ATTEMPT_CONFIG_NVDATA *\r
+IScsiConfigGetAttemptByConfigIndex (\r
+ IN UINT8 AttemptConfigIndex\r
+ )\r
+{\r
+ LIST_ENTRY *Entry;\r
+ ISCSI_ATTEMPT_CONFIG_NVDATA *Attempt;\r
+\r
+ NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) {\r
+ Attempt = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);\r
+ if (Attempt->AttemptConfigIndex == AttemptConfigIndex) {\r
+ return Attempt;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Get the existing attempt config data from global structure by the NicIndex.\r
+\r
+ @param[in] NewAttempt The created new attempt\r
+ @param[in] IScsiMode The IScsi Mode of the new attempt, Enabled or\r
+ Enabled for MPIO.\r
+\r
+ @return Pointer to the existing attempt config data which\r
+ has the same NICIndex as the new created attempt.\r
+ @retval NULL The attempt with NicIndex does not exist.\r
+\r
+**/\r
+ISCSI_ATTEMPT_CONFIG_NVDATA *\r
+IScsiConfigGetAttemptByNic (\r
+ IN ISCSI_ATTEMPT_CONFIG_NVDATA *NewAttempt,\r
+ IN UINT8 IScsiMode\r
+ )\r
+{\r
+ LIST_ENTRY *Entry;\r
+ ISCSI_ATTEMPT_CONFIG_NVDATA *Attempt;\r
+\r
+ NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) {\r
+ Attempt = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);\r
+ if (Attempt != NewAttempt && Attempt->NicIndex == NewAttempt->NicIndex &&\r
+ Attempt->SessionConfigData.Enabled == IScsiMode) {\r
+ return Attempt;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Convert the iSCSI configuration data into the IFR data.\r
+\r
+ @param[in] Attempt The iSCSI attempt config data.\r
+ @param[in, out] IfrNvData The IFR nv data.\r
+\r
+**/\r
+VOID\r
+IScsiConvertAttemptConfigDataToIfrNvData (\r
+ IN ISCSI_ATTEMPT_CONFIG_NVDATA *Attempt,\r
+ IN OUT ISCSI_CONFIG_IFR_NVDATA *IfrNvData\r
+ )\r
+{\r
+ ISCSI_SESSION_CONFIG_NVDATA *SessionConfigData;\r
+ ISCSI_CHAP_AUTH_CONFIG_NVDATA *AuthConfigData;\r
+ EFI_IP_ADDRESS Ip;\r
+\r
+ //\r
+ // Normal session configuration parameters.\r
+ //\r
+ SessionConfigData = &Attempt->SessionConfigData;\r
+ IfrNvData->Enabled = SessionConfigData->Enabled;\r
+ IfrNvData->IpMode = SessionConfigData->IpMode;\r
+\r
+ IfrNvData->InitiatorInfoFromDhcp = SessionConfigData->InitiatorInfoFromDhcp;\r
+ IfrNvData->TargetInfoFromDhcp = SessionConfigData->TargetInfoFromDhcp;\r
+ IfrNvData->TargetPort = SessionConfigData->TargetPort;\r
+\r
+ if (IfrNvData->IpMode == IP_MODE_IP4) {\r
+ CopyMem (&Ip.v4, &SessionConfigData->LocalIp, sizeof (EFI_IPv4_ADDRESS));\r
+ IScsiIpToStr (&Ip, FALSE, IfrNvData->LocalIp);\r
+ CopyMem (&Ip.v4, &SessionConfigData->SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
+ IScsiIpToStr (&Ip, FALSE, IfrNvData->SubnetMask);\r
+ CopyMem (&Ip.v4, &SessionConfigData->Gateway, sizeof (EFI_IPv4_ADDRESS));\r
+ IScsiIpToStr (&Ip, FALSE, IfrNvData->Gateway);\r
+ CopyMem (&Ip.v4, &SessionConfigData->TargetIp, sizeof (EFI_IPv4_ADDRESS));\r
+ IScsiIpToStr (&Ip, FALSE, IfrNvData->TargetIp);\r
+ } else if (IfrNvData->IpMode == IP_MODE_IP6) {\r
+ ZeroMem (IfrNvData->TargetIp, sizeof (IfrNvData->TargetIp));\r
+ IP6_COPY_ADDRESS (&Ip.v6, &SessionConfigData->TargetIp);\r
+ IScsiIpToStr (&Ip, TRUE, IfrNvData->TargetIp);\r
+ }\r
+\r
+ AsciiStrToUnicodeStr (SessionConfigData->TargetName, IfrNvData->TargetName);\r
+ IScsiLunToUnicodeStr (SessionConfigData->BootLun, IfrNvData->BootLun);\r
+ IScsiConvertIsIdToString (IfrNvData->IsId, SessionConfigData->IsId);\r
+\r
+ IfrNvData->ConnectRetryCount = SessionConfigData->ConnectRetryCount;\r
+ IfrNvData->ConnectTimeout = SessionConfigData->ConnectTimeout;\r
+\r
+ //\r
+ // Authentication parameters.\r
+ //\r
+ IfrNvData->AuthenticationType = Attempt->AuthenticationType;\r
+\r
+ if (IfrNvData->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) {\r
+ AuthConfigData = &Attempt->AuthConfigData.CHAP;\r
+ IfrNvData->CHAPType = AuthConfigData->CHAPType;\r
+ AsciiStrToUnicodeStr (AuthConfigData->CHAPName, IfrNvData->CHAPName);\r
+ AsciiStrToUnicodeStr (AuthConfigData->CHAPSecret, IfrNvData->CHAPSecret);\r
+ AsciiStrToUnicodeStr (AuthConfigData->ReverseCHAPName, IfrNvData->ReverseCHAPName);\r
+ AsciiStrToUnicodeStr (AuthConfigData->ReverseCHAPSecret, IfrNvData->ReverseCHAPSecret);\r
+ }\r
+\r
+ //\r
+ // Other parameters.\r
+ //\r
+ AsciiStrToUnicodeStr (Attempt->AttemptName, IfrNvData->AttemptName);\r
+}\r
+\r
+\r
+/**\r
+ Convert the IFR data to iSCSI configuration data.\r
+\r
+ @param[in] IfrNvData The IFR nv data.\r
+ @param[in, out] Attempt The iSCSI attempt config data.\r
+\r
+ @retval EFI_INVALID_PARAMETER Any input or configured parameter is invalid.\r
+ @retval EFI_NOT_FOUND Cannot find the corresponding variable.\r
+ @retval EFI_SUCCESS The operation is completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiConvertIfrNvDataToAttemptConfigData (\r
+ IN ISCSI_CONFIG_IFR_NVDATA *IfrNvData,\r
+ IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA *Attempt\r
+ )\r
+{\r
+ EFI_IP_ADDRESS HostIp;\r
+ EFI_IP_ADDRESS SubnetMask;\r
+ EFI_IP_ADDRESS Gateway;\r
+ CHAR16 *MacString;\r
+ CHAR16 *AttemptName1;\r
+ CHAR16 *AttemptName2;\r
+ ISCSI_ATTEMPT_CONFIG_NVDATA *ExistAttempt;\r
+ ISCSI_ATTEMPT_CONFIG_NVDATA *SameNicAttempt;\r
+ CHAR16 IScsiMode[64];\r
+ CHAR16 IpMode[64];\r
+ ISCSI_NIC_INFO *NicInfo;\r
+ EFI_INPUT_KEY Key;\r
+\r
+ if (IfrNvData == NULL || Attempt == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Update those fields which don't have INTERACTIVE attribute.\r
+ //\r
+ Attempt->SessionConfigData.ConnectRetryCount = IfrNvData->ConnectRetryCount;\r
+ Attempt->SessionConfigData.ConnectTimeout = IfrNvData->ConnectTimeout;\r
+ Attempt->SessionConfigData.IpMode = IfrNvData->IpMode;\r
+\r
+ if (IfrNvData->IpMode < IP_MODE_AUTOCONFIG) {\r
+ Attempt->SessionConfigData.InitiatorInfoFromDhcp = IfrNvData->InitiatorInfoFromDhcp;\r
+ Attempt->SessionConfigData.TargetPort = IfrNvData->TargetPort;\r
+\r
+ if (Attempt->SessionConfigData.TargetPort == 0) {\r
+ Attempt->SessionConfigData.TargetPort = ISCSI_WELL_KNOWN_PORT;\r
+ }\r
+\r
+ Attempt->SessionConfigData.TargetInfoFromDhcp = IfrNvData->TargetInfoFromDhcp;\r
+ }\r
+\r
+ Attempt->AuthenticationType = IfrNvData->AuthenticationType;\r
+\r
+ if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) {\r
+ Attempt->AuthConfigData.CHAP.CHAPType = IfrNvData->CHAPType;\r
+ }\r
+\r
+ //\r
+ // Only do full parameter validation if iSCSI is enabled on this device.\r
+ //\r
+ if (IfrNvData->Enabled != ISCSI_DISABLED) {\r
+ if (Attempt->SessionConfigData.ConnectTimeout < CONNECT_MIN_TIMEOUT) {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Connection Establishing Timeout is less than minimum value 100ms.",\r
+ NULL\r
+ );\r
+ \r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Validate the address configuration of the Initiator if DHCP isn't\r
+ // deployed.\r
+ //\r
+ if (!Attempt->SessionConfigData.InitiatorInfoFromDhcp) {\r
+ CopyMem (&HostIp.v4, &Attempt->SessionConfigData.LocalIp, sizeof (HostIp.v4));\r
+ CopyMem (&SubnetMask.v4, &Attempt->SessionConfigData.SubnetMask, sizeof (SubnetMask.v4));\r
+ CopyMem (&Gateway.v4, &Attempt->SessionConfigData.Gateway, sizeof (Gateway.v4));\r
+\r
+ if ((Gateway.Addr[0] != 0)) {\r
+ if (SubnetMask.Addr[0] == 0) {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Gateway address is set but subnet mask is zero.",\r
+ NULL\r
+ );\r
+ \r
+ return EFI_INVALID_PARAMETER;\r
+ } else if (!IP4_NET_EQUAL (HostIp.Addr[0], Gateway.Addr[0], SubnetMask.Addr[0])) {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Local IP and Gateway are not in the same subnet.",\r
+ NULL\r
+ );\r
+ \r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // Validate target configuration if DHCP isn't deployed.\r
+ //\r
+ if (!Attempt->SessionConfigData.TargetInfoFromDhcp && Attempt->SessionConfigData.IpMode < IP_MODE_AUTOCONFIG) {\r
+ if (!IpIsUnicast (&Attempt->SessionConfigData.TargetIp, IfrNvData->IpMode)) {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Target IP is invalid!",\r
+ NULL\r
+ );\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ //\r
+ // Validate the authentication info.\r
+ //\r
+ if (IfrNvData->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) {\r
+ if ((IfrNvData->CHAPName[0] == '\0') || (IfrNvData->CHAPSecret[0] == '\0')) {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"CHAP Name or CHAP Secret is invalid!",\r
+ NULL\r
+ );\r
+ \r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((IfrNvData->CHAPType == ISCSI_CHAP_MUTUAL) &&\r
+ ((IfrNvData->ReverseCHAPName[0] == '\0') || (IfrNvData->ReverseCHAPSecret[0] == '\0'))\r
+ ) {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Reverse CHAP Name or Reverse CHAP Secret is invalid!",\r
+ NULL\r
+ ); \r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Check whether this attempt uses NIC which is already used by existing attempt.\r
+ //\r
+ SameNicAttempt = IScsiConfigGetAttemptByNic (Attempt, IfrNvData->Enabled);\r
+ if (SameNicAttempt != NULL) {\r
+ AttemptName1 = (CHAR16 *) AllocateZeroPool (ATTEMPT_NAME_MAX_SIZE * sizeof (CHAR16));\r
+ if (AttemptName1 == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ AttemptName2 = (CHAR16 *) AllocateZeroPool (ATTEMPT_NAME_MAX_SIZE * sizeof (CHAR16));\r
+ if (AttemptName2 == NULL) {\r
+ FreePool (AttemptName1);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ } \r
+ \r
+ AsciiStrToUnicodeStr (Attempt->AttemptName, AttemptName1);\r
+ if (StrLen (AttemptName1) > ATTEMPT_NAME_SIZE) {\r
+ CopyMem (&AttemptName1[ATTEMPT_NAME_SIZE], L"...", 4 * sizeof (CHAR16));\r
+ }\r
+\r
+ AsciiStrToUnicodeStr (SameNicAttempt->AttemptName, AttemptName2);\r
+ if (StrLen (AttemptName2) > ATTEMPT_NAME_SIZE) {\r
+ CopyMem (&AttemptName2[ATTEMPT_NAME_SIZE], L"...", 4 * sizeof (CHAR16));\r
+ }\r
+\r
+ UnicodeSPrint (\r
+ mPrivate->PortString,\r
+ (UINTN) ISCSI_NAME_IFR_MAX_SIZE,\r
+ L"Warning! Attempt \"%s\" uses same NIC as Attempt \"%s\".",\r
+ AttemptName1,\r
+ AttemptName2\r
+ );\r
+\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ mPrivate->PortString,\r
+ NULL\r
+ ); \r
+\r
+ FreePool (AttemptName1);\r
+ FreePool (AttemptName2);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Check whether this attempt is an existing one.\r
+ //\r
+ ExistAttempt = IScsiConfigGetAttemptByConfigIndex (Attempt->AttemptConfigIndex);\r
+ if (ExistAttempt != NULL) {\r
+ ASSERT (ExistAttempt == Attempt);\r
+\r
+ if (IfrNvData->Enabled == ISCSI_DISABLED &&\r
+ Attempt->SessionConfigData.Enabled != ISCSI_DISABLED) {\r
+\r
+ //\r
+ // User updates the Attempt from "Enabled"/"Enabled for MPIO" to "Disabled".\r
+ //\r
+ if (Attempt->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {\r
+ if (mPrivate->MpioCount < 1) {\r
+ return EFI_ABORTED;\r
+ }\r
+\r
+ if (--mPrivate->MpioCount == 0) {\r
+ mPrivate->EnableMpio = FALSE;\r
+ }\r
+ } else if (Attempt->SessionConfigData.Enabled == ISCSI_ENABLED) {\r
+ if (mPrivate->SinglePathCount < 1) {\r
+ return EFI_ABORTED;\r
+ }\r
+ mPrivate->SinglePathCount--;\r
+ }\r
+\r
+ } else if (IfrNvData->Enabled == ISCSI_ENABLED_FOR_MPIO &&\r
+ Attempt->SessionConfigData.Enabled == ISCSI_ENABLED) {\r
+ //\r
+ // User updates the Attempt from "Enabled" to "Enabled for MPIO".\r
+ //\r
+ if (mPrivate->SinglePathCount < 1) {\r
+ return EFI_ABORTED;\r
+ }\r
+\r
+ mPrivate->EnableMpio = TRUE;\r
+ mPrivate->MpioCount++;\r
+ mPrivate->SinglePathCount--;\r
+\r
+ } else if (IfrNvData->Enabled == ISCSI_ENABLED &&\r
+ Attempt->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {\r
+ //\r
+ // User updates the Attempt from "Enabled for MPIO" to "Enabled".\r
+ //\r
+ if (mPrivate->MpioCount < 1) {\r
+ return EFI_ABORTED;\r
+ }\r
+\r
+ if (--mPrivate->MpioCount == 0) {\r
+ mPrivate->EnableMpio = FALSE;\r
+ }\r
+ mPrivate->SinglePathCount++;\r
+\r
+ } else if (IfrNvData->Enabled != ISCSI_DISABLED &&\r
+ Attempt->SessionConfigData.Enabled == ISCSI_DISABLED) {\r
+ //\r
+ // User updates the Attempt from "Disabled" to "Enabled"/"Enabled for MPIO".\r
+ //\r
+ if (IfrNvData->Enabled == ISCSI_ENABLED_FOR_MPIO) {\r
+ mPrivate->EnableMpio = TRUE;\r
+ mPrivate->MpioCount++;\r
+\r
+ } else if (IfrNvData->Enabled == ISCSI_ENABLED) {\r
+ mPrivate->SinglePathCount++;\r
+ }\r
+ }\r
+\r
+ } else if (ExistAttempt == NULL && IfrNvData->Enabled != ISCSI_DISABLED) {\r
+ if (IfrNvData->Enabled == ISCSI_ENABLED_FOR_MPIO) {\r
+ //\r
+ // This new Attempt is enabled for MPIO; enable the multipath mode.\r
+ //\r
+ mPrivate->EnableMpio = TRUE;\r
+ mPrivate->MpioCount++;\r
+ } else if (IfrNvData->Enabled == ISCSI_ENABLED) {\r
+ mPrivate->SinglePathCount++;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Update the iSCSI Mode data and record it in attempt help info.\r
+ //\r
+ Attempt->SessionConfigData.Enabled = IfrNvData->Enabled;\r
+ if (IfrNvData->Enabled == ISCSI_DISABLED) {\r
+ UnicodeSPrint (IScsiMode, 64, L"Disabled");\r
+ } else if (IfrNvData->Enabled == ISCSI_ENABLED) {\r
+ UnicodeSPrint (IScsiMode, 64, L"Enabled");\r
+ } else if (IfrNvData->Enabled == ISCSI_ENABLED_FOR_MPIO) {\r
+ UnicodeSPrint (IScsiMode, 64, L"Enabled for MPIO");\r
+ }\r
+\r
+ if (IfrNvData->IpMode == IP_MODE_IP4) {\r
+ UnicodeSPrint (IpMode, 64, L"IP4");\r
+ } else if (IfrNvData->IpMode == IP_MODE_IP6) {\r
+ UnicodeSPrint (IpMode, 64, L"IP6");\r
+ } else if (IfrNvData->IpMode == IP_MODE_AUTOCONFIG) {\r
+ UnicodeSPrint (IpMode, 64, L"Autoconfigure");\r
+ }\r
+\r
+ NicInfo = IScsiGetNicInfoByIndex (Attempt->NicIndex);\r
+ if (NicInfo == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ MacString = (CHAR16 *) AllocateZeroPool (ISCSI_MAX_MAC_STRING_LEN * sizeof (CHAR16));\r
+ if (MacString == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ AsciiStrToUnicodeStr (Attempt->MacString, MacString);\r
+\r
+ UnicodeSPrint (\r
+ mPrivate->PortString,\r
+ (UINTN) ISCSI_NAME_IFR_MAX_SIZE,\r
+ L"MAC: %s, PFA: Bus %d | Dev %d | Func %d, iSCSI mode: %s, IP version: %s",\r
+ MacString,\r
+ NicInfo->BusNumber,\r
+ NicInfo->DeviceNumber,\r
+ NicInfo->FunctionNumber,\r
+ IScsiMode,\r
+ IpMode\r
+ );\r
+\r
+ Attempt->AttemptTitleHelpToken = HiiSetString (\r
+ mCallbackInfo->RegisteredHandle,\r
+ Attempt->AttemptTitleHelpToken,\r
+ mPrivate->PortString,\r
+ NULL\r
+ );\r
+ if (Attempt->AttemptTitleHelpToken == 0) {\r
+ FreePool (MacString);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Record the user configuration information in NVR.\r
+ //\r
+ UnicodeSPrint (\r
+ mPrivate->PortString,\r
+ (UINTN) ISCSI_NAME_IFR_MAX_SIZE,\r
+ L"%s%d",\r
+ MacString,\r
+ (UINTN) Attempt->AttemptConfigIndex\r
+ );\r
+\r
+ FreePool (MacString);\r
+\r
+ return gRT->SetVariable (\r
+ mPrivate->PortString,\r
+ &gEfiIScsiInitiatorNameProtocolGuid,\r
+ ISCSI_CONFIG_VAR_ATTR,\r
+ sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),\r
+ Attempt\r
+ );\r
+}\r
+\r
+/**\r
+ Create Hii Extend Label OpCode as the start opcode and end opcode. It is \r
+ a help function.\r
+\r
+ @param[in] StartLabelNumber The number of start label.\r
+ @param[out] StartOpCodeHandle Points to the start opcode handle.\r
+ @param[out] StartLabel Points to the created start opcode.\r
+ @param[out] EndOpCodeHandle Points to the end opcode handle.\r
+ @param[out] EndLabel Points to the created end opcode.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Do not have sufficient resource to finish this\r
+ operation.\r
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid. \r
+ @retval EFI_SUCCESS The operation is completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiCreateOpCode (\r
+ IN UINT16 StartLabelNumber,\r
+ OUT VOID **StartOpCodeHandle,\r
+ OUT EFI_IFR_GUID_LABEL **StartLabel,\r
+ OUT VOID **EndOpCodeHandle,\r
+ OUT EFI_IFR_GUID_LABEL **EndLabel\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_IFR_GUID_LABEL *InternalStartLabel;\r
+ EFI_IFR_GUID_LABEL *InternalEndLabel;\r
+\r
+ if (StartOpCodeHandle == NULL || StartLabel == NULL || EndOpCodeHandle == NULL || EndLabel == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *StartOpCodeHandle = NULL;\r
+ *EndOpCodeHandle = NULL;\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+\r
+ //\r
+ // Initialize the container for dynamic opcodes.\r
+ //\r
+ *StartOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+ if (*StartOpCodeHandle == NULL) {\r
+ return Status;\r
+ }\r
+\r
+ *EndOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+ if (*EndOpCodeHandle == NULL) {\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Create Hii Extend Label OpCode as the start opcode.\r
+ //\r
+ InternalStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
+ *StartOpCodeHandle,\r
+ &gEfiIfrTianoGuid,\r
+ NULL,\r
+ sizeof (EFI_IFR_GUID_LABEL)\r
+ );\r
+ if (InternalStartLabel == NULL) {\r
+ goto Exit;\r
+ }\r
+ \r
+ InternalStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
+ InternalStartLabel->Number = StartLabelNumber;\r
+\r
+ //\r
+ // Create Hii Extend Label OpCode as the end opcode.\r
+ //\r
+ InternalEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
+ *EndOpCodeHandle,\r
+ &gEfiIfrTianoGuid,\r
+ NULL,\r
+ sizeof (EFI_IFR_GUID_LABEL)\r
+ );\r
+ if (InternalEndLabel == NULL) {\r
+ goto Exit;\r
+ }\r
+\r
+ InternalEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
+ InternalEndLabel->Number = LABEL_END;\r
+\r
+ *StartLabel = InternalStartLabel;\r
+ *EndLabel = InternalEndLabel;\r
+\r
+ return EFI_SUCCESS;\r
+\r
+Exit:\r
+\r
+ if (*StartOpCodeHandle != NULL) {\r
+ HiiFreeOpCodeHandle (*StartOpCodeHandle);\r
+ }\r
+\r
+ if (*EndOpCodeHandle != NULL) {\r
+ HiiFreeOpCodeHandle (*EndOpCodeHandle);\r
+ }\r
+ \r
+ return Status;\r
+}\r
+\r
+/**\r
+ Callback function when user presses "Add an Attempt".\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Does not have sufficient resources to finish this\r
+ operation.\r
+ @retval EFI_SUCCESS The operation is completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiConfigAddAttempt (\r
+ VOID\r
+ )\r
+{\r
+ LIST_ENTRY *Entry;\r
+ ISCSI_NIC_INFO *NicInfo;\r
+ EFI_STRING_ID PortTitleToken;\r
+ EFI_STRING_ID PortTitleHelpToken;\r
+ CHAR16 MacString[ISCSI_MAX_MAC_STRING_LEN];\r
+ EFI_STATUS Status;\r
+ VOID *StartOpCodeHandle;\r
+ EFI_IFR_GUID_LABEL *StartLabel;\r
+ VOID *EndOpCodeHandle;\r
+ EFI_IFR_GUID_LABEL *EndLabel;\r
+\r
+ Status = IScsiCreateOpCode (\r
+ MAC_ENTRY_LABEL,\r
+ &StartOpCodeHandle,\r
+ &StartLabel,\r
+ &EndOpCodeHandle,\r
+ &EndLabel\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Ask user to select a MAC for this attempt.\r
+ //\r
+ NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {\r
+ NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);\r
+ IScsiMacAddrToStr (\r
+ &NicInfo->PermanentAddress,\r
+ NicInfo->HwAddressSize,\r
+ NicInfo->VlanId,\r
+ MacString\r
+ );\r
+\r
+ UnicodeSPrint (mPrivate->PortString, (UINTN) ISCSI_NAME_IFR_MAX_SIZE, L"Port %s", MacString);\r
+ PortTitleToken = HiiSetString (\r
+ mCallbackInfo->RegisteredHandle,\r
+ 0,\r
+ mPrivate->PortString,\r
+ NULL\r
+ );\r
+ if (PortTitleToken == 0) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Exit;\r
+ }\r
+\r
+ UnicodeSPrint (\r
+ mPrivate->PortString,\r
+ (UINTN) ISCSI_NAME_IFR_MAX_SIZE,\r
+ L"PFA: Bus %d | Dev %d | Func %d",\r
+ NicInfo->BusNumber,\r
+ NicInfo->DeviceNumber,\r
+ NicInfo->FunctionNumber\r
+ );\r
+ PortTitleHelpToken = HiiSetString (mCallbackInfo->RegisteredHandle, 0, mPrivate->PortString, NULL);\r
+ if (PortTitleHelpToken == 0) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Exit; \r
+ }\r
+\r
+ HiiCreateGotoOpCode (\r
+ StartOpCodeHandle, // Container for dynamic created opcodes\r
+ FORMID_ATTEMPT_FORM,\r
+ PortTitleToken,\r
+ PortTitleHelpToken,\r
+ EFI_IFR_FLAG_CALLBACK, // Question flag\r
+ (UINT16) (KEY_MAC_ENTRY_BASE + NicInfo->NicIndex)\r
+ );\r
+ }\r
+\r
+ Status = HiiUpdateForm (\r
+ mCallbackInfo->RegisteredHandle, // HII handle\r
+ &mVendorGuid, // Formset GUID\r
+ FORMID_MAC_FORM, // Form ID\r
+ StartOpCodeHandle, // Label for where to insert opcodes\r
+ EndOpCodeHandle // Replace data\r
+ );\r
+\r
+Exit:\r
+ HiiFreeOpCodeHandle (StartOpCodeHandle);\r
+ HiiFreeOpCodeHandle (EndOpCodeHandle);\r
+ \r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Update the MAIN form to display the configured attempts.\r
+\r
+**/\r
+VOID\r
+IScsiConfigUpdateAttempt (\r
+ VOID\r
+ )\r
+{\r
+ CHAR16 AttemptName[ATTEMPT_NAME_MAX_SIZE];\r
+ LIST_ENTRY *Entry;\r
+ ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;\r
+ VOID *StartOpCodeHandle;\r
+ EFI_IFR_GUID_LABEL *StartLabel;\r
+ VOID *EndOpCodeHandle;\r
+ EFI_IFR_GUID_LABEL *EndLabel;\r
+ EFI_STATUS Status;\r
+\r
+ Status = IScsiCreateOpCode (\r
+ ATTEMPT_ENTRY_LABEL,\r
+ &StartOpCodeHandle,\r
+ &StartLabel,\r
+ &EndOpCodeHandle,\r
+ &EndLabel\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return ;\r
+ }\r
+\r
+ NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) {\r
+ AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);\r
+\r
+ AsciiStrToUnicodeStr (AttemptConfigData->AttemptName, AttemptName);\r
+ UnicodeSPrint (mPrivate->PortString, (UINTN) 128, L"Attempt %s", AttemptName);\r
+ AttemptConfigData->AttemptTitleToken = HiiSetString (\r
+ mCallbackInfo->RegisteredHandle,\r
+ 0,\r
+ mPrivate->PortString,\r
+ NULL\r
+ );\r
+ if (AttemptConfigData->AttemptTitleToken == 0) {\r
+ return ;\r
+ }\r
+\r
+ HiiCreateGotoOpCode (\r
+ StartOpCodeHandle, // Container for dynamic created opcodes\r
+ FORMID_ATTEMPT_FORM, // Form ID\r
+ AttemptConfigData->AttemptTitleToken, // Prompt text\r
+ AttemptConfigData->AttemptTitleHelpToken, // Help text\r
+ EFI_IFR_FLAG_CALLBACK, // Question flag\r
+ (UINT16) (KEY_ATTEMPT_ENTRY_BASE + AttemptConfigData->AttemptConfigIndex) // Question ID\r
+ );\r
+ }\r
+\r
+ HiiUpdateForm (\r
+ mCallbackInfo->RegisteredHandle, // HII handle\r
+ &mVendorGuid, // Formset GUID\r
+ FORMID_MAIN_FORM, // Form ID\r
+ StartOpCodeHandle, // Label for where to insert opcodes\r
+ EndOpCodeHandle // Replace data\r
+ ); \r
+\r
+ HiiFreeOpCodeHandle (StartOpCodeHandle);\r
+ HiiFreeOpCodeHandle (EndOpCodeHandle);\r
+}\r
+\r
+\r
+/**\r
+ Callback function when user presses "Commit Changes and Exit" in Delete Attempts.\r
+\r
+ @param[in] IfrNvData The IFR NV data.\r
+\r
+ @retval EFI_NOT_FOUND Cannot find the corresponding variable.\r
+ @retval EFI_SUCCESS The operation is completed successfully.\r
+ @retval EFI_ABOTRED This operation is aborted cause of error\r
+ configuration.\r
+ @retval EFI_OUT_OF_RESOURCES Fail to finish the operation due to lack of\r
+ resources.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiConfigDeleteAttempts (\r
+ IN ISCSI_CONFIG_IFR_NVDATA *IfrNvData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ UINTN NewIndex;\r
+ ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;\r
+ UINT8 *AttemptConfigOrder;\r
+ UINTN AttemptConfigOrderSize;\r
+ UINT8 *AttemptNewOrder;\r
+ UINT32 Attribute;\r
+ UINTN Total;\r
+ UINTN NewTotal;\r
+ LIST_ENTRY *Entry;\r
+ LIST_ENTRY *NextEntry;\r
+ CHAR16 MacString[ISCSI_MAX_MAC_STRING_LEN];\r
+\r
+ AttemptConfigOrder = IScsiGetVariableAndSize (\r
+ L"AttemptOrder",\r
+ &mVendorGuid,\r
+ &AttemptConfigOrderSize\r
+ );\r
+ if ((AttemptConfigOrder == NULL) || (AttemptConfigOrderSize == 0)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ AttemptNewOrder = AllocateZeroPool (AttemptConfigOrderSize);\r
+ if (AttemptNewOrder == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Total = AttemptConfigOrderSize / sizeof (UINT8);\r
+ NewTotal = Total;\r
+ Index = 0;\r
+\r
+ NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &mPrivate->AttemptConfigs) {\r
+ if (IfrNvData->DeleteAttemptList[Index] == 0) {\r
+ Index++;\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Delete the attempt.\r
+ //\r
+\r
+ AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);\r
+ if (AttemptConfigData == NULL) {\r
+ Status = EFI_NOT_FOUND;\r
+ goto Error;\r
+ }\r
+\r
+ //\r
+ // Remove this attempt from UI configured attempt list.\r
+ //\r
+ RemoveEntryList (&AttemptConfigData->Link);\r
+ mPrivate->AttemptCount--;\r
+\r
+ if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {\r
+ if (mPrivate->MpioCount < 1) {\r
+ Status = EFI_ABORTED;\r
+ goto Error;\r
+ }\r
+\r
+ //\r
+ // No more attempt is enabled for MPIO. Transit the iSCSI mode to single path.\r
+ //\r
+ if (--mPrivate->MpioCount == 0) {\r
+ mPrivate->EnableMpio = FALSE;\r
+ }\r
+ } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) {\r
+ if (mPrivate->SinglePathCount < 1) {\r
+ Status = EFI_ABORTED;\r
+ goto Error;\r
+ }\r
+\r
+ mPrivate->SinglePathCount--;\r
+ }\r
+\r
+ AsciiStrToUnicodeStr (AttemptConfigData->MacString, MacString);\r
+\r
+ UnicodeSPrint (\r
+ mPrivate->PortString,\r
+ (UINTN) 128,\r
+ L"%s%d",\r
+ MacString,\r
+ (UINTN) AttemptConfigData->AttemptConfigIndex\r
+ );\r
+\r
+ gRT->SetVariable (\r
+ mPrivate->PortString,\r
+ &gEfiIScsiInitiatorNameProtocolGuid,\r
+ 0,\r
+ 0,\r
+ NULL\r
+ );\r
+\r
+ //\r
+ // Mark the attempt order in NVR to be deleted - 0.\r
+ //\r
+ for (NewIndex = 0; NewIndex < Total; NewIndex++) {\r
+ if (AttemptConfigOrder[NewIndex] == AttemptConfigData->AttemptConfigIndex) {\r
+ AttemptConfigOrder[NewIndex] = 0;\r
+ break;\r
+ }\r
+ }\r
+\r
+ NewTotal--;\r
+ FreePool (AttemptConfigData);\r
+\r
+ //\r
+ // Check next Attempt.\r
+ //\r
+ Index++;\r
+ }\r
+\r
+ //\r
+ // Construct AttemptNewOrder.\r
+ //\r
+ for (Index = 0, NewIndex = 0; Index < Total; Index++) {\r
+ if (AttemptConfigOrder[Index] != 0) {\r
+ AttemptNewOrder[NewIndex] = AttemptConfigOrder[Index];\r
+ NewIndex++;\r
+ }\r
+ }\r
+\r
+ Attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS\r
+ | EFI_VARIABLE_NON_VOLATILE;\r
+\r
+ //\r
+ // Update AttemptOrder in NVR.\r
+ //\r
+ Status = gRT->SetVariable (\r
+ L"AttemptOrder",\r
+ &mVendorGuid,\r
+ Attribute,\r
+ NewTotal * sizeof (UINT8),\r
+ AttemptNewOrder\r
+ );\r
+\r
+Error:\r
+ FreePool (AttemptConfigOrder);\r
+ FreePool (AttemptNewOrder);\r
+ \r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Callback function when user presses "Delete Attempts".\r
+\r
+ @param[in] IfrNvData The IFR nv data.\r
+\r
+ @retval EFI_INVALID_PARAMETER Any parameter is invalid.\r
+ @retval EFI_BUFFER_TOO_SMALL The buffer in UpdateData is too small.\r
+ @retval EFI_SUCCESS The operation is completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiConfigDisplayDeleteAttempts (\r
+ IN ISCSI_CONFIG_IFR_NVDATA *IfrNvData\r
+ )\r
+{\r
+\r
+ UINT8 *AttemptConfigOrder;\r
+ UINTN AttemptConfigOrderSize;\r
+ LIST_ENTRY *Entry;\r
+ ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;\r
+ UINT8 Index;\r
+ VOID *StartOpCodeHandle;\r
+ EFI_IFR_GUID_LABEL *StartLabel;\r
+ VOID *EndOpCodeHandle;\r
+ EFI_IFR_GUID_LABEL *EndLabel;\r
+ EFI_STATUS Status;\r
+\r
+ Status = IScsiCreateOpCode (\r
+ DELETE_ENTRY_LABEL,\r
+ &StartOpCodeHandle,\r
+ &StartLabel,\r
+ &EndOpCodeHandle,\r
+ &EndLabel\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ AttemptConfigOrder = IScsiGetVariableAndSize (\r
+ L"AttemptOrder",\r
+ &mVendorGuid,\r
+ &AttemptConfigOrderSize\r
+ );\r
+ if (AttemptConfigOrder != NULL) {\r
+ //\r
+ // Create the check box opcode to be deleted.\r
+ //\r
+ Index = 0;\r
+\r
+ NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) {\r
+ AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);\r
+ IfrNvData->DeleteAttemptList[Index] = 0x00;\r
+\r
+ HiiCreateCheckBoxOpCode(\r
+ StartOpCodeHandle,\r
+ (EFI_QUESTION_ID) (ATTEMPT_DEL_QUESTION_ID + Index),\r
+ CONFIGURATION_VARSTORE_ID,\r
+ (UINT16) (ATTEMPT_DEL_VAR_OFFSET + Index),\r
+ AttemptConfigData->AttemptTitleToken,\r
+ AttemptConfigData->AttemptTitleHelpToken,\r
+ 0,\r
+ 0,\r
+ NULL\r
+ );\r
+\r
+ Index++;\r
+\r
+ if (Index == ISCSI_MAX_ATTEMPTS_NUM) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ FreePool (AttemptConfigOrder);\r
+ }\r
+\r
+ Status = HiiUpdateForm (\r
+ mCallbackInfo->RegisteredHandle, // HII handle\r
+ &mVendorGuid, // Formset GUID\r
+ FORMID_DELETE_FORM, // Form ID\r
+ StartOpCodeHandle, // Label for where to insert opcodes\r
+ EndOpCodeHandle // Replace data\r
+ ); \r
+\r
+ HiiFreeOpCodeHandle (StartOpCodeHandle);\r
+ HiiFreeOpCodeHandle (EndOpCodeHandle);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Callback function when user presses "Change Attempt Order".\r
+\r
+ @retval EFI_INVALID_PARAMETER Any parameter is invalid.\r
+ @retval EFI_OUT_OF_RESOURCES Does not have sufficient resources to finish this\r
+ operation.\r
+ @retval EFI_SUCCESS The operation is completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiConfigDisplayOrderAttempts (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 Index;\r
+ LIST_ENTRY *Entry;\r
+ ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;\r
+ VOID *StartOpCodeHandle;\r
+ EFI_IFR_GUID_LABEL *StartLabel;\r
+ VOID *EndOpCodeHandle;\r
+ EFI_IFR_GUID_LABEL *EndLabel;\r
+ VOID *OptionsOpCodeHandle; \r
+ \r
+ Status = IScsiCreateOpCode (\r
+ ORDER_ENTRY_LABEL,\r
+ &StartOpCodeHandle,\r
+ &StartLabel,\r
+ &EndOpCodeHandle,\r
+ &EndLabel\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ OptionsOpCodeHandle = NULL;\r
+\r
+ //\r
+ // If no attempt to be ordered, update the original form and exit.\r
+ //\r
+ if (mPrivate->AttemptCount == 0) {\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Create Option OpCode.\r
+ //\r
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+ if (OptionsOpCodeHandle == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error;\r
+ }\r
+\r
+ Index = 0;\r
+\r
+ NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) {\r
+ AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);\r
+ HiiCreateOneOfOptionOpCode (\r
+ OptionsOpCodeHandle,\r
+ AttemptConfigData->AttemptTitleToken,\r
+ 0,\r
+ EFI_IFR_NUMERIC_SIZE_1,\r
+ AttemptConfigData->AttemptConfigIndex\r
+ );\r
+ Index++;\r
+ }\r
+\r
+ ASSERT (Index == mPrivate->AttemptCount);\r
+\r
+ HiiCreateOrderedListOpCode (\r
+ StartOpCodeHandle, // Container for dynamic created opcodes\r
+ DYNAMIC_ORDERED_LIST_QUESTION_ID, // Question ID\r
+ CONFIGURATION_VARSTORE_ID, // VarStore ID\r
+ DYNAMIC_ORDERED_LIST_VAR_OFFSET, // Offset in Buffer Storage\r
+ STRING_TOKEN (STR_ORDER_ATTEMPT_ENTRY), // Question prompt text \r
+ STRING_TOKEN (STR_ORDER_ATTEMPT_ENTRY), // Question help text \r
+ 0, // Question flag\r
+ EFI_IFR_UNIQUE_SET, // Ordered list flag, e.g. EFI_IFR_UNIQUE_SET\r
+ EFI_IFR_NUMERIC_SIZE_1, // Data type of Question value\r
+ ISCSI_MAX_ATTEMPTS_NUM, // Maximum container\r
+ OptionsOpCodeHandle, // Option Opcode list \r
+ NULL // Default Opcode is NULL \r
+ );\r
+\r
+Exit:\r
+ Status = HiiUpdateForm (\r
+ mCallbackInfo->RegisteredHandle, // HII handle\r
+ &mVendorGuid, // Formset GUID\r
+ FORMID_ORDER_FORM, // Form ID\r
+ StartOpCodeHandle, // Label for where to insert opcodes\r
+ EndOpCodeHandle // Replace data\r
+ ); \r
+\r
+Error:\r
+ HiiFreeOpCodeHandle (StartOpCodeHandle);\r
+ HiiFreeOpCodeHandle (EndOpCodeHandle); \r
+ if (OptionsOpCodeHandle != NULL) {\r
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Callback function when user presses "Commit Changes and Exit" in Change Attempt Order.\r
+\r
+ @param[in] IfrNvData The IFR nv data.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Does not have sufficient resources to finish this\r
+ operation.\r
+ @retval EFI_NOT_FOUND Cannot find the corresponding variable.\r
+ @retval EFI_SUCCESS The operation is completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiConfigOrderAttempts (\r
+ IN ISCSI_CONFIG_IFR_NVDATA *IfrNvData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ UINTN Indexj;\r
+ UINT8 AttemptConfigIndex;\r
+ ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;\r
+ UINT8 *AttemptConfigOrder;\r
+ UINT8 *AttemptConfigOrderTmp;\r
+ UINTN AttemptConfigOrderSize;\r
+\r
+ AttemptConfigOrder = IScsiGetVariableAndSize (\r
+ L"AttemptOrder",\r
+ &mVendorGuid,\r
+ &AttemptConfigOrderSize\r
+ );\r
+ if (AttemptConfigOrder == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ AttemptConfigOrderTmp = AllocateZeroPool (AttemptConfigOrderSize);\r
+ if (AttemptConfigOrderTmp == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Exit;\r
+ }\r
+\r
+ for (Index = 0; Index < ISCSI_MAX_ATTEMPTS_NUM; Index++) {\r
+ //\r
+ // The real content ends with 0.\r
+ //\r
+ if (IfrNvData->DynamicOrderedList[Index] == 0) {\r
+ break;\r
+ }\r
+\r
+ AttemptConfigIndex = IfrNvData->DynamicOrderedList[Index];\r
+ AttemptConfigData = IScsiConfigGetAttemptByConfigIndex (AttemptConfigIndex);\r
+ if (AttemptConfigData == NULL) {\r
+ Status = EFI_NOT_FOUND;\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Reorder the Attempt List.\r
+ //\r
+ RemoveEntryList (&AttemptConfigData->Link);\r
+ InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);\r
+\r
+ AttemptConfigOrderTmp[Index] = AttemptConfigIndex;\r
+\r
+ //\r
+ // Mark it to be deleted - 0.\r
+ //\r
+ for (Indexj = 0; Indexj < AttemptConfigOrderSize / sizeof (UINT8); Indexj++) {\r
+ if (AttemptConfigOrder[Indexj] == AttemptConfigIndex) {\r
+ AttemptConfigOrder[Indexj] = 0;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Adjust the attempt order in NVR.\r
+ //\r
+ for (; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {\r
+ for (Indexj = 0; Indexj < AttemptConfigOrderSize / sizeof (UINT8); Indexj++) {\r
+ if (AttemptConfigOrder[Indexj] != 0) {\r
+ AttemptConfigOrderTmp[Index] = AttemptConfigOrder[Indexj];\r
+ AttemptConfigOrder[Indexj] = 0;\r
+ continue;\r
+ }\r
+ }\r
+ }\r
+\r
+ Status = gRT->SetVariable (\r
+ L"AttemptOrder",\r
+ &mVendorGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+ AttemptConfigOrderSize,\r
+ AttemptConfigOrderTmp\r
+ );\r
+\r
+Exit:\r
+ if (AttemptConfigOrderTmp != NULL) {\r
+ FreePool (AttemptConfigOrderTmp);\r
+ }\r
+\r
+ FreePool (AttemptConfigOrder);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Callback function when a user presses "Attempt *" or when a user selects a NIC to\r
+ create the new attempt.\r
+\r
+ @param[in] KeyValue A unique value which is sent to the original\r
+ exporting driver so that it can identify the type\r
+ of data to expect.\r
+ @param[in] IfrNvData The IFR nv data.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Does not have sufficient resources to finish this\r
+ operation.\r
+ @retval EFI_NOT_FOUND Cannot find the corresponding variable.\r
+ @retval EFI_SUCCESS The operation is completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiConfigProcessDefault (\r
+ IN EFI_QUESTION_ID KeyValue,\r
+ IN ISCSI_CONFIG_IFR_NVDATA *IfrNvData\r
+ )\r
+{\r
+ BOOLEAN NewAttempt;\r
+ ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;\r
+ ISCSI_SESSION_CONFIG_NVDATA *ConfigData;\r
+ UINT8 CurrentAttemptConfigIndex;\r
+ ISCSI_NIC_INFO *NicInfo;\r
+ UINT8 NicIndex;\r
+ CHAR16 MacString[ISCSI_MAX_MAC_STRING_LEN];\r
+ UINT8 *AttemptConfigOrder;\r
+ UINTN AttemptConfigOrderSize;\r
+ UINTN TotalNumber;\r
+ UINT8 *AttemptOrderTmp;\r
+ UINTN Index;\r
+ EFI_STATUS Status;\r
+\r
+ NewAttempt = FALSE;\r
+\r
+ if ((KeyValue >= KEY_MAC_ENTRY_BASE) &&\r
+ (KeyValue <= (UINT16) (mPrivate->MaxNic + KEY_MAC_ENTRY_BASE))) {\r
+ //\r
+ // User has pressed "Add an Attempt" and then selects a NIC.\r
+ //\r
+ NewAttempt = TRUE;\r
+ } else if ((KeyValue >= KEY_ATTEMPT_ENTRY_BASE) &&\r
+ (KeyValue < (ISCSI_MAX_ATTEMPTS_NUM + KEY_ATTEMPT_ENTRY_BASE))) {\r
+\r
+ //\r
+ // User has pressed "Attempt *".\r
+ //\r
+ NewAttempt = FALSE;\r
+ } else {\r
+ //\r
+ // Don't process anything.\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (NewAttempt) {\r
+ //\r
+ // Determine which NIC user has selected for the new created attempt.\r
+ //\r
+ NicIndex = (UINT8) (KeyValue - KEY_MAC_ENTRY_BASE);\r
+ NicInfo = IScsiGetNicInfoByIndex (NicIndex);\r
+ if (NicInfo == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ \r
+ //\r
+ // Create the new attempt and save to NVR.\r
+ //\r
+\r
+ AttemptConfigData = AllocateZeroPool (sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA));\r
+ if (AttemptConfigData == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ ConfigData = &AttemptConfigData->SessionConfigData;\r
+ ConfigData->TargetPort = ISCSI_WELL_KNOWN_PORT;\r
+ ConfigData->ConnectTimeout = CONNECT_DEFAULT_TIMEOUT;\r
+ ConfigData->ConnectRetryCount = CONNECT_MIN_RETRY;\r
+\r
+ AttemptConfigData->AuthenticationType = ISCSI_AUTH_TYPE_CHAP;\r
+ AttemptConfigData->AuthConfigData.CHAP.CHAPType = ISCSI_CHAP_UNI;\r
+\r
+ //\r
+ // Get current order number for this attempt.\r
+ //\r
+ AttemptConfigOrder = IScsiGetVariableAndSize (\r
+ L"AttemptOrder",\r
+ &mVendorGuid,\r
+ &AttemptConfigOrderSize\r
+ );\r
+\r
+ TotalNumber = AttemptConfigOrderSize / sizeof (UINT8);\r
+\r
+ if (AttemptConfigOrder == NULL) {\r
+ CurrentAttemptConfigIndex = 1;\r
+ } else {\r
+ //\r
+ // Get the max attempt config index.\r
+ //\r
+ CurrentAttemptConfigIndex = AttemptConfigOrder[0];\r
+ for (Index = 1; Index < TotalNumber; Index++) {\r
+ if (CurrentAttemptConfigIndex < AttemptConfigOrder[Index]) {\r
+ CurrentAttemptConfigIndex = AttemptConfigOrder[Index];\r
+ }\r
+ }\r
+\r
+ CurrentAttemptConfigIndex++;\r
+ }\r
+\r
+ TotalNumber++;\r
+\r
+ //\r
+ // Append the new created attempt order to the end.\r
+ //\r
+ AttemptOrderTmp = AllocateZeroPool (TotalNumber * sizeof (UINT8));\r
+ if (AttemptOrderTmp == NULL) {\r
+ FreePool (AttemptConfigData);\r
+ if (AttemptConfigOrder != NULL) {\r
+ FreePool (AttemptConfigOrder);\r
+ }\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ if (AttemptConfigOrder != NULL) {\r
+ CopyMem (AttemptOrderTmp, AttemptConfigOrder, AttemptConfigOrderSize);\r
+ FreePool (AttemptConfigOrder); \r
+ }\r
+\r
+ AttemptOrderTmp[TotalNumber - 1] = CurrentAttemptConfigIndex; \r
+ AttemptConfigOrder = AttemptOrderTmp;\r
+ AttemptConfigOrderSize = TotalNumber * sizeof (UINT8);\r
+\r
+ Status = gRT->SetVariable (\r
+ L"AttemptOrder",\r
+ &mVendorGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+ AttemptConfigOrderSize,\r
+ AttemptConfigOrder\r
+ );\r
+ FreePool (AttemptConfigOrder);\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (AttemptConfigData);\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Record the mapping between attempt order and attempt's configdata.\r
+ //\r
+ AttemptConfigData->AttemptConfigIndex = CurrentAttemptConfigIndex;\r
+ InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);\r
+ mPrivate->AttemptCount++;\r
+\r
+ //\r
+ // Record the MAC info in Config Data.\r
+ //\r
+ IScsiMacAddrToStr (\r
+ &NicInfo->PermanentAddress,\r
+ NicInfo->HwAddressSize,\r
+ NicInfo->VlanId,\r
+ MacString\r
+ );\r
+\r
+ UnicodeStrToAsciiStr (MacString, AttemptConfigData->MacString);\r
+ AttemptConfigData->NicIndex = NicIndex;\r
+\r
+ //\r
+ // Generate OUI-format ISID based on MAC address.\r
+ //\r
+ CopyMem (AttemptConfigData->SessionConfigData.IsId, &NicInfo->PermanentAddress, 6);\r
+ AttemptConfigData->SessionConfigData.IsId[0] = \r
+ (UINT8) (AttemptConfigData->SessionConfigData.IsId[0] & 0x3F);\r
+\r
+ //\r
+ // Add the help info for the new attempt.\r
+ //\r
+ UnicodeSPrint (\r
+ mPrivate->PortString,\r
+ (UINTN) ISCSI_NAME_IFR_MAX_SIZE,\r
+ L"MAC: %s, PFA: Bus %d | Dev %d | Func %d",\r
+ MacString,\r
+ NicInfo->BusNumber,\r
+ NicInfo->DeviceNumber,\r
+ NicInfo->FunctionNumber\r
+ );\r
+\r
+ AttemptConfigData->AttemptTitleHelpToken = HiiSetString (\r
+ mCallbackInfo->RegisteredHandle,\r
+ 0,\r
+ mPrivate->PortString,\r
+ NULL\r
+ );\r
+ if (AttemptConfigData->AttemptTitleHelpToken == 0) {\r
+ FreePool (AttemptConfigData);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Set the attempt name to default.\r
+ //\r
+ UnicodeSPrint (\r
+ mPrivate->PortString,\r
+ (UINTN) 128,\r
+ L"%d",\r
+ (UINTN) AttemptConfigData->AttemptConfigIndex\r
+ );\r
+ UnicodeStrToAsciiStr (mPrivate->PortString, AttemptConfigData->AttemptName);\r
+\r
+ } else {\r
+ //\r
+ // Determine which Attempt user has selected to configure.\r
+ // Get the attempt configuration data.\r
+ //\r
+ CurrentAttemptConfigIndex = (UINT8) (KeyValue - KEY_ATTEMPT_ENTRY_BASE);\r
+\r
+ AttemptConfigData = IScsiConfigGetAttemptByConfigIndex (CurrentAttemptConfigIndex);\r
+ if (AttemptConfigData == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "Corresponding configuration data can not be retrieved!\n"));\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Clear the old IFR data to avoid sharing it with other attempts.\r
+ //\r
+ if (IfrNvData->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) {\r
+ ZeroMem (IfrNvData->CHAPName, sizeof (IfrNvData->CHAPName));\r
+ ZeroMem (IfrNvData->CHAPSecret, sizeof (IfrNvData->CHAPSecret));\r
+ ZeroMem (IfrNvData->ReverseCHAPName, sizeof (IfrNvData->ReverseCHAPName));\r
+ ZeroMem (IfrNvData->ReverseCHAPSecret, sizeof (IfrNvData->ReverseCHAPSecret));\r
+ }\r
+ \r
+ IScsiConvertAttemptConfigDataToIfrNvData (AttemptConfigData, IfrNvData);\r
+\r
+ mCallbackInfo->Current = AttemptConfigData;\r
+\r
+ IScsiConfigUpdateAttempt ();\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ \r
+ This function allows the caller to request the current\r
+ configuration for one or more named elements. The resulting\r
+ string is in <ConfigAltResp> format. Also, any and all alternative\r
+ configuration strings shall be appended to the end of the\r
+ current configuration string. If they are, they must appear\r
+ after the current configuration. They must contain the same\r
+ routing (GUID, NAME, PATH) as the current configuration string.\r
+ They must have an additional description indicating the type of\r
+ alternative configuration the string represents,\r
+ "ALTCFG=<StringToken>". That <StringToken> (when\r
+ converted from Hex UNICODE to binary) is a reference to a\r
+ string in the associated string pack.\r
+\r
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+\r
+ @param[in] Request A null-terminated Unicode string in\r
+ <ConfigRequest> format. Note that this\r
+ includes the routing information as well as\r
+ the configurable name / value pairs. It is\r
+ invalid for this string to be in\r
+ <MultiConfigRequest> format.\r
+\r
+ @param[out] Progress On return, points to a character in the\r
+ Request string. Points to the string's null\r
+ terminator if request was successful. Points\r
+ to the most recent "&" before the first\r
+ failing name / value pair (or the beginning\r
+ of the string if the failure is in the first\r
+ name / value pair) if the request was not successful. \r
+\r
+ @param[out] Results A null-terminated Unicode string in\r
+ <ConfigAltResp> format which has all values\r
+ filled in for the names in the Request string.\r
+ String to be allocated by the called function.\r
+\r
+ @retval EFI_SUCCESS The Results string is filled with the\r
+ values corresponding to all requested\r
+ names.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the\r
+ parts of the results that must be\r
+ stored awaiting possible future\r
+ protocols.\r
+\r
+ @retval EFI_INVALID_PARAMETER For example, passing in a NULL\r
+ for the Request parameter\r
+ would result in this type of\r
+ error. In this case, the\r
+ Progress parameter would be\r
+ set to NULL. \r
+\r
+ @retval EFI_NOT_FOUND Routing data doesn't match any\r
+ known driver. Progress set to the\r
+ first character in the routing header.\r
+ Note: There is no requirement that the\r
+ driver validate the routing data. It\r
+ must skip the <ConfigHdr> in order to\r
+ process the names.\r
+\r
+ @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set\r
+ to most recent "&" before the\r
+ error or the beginning of the\r
+ string.\r
+\r
+ @retval EFI_INVALID_PARAMETER Unknown name. Progress points\r
+ to the & before the name in\r
+ question.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiFormExtractConfig (\r
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
+ IN CONST EFI_STRING Request,\r
+ OUT EFI_STRING *Progress,\r
+ OUT EFI_STRING *Results\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CHAR8 *InitiatorName;\r
+ UINTN BufferSize;\r
+ ISCSI_CONFIG_IFR_NVDATA *IfrNvData;\r
+ ISCSI_FORM_CALLBACK_INFO *Private;\r
+ EFI_STRING ConfigRequestHdr;\r
+ EFI_STRING ConfigRequest;\r
+ BOOLEAN AllocatedRequest;\r
+ UINTN Size;\r
+\r
+ if (This == NULL || Progress == NULL || Results == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *Progress = Request;\r
+ if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &mVendorGuid, mVendorStorageName)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ ConfigRequestHdr = NULL;\r
+ ConfigRequest = NULL;\r
+ AllocatedRequest = FALSE;\r
+ Size = 0;\r
+\r
+ Private = ISCSI_FORM_CALLBACK_INFO_FROM_FORM_CALLBACK (This);\r
+ IfrNvData = AllocateZeroPool (sizeof (ISCSI_CONFIG_IFR_NVDATA));\r
+ if (IfrNvData == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ \r
+ if (Private->Current != NULL) {\r
+ IScsiConvertAttemptConfigDataToIfrNvData (Private->Current, IfrNvData);\r
+ }\r
+\r
+ BufferSize = ISCSI_NAME_MAX_SIZE;\r
+ InitiatorName = (CHAR8 *) AllocateZeroPool (BufferSize);\r
+ if (InitiatorName == NULL) {\r
+ FreePool (IfrNvData);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ \r
+ Status = gIScsiInitiatorName.Get (&gIScsiInitiatorName, &BufferSize, InitiatorName);\r
+ if (EFI_ERROR (Status)) {\r
+ IfrNvData->InitiatorName[0] = L'\0';\r
+ } else {\r
+ AsciiStrToUnicodeStr (InitiatorName, IfrNvData->InitiatorName);\r
+ }\r
+\r
+ //\r
+ // Convert buffer data to <ConfigResp> by helper function BlockToConfig().\r
+ //\r
+ BufferSize = sizeof (ISCSI_CONFIG_IFR_NVDATA);\r
+ ConfigRequest = Request;\r
+ if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {\r
+ //\r
+ // Request has no request element, construct full request string.\r
+ // Allocate and fill a buffer large enough to hold the <ConfigHdr> template\r
+ // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator\r
+ //\r
+ ConfigRequestHdr = HiiConstructConfigHdr (&mVendorGuid, mVendorStorageName, Private->DriverHandle);\r
+ Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);\r
+ ConfigRequest = AllocateZeroPool (Size);\r
+ ASSERT (ConfigRequest != NULL);\r
+ AllocatedRequest = TRUE;\r
+ UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);\r
+ FreePool (ConfigRequestHdr);\r
+ }\r
+\r
+ Status = gHiiConfigRouting->BlockToConfig (\r
+ gHiiConfigRouting,\r
+ ConfigRequest,\r
+ (UINT8 *) IfrNvData,\r
+ BufferSize,\r
+ Results,\r
+ Progress\r
+ );\r
+ FreePool (IfrNvData);\r
+ FreePool (InitiatorName);\r
+\r
+ //\r
+ // Free the allocated config request string.\r
+ //\r
+ if (AllocatedRequest) {\r
+ FreePool (ConfigRequest);\r
+ ConfigRequest = NULL;\r
+ }\r
+ //\r
+ // Set Progress string to the original request string.\r
+ //\r
+ if (Request == NULL) {\r
+ *Progress = NULL;\r
+ } else if (StrStr (Request, L"OFFSET") == NULL) {\r
+ *Progress = Request + StrLen (Request);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ \r
+ This function applies changes in a driver's configuration.\r
+ Input is a Configuration, which has the routing data for this\r
+ driver followed by name / value configuration pairs. The driver\r
+ must apply those pairs to its configurable storage. If the\r
+ driver's configuration is stored in a linear block of data\r
+ and the driver's name / value pairs are in <BlockConfig>\r
+ format, it may use the ConfigToBlock helper function (above) to\r
+ simplify the job.\r
+\r
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+\r
+ @param[in] Configuration A null-terminated Unicode string in\r
+ <ConfigString> format. \r
+ \r
+ @param[out] Progress A pointer to a string filled in with the\r
+ offset of the most recent '&' before the\r
+ first failing name / value pair (or the\r
+ beginning of the string if the failure\r
+ is in the first name / value pair) or\r
+ the terminating NULL if all was\r
+ successful.\r
+\r
+ @retval EFI_SUCCESS The results have been distributed or are\r
+ awaiting distribution.\r
+ \r
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the\r
+ parts of the results that must be\r
+ stored awaiting possible future\r
+ protocols.\r
+ \r
+ @retval EFI_INVALID_PARAMETERS Passing in a NULL for the\r
+ Results parameter would result\r
+ in this type of error.\r
+ \r
+ @retval EFI_NOT_FOUND Target for the specified routing data\r
+ was not found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiFormRouteConfig (\r
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
+ IN CONST EFI_STRING Configuration,\r
+ OUT EFI_STRING *Progress\r
+ )\r
+{\r
+ if (This == NULL || Configuration == NULL || Progress == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Check routing data in <ConfigHdr>.\r
+ // Note: if only one Storage is used, then this checking could be skipped.\r
+ //\r
+ if (!HiiIsConfigHdrMatch (Configuration, &mVendorGuid, mVendorStorageName)) {\r
+ *Progress = Configuration;\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ *Progress = Configuration + StrLen (Configuration);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ \r
+ This function is called to provide results data to the driver.\r
+ This data consists of a unique key that is used to identify\r
+ which data is either being passed back or being asked for.\r
+\r
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+ @param[in] Action Specifies the type of action taken by the browser.\r
+ @param[in] QuestionId A unique value which is sent to the original\r
+ exporting driver so that it can identify the type\r
+ of data to expect. The format of the data tends to \r
+ vary based on the opcode that generated the callback.\r
+ @param[in] Type The type of value for the question.\r
+ @param[in, out] Value A pointer to the data being sent to the original\r
+ exporting driver.\r
+ @param[out] ActionRequest On return, points to the action requested by the\r
+ callback function.\r
+\r
+ @retval EFI_SUCCESS The callback successfully handled the action.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the\r
+ variable and its data.\r
+ @retval EFI_DEVICE_ERROR The variable could not be saved.\r
+ @retval EFI_UNSUPPORTED The specified Action is not supported by the\r
+ callback.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiFormCallback (\r
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
+ IN EFI_BROWSER_ACTION Action,\r
+ IN EFI_QUESTION_ID QuestionId,\r
+ IN UINT8 Type,\r
+ IN OUT EFI_IFR_TYPE_VALUE *Value,\r
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest\r
+ )\r
+{\r
+ ISCSI_FORM_CALLBACK_INFO *Private;\r
+ UINTN BufferSize;\r
+ CHAR8 *IScsiName;\r
+ CHAR8 IpString[IP_STR_MAX_SIZE];\r
+ CHAR8 LunString[ISCSI_LUN_STR_MAX_LEN];\r
+ UINT64 Lun;\r
+ EFI_IP_ADDRESS HostIp;\r
+ EFI_IP_ADDRESS SubnetMask;\r
+ EFI_IP_ADDRESS Gateway;\r
+ ISCSI_CONFIG_IFR_NVDATA *IfrNvData;\r
+ ISCSI_CONFIG_IFR_NVDATA OldIfrNvData;\r
+ EFI_STATUS Status;\r
+ CHAR16 AttemptName[ATTEMPT_NAME_SIZE + 4];\r
+ EFI_INPUT_KEY Key;\r
+\r
+ if ((Action == EFI_BROWSER_ACTION_FORM_OPEN) || (Action == EFI_BROWSER_ACTION_FORM_CLOSE)) {\r
+ //\r
+ // Do nothing for UEFI OPEN/CLOSE Action\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (Action == EFI_BROWSER_ACTION_CHANGING) {\r
+ if (This == NULL || Value == NULL || ActionRequest == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = ISCSI_FORM_CALLBACK_INFO_FROM_FORM_CALLBACK (This);\r
+\r
+ //\r
+ // Retrieve uncommitted data from Browser\r
+ //\r
+\r
+ BufferSize = sizeof (ISCSI_CONFIG_IFR_NVDATA);\r
+ IfrNvData = AllocateZeroPool (BufferSize);\r
+ if (IfrNvData == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ IScsiName = (CHAR8 *) AllocateZeroPool (ISCSI_NAME_MAX_SIZE);\r
+ if (IScsiName == NULL) {\r
+ FreePool (IfrNvData);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ ZeroMem (&OldIfrNvData, BufferSize);\r
+\r
+ HiiGetBrowserData (NULL, NULL, BufferSize, (UINT8 *) IfrNvData);\r
+\r
+ CopyMem (&OldIfrNvData, IfrNvData, BufferSize);\r
+\r
+ switch (QuestionId) {\r
+ case KEY_INITIATOR_NAME:\r
+ UnicodeStrToAsciiStr (IfrNvData->InitiatorName, IScsiName);\r
+ BufferSize = AsciiStrSize (IScsiName);\r
+\r
+ Status = gIScsiInitiatorName.Set (&gIScsiInitiatorName, &BufferSize, IScsiName);\r
+ if (EFI_ERROR (Status)) {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Invalid iSCSI Name!",\r
+ NULL\r
+ ); \r
+ }\r
+\r
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;\r
+ break;\r
+\r
+ case KEY_ADD_ATTEMPT:\r
+ Status = IScsiConfigAddAttempt ();\r
+ break;\r
+\r
+ case KEY_DELETE_ATTEMPT:\r
+ CopyMem (\r
+ OldIfrNvData.DeleteAttemptList,\r
+ IfrNvData->DeleteAttemptList,\r
+ sizeof (IfrNvData->DeleteAttemptList)\r
+ );\r
+ Status = IScsiConfigDisplayDeleteAttempts (IfrNvData);\r
+ break;\r
+\r
+ case KEY_SAVE_DELETE_ATTEMPT:\r
+ //\r
+ // Delete the Attempt Order from NVR\r
+ //\r
+ Status = IScsiConfigDeleteAttempts (IfrNvData);\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+\r
+ IScsiConfigUpdateAttempt ();\r
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;\r
+ break;\r
+\r
+ case KEY_IGNORE_DELETE_ATTEMPT:\r
+ CopyMem (\r
+ IfrNvData->DeleteAttemptList,\r
+ OldIfrNvData.DeleteAttemptList,\r
+ sizeof (IfrNvData->DeleteAttemptList)\r
+ );\r
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;\r
+ break;\r
+\r
+ case KEY_ORDER_ATTEMPT_CONFIG:\r
+ //\r
+ // Order the attempt according to user input.\r
+ //\r
+ CopyMem (\r
+ OldIfrNvData.DynamicOrderedList,\r
+ IfrNvData->DynamicOrderedList,\r
+ sizeof (IfrNvData->DynamicOrderedList)\r
+ );\r
+ IScsiConfigDisplayOrderAttempts ();\r
+ break;\r
+\r
+ case KEY_SAVE_ORDER_CHANGES:\r
+ //\r
+ // Sync the Attempt Order to NVR.\r
+ //\r
+ Status = IScsiConfigOrderAttempts (IfrNvData);\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+\r
+ IScsiConfigUpdateAttempt ();\r
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;\r
+ break;\r
+\r
+ case KEY_IGNORE_ORDER_CHANGES:\r
+ CopyMem (\r
+ IfrNvData->DynamicOrderedList,\r
+ OldIfrNvData.DynamicOrderedList,\r
+ sizeof (IfrNvData->DynamicOrderedList)\r
+ );\r
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;\r
+ break;\r
+\r
+ case KEY_ATTEMPT_NAME:\r
+ if (StrLen (IfrNvData->AttemptName) > ATTEMPT_NAME_SIZE) {\r
+ CopyMem (AttemptName, IfrNvData->AttemptName, ATTEMPT_NAME_SIZE * sizeof (CHAR16));\r
+ CopyMem (&AttemptName[ATTEMPT_NAME_SIZE], L"...", 4 * sizeof (CHAR16));\r
+ } else {\r
+ CopyMem (\r
+ AttemptName,\r
+ IfrNvData->AttemptName,\r
+ (StrLen (IfrNvData->AttemptName) + 1) * sizeof (CHAR16)\r
+ );\r
+ }\r
+\r
+ UnicodeStrToAsciiStr (IfrNvData->AttemptName, Private->Current->AttemptName);\r
+\r
+ IScsiConfigUpdateAttempt ();\r
+\r
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;\r
+ break;\r
+\r
+ case KEY_IP_MODE:\r
+ switch (Value->u8) {\r
+ case IP_MODE_IP6:\r
+ ZeroMem (IfrNvData->TargetIp, sizeof (IfrNvData->TargetIp));\r
+ IScsiIpToStr (&Private->Current->SessionConfigData.TargetIp, TRUE, IfrNvData->TargetIp);\r
+ Private->Current->AutoConfigureMode = 0;\r
+ break;\r
+\r
+ case IP_MODE_IP4:\r
+ ZeroMem (IfrNvData->TargetIp, sizeof (IfrNvData->TargetIp));\r
+ IScsiIpToStr (&Private->Current->SessionConfigData.TargetIp, FALSE, IfrNvData->TargetIp);\r
+ Private->Current->AutoConfigureMode = 0;\r
+\r
+ break;\r
+ }\r
+\r
+ break;\r
+\r
+ case KEY_LOCAL_IP:\r
+ Status = NetLibStrToIp4 (IfrNvData->LocalIp, &HostIp.v4);\r
+ if (EFI_ERROR (Status) || !NetIp4IsUnicast (NTOHL (HostIp.Addr[0]), 0)) {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Invalid IP address!",\r
+ NULL\r
+ ); \r
+ \r
+ Status = EFI_INVALID_PARAMETER;\r
+ } else {\r
+ CopyMem (&Private->Current->SessionConfigData.LocalIp, &HostIp.v4, sizeof (HostIp.v4));\r
+ }\r
+\r
+ break;\r
+\r
+ case KEY_SUBNET_MASK:\r
+ Status = NetLibStrToIp4 (IfrNvData->SubnetMask, &SubnetMask.v4);\r
+ if (EFI_ERROR (Status) || ((SubnetMask.Addr[0] != 0) && (IScsiGetSubnetMaskPrefixLength (&SubnetMask.v4) == 0))) {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Invalid Subnet Mask!",\r
+ NULL\r
+ ); \r
+ \r
+ Status = EFI_INVALID_PARAMETER;\r
+ } else {\r
+ CopyMem (&Private->Current->SessionConfigData.SubnetMask, &SubnetMask.v4, sizeof (SubnetMask.v4));\r
+ }\r
+\r
+ break;\r
+\r
+ case KEY_GATE_WAY:\r
+ Status = NetLibStrToIp4 (IfrNvData->Gateway, &Gateway.v4);\r
+ if (EFI_ERROR (Status) || ((Gateway.Addr[0] != 0) && !NetIp4IsUnicast (NTOHL (Gateway.Addr[0]), 0))) {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Invalid Gateway!",\r
+ NULL\r
+ ); \r
+ Status = EFI_INVALID_PARAMETER;\r
+ } else {\r
+ CopyMem (&Private->Current->SessionConfigData.Gateway, &Gateway.v4, sizeof (Gateway.v4));\r
+ }\r
+\r
+ break;\r
+\r
+ case KEY_TARGET_IP:\r
+ UnicodeStrToAsciiStr (IfrNvData->TargetIp, IpString);\r
+ Status = IScsiAsciiStrToIp (IpString, IfrNvData->IpMode, &HostIp);\r
+ if (EFI_ERROR (Status) || !IpIsUnicast (&HostIp, IfrNvData->IpMode)) {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Invalid IP address!",\r
+ NULL\r
+ ); \r
+ Status = EFI_INVALID_PARAMETER;\r
+ } else {\r
+ CopyMem (&Private->Current->SessionConfigData.TargetIp, &HostIp, sizeof (HostIp));\r
+ }\r
+\r
+ break;\r
+\r
+ case KEY_TARGET_NAME:\r
+ UnicodeStrToAsciiStr (IfrNvData->TargetName, IScsiName);\r
+ Status = IScsiNormalizeName (IScsiName, AsciiStrLen (IScsiName));\r
+ if (EFI_ERROR (Status)) {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Invalid iSCSI Name!",\r
+ NULL\r
+ ); \r
+ } else {\r
+ AsciiStrCpy (Private->Current->SessionConfigData.TargetName, IScsiName);\r
+ }\r
+\r
+ break;\r
+\r
+ case KEY_DHCP_ENABLE:\r
+ if (IfrNvData->InitiatorInfoFromDhcp == 0) {\r
+ IfrNvData->TargetInfoFromDhcp = 0;\r
+ }\r
+\r
+ break;\r
+\r
+ case KEY_BOOT_LUN:\r
+ UnicodeStrToAsciiStr (IfrNvData->BootLun, LunString);\r
+ Status = IScsiAsciiStrToLun (LunString, (UINT8 *) &Lun);\r
+ if (EFI_ERROR (Status)) {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Invalid LUN string!",\r
+ NULL\r
+ ); \r
+ } else {\r
+ CopyMem (Private->Current->SessionConfigData.BootLun, &Lun, sizeof (Lun));\r
+ }\r
+\r
+ break;\r
+\r
+ case KEY_AUTH_TYPE:\r
+ switch (Value->u8) {\r
+ case ISCSI_AUTH_TYPE_CHAP:\r
+ IfrNvData->CHAPType = ISCSI_CHAP_UNI;\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+\r
+ break;\r
+\r
+ case KEY_CHAP_NAME:\r
+ UnicodeStrToAsciiStr (\r
+ IfrNvData->CHAPName,\r
+ Private->Current->AuthConfigData.CHAP.CHAPName\r
+ );\r
+ break;\r
+\r
+ case KEY_CHAP_SECRET:\r
+ UnicodeStrToAsciiStr (\r
+ IfrNvData->CHAPSecret,\r
+ Private->Current->AuthConfigData.CHAP.CHAPSecret\r
+ );\r
+ break;\r
+\r
+ case KEY_REVERSE_CHAP_NAME:\r
+ UnicodeStrToAsciiStr (\r
+ IfrNvData->ReverseCHAPName,\r
+ Private->Current->AuthConfigData.CHAP.ReverseCHAPName\r
+ );\r
+ break;\r
+\r
+ case KEY_REVERSE_CHAP_SECRET:\r
+ UnicodeStrToAsciiStr (\r
+ IfrNvData->ReverseCHAPSecret,\r
+ Private->Current->AuthConfigData.CHAP.ReverseCHAPSecret\r
+ );\r
+ break;\r
+\r
+ case KEY_CONFIG_ISID:\r
+ IScsiParseIsIdFromString (IfrNvData->IsId, Private->Current->SessionConfigData.IsId);\r
+ IScsiConvertIsIdToString (IfrNvData->IsId, Private->Current->SessionConfigData.IsId);\r
+\r
+ break;\r
+\r
+ case KEY_SAVE_ATTEMPT_CONFIG:\r
+ Status = IScsiConvertIfrNvDataToAttemptConfigData (IfrNvData, Private->Current);\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+\r
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;\r
+ break;\r
+\r
+ default:\r
+ Status = IScsiConfigProcessDefault (QuestionId, IfrNvData);\r
+ break;\r
+ }\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Pass changed uncommitted data back to Form Browser.\r
+ //\r
+ BufferSize = sizeof (ISCSI_CONFIG_IFR_NVDATA);\r
+ HiiSetBrowserData (NULL, NULL, BufferSize, (UINT8 *) IfrNvData, NULL);\r
+ }\r
+\r
+ FreePool (IfrNvData);\r
+ FreePool (IScsiName);\r
+\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // All other action return unsupported.\r
+ //\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+\r
+/**\r
+ Initialize the iSCSI configuration form.\r
+\r
+ @param[in] DriverBindingHandle The iSCSI driverbinding handle.\r
+\r
+ @retval EFI_SUCCESS The iSCSI configuration form is initialized.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiConfigFormInit (\r
+ IN EFI_HANDLE DriverBindingHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ ISCSI_FORM_CALLBACK_INFO *CallbackInfo;\r
+\r
+ CallbackInfo = (ISCSI_FORM_CALLBACK_INFO *) AllocateZeroPool (sizeof (ISCSI_FORM_CALLBACK_INFO));\r
+ if (CallbackInfo == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ CallbackInfo->Signature = ISCSI_FORM_CALLBACK_INFO_SIGNATURE;\r
+ CallbackInfo->Current = NULL;\r
+\r
+ CallbackInfo->ConfigAccess.ExtractConfig = IScsiFormExtractConfig;\r
+ CallbackInfo->ConfigAccess.RouteConfig = IScsiFormRouteConfig;\r
+ CallbackInfo->ConfigAccess.Callback = IScsiFormCallback;\r
+\r
+ //\r
+ // Install Device Path Protocol and Config Access protocol to driver handle.\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &CallbackInfo->DriverHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ &mIScsiHiiVendorDevicePath,\r
+ &gEfiHiiConfigAccessProtocolGuid,\r
+ &CallbackInfo->ConfigAccess,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ \r
+ //\r
+ // Publish our HII data.\r
+ //\r
+ CallbackInfo->RegisteredHandle = HiiAddPackages (\r
+ &mVendorGuid,\r
+ CallbackInfo->DriverHandle,\r
+ IScsiDxeStrings,\r
+ IScsiConfigVfrBin,\r
+ NULL\r
+ );\r
+ if (CallbackInfo->RegisteredHandle == NULL) {\r
+ gBS->UninstallMultipleProtocolInterfaces (\r
+ &CallbackInfo->DriverHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ &mIScsiHiiVendorDevicePath,\r
+ &gEfiHiiConfigAccessProtocolGuid,\r
+ &CallbackInfo->ConfigAccess,\r
+ NULL\r
+ );\r
+ FreePool(CallbackInfo);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ mCallbackInfo = CallbackInfo;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Unload the iSCSI configuration form, this includes: delete all the iSCSI\r
+ configuration entries, uninstall the form callback protocol, and\r
+ free the resources used.\r
+\r
+ @param[in] DriverBindingHandle The iSCSI driverbinding handle.\r
+\r
+ @retval EFI_SUCCESS The iSCSI configuration form is unloaded.\r
+ @retval Others Failed to unload the form.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiConfigFormUnload (\r
+ IN EFI_HANDLE DriverBindingHandle\r
+ )\r
+{\r
+ ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;\r
+ ISCSI_NIC_INFO *NicInfo;\r
+ LIST_ENTRY *Entry;\r
+ EFI_STATUS Status;\r
+\r
+ while (!IsListEmpty (&mPrivate->AttemptConfigs)) {\r
+ Entry = NetListRemoveHead (&mPrivate->AttemptConfigs);\r
+ AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);\r
+ FreePool (AttemptConfigData);\r
+ mPrivate->AttemptCount--;\r
+ }\r
+\r
+ ASSERT (mPrivate->AttemptCount == 0);\r
+\r
+ while (!IsListEmpty (&mPrivate->NicInfoList)) {\r
+ Entry = NetListRemoveHead (&mPrivate->NicInfoList);\r
+ NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);\r
+ FreePool (NicInfo);\r
+ mPrivate->NicCount--;\r
+ }\r
+\r
+ ASSERT (mPrivate->NicCount == 0);\r
+\r
+ FreePool (mPrivate);\r
+ mPrivate = NULL;\r
+\r
+ //\r
+ // Remove HII package list.\r
+ //\r
+ HiiRemovePackages (mCallbackInfo->RegisteredHandle);\r
+\r
+ //\r
+ // Uninstall Device Path Protocol and Config Access protocol.\r
+ //\r
+ Status = gBS->UninstallMultipleProtocolInterfaces (\r
+ mCallbackInfo->DriverHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ &mIScsiHiiVendorDevicePath,\r
+ &gEfiHiiConfigAccessProtocolGuid,\r
+ &mCallbackInfo->ConfigAccess,\r
+ NULL\r
+ );\r
+\r
+ FreePool (mCallbackInfo);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+ The header file of functions for configuring or getting the parameters\r
+ relating to iSCSI.\r
+\r
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _ISCSI_CONFIG_H_\r
+#define _ISCSI_CONFIG_H_\r
+\r
+#include "IScsiConfigNVDataStruc.h"\r
+\r
+typedef struct _ISCSI_FORM_CALLBACK_INFO ISCSI_FORM_CALLBACK_INFO;\r
+\r
+extern UINT8 IScsiConfigVfrBin[];\r
+extern UINT8 IScsiDxeStrings[];\r
+extern ISCSI_FORM_CALLBACK_INFO *mCallbackInfo;\r
+extern EFI_GUID mVendorGuid;\r
+\r
+\r
+#define VAR_OFFSET(Field) \\r
+ ((UINT16) ((UINTN) &(((ISCSI_CONFIG_IFR_NVDATA *) 0)->Field)))\r
+\r
+#define QUESTION_ID(Field) \\r
+ ((UINT16) (VAR_OFFSET (Field) + CONFIG_OPTION_OFFSET))\r
+\r
+\r
+#define DYNAMIC_ONE_OF_VAR_OFFSET VAR_OFFSET (Enabled)\r
+#define DYNAMIC_ORDERED_LIST_QUESTION_ID QUESTION_ID (DynamicOrderedList)\r
+#define DYNAMIC_ORDERED_LIST_VAR_OFFSET VAR_OFFSET (DynamicOrderedList)\r
+#define ATTEMPT_DEL_QUESTION_ID QUESTION_ID (DeleteAttemptList)\r
+#define ATTEMPT_DEL_VAR_OFFSET VAR_OFFSET (DeleteAttemptList)\r
+\r
+//\r
+// sizeof (EFI_MAC_ADDRESS) * 3\r
+//\r
+#define ISCSI_MAX_MAC_STRING_LEN 96\r
+\r
+#define ISCSI_INITATOR_NAME_VAR_NAME L"I_NAME"\r
+\r
+#define ISCSI_CONFIG_VAR_ATTR (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE)\r
+\r
+#define ISCSI_FORM_CALLBACK_INFO_SIGNATURE SIGNATURE_32 ('I', 'f', 'c', 'i')\r
+\r
+#define ISCSI_FORM_CALLBACK_INFO_FROM_FORM_CALLBACK(Callback) \\r
+ CR ( \\r
+ Callback, \\r
+ ISCSI_FORM_CALLBACK_INFO, \\r
+ ConfigAccess, \\r
+ ISCSI_FORM_CALLBACK_INFO_SIGNATURE \\r
+ )\r
+\r
+#pragma pack(1)\r
+struct _ISCSI_ATTEMPT_CONFIG_NVDATA {\r
+ LIST_ENTRY Link;\r
+ UINT8 NicIndex;\r
+ UINT8 AttemptConfigIndex;\r
+ BOOLEAN DhcpSuccess;\r
+ BOOLEAN ValidiBFTPath;\r
+ BOOLEAN ValidPath;\r
+ UINT8 AutoConfigureMode;\r
+ EFI_STRING_ID AttemptTitleToken;\r
+ EFI_STRING_ID AttemptTitleHelpToken;\r
+ CHAR8 AttemptName[ATTEMPT_NAME_MAX_SIZE];\r
+ CHAR8 MacString[ISCSI_MAX_MAC_STRING_LEN];\r
+ EFI_IP_ADDRESS PrimaryDns;\r
+ EFI_IP_ADDRESS SecondaryDns;\r
+ EFI_IP_ADDRESS DhcpServer;\r
+ ISCSI_SESSION_CONFIG_NVDATA SessionConfigData;\r
+ UINT8 AuthenticationType;\r
+ union {\r
+ ISCSI_CHAP_AUTH_CONFIG_NVDATA CHAP;\r
+ } AuthConfigData;\r
+\r
+};\r
+\r
+///\r
+/// HII specific Vendor Device Path definition.\r
+///\r
+typedef struct {\r
+ VENDOR_DEVICE_PATH VendorDevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL End;\r
+} HII_VENDOR_DEVICE_PATH;\r
+\r
+#pragma pack()\r
+\r
+struct _ISCSI_FORM_CALLBACK_INFO {\r
+ UINT32 Signature;\r
+ EFI_HANDLE DriverHandle;\r
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;\r
+ UINT16 *KeyList;\r
+ VOID *FormBuffer;\r
+ EFI_HII_HANDLE RegisteredHandle;\r
+ ISCSI_ATTEMPT_CONFIG_NVDATA *Current;\r
+};\r
+\r
+/**\r
+ Initialize the iSCSI configuration form.\r
+\r
+ @param[in] DriverBindingHandle The iSCSI driverbinding handle.\r
+\r
+ @retval EFI_SUCCESS The iSCSI configuration form is initialized.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiConfigFormInit (\r
+ IN EFI_HANDLE DriverBindingHandle\r
+ );\r
+\r
+/**\r
+ Unload the iSCSI configuration form, this includes: delete all the iSCSI\r
+ configuration entries, uninstall the form callback protocol, and\r
+ free the resources used.\r
+\r
+ @param[in] DriverBindingHandle The iSCSI driverbinding handle.\r
+\r
+ @retval EFI_SUCCESS The iSCSI configuration form is unloaded.\r
+ @retval Others Failed to unload the form.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiConfigFormUnload (\r
+ IN EFI_HANDLE DriverBindingHandle\r
+ );\r
+\r
+/**\r
+ Update the MAIN form to display the configured attempts.\r
+\r
+**/\r
+VOID\r
+IScsiConfigUpdateAttempt (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Get the attempt config data from global structure by the ConfigIndex.\r
+\r
+ @param[in] AttemptConfigIndex The unique index indicates the attempt.\r
+\r
+ @return Pointer to the attempt config data.\r
+ @retval NULL The attempt configuration data can not be found.\r
+\r
+**/\r
+ISCSI_ATTEMPT_CONFIG_NVDATA *\r
+IScsiConfigGetAttemptByConfigIndex (\r
+ IN UINT8 AttemptConfigIndex\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+ Define NVData structures used by the iSCSI configuration component.\r
+\r
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _ISCSI_NVDATASTRUC_H_\r
+#define _ISCSI_NVDATASTRUC_H_\r
+\r
+#define ISCSI_CONFIG_GUID \\r
+ { \\r
+ 0x6456ed61, 0x3579, 0x41c9, { 0x8a, 0x26, 0x0a, 0x0b, 0xd6, 0x2b, 0x78, 0xfc } \\r
+ }\r
+\r
+#define VAR_EQ_TEST_NAME 0x100\r
+#define CONFIGURATION_VARSTORE_ID 0x6666\r
+\r
+#define FORMID_MAIN_FORM 1\r
+#define FORMID_MAC_FORM 2\r
+#define FORMID_ATTEMPT_FORM 3\r
+#define FORMID_ORDER_FORM 4\r
+#define FORMID_DELETE_FORM 5\r
+\r
+#define ISCSI_NAME_IFR_MIN_SIZE 4\r
+#define ISCSI_NAME_IFR_MAX_SIZE 223\r
+#define ISCSI_NAME_MAX_SIZE 224\r
+\r
+#define ATTEMPT_NAME_MAX_SIZE 96\r
+#define ATTEMPT_NAME_SIZE 10\r
+\r
+#define CONNECT_MIN_RETRY 0\r
+#define CONNECT_MAX_RETRY 16\r
+\r
+#define CONNECT_MIN_TIMEOUT 100\r
+#define CONNECT_MAX_TIMEOUT 20000\r
+#define CONNECT_DEFAULT_TIMEOUT 1000\r
+\r
+#define ISCSI_MAX_ATTEMPTS_NUM 255\r
+\r
+#define ISCSI_DISABLED 0\r
+#define ISCSI_ENABLED 1\r
+#define ISCSI_ENABLED_FOR_MPIO 2\r
+\r
+#define IP_MODE_IP4 0\r
+#define IP_MODE_IP6 1\r
+#define IP_MODE_AUTOCONFIG 2\r
+\r
+#define ISCSI_AUTH_TYPE_NONE 0\r
+#define ISCSI_AUTH_TYPE_CHAP 1\r
+#define ISCSI_AUTH_TYPE_KRB 2\r
+\r
+#define IP4_MIN_SIZE 7\r
+#define IP4_MAX_SIZE 15\r
+#define IP4_STR_MAX_SIZE 16\r
+\r
+//\r
+// Macros used for an IPv4 or an IPv6 address.\r
+//\r
+#define IP_MIN_SIZE 2\r
+#define IP_MAX_SIZE 39\r
+#define IP_STR_MAX_SIZE 40\r
+\r
+#define LUN_MIN_SIZE 1\r
+#define LUN_MAX_SIZE 20\r
+\r
+#define ISCSI_CHAP_UNI 1\r
+#define ISCSI_CHAP_MUTUAL 2\r
+\r
+#define TARGET_PORT_MIN_NUM 0\r
+#define TARGET_PORT_MAX_NUM 65535\r
+#define LABEL_END 0xffff\r
+\r
+#define KEY_INITIATOR_NAME 0x101\r
+#define KEY_DHCP_ENABLE 0x102\r
+#define KEY_LOCAL_IP 0x103\r
+#define KEY_SUBNET_MASK 0x104\r
+#define KEY_GATE_WAY 0x105\r
+#define KEY_TARGET_IP 0x106\r
+#define KEY_CHAP_NAME 0x107\r
+#define KEY_CHAP_SECRET 0x108\r
+#define KEY_REVERSE_CHAP_NAME 0x109\r
+#define KEY_REVERSE_CHAP_SECRET 0x10a\r
+#define KEY_SAVE_CHANGES 0x10b\r
+#define KEY_TARGET_NAME 0x10c\r
+#define KEY_BOOT_LUN 0x10d\r
+\r
+#define KEY_ADD_ATTEMPT 0x10e\r
+#define KEY_SAVE_ATTEMPT_CONFIG 0x10f\r
+#define KEY_ORDER_ATTEMPT_CONFIG 0x110\r
+#define KEY_SAVE_ORDER_CHANGES 0x111\r
+#define KEY_IGNORE_ORDER_CHANGES 0x112\r
+#define KEY_ATTEMPT_NAME 0x113\r
+#define KEY_SAVE_DELETE_ATTEMPT 0x114\r
+#define KEY_IGNORE_DELETE_ATTEMPT 0x115\r
+#define KEY_DELETE_ATTEMPT 0x116\r
+\r
+#define KEY_KERBEROS_USER_NAME 0x117\r
+#define KEY_KERBEROS_USER_SECRET 0x118\r
+#define KEY_KERBEROS_KDC_NAME 0x119\r
+#define KEY_KERBEROS_KDC_REALM 0x11a\r
+#define KEY_KERBEROS_KDC_IP_ADDR 0x11b\r
+\r
+#define KEY_IP_MODE 0x11c\r
+#define KEY_AUTH_TYPE 0x11d\r
+#define KEY_CONFIG_ISID 0x11e\r
+\r
+#define ATTEMPT_ENTRY_LABEL 0x9000\r
+#define KEY_ATTEMPT_ENTRY_BASE 0xa000\r
+#define KEY_DE_ATTEMPT_ENTRY_BASE 0xb000\r
+\r
+#define KEY_DEVICE_ENTRY_BASE 0x1000\r
+#define KEY_MAC_ENTRY_BASE 0x2000\r
+#define MAC_ENTRY_LABEL 0x3000\r
+#define ORDER_ENTRY_LABEL 0x4000\r
+#define DELETE_ENTRY_LABEL 0x5000\r
+#define CONFIG_OPTION_OFFSET 0x9000\r
+\r
+#define ISCSI_LUN_STR_MAX_LEN 21\r
+#define ISCSI_CHAP_SECRET_MIN_LEN 12\r
+#define ISCSI_CHAP_SECRET_MAX_LEN 16\r
+//\r
+// ISCSI_CHAP_SECRET_STORAGE = ISCSI_CHAP_SECRET_MAX_LEN + sizeof (NULL-Terminator)\r
+//\r
+#define ISCSI_CHAP_SECRET_STORAGE 17\r
+#define ISCSI_CHAP_NAME_MAX_LEN 126\r
+#define ISCSI_CHAP_NAME_STORAGE 127\r
+\r
+#define KERBEROS_SECRET_MIN_LEN 12\r
+#define KERBEROS_SECRET_MAX_LEN 16\r
+#define KERBEROS_SECRET_STORAGE 17\r
+#define KERBEROS_NAME_MAX_LEN 96\r
+#define KERBEROS_KDC_PORT_MIN_NUM 0\r
+#define KERBEROS_KDC_PORT_MAX_NUM 65535\r
+\r
+#define ISID_CONFIGURABLE_MIN_LEN 6\r
+#define ISID_CONFIGURABLE_MAX_LEN 12\r
+#define ISID_CONFIGURABLE_STORAGE 13\r
+\r
+#pragma pack(1)\r
+typedef struct _ISCSI_CONFIG_IFR_NVDATA {\r
+ CHAR16 InitiatorName[ISCSI_NAME_MAX_SIZE];\r
+ CHAR16 AttemptName[ATTEMPT_NAME_MAX_SIZE];\r
+\r
+ UINT8 Enabled;\r
+ UINT8 IpMode;\r
+\r
+ UINT8 ConnectRetryCount;\r
+ UINT8 Padding1;\r
+ UINT16 ConnectTimeout; // Timeout value in milliseconds.\r
+\r
+ UINT8 InitiatorInfoFromDhcp;\r
+ UINT8 TargetInfoFromDhcp;\r
+ CHAR16 LocalIp[IP4_STR_MAX_SIZE];\r
+ CHAR16 SubnetMask[IP4_STR_MAX_SIZE];\r
+ CHAR16 Gateway[IP4_STR_MAX_SIZE];\r
+\r
+ CHAR16 TargetName[ISCSI_NAME_MAX_SIZE];\r
+ CHAR16 TargetIp[IP_STR_MAX_SIZE];\r
+ UINT16 TargetPort;\r
+ CHAR16 BootLun[ISCSI_LUN_STR_MAX_LEN];\r
+\r
+ UINT8 AuthenticationType;\r
+\r
+ UINT8 CHAPType;\r
+ CHAR16 CHAPName[ISCSI_CHAP_NAME_STORAGE];\r
+ CHAR16 CHAPSecret[ISCSI_CHAP_SECRET_STORAGE];\r
+ CHAR16 ReverseCHAPName[ISCSI_CHAP_NAME_STORAGE];\r
+ CHAR16 ReverseCHAPSecret[ISCSI_CHAP_SECRET_STORAGE];\r
+\r
+ BOOLEAN MutualRequired;\r
+ UINT8 Padding2;\r
+ CHAR16 KerberosUserName[KERBEROS_NAME_MAX_LEN];\r
+ CHAR16 KerberosUserSecret[KERBEROS_SECRET_STORAGE];\r
+ CHAR16 KerberosKDCName[KERBEROS_NAME_MAX_LEN];\r
+ CHAR16 KerberosKDCRealm[KERBEROS_NAME_MAX_LEN];\r
+ CHAR16 KerberosKDCIp[IP_STR_MAX_SIZE];\r
+ UINT16 KerberosKDCPort;\r
+\r
+ UINT8 DynamicOrderedList[ISCSI_MAX_ATTEMPTS_NUM];\r
+ UINT8 DeleteAttemptList[ISCSI_MAX_ATTEMPTS_NUM];\r
+\r
+ CHAR16 IsId[ISID_CONFIGURABLE_STORAGE];\r
+} ISCSI_CONFIG_IFR_NVDATA;\r
+#pragma pack()\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+ VFR file used by the iSCSI configuration component.\r
+ \r
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "IScsiConfigNVDataStruc.h"\r
+\r
+#define EFI_NETWORK_DEVICE_CLASS 0x04\r
+\r
+formset\r
+ guid = ISCSI_CONFIG_GUID,\r
+ title = STRING_TOKEN(STR_ISCSI_CONFIG_FORM_TITLE),\r
+ help = STRING_TOKEN(STR_ISCSI_CONFIG_FORM_HELP),\r
+ class = EFI_NETWORK_DEVICE_CLASS,\r
+ subclass = 0x03,\r
+\r
+ varstore ISCSI_CONFIG_IFR_NVDATA,\r
+ varid = CONFIGURATION_VARSTORE_ID,\r
+ name = ISCSI_CONFIG_IFR_NVDATA,\r
+ guid = ISCSI_CONFIG_GUID;\r
+\r
+ form formid = FORMID_MAIN_FORM,\r
+ title = STRING_TOKEN(STR_ISCSI_MAIN_FORM_TITLE);\r
+\r
+ string varid = ISCSI_CONFIG_IFR_NVDATA.InitiatorName,\r
+ prompt = STRING_TOKEN(STR_ISCSI_CONFIG_INIT_NAME),\r
+ help = STRING_TOKEN(STR_ISCSI_CONFIG_INIT_NAME_HELP),\r
+ flags = INTERACTIVE,\r
+ key = KEY_INITIATOR_NAME,\r
+ minsize = ISCSI_NAME_IFR_MIN_SIZE,\r
+ maxsize = ISCSI_NAME_IFR_MAX_SIZE,\r
+ endstring;\r
+\r
+ subtitle text = STRING_TOKEN(STR_NULL);\r
+\r
+ goto FORMID_MAC_FORM,\r
+ prompt = STRING_TOKEN(STR_ADD_ATTEMPT_ENTRY),\r
+ help = STRING_TOKEN(STR_ADD_ATTEMPT_ENTRY),\r
+ flags = INTERACTIVE,\r
+ key = KEY_ADD_ATTEMPT;\r
+\r
+ label ATTEMPT_ENTRY_LABEL;\r
+ label LABEL_END;\r
+\r
+ subtitle text = STRING_TOKEN(STR_NULL);\r
+\r
+ goto FORMID_DELETE_FORM,\r
+ prompt = STRING_TOKEN (STR_DEL_ATTEMPT_ENTRY),\r
+ help = STRING_TOKEN (STR_DEL_ATTEMPT_ENTRY_HELP),\r
+ flags = INTERACTIVE,\r
+ key = KEY_DELETE_ATTEMPT;\r
+\r
+ subtitle text = STRING_TOKEN(STR_NULL);\r
+\r
+ goto FORMID_ORDER_FORM,\r
+ prompt = STRING_TOKEN (STR_ORDER_ATTEMPT_ENTRY),\r
+ help = STRING_TOKEN (STR_ORDER_ATTEMPT_ENTRY),\r
+ flags = INTERACTIVE,\r
+ key = KEY_ORDER_ATTEMPT_CONFIG;\r
+\r
+ subtitle text = STRING_TOKEN(STR_NULL);\r
+\r
+ endform;\r
+\r
+ form formid = FORMID_MAC_FORM,\r
+ title = STRING_TOKEN(STR_ISCSI_MAC_FORM_TITLE);\r
+\r
+ label MAC_ENTRY_LABEL;\r
+ label LABEL_END;\r
+\r
+ endform;\r
+\r
+ form formid = FORMID_ORDER_FORM,\r
+ title = STRING_TOKEN(STR_ORDER_ATTEMPT_ENTRY);\r
+\r
+ label ORDER_ENTRY_LABEL;\r
+ label LABEL_END;\r
+\r
+ goto FORMID_MAIN_FORM,\r
+ prompt = STRING_TOKEN (STR_SAVE_AND_EXIT),\r
+ help = STRING_TOKEN (STR_SAVE_AND_EXIT),\r
+ flags = INTERACTIVE,\r
+ key = KEY_SAVE_ORDER_CHANGES;\r
+ \r
+ goto FORMID_MAIN_FORM,\r
+ prompt = STRING_TOKEN (STR_NO_SAVE_AND_EXIT),\r
+ help = STRING_TOKEN (STR_NO_SAVE_AND_EXIT),\r
+ flags = INTERACTIVE,\r
+ key = KEY_IGNORE_ORDER_CHANGES;\r
+\r
+ endform;\r
+\r
+ form formid = FORMID_DELETE_FORM,\r
+ title = STRING_TOKEN(STR_DEL_ATTEMPT_ENTRY);\r
+\r
+ label DELETE_ENTRY_LABEL;\r
+ label LABEL_END;\r
+\r
+ goto FORMID_MAIN_FORM,\r
+ prompt = STRING_TOKEN (STR_SAVE_AND_EXIT),\r
+ help = STRING_TOKEN (STR_SAVE_AND_EXIT),\r
+ flags = INTERACTIVE,\r
+ key = KEY_SAVE_DELETE_ATTEMPT;\r
+ \r
+ goto FORMID_MAIN_FORM,\r
+ prompt = STRING_TOKEN (STR_NO_SAVE_AND_EXIT),\r
+ help = STRING_TOKEN (STR_NO_SAVE_AND_EXIT),\r
+ flags = INTERACTIVE,\r
+ key = KEY_IGNORE_DELETE_ATTEMPT;\r
+ \r
+ endform; \r
+\r
+ form formid = FORMID_ATTEMPT_FORM,\r
+ title = STRING_TOKEN(STR_ISCSI_ATTEMPT_FORM_TITLE);\r
+\r
+ string varid = ISCSI_CONFIG_IFR_NVDATA.AttemptName,\r
+ prompt = STRING_TOKEN(STR_ISCSI_ATTEMPT_NAME),\r
+ help = STRING_TOKEN(STR_ISCSI_ATTEMPT_NAME_HELP),\r
+ flags = INTERACTIVE,\r
+ key = KEY_ATTEMPT_NAME,\r
+ minsize = 0,\r
+ maxsize = ATTEMPT_NAME_MAX_SIZE,\r
+ endstring;\r
+\r
+ subtitle text = STRING_TOKEN(STR_NULL);\r
+\r
+ oneof varid = ISCSI_CONFIG_IFR_NVDATA.Enabled,\r
+ prompt = STRING_TOKEN(STR_ISCSI_MODE_PROMPT),\r
+ help = STRING_TOKEN(STR_ISCSI_MODE_HELP),\r
+ option text = STRING_TOKEN(STR_ISCSI_MODE_DISABLED), value = ISCSI_DISABLED, flags = DEFAULT;\r
+ option text = STRING_TOKEN(STR_ISCSI_MODE_ENABLED), value = ISCSI_ENABLED, flags = 0;\r
+ option text = STRING_TOKEN(STR_ISCSI_MODE_ENABLED_FOR_MPIO), value = ISCSI_ENABLED_FOR_MPIO, flags = 0;\r
+ endoneof;\r
+\r
+ subtitle text = STRING_TOKEN(STR_NULL);\r
+\r
+ oneof varid = ISCSI_CONFIG_IFR_NVDATA.IpMode,\r
+ questionid = KEY_IP_MODE,\r
+ prompt = STRING_TOKEN(STR_IP_MODE_PROMPT),\r
+ help = STRING_TOKEN(STR_IP_MODE_HELP),\r
+ option text = STRING_TOKEN(STR_IP_MODE_IP4), value = IP_MODE_IP4, flags = INTERACTIVE;\r
+ option text = STRING_TOKEN(STR_IP_MODE_IP6), value = IP_MODE_IP6, flags = INTERACTIVE;\r
+ option text = STRING_TOKEN(STR_IP_MODE_AUTOCONFIG), value = IP_MODE_AUTOCONFIG, flags = INTERACTIVE;\r
+ endoneof;\r
+\r
+ subtitle text = STRING_TOKEN(STR_NULL);\r
+\r
+ numeric varid = ISCSI_CONFIG_IFR_NVDATA.ConnectRetryCount,\r
+ prompt = STRING_TOKEN(STR_ISCSI_CONFIG_RETRY),\r
+ help = STRING_TOKEN(STR_ISCSI_CONFIG_RETRY_HELP),\r
+ flags = 0,\r
+ minimum = CONNECT_MIN_RETRY,\r
+ maximum = CONNECT_MAX_RETRY,\r
+ step = 0,\r
+ endnumeric; \r
+ \r
+ numeric varid = ISCSI_CONFIG_IFR_NVDATA.ConnectTimeout,\r
+ prompt = STRING_TOKEN(STR_ISCSI_CONFIG_TIMEOUT),\r
+ help = STRING_TOKEN(STR_ISCSI_CONFIG_TIMEOUT_HELP),\r
+ flags = 0,\r
+ minimum = CONNECT_MIN_TIMEOUT,\r
+ maximum = CONNECT_MAX_TIMEOUT,\r
+ step = 0,\r
+ default = CONNECT_DEFAULT_TIMEOUT,\r
+ endnumeric;\r
+\r
+ subtitle text = STRING_TOKEN(STR_NULL);\r
+\r
+ string varid = ISCSI_CONFIG_IFR_NVDATA.IsId, \r
+ prompt = STRING_TOKEN(STR_ISCSI_CONFIG_ISID),\r
+ help = STRING_TOKEN(STR_ISCSI_CONFIG_ISID_HELP),\r
+ flags = INTERACTIVE,\r
+ key = KEY_CONFIG_ISID,\r
+ minsize = ISID_CONFIGURABLE_MIN_LEN,\r
+ maxsize = ISID_CONFIGURABLE_MAX_LEN,\r
+ endstring;\r
+\r
+ subtitle text = STRING_TOKEN(STR_NULL);\r
+\r
+ suppressif ideqval ISCSI_CONFIG_IFR_NVDATA.IpMode == IP_MODE_AUTOCONFIG;\r
+ checkbox varid = ISCSI_CONFIG_IFR_NVDATA.InitiatorInfoFromDhcp,\r
+ prompt = STRING_TOKEN(STR_ISCSI_ENABLE_DHCP),\r
+ help = STRING_TOKEN(STR_ISCSI_ENABLE_DHCP),\r
+ flags = INTERACTIVE,\r
+ key = KEY_DHCP_ENABLE,\r
+ endcheckbox;\r
+ endif;\r
+\r
+ suppressif ideqval ISCSI_CONFIG_IFR_NVDATA.InitiatorInfoFromDhcp == 0x01 OR\r
+ ideqval ISCSI_CONFIG_IFR_NVDATA.IpMode == IP_MODE_IP6 OR \r
+ ideqval ISCSI_CONFIG_IFR_NVDATA.IpMode == IP_MODE_AUTOCONFIG;\r
+ string varid = ISCSI_CONFIG_IFR_NVDATA.LocalIp,\r
+ prompt = STRING_TOKEN(STR_ISCSI_LOCAL_IP_ADDRESS),\r
+ help = STRING_TOKEN(STR_ISCSI_IP_ADDRESS_HELP),\r
+ flags = INTERACTIVE,\r
+ key = KEY_LOCAL_IP,\r
+ minsize = IP4_MIN_SIZE,\r
+ maxsize = IP4_MAX_SIZE,\r
+ endstring;\r
+\r
+ string varid = ISCSI_CONFIG_IFR_NVDATA.SubnetMask,\r
+ prompt = STRING_TOKEN(STR_ISCSI_LOCAL_MASK),\r
+ help = STRING_TOKEN(STR_ISCSI_IP_ADDRESS_HELP),\r
+ flags = INTERACTIVE,\r
+ key = KEY_SUBNET_MASK,\r
+ minsize = IP4_MIN_SIZE,\r
+ maxsize = IP4_MAX_SIZE,\r
+ endstring;\r
+\r
+ string varid = ISCSI_CONFIG_IFR_NVDATA.Gateway,\r
+ prompt = STRING_TOKEN(STR_ISCSI_LOCAL_GATEWAY),\r
+ help = STRING_TOKEN(STR_ISCSI_IP_ADDRESS_HELP),\r
+ flags = INTERACTIVE,\r
+ key = KEY_GATE_WAY,\r
+ minsize = IP4_MIN_SIZE,\r
+ maxsize = IP4_MAX_SIZE,\r
+ endstring;\r
+ \r
+ endif;\r
+\r
+ suppressif ideqval ISCSI_CONFIG_IFR_NVDATA.IpMode == IP_MODE_AUTOCONFIG;\r
+ subtitle text = STRING_TOKEN(STR_NULL);\r
+ endif; \r
+\r
+ suppressif ideqval ISCSI_CONFIG_IFR_NVDATA.IpMode == IP_MODE_AUTOCONFIG OR\r
+ ideqval ISCSI_CONFIG_IFR_NVDATA.InitiatorInfoFromDhcp == 0x00;\r
+ checkbox varid = ISCSI_CONFIG_IFR_NVDATA.TargetInfoFromDhcp,\r
+ prompt = STRING_TOKEN(STR_ISCSI_ENABLE_DHCP_ON_TARGET),\r
+ help = STRING_TOKEN(STR_ISCSI_ENABLE_DHCP_ON_TARGET),\r
+ flags = 0,\r
+ endcheckbox;\r
+ endif;\r
+\r
+ suppressif ideqval ISCSI_CONFIG_IFR_NVDATA.IpMode == IP_MODE_AUTOCONFIG OR\r
+ ideqval ISCSI_CONFIG_IFR_NVDATA.TargetInfoFromDhcp == 0x01;\r
+\r
+ string varid = ISCSI_CONFIG_IFR_NVDATA.TargetName,\r
+ prompt = STRING_TOKEN(STR_ISCSI_TARGET_NAME),\r
+ help = STRING_TOKEN(STR_ISCSI_TARGET_NAME_HELP),\r
+ flags = INTERACTIVE,\r
+ key = KEY_TARGET_NAME,\r
+ minsize = ISCSI_NAME_IFR_MIN_SIZE,\r
+ maxsize = ISCSI_NAME_IFR_MAX_SIZE,\r
+ endstring;\r
+\r
+ string varid = ISCSI_CONFIG_IFR_NVDATA.TargetIp,\r
+ prompt = STRING_TOKEN(STR_ISCSI_TARGET_IP_ADDRESS),\r
+ help = STRING_TOKEN(STR_ISCSI_IP_ADDRESS_HELP),\r
+ flags = INTERACTIVE,\r
+ key = KEY_TARGET_IP,\r
+ minsize = IP_MIN_SIZE,\r
+ maxsize = IP_MAX_SIZE,\r
+ endstring;\r
+\r
+ numeric varid = ISCSI_CONFIG_IFR_NVDATA.TargetPort,\r
+ prompt = STRING_TOKEN(STR_ISCSI_TARGET_PORT),\r
+ help = STRING_TOKEN(STR_ISCSI_TARGET_PORT),\r
+ flags = 0,\r
+ minimum = TARGET_PORT_MIN_NUM,\r
+ maximum = TARGET_PORT_MAX_NUM,\r
+ step = 0,\r
+ endnumeric;\r
+\r
+ string varid = ISCSI_CONFIG_IFR_NVDATA.BootLun,\r
+ prompt = STRING_TOKEN(STR_ISCSI_BOOT_LUN),\r
+ help = STRING_TOKEN(STR_ISCSI_BOOT_LUN_HELP),\r
+ flags = INTERACTIVE,\r
+ key = KEY_BOOT_LUN,\r
+ minsize = LUN_MIN_SIZE,\r
+ maxsize = LUN_MAX_SIZE,\r
+ endstring;\r
+ \r
+ endif;\r
+\r
+ suppressif ideqval ISCSI_CONFIG_IFR_NVDATA.IpMode == IP_MODE_AUTOCONFIG;\r
+ subtitle text = STRING_TOKEN(STR_NULL);\r
+ endif; \r
+\r
+ oneof varid = ISCSI_CONFIG_IFR_NVDATA.AuthenticationType,\r
+ questionid = KEY_AUTH_TYPE, \r
+ prompt = STRING_TOKEN(STR_AUTHEN_TYPE_PROMPT),\r
+ help = STRING_TOKEN(STR_AUTHEN_TYPE_HELP),\r
+ option text = STRING_TOKEN(STR_AUTHEN_TYPE_CHAP), value = ISCSI_AUTH_TYPE_CHAP, flags = 0;\r
+ option text = STRING_TOKEN(STR_AUTHEN_TYPE_NONE), value = ISCSI_AUTH_TYPE_NONE, flags = DEFAULT;\r
+ endoneof;\r
+\r
+ suppressif NOT ideqval ISCSI_CONFIG_IFR_NVDATA.AuthenticationType == ISCSI_AUTH_TYPE_CHAP; \r
+ oneof varid = ISCSI_CONFIG_IFR_NVDATA.CHAPType,\r
+ prompt = STRING_TOKEN(STR_CHAP_TYPE_PROMPT),\r
+ help = STRING_TOKEN(STR_CHAP_TYPE_HELP),\r
+ option text = STRING_TOKEN(STR_CHAP_TYPE_UNI), value = ISCSI_CHAP_UNI, flags = 0;\r
+ option text = STRING_TOKEN(STR_CHAP_TYPE_MUTUAL), value = ISCSI_CHAP_MUTUAL, flags = DEFAULT;\r
+ endoneof;\r
+ endif;\r
+\r
+ suppressif NOT ideqval ISCSI_CONFIG_IFR_NVDATA.AuthenticationType == ISCSI_AUTH_TYPE_CHAP;\r
+ string varid = ISCSI_CONFIG_IFR_NVDATA.CHAPName,\r
+ prompt = STRING_TOKEN(STR_ISCSI_CHAP_NAME),\r
+ help = STRING_TOKEN(STR_ISCSI_CHAP_NAME),\r
+ flags = INTERACTIVE,\r
+ key = KEY_CHAP_NAME,\r
+ minsize = 0,\r
+ maxsize = ISCSI_CHAP_NAME_MAX_LEN,\r
+ endstring;\r
+\r
+ string varid = ISCSI_CONFIG_IFR_NVDATA.CHAPSecret,\r
+ prompt = STRING_TOKEN(STR_ISCSI_CHAP_SECRET),\r
+ help = STRING_TOKEN(STR_ISCSI_CHAP_SECRET_HELP),\r
+ flags = INTERACTIVE,\r
+ key = KEY_CHAP_SECRET,\r
+ minsize = ISCSI_CHAP_SECRET_MIN_LEN,\r
+ maxsize = ISCSI_CHAP_SECRET_MAX_LEN,\r
+ endstring;\r
+\r
+ endif;\r
+\r
+ suppressif NOT ideqval ISCSI_CONFIG_IFR_NVDATA.AuthenticationType == ISCSI_AUTH_TYPE_CHAP OR\r
+ NOT ideqval ISCSI_CONFIG_IFR_NVDATA.CHAPType == ISCSI_CHAP_MUTUAL;\r
+\r
+ string varid = ISCSI_CONFIG_IFR_NVDATA.ReverseCHAPName,\r
+ prompt = STRING_TOKEN(STR_ISCSI_REVERSE_CHAP_NAME),\r
+ help = STRING_TOKEN(STR_ISCSI_REVERSE_CHAP_NAME),\r
+ flags = INTERACTIVE,\r
+ key = KEY_REVERSE_CHAP_NAME,\r
+ minsize = 0,\r
+ maxsize = ISCSI_CHAP_NAME_MAX_LEN,\r
+ endstring;\r
+\r
+ string varid = ISCSI_CONFIG_IFR_NVDATA.ReverseCHAPSecret,\r
+ prompt = STRING_TOKEN(STR_ISCSI_REVERSE_CHAP_SECRET),\r
+ help = STRING_TOKEN(STR_ISCSI_CHAP_SECRET_HELP),\r
+ flags = INTERACTIVE,\r
+ key = KEY_REVERSE_CHAP_SECRET,\r
+ minsize = ISCSI_CHAP_SECRET_MIN_LEN,\r
+ maxsize = ISCSI_CHAP_SECRET_MAX_LEN,\r
+ endstring;\r
+\r
+ endif;\r
+\r
+ suppressif NOT ideqval ISCSI_CONFIG_IFR_NVDATA.AuthenticationType == ISCSI_AUTH_TYPE_KRB;\r
+\r
+ checkbox varid = ISCSI_CONFIG_IFR_NVDATA.MutualRequired,\r
+ prompt = STRING_TOKEN(STR_ISCSI_MUTUAL_REQUIRED),\r
+ help = STRING_TOKEN(STR_ISCSI_MUTUAL_REQUIRED_HELP),\r
+ flags = 0,\r
+ endcheckbox;\r
+ \r
+ string varid = ISCSI_CONFIG_IFR_NVDATA.KerberosUserName,\r
+ prompt = STRING_TOKEN(STR_ISCSI_KERBEROS_USER_NAME),\r
+ help = STRING_TOKEN(STR_ISCSI_KERBEROS_USER_NAME),\r
+ flags = INTERACTIVE,\r
+ key = KEY_KERBEROS_USER_NAME,\r
+ minsize = 0,\r
+ maxsize = KERBEROS_NAME_MAX_LEN,\r
+ endstring;\r
+\r
+ string varid = ISCSI_CONFIG_IFR_NVDATA.KerberosUserSecret,\r
+ prompt = STRING_TOKEN(STR_ISCSI_KERBEROS_USER_SECRET),\r
+ help = STRING_TOKEN(STR_ISCSI_KERBEROS_USER_SECRET),\r
+ flags = INTERACTIVE,\r
+ key = KEY_KERBEROS_USER_SECRET,\r
+ minsize = KERBEROS_SECRET_MIN_LEN,\r
+ maxsize = KERBEROS_SECRET_MAX_LEN,\r
+ endstring;\r
+ \r
+ string varid = ISCSI_CONFIG_IFR_NVDATA.KerberosKDCName,\r
+ prompt = STRING_TOKEN(STR_ISCSI_KERBEROS_KDC_NAME),\r
+ help = STRING_TOKEN(STR_ISCSI_KERBEROS_KDC_NAME),\r
+ flags = INTERACTIVE,\r
+ key = KEY_KERBEROS_KDC_NAME,\r
+ minsize = 0,\r
+ maxsize = KERBEROS_NAME_MAX_LEN,\r
+ endstring;\r
+\r
+ string varid = ISCSI_CONFIG_IFR_NVDATA.KerberosKDCRealm,\r
+ prompt = STRING_TOKEN(STR_ISCSI_KERBEROS_KDC_REALM),\r
+ help = STRING_TOKEN(STR_ISCSI_KERBEROS_KDC_REALM),\r
+ flags = INTERACTIVE,\r
+ key = KEY_KERBEROS_KDC_REALM,\r
+ minsize = 0,\r
+ maxsize = KERBEROS_NAME_MAX_LEN,\r
+ endstring;\r
+\r
+ string varid = ISCSI_CONFIG_IFR_NVDATA.KerberosKDCIp,\r
+ prompt = STRING_TOKEN(STR_ISCSI_KERBEROS_KDC_IP),\r
+ help = STRING_TOKEN(STR_ISCSI_KERBEROS_KDC_IP),\r
+ flags = INTERACTIVE,\r
+ key = KEY_KERBEROS_KDC_IP_ADDR,\r
+ minsize = IP_MIN_SIZE,\r
+ maxsize = IP_MAX_SIZE,\r
+ endstring;\r
+\r
+ numeric varid = ISCSI_CONFIG_IFR_NVDATA.KerberosKDCPort,\r
+ prompt = STRING_TOKEN(STR_ISCSI_KERBEROS_KDC_PORT),\r
+ help = STRING_TOKEN(STR_ISCSI_KERBEROS_KDC_PORT),\r
+ flags = 0,\r
+ minimum = KERBEROS_KDC_PORT_MIN_NUM,\r
+ maximum = KERBEROS_KDC_PORT_MAX_NUM,\r
+ step = 0,\r
+ endnumeric;\r
+ \r
+ endif;\r
+\r
+ subtitle text = STRING_TOKEN(STR_NULL);\r
+\r
+ goto FORMID_ATTEMPT_FORM,\r
+ prompt = STRING_TOKEN (STR_SAVE_CHANGES),\r
+ help = STRING_TOKEN (STR_SAVE_CHANGES),\r
+ flags = INTERACTIVE,\r
+ key = KEY_SAVE_ATTEMPT_CONFIG;\r
+\r
+ goto FORMID_MAIN_FORM,\r
+ prompt = STRING_TOKEN (STR_RETURN_MAIN_FORM),\r
+ help = STRING_TOKEN (STR_RETURN_MAIN_FORM),\r
+ flags = 0;\r
+\r
+ endform;\r
+\r
+endformset;\r
+\r
--- /dev/null
+/** @file\r
+ iSCSI DHCP4 related configuration routines.\r
+\r
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "IScsiImpl.h"\r
+\r
+\r
+/**\r
+ Extract the Root Path option and get the required target information.\r
+\r
+ @param[in] RootPath The RootPath.\r
+ @param[in] Length Length of the RootPath option payload.\r
+ @param[in, out] ConfigData The iSCSI attempt configuration data read\r
+ from a nonvolatile device.\r
+\r
+ @retval EFI_SUCCESS All required information is extracted from the RootPath option.\r
+ @retval EFI_NOT_FOUND The RootPath is not an iSCSI RootPath.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+ @retval EFI_INVALID_PARAMETER The RootPath is malformatted.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiDhcpExtractRootPath (\r
+ IN CHAR8 *RootPath,\r
+ IN UINT8 Length,\r
+ IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 IScsiRootPathIdLen;\r
+ CHAR8 *TmpStr;\r
+ ISCSI_ROOT_PATH_FIELD Fields[RP_FIELD_IDX_MAX];\r
+ ISCSI_ROOT_PATH_FIELD *Field;\r
+ UINT32 FieldIndex;\r
+ UINT8 Index;\r
+ ISCSI_SESSION_CONFIG_NVDATA *ConfigNvData;\r
+ EFI_IP_ADDRESS Ip;\r
+ UINT8 IpMode;\r
+\r
+ ConfigNvData = &ConfigData->SessionConfigData;\r
+\r
+ //\r
+ // "iscsi:"<servername>":"<protocol>":"<port>":"<LUN>":"<targetname>\r
+ //\r
+ IScsiRootPathIdLen = (UINT8) AsciiStrLen (ISCSI_ROOT_PATH_ID);\r
+\r
+ if ((Length <= IScsiRootPathIdLen) || (CompareMem (RootPath, ISCSI_ROOT_PATH_ID, IScsiRootPathIdLen) != 0)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ //\r
+ // Skip the iSCSI RootPath ID "iscsi:".\r
+ //\r
+ RootPath += IScsiRootPathIdLen;\r
+ Length = (UINT8) (Length - IScsiRootPathIdLen);\r
+\r
+ TmpStr = (CHAR8 *) AllocatePool (Length + 1);\r
+ if (TmpStr == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ CopyMem (TmpStr, RootPath, Length);\r
+ TmpStr[Length] = '\0';\r
+\r
+ Index = 0;\r
+ FieldIndex = RP_FIELD_IDX_SERVERNAME;\r
+ ZeroMem (&Fields[0], sizeof (Fields));\r
+\r
+ //\r
+ // Extract the fields in the Root Path option string.\r
+ //\r
+ for (FieldIndex = RP_FIELD_IDX_SERVERNAME; (FieldIndex < RP_FIELD_IDX_MAX) && (Index < Length); FieldIndex++) {\r
+ if (TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) {\r
+ Fields[FieldIndex].Str = &TmpStr[Index];\r
+ }\r
+\r
+ while ((TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) && (Index < Length)) {\r
+ Index++;\r
+ }\r
+\r
+ if (TmpStr[Index] == ISCSI_ROOT_PATH_FIELD_DELIMITER) {\r
+ if (FieldIndex != RP_FIELD_IDX_TARGETNAME) {\r
+ TmpStr[Index] = '\0';\r
+ Index++;\r
+ }\r
+\r
+ if (Fields[FieldIndex].Str != NULL) {\r
+ Fields[FieldIndex].Len = (UINT8) AsciiStrLen (Fields[FieldIndex].Str);\r
+ }\r
+ }\r
+ }\r
+\r
+ if (FieldIndex != RP_FIELD_IDX_MAX) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if ((Fields[RP_FIELD_IDX_SERVERNAME].Str == NULL) ||\r
+ (Fields[RP_FIELD_IDX_TARGETNAME].Str == NULL) ||\r
+ (Fields[RP_FIELD_IDX_PROTOCOL].Len > 1)\r
+ ) {\r
+\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // Get the IP address of the target.\r
+ //\r
+ Field = &Fields[RP_FIELD_IDX_SERVERNAME];\r
+\r
+ if (ConfigNvData->IpMode < IP_MODE_AUTOCONFIG) {\r
+ IpMode = ConfigNvData->IpMode;\r
+ } else {\r
+ IpMode = ConfigData->AutoConfigureMode;\r
+ }\r
+\r
+ Status = IScsiAsciiStrToIp (Field->Str, IpMode, &Ip);\r
+ CopyMem (&ConfigNvData->TargetIp, &Ip, sizeof (EFI_IP_ADDRESS));\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // Check the protocol type.\r
+ //\r
+ Field = &Fields[RP_FIELD_IDX_PROTOCOL];\r
+ if ((Field->Str != NULL) && ((*(Field->Str) - '0') != EFI_IP_PROTO_TCP)) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // Get the port of the iSCSI target.\r
+ //\r
+ Field = &Fields[RP_FIELD_IDX_PORT];\r
+ if (Field->Str != NULL) {\r
+ ConfigNvData->TargetPort = (UINT16) AsciiStrDecimalToUintn (Field->Str);\r
+ } else {\r
+ ConfigNvData->TargetPort = ISCSI_WELL_KNOWN_PORT;\r
+ }\r
+ //\r
+ // Get the LUN.\r
+ //\r
+ Field = &Fields[RP_FIELD_IDX_LUN];\r
+ if (Field->Str != NULL) {\r
+ Status = IScsiAsciiStrToLun (Field->Str, ConfigNvData->BootLun);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+ } else {\r
+ ZeroMem (ConfigNvData->BootLun, sizeof (ConfigNvData->BootLun));\r
+ }\r
+ //\r
+ // Get the target iSCSI Name.\r
+ //\r
+ Field = &Fields[RP_FIELD_IDX_TARGETNAME];\r
+\r
+ if (AsciiStrLen (Field->Str) > ISCSI_NAME_MAX_SIZE - 1) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // Validate the iSCSI name.\r
+ //\r
+ Status = IScsiNormalizeName (Field->Str, AsciiStrLen (Field->Str));\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ AsciiStrCpy (ConfigNvData->TargetName, Field->Str);\r
+\r
+ON_EXIT:\r
+\r
+ FreePool (TmpStr);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ The callback function registerd to the DHCP4 instance that is used to select\r
+ the qualified DHCP OFFER.\r
+ \r
+ @param[in] This The DHCP4 protocol.\r
+ @param[in] Context The context set when configuring the DHCP4 protocol.\r
+ @param[in] CurrentState The current state of the DHCP4 protocol.\r
+ @param[in] Dhcp4Event The event occurs in the current state.\r
+ @param[in] Packet The DHCP packet that is to be sent or was already received. \r
+ @param[out] NewPacket The packet used to replace the above Packet.\r
+ \r
+ @retval EFI_SUCCESS Either the DHCP OFFER is qualified or we're not intereseted\r
+ in the Dhcp4Event.\r
+ @retval EFI_NOT_READY The DHCP OFFER packet doesn't match our requirements.\r
+ @retval Others Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiDhcpSelectOffer (\r
+ IN EFI_DHCP4_PROTOCOL *This,\r
+ IN VOID *Context,\r
+ IN EFI_DHCP4_STATE CurrentState,\r
+ IN EFI_DHCP4_EVENT Dhcp4Event,\r
+ IN EFI_DHCP4_PACKET *Packet, OPTIONAL\r
+ OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 OptionCount;\r
+ EFI_DHCP4_PACKET_OPTION **OptionList;\r
+ UINT32 Index;\r
+\r
+ if ((Dhcp4Event != Dhcp4RcvdOffer) && (Dhcp4Event != Dhcp4SelectOffer)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ OptionCount = 0;\r
+\r
+ Status = This->Parse (This, Packet, &OptionCount, NULL);\r
+ if (Status != EFI_BUFFER_TOO_SMALL) {\r
+ return EFI_NOT_READY;\r
+ }\r
+\r
+ OptionList = AllocatePool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));\r
+ if (OptionList == NULL) {\r
+ return EFI_NOT_READY;\r
+ }\r
+\r
+ Status = This->Parse (This, Packet, &OptionCount, OptionList);\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (OptionList);\r
+ return EFI_NOT_READY;\r
+ }\r
+\r
+ for (Index = 0; Index < OptionCount; Index++) {\r
+ if (OptionList[Index]->OpCode != DHCP4_TAG_ROOT_PATH) {\r
+ continue;\r
+ }\r
+\r
+ Status = IScsiDhcpExtractRootPath (\r
+ (CHAR8 *) &OptionList[Index]->Data[0],\r
+ OptionList[Index]->Length,\r
+ (ISCSI_ATTEMPT_CONFIG_NVDATA *) Context\r
+ );\r
+\r
+ break;\r
+ }\r
+\r
+ if ((Index == OptionCount)) {\r
+ Status = EFI_NOT_READY;\r
+ }\r
+\r
+ FreePool (OptionList);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Parse the DHCP ACK to get the address configuration and DNS information.\r
+\r
+ @param[in] Dhcp4 The DHCP4 protocol.\r
+ @param[in, out] ConfigData The session configuration data.\r
+\r
+ @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.\r
+ @retval EFI_NO_MAPPING DHCP failed to acquire address and other information.\r
+ @retval EFI_INVALID_PARAMETER The DHCP ACK's DNS option is malformatted.\r
+ @retval EFI_DEVICE_ERROR Other errors as indicated.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiParseDhcpAck (\r
+ IN EFI_DHCP4_PROTOCOL *Dhcp4,\r
+ IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DHCP4_MODE_DATA Dhcp4ModeData;\r
+ UINT32 OptionCount;\r
+ EFI_DHCP4_PACKET_OPTION **OptionList;\r
+ UINT32 Index;\r
+ ISCSI_SESSION_CONFIG_NVDATA *NvData;\r
+\r
+ Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4ModeData);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Dhcp4ModeData.State != Dhcp4Bound) {\r
+ return EFI_NO_MAPPING;\r
+ }\r
+\r
+ NvData = &ConfigData->SessionConfigData;\r
+\r
+ CopyMem (&NvData->LocalIp, &Dhcp4ModeData.ClientAddress, sizeof (EFI_IPv4_ADDRESS));\r
+ CopyMem (&NvData->SubnetMask, &Dhcp4ModeData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
+ CopyMem (&NvData->Gateway, &Dhcp4ModeData.RouterAddress, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+ OptionCount = 0;\r
+ OptionList = NULL;\r
+\r
+ Status = Dhcp4->Parse (Dhcp4, Dhcp4ModeData.ReplyPacket, &OptionCount, OptionList);\r
+ if (Status != EFI_BUFFER_TOO_SMALL) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ OptionList = AllocatePool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));\r
+ if (OptionList == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = Dhcp4->Parse (Dhcp4, Dhcp4ModeData.ReplyPacket, &OptionCount, OptionList);\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (OptionList);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ for (Index = 0; Index < OptionCount; Index++) {\r
+ //\r
+ // Get DNS server addresses and DHCP server address from this offer.\r
+ //\r
+ if (OptionList[Index]->OpCode == DHCP4_TAG_DNS) {\r
+\r
+ if (((OptionList[Index]->Length & 0x3) != 0) || (OptionList[Index]->Length == 0)) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ break;\r
+ }\r
+ //\r
+ // Primary DNS server address.\r
+ //\r
+ CopyMem (&ConfigData->PrimaryDns, &OptionList[Index]->Data[0], sizeof (EFI_IPv4_ADDRESS));\r
+\r
+ if (OptionList[Index]->Length > 4) {\r
+ //\r
+ // Secondary DNS server address.\r
+ //\r
+ CopyMem (&ConfigData->SecondaryDns, &OptionList[Index]->Data[4], sizeof (EFI_IPv4_ADDRESS));\r
+ }\r
+ } else if (OptionList[Index]->OpCode == DHCP4_TAG_SERVER_ID) {\r
+ if (OptionList[Index]->Length != 4) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ break;\r
+ }\r
+\r
+ CopyMem (&ConfigData->DhcpServer, &OptionList[Index]->Data[0], sizeof (EFI_IPv4_ADDRESS));\r
+ }\r
+ }\r
+\r
+ FreePool (OptionList);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Parse the DHCP ACK to get the address configuration and DNS information.\r
+\r
+ @param[in] Image The handle of the driver image.\r
+ @param[in] Controller The handle of the controller.\r
+ @param[in, out] ConfigData The attempt configuration data.\r
+\r
+ @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+ @retval EFI_NO_MEDIA There was a media error.\r
+ @retval Others Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiDoDhcp (\r
+ IN EFI_HANDLE Image,\r
+ IN EFI_HANDLE Controller,\r
+ IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData\r
+ )\r
+{\r
+ EFI_HANDLE Dhcp4Handle;\r
+ EFI_DHCP4_PROTOCOL *Dhcp4;\r
+ EFI_STATUS Status;\r
+ EFI_DHCP4_PACKET_OPTION *ParaList;\r
+ EFI_DHCP4_CONFIG_DATA Dhcp4ConfigData;\r
+ ISCSI_SESSION_CONFIG_NVDATA *NvData;\r
+ BOOLEAN MediaPresent;\r
+\r
+ Dhcp4Handle = NULL;\r
+ Dhcp4 = NULL;\r
+ ParaList = NULL;\r
+\r
+ //\r
+ // Check media status before doing DHCP.\r
+ //\r
+ MediaPresent = TRUE;\r
+ NetLibDetectMedia (Controller, &MediaPresent);\r
+ if (!MediaPresent) {\r
+ return EFI_NO_MEDIA;\r
+ }\r
+\r
+ //\r
+ // Create a DHCP4 child instance and get the protocol.\r
+ //\r
+ Status = NetLibCreateServiceChild (\r
+ Controller,\r
+ Image,\r
+ &gEfiDhcp4ServiceBindingProtocolGuid,\r
+ &Dhcp4Handle\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Dhcp4Handle,\r
+ &gEfiDhcp4ProtocolGuid,\r
+ (VOID **) &Dhcp4,\r
+ Image,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ NvData = &ConfigData->SessionConfigData;\r
+\r
+ ParaList = AllocatePool (sizeof (EFI_DHCP4_PACKET_OPTION) + 3);\r
+ if (ParaList == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Ask the server to reply with Netmask, Router, DNS, and RootPath options.\r
+ //\r
+ ParaList->OpCode = DHCP4_TAG_PARA_LIST;\r
+ ParaList->Length = (UINT8) (NvData->TargetInfoFromDhcp ? 4 : 3);\r
+ ParaList->Data[0] = DHCP4_TAG_NETMASK;\r
+ ParaList->Data[1] = DHCP4_TAG_ROUTER;\r
+ ParaList->Data[2] = DHCP4_TAG_DNS;\r
+ ParaList->Data[3] = DHCP4_TAG_ROOT_PATH;\r
+\r
+ ZeroMem (&Dhcp4ConfigData, sizeof (EFI_DHCP4_CONFIG_DATA));\r
+ Dhcp4ConfigData.OptionCount = 1;\r
+ Dhcp4ConfigData.OptionList = &ParaList;\r
+\r
+ if (NvData->TargetInfoFromDhcp) {\r
+ //\r
+ // Use callback to select an offer that contains target information.\r
+ //\r
+ Dhcp4ConfigData.Dhcp4Callback = IScsiDhcpSelectOffer;\r
+ Dhcp4ConfigData.CallbackContext = ConfigData;\r
+ }\r
+\r
+ Status = Dhcp4->Configure (Dhcp4, &Dhcp4ConfigData);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = Dhcp4->Start (Dhcp4, NULL);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // Parse the ACK to get required information.\r
+ //\r
+ Status = IScsiParseDhcpAck (Dhcp4, ConfigData);\r
+\r
+ON_EXIT:\r
+\r
+ if (ParaList != NULL) {\r
+ FreePool (ParaList);\r
+ }\r
+\r
+ if (Dhcp4 != NULL) {\r
+ Dhcp4->Stop (Dhcp4);\r
+ Dhcp4->Configure (Dhcp4, NULL);\r
+\r
+ gBS->CloseProtocol (\r
+ Dhcp4Handle,\r
+ &gEfiDhcp4ProtocolGuid,\r
+ Image,\r
+ Controller\r
+ );\r
+ }\r
+\r
+ NetLibDestroyServiceChild (\r
+ Controller,\r
+ Image,\r
+ &gEfiDhcp4ServiceBindingProtocolGuid,\r
+ Dhcp4Handle\r
+ );\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+ The head file of iSCSI DHCP4 related configuration routines.\r
+\r
+Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _ISCSI_DHCP_H_\r
+#define _ISCSI_DHCP_H_\r
+\r
+\r
+#define DHCP4_TAG_PARA_LIST 55\r
+#define DHCP4_TAG_NETMASK 1\r
+#define DHCP4_TAG_ROUTER 3\r
+#define DHCP4_TAG_DNS 6\r
+#define DHCP4_TAG_SERVER_ID 54\r
+#define DHCP4_TAG_ROOT_PATH 17\r
+#define ISCSI_ROOT_PATH_ID "iscsi:"\r
+#define ISCSI_ROOT_PATH_FIELD_DELIMITER ':'\r
+\r
+#define RP_FIELD_IDX_SERVERNAME 0\r
+#define RP_FIELD_IDX_PROTOCOL 1\r
+#define RP_FIELD_IDX_PORT 2\r
+#define RP_FIELD_IDX_LUN 3\r
+#define RP_FIELD_IDX_TARGETNAME 4\r
+#define RP_FIELD_IDX_MAX 5\r
+\r
+typedef struct _ISCSI_ATTEMPT_CONFIG_NVDATA ISCSI_ATTEMPT_CONFIG_NVDATA;\r
+\r
+typedef struct _ISCSI_ROOT_PATH_FIELD {\r
+ CHAR8 *Str;\r
+ UINT8 Len;\r
+} ISCSI_ROOT_PATH_FIELD;\r
+\r
+/**\r
+ Parse the DHCP ACK to get the address configuration and DNS information.\r
+\r
+ @param[in] Image The handle of the driver image.\r
+ @param[in] Controller The handle of the controller.\r
+ @param[in, out] ConfigData The attempt configuration data.\r
+\r
+ @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+ @retval EFI_NO_MEDIA There was a media error.\r
+ @retval Others Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiDoDhcp (\r
+ IN EFI_HANDLE Image,\r
+ IN EFI_HANDLE Controller,\r
+ IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+ iSCSI DHCP6 related configuration routines.\r
+\r
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "IScsiImpl.h"\r
+\r
+\r
+/**\r
+ Extract the Root Path option and get the required target information from\r
+ Boot File Uniform Resource Locator (URL) Option.\r
+\r
+ @param[in] RootPath The RootPath string.\r
+ @param[in] Length Length of the RootPath option payload.\r
+ @param[in, out] ConfigData The iSCSI session configuration data read from\r
+ nonvolatile device.\r
+\r
+ @retval EFI_SUCCESS All required information is extracted from the\r
+ RootPath option.\r
+ @retval EFI_NOT_FOUND The RootPath is not an iSCSI RootPath.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+ @retval EFI_INVALID_PARAMETER The RootPath is malformatted.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiDhcp6ExtractRootPath (\r
+ IN CHAR8 *RootPath,\r
+ IN UINT16 Length,\r
+ IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT16 IScsiRootPathIdLen;\r
+ CHAR8 *TmpStr;\r
+ ISCSI_ROOT_PATH_FIELD Fields[RP_FIELD_IDX_MAX];\r
+ ISCSI_ROOT_PATH_FIELD *Field;\r
+ UINT32 FieldIndex;\r
+ UINT8 Index;\r
+ ISCSI_SESSION_CONFIG_NVDATA *ConfigNvData;\r
+ EFI_IP_ADDRESS Ip;\r
+ UINT8 IpMode; \r
+\r
+ ConfigNvData = &ConfigData->SessionConfigData;\r
+\r
+ //\r
+ // "iscsi:"<servername>":"<protocol>":"<port>":"<LUN>":"<targetname>\r
+ //\r
+ IScsiRootPathIdLen = (UINT16) AsciiStrLen (ISCSI_ROOT_PATH_ID);\r
+\r
+ if ((Length <= IScsiRootPathIdLen) ||\r
+ (CompareMem (RootPath, ISCSI_ROOT_PATH_ID, IScsiRootPathIdLen) != 0)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ //\r
+ // Skip the iSCSI RootPath ID "iscsi:".\r
+ //\r
+ RootPath = RootPath + IScsiRootPathIdLen;\r
+ Length = (UINT16) (Length - IScsiRootPathIdLen);\r
+\r
+ TmpStr = (CHAR8 *) AllocatePool (Length + 1);\r
+ if (TmpStr == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ CopyMem (TmpStr, RootPath, Length);\r
+ TmpStr[Length] = '\0';\r
+\r
+ Index = 0;\r
+ FieldIndex = 0;\r
+ ZeroMem (&Fields[0], sizeof (Fields));\r
+\r
+ //\r
+ // Extract SERVERNAME field in the Root Path option.\r
+ //\r
+ if (TmpStr[Index] != ISCSI_ROOT_PATH_ADDR_START_DELIMITER) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ } else {\r
+ Index++;\r
+ }\r
+\r
+ Fields[RP_FIELD_IDX_SERVERNAME].Str = &TmpStr[Index];\r
+\r
+ while ((TmpStr[Index] != ISCSI_ROOT_PATH_ADDR_END_DELIMITER) && (Index < Length)) {\r
+ Index++;\r
+ }\r
+\r
+ //\r
+ // Skip ']' and ':'.\r
+ //\r
+ TmpStr[Index] = '\0';\r
+ Index += 2;\r
+\r
+ Fields[RP_FIELD_IDX_SERVERNAME].Len = (UINT8) AsciiStrLen (Fields[RP_FIELD_IDX_SERVERNAME].Str);\r
+\r
+ //\r
+ // Extract others fields in the Root Path option string.\r
+ //\r
+ for (FieldIndex = 1; (FieldIndex < RP_FIELD_IDX_MAX) && (Index < Length); FieldIndex++) {\r
+\r
+ if (TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) {\r
+ Fields[FieldIndex].Str = &TmpStr[Index];\r
+ }\r
+\r
+ while ((TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) && (Index < Length)) {\r
+ Index++;\r
+ }\r
+\r
+ if (TmpStr[Index] == ISCSI_ROOT_PATH_FIELD_DELIMITER) {\r
+ if (FieldIndex != RP_FIELD_IDX_TARGETNAME) {\r
+ TmpStr[Index] = '\0';\r
+ Index++;\r
+ }\r
+\r
+ if (Fields[FieldIndex].Str != NULL) {\r
+ Fields[FieldIndex].Len = (UINT8) AsciiStrLen (Fields[FieldIndex].Str);\r
+ }\r
+ }\r
+ }\r
+\r
+ if (FieldIndex != RP_FIELD_IDX_MAX) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if ((Fields[RP_FIELD_IDX_SERVERNAME].Str == NULL) ||\r
+ (Fields[RP_FIELD_IDX_TARGETNAME].Str == NULL) ||\r
+ (Fields[RP_FIELD_IDX_PROTOCOL].Len > 1)\r
+ ) {\r
+\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // Get the IP address of the target.\r
+ //\r
+ Field = &Fields[RP_FIELD_IDX_SERVERNAME]; \r
+ if (ConfigNvData->IpMode < IP_MODE_AUTOCONFIG) {\r
+ IpMode = ConfigNvData->IpMode;\r
+ } else {\r
+ IpMode = ConfigData->AutoConfigureMode;\r
+ }\r
+\r
+ Status = IScsiAsciiStrToIp (Field->Str, IpMode, &Ip);\r
+ CopyMem (&ConfigNvData->TargetIp, &Ip, sizeof (EFI_IP_ADDRESS));\r
+\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // Check the protocol type.\r
+ //\r
+ Field = &Fields[RP_FIELD_IDX_PROTOCOL];\r
+ if ((Field->Str != NULL) && ((*(Field->Str) - '0') != EFI_IP_PROTO_TCP)) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // Get the port of the iSCSI target.\r
+ //\r
+ Field = &Fields[RP_FIELD_IDX_PORT];\r
+ if (Field->Str != NULL) {\r
+ ConfigNvData->TargetPort = (UINT16) AsciiStrDecimalToUintn (Field->Str);\r
+ } else {\r
+ ConfigNvData->TargetPort = ISCSI_WELL_KNOWN_PORT;\r
+ }\r
+ //\r
+ // Get the LUN.\r
+ //\r
+ Field = &Fields[RP_FIELD_IDX_LUN];\r
+ if (Field->Str != NULL) {\r
+ Status = IScsiAsciiStrToLun (Field->Str, ConfigNvData->BootLun);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+ } else {\r
+ ZeroMem (ConfigNvData->BootLun, sizeof (ConfigNvData->BootLun));\r
+ }\r
+ //\r
+ // Get the target iSCSI Name.\r
+ //\r
+ Field = &Fields[RP_FIELD_IDX_TARGETNAME];\r
+\r
+ if (AsciiStrLen (Field->Str) > ISCSI_NAME_MAX_SIZE - 1) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // Validate the iSCSI name.\r
+ //\r
+ Status = IScsiNormalizeName (Field->Str, AsciiStrLen (Field->Str));\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ AsciiStrCpy (ConfigNvData->TargetName, Field->Str);\r
+\r
+ON_EXIT:\r
+\r
+ FreePool (TmpStr);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ EFI_DHCP6_INFO_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol \r
+ instance to intercept events that occurs in the DHCPv6 Information Request\r
+ exchange process.\r
+\r
+ @param[in] This Pointer to the EFI_DHCP6_PROTOCOL instance that \r
+ is used to configure this callback function.\r
+ @param[in] Context Pointer to the context that is initialized in\r
+ the EFI_DHCP6_PROTOCOL.InfoRequest().\r
+ @param[in] Packet Pointer to Reply packet that has been received.\r
+ The EFI DHCPv6 Protocol instance is responsible\r
+ for freeing the buffer.\r
+\r
+ @retval EFI_SUCCESS Tell the EFI DHCPv6 Protocol instance to finish\r
+ Information Request exchange process.\r
+ @retval EFI_NOT_READY Tell the EFI DHCPv6 Protocol instance to continue\r
+ Information Request exchange process.\r
+ @retval EFI_ABORTED Tell the EFI DHCPv6 Protocol instance to abort\r
+ the Information Request exchange process.\r
+ @retval EFI_UNSUPPORTED Tell the EFI DHCPv6 Protocol instance to finish\r
+ the Information Request exchange process because some\r
+ request information are not received.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiDhcp6ParseReply (\r
+ IN EFI_DHCP6_PROTOCOL *This,\r
+ IN VOID *Context,\r
+ IN EFI_DHCP6_PACKET *Packet\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 Index;\r
+ UINT32 OptionCount;\r
+ EFI_DHCP6_PACKET_OPTION *BootFileOpt;\r
+ EFI_DHCP6_PACKET_OPTION **OptionList;\r
+ ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData;\r
+ \r
+ OptionCount = 0;\r
+ BootFileOpt = NULL;\r
+ \r
+ Status = This->Parse (This, Packet, &OptionCount, NULL);\r
+ if (Status != EFI_BUFFER_TOO_SMALL) {\r
+ return EFI_NOT_READY;\r
+ }\r
+\r
+ OptionList = AllocateZeroPool (OptionCount * sizeof (EFI_DHCP6_PACKET_OPTION *));\r
+ if (OptionList == NULL) {\r
+ return EFI_NOT_READY;\r
+ }\r
+\r
+ Status = This->Parse (This, Packet, &OptionCount, OptionList);\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_NOT_READY;\r
+ goto Exit;\r
+ }\r
+\r
+ ConfigData = (ISCSI_ATTEMPT_CONFIG_NVDATA *) Context;\r
+\r
+ for (Index = 0; Index < OptionCount; Index++) {\r
+ OptionList[Index]->OpCode = NTOHS (OptionList[Index]->OpCode);\r
+ OptionList[Index]->OpLen = NTOHS (OptionList[Index]->OpLen);\r
+\r
+ //\r
+ // Get DNS server addresses from this reply packet.\r
+ //\r
+ if (OptionList[Index]->OpCode == DHCP6_OPT_DNS_SERVERS) {\r
+\r
+ if (((OptionList[Index]->OpLen & 0xf) != 0) || (OptionList[Index]->OpLen == 0)) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Exit;\r
+ }\r
+ //\r
+ // Primary DNS server address.\r
+ //\r
+ CopyMem (&ConfigData->PrimaryDns, &OptionList[Index]->Data[0], sizeof (EFI_IPv6_ADDRESS));\r
+\r
+ if (OptionList[Index]->OpLen > 16) {\r
+ //\r
+ // Secondary DNS server address\r
+ //\r
+ CopyMem (&ConfigData->SecondaryDns, &OptionList[Index]->Data[16], sizeof (EFI_IPv6_ADDRESS));\r
+ }\r
+\r
+ } else if (OptionList[Index]->OpCode == DHCP6_OPT_BOOT_FILE_URL) {\r
+ //\r
+ // The server sends this option to inform the client about an URL to a boot file.\r
+ //\r
+ BootFileOpt = OptionList[Index];\r
+ }\r
+ }\r
+\r
+ if (BootFileOpt == NULL) {\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Exit;\r
+ }\r
+ \r
+ //\r
+ // Get iSCSI root path from Boot File Uniform Resource Locator (URL) Option\r
+ //\r
+ Status = IScsiDhcp6ExtractRootPath (\r
+ (CHAR8 *) BootFileOpt->Data,\r
+ BootFileOpt->OpLen,\r
+ ConfigData\r
+ );\r
+\r
+Exit:\r
+\r
+ FreePool (OptionList);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Parse the DHCP ACK to get the address configuration and DNS information.\r
+\r
+ @param[in] Image The handle of the driver image.\r
+ @param[in] Controller The handle of the controller;\r
+ @param[in, out] ConfigData The attempt configuration data.\r
+\r
+ @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.\r
+ @retval EFI_NO_MAPPING DHCP failed to acquire address and other\r
+ information.\r
+ @retval EFI_INVALID_PARAMETER The DHCP ACK's DNS option is malformatted.\r
+ @retval EFI_DEVICE_ERROR Some unexpected error occurred.\r
+ @retval EFI_OUT_OF_RESOURCES There is no sufficient resource to finish the\r
+ operation.\r
+ @retval EFI_NO_MEDIA There was a media error.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiDoDhcp6 (\r
+ IN EFI_HANDLE Image,\r
+ IN EFI_HANDLE Controller,\r
+ IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData\r
+ )\r
+{\r
+ EFI_HANDLE Dhcp6Handle;\r
+ EFI_DHCP6_PROTOCOL *Dhcp6;\r
+ EFI_STATUS Status;\r
+ EFI_STATUS TimerStatus;\r
+ EFI_DHCP6_PACKET_OPTION *Oro;\r
+ EFI_DHCP6_RETRANSMISSION InfoReqReXmit;\r
+ EFI_EVENT Timer;\r
+ BOOLEAN MediaPresent;\r
+\r
+ //\r
+ // Check media status before doing DHCP.\r
+ //\r
+ MediaPresent = TRUE;\r
+ NetLibDetectMedia (Controller, &MediaPresent);\r
+ if (!MediaPresent) {\r
+ return EFI_NO_MEDIA;\r
+ }\r
+\r
+ //\r
+ // iSCSI will only request target info from DHCPv6 server.\r
+ //\r
+ if (!ConfigData->SessionConfigData.TargetInfoFromDhcp) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Dhcp6Handle = NULL;\r
+ Dhcp6 = NULL;\r
+ Oro = NULL;\r
+ Timer = NULL;\r
+\r
+ //\r
+ // Create a DHCP6 child instance and get the protocol.\r
+ //\r
+ Status = NetLibCreateServiceChild (\r
+ Controller,\r
+ Image,\r
+ &gEfiDhcp6ServiceBindingProtocolGuid,\r
+ &Dhcp6Handle\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Dhcp6Handle,\r
+ &gEfiDhcp6ProtocolGuid,\r
+ (VOID **) &Dhcp6,\r
+ Image,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Oro = AllocateZeroPool (sizeof (EFI_DHCP6_PACKET_OPTION) + 3);\r
+ if (Oro == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Ask the server to reply with DNS and Boot File URL options by info request.\r
+ // All members in EFI_DHCP6_PACKET_OPTION are in network order.\r
+ //\r
+ Oro->OpCode = HTONS (DHCP6_OPT_REQUEST_OPTION);\r
+ Oro->OpLen = HTONS (2 * 2);\r
+ Oro->Data[1] = DHCP6_OPT_DNS_SERVERS;\r
+ Oro->Data[3] = DHCP6_OPT_BOOT_FILE_URL;\r
+\r
+ InfoReqReXmit.Irt = 4;\r
+ InfoReqReXmit.Mrc = 1;\r
+ InfoReqReXmit.Mrt = 10;\r
+ InfoReqReXmit.Mrd = 30;\r
+\r
+ Status = Dhcp6->InfoRequest (\r
+ Dhcp6,\r
+ TRUE,\r
+ Oro,\r
+ 0,\r
+ NULL,\r
+ &InfoReqReXmit,\r
+ NULL,\r
+ IScsiDhcp6ParseReply,\r
+ ConfigData\r
+ );\r
+ if (Status == EFI_NO_MAPPING) {\r
+ Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = gBS->SetTimer (\r
+ Timer,\r
+ TimerRelative,\r
+ ISCSI_GET_MAPPING_TIMEOUT\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ do {\r
+\r
+ TimerStatus = gBS->CheckEvent (Timer);\r
+\r
+ if (!EFI_ERROR (TimerStatus)) {\r
+ Status = Dhcp6->InfoRequest (\r
+ Dhcp6,\r
+ TRUE,\r
+ Oro,\r
+ 0,\r
+ NULL,\r
+ &InfoReqReXmit,\r
+ NULL,\r
+ IScsiDhcp6ParseReply,\r
+ ConfigData\r
+ );\r
+ }\r
+\r
+ } while (TimerStatus == EFI_NOT_READY);\r
+\r
+ }\r
+\r
+ON_EXIT:\r
+\r
+ if (Oro != NULL) {\r
+ FreePool (Oro);\r
+ } \r
+\r
+ if (Timer != NULL) {\r
+ gBS->CloseEvent (Timer);\r
+ }\r
+\r
+ if (Dhcp6 != NULL) {\r
+ gBS->CloseProtocol (\r
+ Dhcp6Handle,\r
+ &gEfiDhcp6ProtocolGuid,\r
+ Image,\r
+ Controller\r
+ );\r
+ }\r
+\r
+ NetLibDestroyServiceChild (\r
+ Controller,\r
+ Image,\r
+ &gEfiDhcp6ServiceBindingProtocolGuid,\r
+ Dhcp6Handle\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+ The header file of iSCSI DHCP6 related configuration routines.\r
+\r
+Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _ISCSI_DHCP6_H_\r
+#define _ISCSI_DHCP6_H_\r
+\r
+#define DHCP6_OPT_REQUEST_OPTION 6\r
+#define DHCP6_OPT_VENDOR_INFO 17\r
+#define DHCP6_OPT_DNS_SERVERS 23\r
+///\r
+/// Assigned by IANA, RFC 5970\r
+///\r
+#define DHCP6_OPT_BOOT_FILE_URL 59\r
+\r
+#define ISCSI_ROOT_PATH_ID "iscsi:"\r
+#define ISCSI_ROOT_PATH_FIELD_DELIMITER ':'\r
+#define ISCSI_ROOT_PATH_ADDR_START_DELIMITER '['\r
+#define ISCSI_ROOT_PATH_ADDR_END_DELIMITER ']'\r
+\r
+\r
+/**\r
+ Extract the Root Path option and get the required target information from\r
+ Boot File Uniform Resource Locator (URL) Option.\r
+\r
+ @param[in] RootPath The RootPath string.\r
+ @param[in] Length Length of the RootPath option payload.\r
+ @param[in, out] ConfigData The iSCSI session configuration data read from\r
+ nonvolatile device.\r
+\r
+ @retval EFI_SUCCESS All required information is extracted from the\r
+ RootPath option.\r
+ @retval EFI_NOT_FOUND The RootPath is not an iSCSI RootPath.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+ @retval EFI_INVALID_PARAMETER The RootPath is malformatted.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiDhcp6ExtractRootPath (\r
+ IN CHAR8 *RootPath,\r
+ IN UINT16 Length,\r
+ IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData\r
+ );\r
+\r
+/**\r
+ Parse the DHCP ACK to get the address configuration and DNS information.\r
+\r
+ @param[in] Image The handle of the driver image.\r
+ @param[in] Controller The handle of the controller;\r
+ @param[in, out] ConfigData The attempt configuration data.\r
+\r
+ @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.\r
+ @retval EFI_NO_MAPPING DHCP failed to acquire address and other\r
+ information.\r
+ @retval EFI_INVALID_PARAMETER The DHCP ACK's DNS option is malformatted.\r
+ @retval EFI_DEVICE_ERROR Some unexpected error happened.\r
+ @retval EFI_OUT_OF_RESOURCES There is no sufficient resource to finish the\r
+ operation.\r
+ @retval EFI_NO_MEDIA There was a media error.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiDoDhcp6 (\r
+ IN EFI_HANDLE Image,\r
+ IN EFI_HANDLE Controller,\r
+ IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+ The entry point of IScsi driver.\r
+\r
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "IScsiImpl.h"\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL gIScsiDriverBinding = {\r
+ IScsiDriverBindingSupported,\r
+ IScsiDriverBindingStart,\r
+ IScsiDriverBindingStop,\r
+ 0xa,\r
+ NULL,\r
+ NULL\r
+};\r
+\r
+EFI_GUID mIScsiV4PrivateGuid = ISCSI_V4_PRIVATE_GUID;\r
+EFI_GUID mIScsiV6PrivateGuid = ISCSI_V6_PRIVATE_GUID;\r
+ISCSI_PRIVATE_DATA *mPrivate = NULL;\r
+\r
+/**\r
+ Tests to see if this driver supports the RemainingDevicePath.\r
+\r
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This \r
+ parameter is ignored by device drivers, and is optional for bus \r
+ drivers. For bus drivers, if this parameter is not NULL, then \r
+ the bus driver must determine if the bus controller specified \r
+ by ControllerHandle and the child controller specified \r
+ by RemainingDevicePath are both supported by this \r
+ bus driver.\r
+\r
+ @retval EFI_SUCCESS The RemainingDevicePath is supported or NULL.\r
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and\r
+ RemainingDevicePath is not supported by the driver specified by This.\r
+**/\r
+EFI_STATUS\r
+IScsiIsDevicePathSupported (\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
+ )\r
+{\r
+ EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;\r
+\r
+ CurrentDevicePath = RemainingDevicePath;\r
+ if (CurrentDevicePath != NULL) {\r
+ while (!IsDevicePathEnd (CurrentDevicePath)) {\r
+ if ((CurrentDevicePath->Type == MESSAGING_DEVICE_PATH) && (CurrentDevicePath->SubType == MSG_ISCSI_DP)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);\r
+ }\r
+\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Tests to see if this driver supports a given controller. If a child device is provided, \r
+ it further tests to see if this driver supports creating a handle for the specified child device.\r
+\r
+ This function checks to see if the driver specified by This supports the device specified by \r
+ ControllerHandle. Drivers typically use the device path attached to \r
+ ControllerHandle and/or the services from the bus I/O abstraction attached to \r
+ ControllerHandle to determine if the driver supports ControllerHandle. This function \r
+ may be called many times during platform initialization. In order to reduce boot times, the tests \r
+ performed by this function must be very small and take as little time as possible to execute. This \r
+ function must not change the state of any hardware devices, and this function must be aware that the \r
+ device specified by ControllerHandle may already be managed by the same driver or a \r
+ different driver. This function must match its calls to AllocatePages() with FreePages(), \r
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol(). \r
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is \r
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required \r
+ to guarantee the state of ControllerHandle is not modified by this function.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle The handle of the controller to test. This handle \r
+ must support a protocol interface that supplies \r
+ an I/O abstraction to the driver.\r
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This \r
+ parameter is ignored by device drivers, and is optional for bus \r
+ drivers. For bus drivers, if this parameter is not NULL, then \r
+ the bus driver must determine if the bus controller specified \r
+ by ControllerHandle and the child controller specified \r
+ by RemainingDevicePath are both supported by this \r
+ bus driver.\r
+\r
+ @retval EFI_SUCCESS The device specified by ControllerHandle and\r
+ RemainingDevicePath is supported by the driver specified by This.\r
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and\r
+ RemainingDevicePath is already being managed by the driver\r
+ specified by This.\r
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and\r
+ RemainingDevicePath is already being managed by a different\r
+ driver or an application that requires exclusive access.\r
+ Currently not implemented.\r
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and\r
+ RemainingDevicePath is not supported by the driver specified by This.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiDriverBindingSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ BOOLEAN IsIscsi4Started;\r
+\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &mIScsiV4PrivateGuid,\r
+ NULL,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ IsIscsi4Started = TRUE;\r
+ } else {\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiTcp4ServiceBindingProtocolGuid,\r
+ NULL,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = IScsiIsDevicePathSupported (RemainingDevicePath);\r
+ if (!EFI_ERROR (Status)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ IsIscsi4Started = FALSE;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &mIScsiV6PrivateGuid,\r
+ NULL,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ if (IsIscsi4Started) {\r
+ return EFI_ALREADY_STARTED;\r
+ }\r
+ } else {\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiTcp6ServiceBindingProtocolGuid,\r
+ NULL,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = IScsiIsDevicePathSupported (RemainingDevicePath);\r
+ if (!EFI_ERROR (Status)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ }\r
+\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+\r
+/**\r
+ Start to manage the controller. This is the worker function for\r
+ IScsiDriverBindingStart.\r
+\r
+ @param[in] Image Handle of the image.\r
+ @param[in] ControllerHandle Handle of the controller.\r
+ @param[in] IpVersion Ip4 or Ip6\r
+\r
+ @retval EFI_SUCCES This driver supports this device.\r
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.\r
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.\r
+ @retval EFI_NOT_FOUND There is no sufficient information to establish\r
+ the iScsi session.\r
+ @retval EFI_DEVICE_ERROR Failed to get TCP connection device path. \r
+\r
+**/\r
+EFI_STATUS\r
+IScsiStart (\r
+ IN EFI_HANDLE Image,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN UINT8 IpVersion\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ ISCSI_DRIVER_DATA *Private;\r
+ LIST_ENTRY *Entry;\r
+ LIST_ENTRY *NextEntry;\r
+ ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;\r
+ ISCSI_SESSION *Session;\r
+ UINT8 Index;\r
+ EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExistIScsiExtScsiPassThru;\r
+ ISCSI_DRIVER_DATA *ExistPrivate;\r
+ UINT8 *AttemptConfigOrder;\r
+ UINTN AttemptConfigOrderSize;\r
+ UINT8 BootSelected;\r
+ EFI_HANDLE *HandleBuffer;\r
+ UINTN NumberOfHandles;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ EFI_GUID *IScsiPrivateGuid;\r
+ EFI_GUID *TcpServiceBindingGuid;\r
+ CHAR16 MacString[ISCSI_MAX_MAC_STRING_LEN];\r
+ BOOLEAN NeedUpdate;\r
+ VOID *Interface;\r
+ EFI_GUID *ProtocolGuid;\r
+\r
+ //\r
+ // Test to see if iSCSI driver supports the given controller.\r
+ //\r
+\r
+ if (IpVersion == IP_VERSION_4) {\r
+ IScsiPrivateGuid = &mIScsiV4PrivateGuid;\r
+ TcpServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;\r
+ ProtocolGuid = &gEfiTcp4ProtocolGuid;\r
+ } else if (IpVersion == IP_VERSION_6) {\r
+ IScsiPrivateGuid = &mIScsiV6PrivateGuid;\r
+ TcpServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;\r
+ ProtocolGuid = &gEfiTcp6ProtocolGuid;\r
+ } else {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ IScsiPrivateGuid,\r
+ NULL,\r
+ Image,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ return EFI_ALREADY_STARTED;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ TcpServiceBindingGuid,\r
+ NULL,\r
+ Image,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Record the incoming NIC info.\r
+ //\r
+ Status = IScsiAddNic (ControllerHandle);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Create the instance private data.\r
+ //\r
+ Private = IScsiCreateDriverData (Image, ControllerHandle);\r
+ if (Private == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Create a underlayer child instance, but not need to configure it. Just open ChildHandle\r
+ // via BY_DRIVER. That is, establishing the relationship between ControllerHandle and ChildHandle.\r
+ // Therefore, when DisconnectController(), especially VLAN virtual controller handle,\r
+ // IScsiDriverBindingStop() will be called.\r
+ //\r
+ Status = NetLibCreateServiceChild (\r
+ ControllerHandle,\r
+ Image,\r
+ TcpServiceBindingGuid,\r
+ &Private->ChildHandle\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Private->ChildHandle,\r
+ ProtocolGuid,\r
+ &Interface,\r
+ Image,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ \r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ //\r
+ // Always install private protocol no matter what happens later. We need to \r
+ // keep the relationship between ControllerHandle and ChildHandle.\r
+ //\r
+ Status = gBS->InstallProtocolInterface (\r
+ &ControllerHandle,\r
+ IScsiPrivateGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &Private->IScsiIdentifier\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+ \r
+ if (IpVersion == IP_VERSION_4) {\r
+ mPrivate->Ipv6Flag = FALSE;\r
+ } else {\r
+ mPrivate->Ipv6Flag = TRUE;\r
+ }\r
+\r
+ //\r
+ // Get the current iSCSI configuration data.\r
+ //\r
+ Status = IScsiGetConfigData (Private);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ //\r
+ // If there is already a successul attempt, check whether this attempt is the\r
+ // first "enabled for MPIO" attempt. If not, still try the first attempt.\r
+ // In single path mode, try all attempts.\r
+ //\r
+ ExistPrivate = NULL;\r
+ Status = EFI_NOT_FOUND;\r
+\r
+ if (mPrivate->OneSessionEstablished && mPrivate->EnableMpio) {\r
+ AttemptConfigData = NULL;\r
+ NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) {\r
+ AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);\r
+ if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (AttemptConfigData == NULL) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ if (AttemptConfigData->AttemptConfigIndex == mPrivate->BootSelectedIndex) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Uninstall the original ExtScsiPassThru first.\r
+ //\r
+\r
+ //\r
+ // Locate all ExtScsiPassThru protocol instances.\r
+ //\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiExtScsiPassThruProtocolGuid,\r
+ NULL,\r
+ &NumberOfHandles,\r
+ &HandleBuffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ //\r
+ // Find ExtScsiPassThru protocol instance produced by this driver.\r
+ //\r
+ ExistIScsiExtScsiPassThru = NULL;\r
+ for (Index = 0; Index < NumberOfHandles && ExistIScsiExtScsiPassThru == NULL; Index++) {\r
+ Status = gBS->HandleProtocol (\r
+ HandleBuffer[Index],\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &DevicePath\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ while (!IsDevicePathEnd (DevicePath)) {\r
+ if ((DevicePath->Type == MESSAGING_DEVICE_PATH) && (DevicePath->SubType == MSG_MAC_ADDR_DP)) {\r
+ //\r
+ // Get the ExtScsiPassThru protocol instance.\r
+ //\r
+ Status = gBS->HandleProtocol (\r
+ HandleBuffer[Index],\r
+ &gEfiExtScsiPassThruProtocolGuid,\r
+ (VOID **) &ExistIScsiExtScsiPassThru\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ break;\r
+ }\r
+\r
+ DevicePath = NextDevicePathNode (DevicePath);\r
+ }\r
+ }\r
+\r
+ FreePool (HandleBuffer);\r
+\r
+ if (ExistIScsiExtScsiPassThru == NULL) {\r
+ Status = EFI_NOT_FOUND;\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ ExistPrivate = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (ExistIScsiExtScsiPassThru);\r
+\r
+ Status = gBS->UninstallProtocolInterface (\r
+ ExistPrivate->ExtScsiPassThruHandle,\r
+ &gEfiExtScsiPassThruProtocolGuid,\r
+ &ExistPrivate->IScsiExtScsiPassThru\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Install the Ext SCSI PASS THRU protocol.\r
+ //\r
+ Status = gBS->InstallProtocolInterface (\r
+ &Private->ExtScsiPassThruHandle,\r
+ &gEfiExtScsiPassThruProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &Private->IScsiExtScsiPassThru\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ BootSelected = 0;\r
+\r
+ NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &mPrivate->AttemptConfigs) {\r
+ AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);\r
+ //\r
+ // Don't process the attempt that does not associate with the current NIC or\r
+ // this attempt is disabled or established.\r
+ //\r
+ if (AttemptConfigData->NicIndex != mPrivate->CurrentNic ||\r
+ AttemptConfigData->SessionConfigData.Enabled == ISCSI_DISABLED ||\r
+ AttemptConfigData->ValidPath) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // In multipath mode, don't process attempts configured for single path.\r
+ // In default single path mode, don't process attempts configured for multipath.\r
+ //\r
+ if ((mPrivate->EnableMpio &&\r
+ AttemptConfigData->SessionConfigData.Enabled != ISCSI_ENABLED_FOR_MPIO) ||\r
+ (!mPrivate->EnableMpio &&\r
+ AttemptConfigData->SessionConfigData.Enabled != ISCSI_ENABLED)) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Don't process the attempt that fails to get the init/target information from DHCP.\r
+ //\r
+ if (AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp &&\r
+ !AttemptConfigData->DhcpSuccess) {\r
+ if (!mPrivate->EnableMpio && mPrivate->ValidSinglePathCount > 0) {\r
+ mPrivate->ValidSinglePathCount--;\r
+ }\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Don't process the autoconfigure path if it is already established.\r
+ //\r
+ if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG &&\r
+ AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_SUCCESS) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Don't process the attempt if its IP mode is not in the current IP version.\r
+ //\r
+ if (!mPrivate->Ipv6Flag) {\r
+ if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6) {\r
+ continue;\r
+ }\r
+ if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG &&\r
+ AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6) {\r
+ continue;\r
+ }\r
+ } else {\r
+ if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4) {\r
+ continue;\r
+ }\r
+ if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG &&\r
+ AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4) {\r
+ continue;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Fill in the Session and init it.\r
+ //\r
+ Session = (ISCSI_SESSION *) AllocateZeroPool (sizeof (ISCSI_SESSION));\r
+ if (Session == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Session->Private = Private;\r
+ Session->ConfigData = AttemptConfigData;\r
+ Session->AuthType = AttemptConfigData->AuthenticationType;\r
+\r
+ AsciiStrToUnicodeStr (AttemptConfigData->MacString, MacString);\r
+ UnicodeSPrint (\r
+ mPrivate->PortString,\r
+ (UINTN) ISCSI_NAME_IFR_MAX_SIZE,\r
+ L"%s%d",\r
+ MacString,\r
+ (UINTN) AttemptConfigData->AttemptConfigIndex\r
+ );\r
+\r
+ if (Session->AuthType == ISCSI_AUTH_TYPE_CHAP) {\r
+ Session->AuthData.CHAP.AuthConfig = &AttemptConfigData->AuthConfigData.CHAP;\r
+ }\r
+\r
+ IScsiSessionInit (Session, FALSE);\r
+\r
+ //\r
+ // Try to login and create an iSCSI session according to the configuration.\r
+ //\r
+ Status = IScsiSessionLogin (Session);\r
+ if (Status == EFI_MEDIA_CHANGED) {\r
+ //\r
+ // The specified target is not available, and the redirection information is\r
+ // received. Login the session again with the updated target address.\r
+ //\r
+ Status = IScsiSessionLogin (Session);\r
+ } else if (Status == EFI_NOT_READY) {\r
+ Status = IScsiSessionReLogin (Session);\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // In Single path mode, only the successful attempt will be recorded in iBFT;\r
+ // in multi-path mode, all the attempt entries in MPIO will be recorded in iBFT.\r
+ //\r
+ if (!mPrivate->EnableMpio && mPrivate->ValidSinglePathCount > 0) {\r
+ mPrivate->ValidSinglePathCount--;\r
+ }\r
+\r
+ FreePool (Session);\r
+\r
+ } else {\r
+ AttemptConfigData->ValidPath = TRUE;\r
+\r
+ //\r
+ // Do not record the attempt in iBFT if it login with KRB5.\r
+ // TODO: record KRB5 attempt information in the iSCSI device path.\r
+ //\r
+ if (Session->AuthType == ISCSI_AUTH_TYPE_KRB) {\r
+ if (!mPrivate->EnableMpio && mPrivate->ValidSinglePathCount > 0) {\r
+ mPrivate->ValidSinglePathCount--;\r
+ }\r
+\r
+ AttemptConfigData->ValidiBFTPath = FALSE;\r
+ } else {\r
+ AttemptConfigData->ValidiBFTPath = TRUE;\r
+ }\r
+\r
+ //\r
+ // IScsi session success. Update the attempt state to NVR.\r
+ //\r
+ if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) {\r
+ AttemptConfigData->AutoConfigureMode = IP_MODE_AUTOCONFIG_SUCCESS;\r
+ }\r
+\r
+ gRT->SetVariable (\r
+ mPrivate->PortString,\r
+ &gEfiIScsiInitiatorNameProtocolGuid,\r
+ ISCSI_CONFIG_VAR_ATTR,\r
+ sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),\r
+ AttemptConfigData\r
+ );\r
+\r
+ //\r
+ // Select the first login session. Abort others.\r
+ //\r
+ if (Private->Session == NULL) {\r
+ Private->Session = Session;\r
+ BootSelected = AttemptConfigData->AttemptConfigIndex;\r
+ //\r
+ // Don't validate other attempt in multipath mode if one is success.\r
+ //\r
+ if (mPrivate->EnableMpio) {\r
+ break;\r
+ }\r
+ } else {\r
+ IScsiSessionAbort (Session);\r
+ FreePool (Session);\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // All attempts configured for this driver instance are not valid.\r
+ //\r
+ if (Private->Session == NULL) {\r
+ Status = gBS->UninstallProtocolInterface (\r
+ Private->ExtScsiPassThruHandle,\r
+ &gEfiExtScsiPassThruProtocolGuid,\r
+ &Private->IScsiExtScsiPassThru\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ Private->ExtScsiPassThruHandle = NULL;\r
+\r
+ //\r
+ // Reinstall the original ExtScsiPassThru back.\r
+ //\r
+ if (mPrivate->OneSessionEstablished && ExistPrivate != NULL) {\r
+ Status = gBS->InstallProtocolInterface (\r
+ &ExistPrivate->ExtScsiPassThruHandle,\r
+ &gEfiExtScsiPassThruProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &ExistPrivate->IScsiExtScsiPassThru\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = EFI_NOT_FOUND;\r
+\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ NeedUpdate = TRUE;\r
+ //\r
+ // More than one attempt successes.\r
+ //\r
+ if (Private->Session != NULL && mPrivate->OneSessionEstablished) {\r
+\r
+ AttemptConfigOrder = IScsiGetVariableAndSize (\r
+ L"AttemptOrder",\r
+ &mVendorGuid,\r
+ &AttemptConfigOrderSize\r
+ );\r
+ ASSERT (AttemptConfigOrder != NULL);\r
+ for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {\r
+ if (AttemptConfigOrder[Index] == mPrivate->BootSelectedIndex ||\r
+ AttemptConfigOrder[Index] == BootSelected) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (mPrivate->EnableMpio) {\r
+ //\r
+ // Use the attempt in earlier order. Abort the later one in MPIO.\r
+ //\r
+ if (AttemptConfigOrder[Index] == mPrivate->BootSelectedIndex) {\r
+ IScsiSessionAbort (Private->Session);\r
+ FreePool (Private->Session);\r
+ Private->Session = NULL;\r
+ gBS->UninstallProtocolInterface (\r
+ Private->ExtScsiPassThruHandle,\r
+ &gEfiExtScsiPassThruProtocolGuid,\r
+ &Private->IScsiExtScsiPassThru\r
+ );\r
+ Private->ExtScsiPassThruHandle = NULL;\r
+\r
+ //\r
+ // Reinstall the original ExtScsiPassThru back.\r
+ //\r
+ Status = gBS->InstallProtocolInterface (\r
+ &ExistPrivate->ExtScsiPassThruHandle,\r
+ &gEfiExtScsiPassThruProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &ExistPrivate->IScsiExtScsiPassThru\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ goto ON_EXIT;\r
+ } else {\r
+ ASSERT (AttemptConfigOrder[Index] == BootSelected);\r
+ mPrivate->BootSelectedIndex = BootSelected;\r
+ //\r
+ // Clear the resource in ExistPrivate.\r
+ //\r
+ gBS->UninstallProtocolInterface (\r
+ ExistPrivate->Controller,\r
+ IScsiPrivateGuid,\r
+ &ExistPrivate->IScsiIdentifier\r
+ ); \r
+ \r
+ IScsiRemoveNic (ExistPrivate->Controller);\r
+ if (ExistPrivate->Session != NULL) {\r
+ IScsiSessionAbort (ExistPrivate->Session);\r
+ }\r
+\r
+ IScsiCleanDriverData (ExistPrivate);\r
+ }\r
+ } else {\r
+ //\r
+ // Use the attempt in earlier order as boot selected in single path mode.\r
+ //\r
+ if (AttemptConfigOrder[Index] == mPrivate->BootSelectedIndex) {\r
+ NeedUpdate = FALSE;\r
+ }\r
+ }\r
+\r
+ }\r
+\r
+ if (NeedUpdate) {\r
+ mPrivate->OneSessionEstablished = TRUE;\r
+ mPrivate->BootSelectedIndex = BootSelected;\r
+ }\r
+\r
+ //\r
+ // Duplicate the Session's tcp connection device path. The source port field\r
+ // will be set to zero as one iSCSI session is comprised of several iSCSI\r
+ // connections.\r
+ //\r
+ Private->DevicePath = IScsiGetTcpConnDevicePath (Private->Session);\r
+ if (Private->DevicePath == NULL) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto ON_ERROR;\r
+ }\r
+ //\r
+ // Install the updated device path onto the ExtScsiPassThruHandle.\r
+ //\r
+ Status = gBS->InstallProtocolInterface (\r
+ &Private->ExtScsiPassThruHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ Private->DevicePath\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ON_EXIT:\r
+\r
+ //\r
+ // Update/Publish the iSCSI Boot Firmware Table.\r
+ //\r
+ if (mPrivate->BootSelectedIndex != 0) {\r
+ IScsiPublishIbft ();\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+\r
+ if (Private->Session != NULL) {\r
+ IScsiSessionAbort (Private->Session);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Starts a device controller or a bus controller.\r
+\r
+ The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
+ As a result, much of the error checking on the parameters to Start() has been moved into this \r
+ common boot service. It is legal to call Start() from other locations, \r
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+ 1. ControllerHandle must be a valid EFI_HANDLE.\r
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
+ EFI_DEVICE_PATH_PROTOCOL.\r
+ 3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
+ have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS. \r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle The handle of the controller to start. This handle \r
+ must support a protocol interface that supplies \r
+ an I/O abstraction to the driver.\r
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This \r
+ parameter is ignored by device drivers, and is optional for bus \r
+ drivers. For a bus driver, if this parameter is NULL, then handles \r
+ for all the children of Controller are created by this driver. \r
+ If this parameter is not NULL and the first Device Path Node is \r
+ not the End of Device Path Node, then only the handle for the \r
+ child device specified by the first Device Path Node of \r
+ RemainingDevicePath is created by this driver.\r
+ If the first Device Path Node of RemainingDevicePath is \r
+ the End of Device Path Node, no child handle is created by this\r
+ driver.\r
+\r
+ @retval EFI_SUCCESS The device was started.\r
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+ @retval Others The driver failed to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiDriverBindingStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS V4Status;\r
+ EFI_STATUS V6Status;\r
+\r
+ V4Status = IScsiStart (This->DriverBindingHandle, ControllerHandle, IP_VERSION_4);\r
+ if (V4Status == EFI_ALREADY_STARTED) {\r
+ V4Status = EFI_SUCCESS;\r
+ }\r
+\r
+ V6Status = IScsiStart (This->DriverBindingHandle, ControllerHandle, IP_VERSION_6);\r
+ if (V6Status == EFI_ALREADY_STARTED) {\r
+ V6Status = EFI_SUCCESS;\r
+ }\r
+\r
+ if (!EFI_ERROR (V4Status) || !EFI_ERROR (V6Status)) {\r
+ return EFI_SUCCESS;\r
+ } else if (EFI_ERROR (V4Status)) {\r
+ return V4Status;\r
+ } else {\r
+ return V6Status;\r
+ }\r
+}\r
+\r
+/**\r
+ Stops a device controller or a bus controller.\r
+ \r
+ The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). \r
+ As a result, much of the error checking on the parameters to Stop() has been moved \r
+ into this common boot service. It is legal to call Stop() from other locations, \r
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
+ same driver's Start() function.\r
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
+ EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
+ Start() function, and the Start() function must have called OpenProtocol() on\r
+ ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+ \r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle A handle to the device being stopped. The handle must \r
+ support a bus specific I/O protocol for the driver \r
+ to use to stop the device.\r
+ @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.\r
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL \r
+ if NumberOfChildren is 0.\r
+\r
+ @retval EFI_SUCCESS The device was stopped.\r
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiDriverBindingStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL\r
+ )\r
+{\r
+ EFI_HANDLE IScsiController;\r
+ EFI_STATUS Status;\r
+ ISCSI_PRIVATE_PROTOCOL *IScsiIdentifier;\r
+ ISCSI_DRIVER_DATA *Private;\r
+ EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;\r
+ ISCSI_CONNECTION *Conn;\r
+ EFI_GUID *ProtocolGuid;\r
+ EFI_GUID *TcpServiceBindingGuid;\r
+ EFI_GUID *TcpProtocolGuid;\r
+\r
+\r
+ if (NumberOfChildren != 0) {\r
+ //\r
+ // We should have only one child.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ChildHandleBuffer[0],\r
+ &gEfiExtScsiPassThruProtocolGuid,\r
+ (VOID **) &PassThru,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Private = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (PassThru);\r
+ Conn = NET_LIST_HEAD (&Private->Session->Conns, ISCSI_CONNECTION, Link);\r
+\r
+ //\r
+ // Previously the TCP protocol is opened BY_CHILD_CONTROLLER. Just close\r
+ // the protocol here, but do not uninstall the device path protocol and\r
+ // EXT SCSI PASS THRU protocol installed on ExtScsiPassThruHandle.\r
+ //\r
+ if (!Conn->Ipv6Flag) {\r
+ ProtocolGuid = &gEfiTcp4ProtocolGuid;\r
+ } else {\r
+ ProtocolGuid = &gEfiTcp6ProtocolGuid;\r
+ }\r
+\r
+ gBS->CloseProtocol (\r
+ Conn->TcpIo.Handle,\r
+ ProtocolGuid,\r
+ Private->Image,\r
+ Private->ExtScsiPassThruHandle\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+ //\r
+ // Get the handle of the controller we are controling.\r
+ //\r
+ IScsiController = NetLibGetNicHandle (ControllerHandle, &gEfiTcp4ProtocolGuid);\r
+ if (IScsiController != NULL) {\r
+ ProtocolGuid = &mIScsiV4PrivateGuid;\r
+ TcpProtocolGuid = &gEfiTcp4ProtocolGuid;\r
+ TcpServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;\r
+ } else {\r
+ IScsiController = NetLibGetNicHandle (ControllerHandle, &gEfiTcp6ProtocolGuid);\r
+ ASSERT (IScsiController != NULL);\r
+ ProtocolGuid = &mIScsiV6PrivateGuid;\r
+ TcpProtocolGuid = &gEfiTcp6ProtocolGuid;\r
+ TcpServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ IScsiController,\r
+ ProtocolGuid,\r
+ (VOID **) &IScsiIdentifier,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Private = ISCSI_DRIVER_DATA_FROM_IDENTIFIER (IScsiIdentifier);\r
+ ASSERT (Private != NULL);\r
+\r
+ if (Private->ChildHandle != NULL) {\r
+ Status = gBS->CloseProtocol (\r
+ Private->ChildHandle,\r
+ TcpProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ IScsiController\r
+ );\r
+ \r
+ ASSERT (!EFI_ERROR (Status));\r
+\r
+ Status = NetLibDestroyServiceChild (\r
+ IScsiController,\r
+ This->DriverBindingHandle,\r
+ TcpServiceBindingGuid,\r
+ Private->ChildHandle\r
+ );\r
+\r
+ ASSERT (!EFI_ERROR (Status));\r
+ }\r
+\r
+ gBS->UninstallProtocolInterface (\r
+ IScsiController,\r
+ ProtocolGuid,\r
+ &Private->IScsiIdentifier\r
+ ); \r
+\r
+ //\r
+ // Remove this NIC.\r
+ //\r
+ IScsiRemoveNic (IScsiController);\r
+\r
+ //\r
+ // Update the iSCSI Boot Firware Table.\r
+ //\r
+ IScsiPublishIbft ();\r
+\r
+ if (Private->Session != NULL) {\r
+ IScsiSessionAbort (Private->Session);\r
+ }\r
+\r
+ IScsiCleanDriverData (Private);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Unload the iSCSI driver.\r
+\r
+ @param[in] ImageHandle The handle of the driver image.\r
+\r
+ @retval EFI_SUCCESS The driver is unloaded.\r
+ @retval EFI_DEVICE_ERROR An unexpected error occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiUnload (\r
+ IN EFI_HANDLE ImageHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN DeviceHandleCount;\r
+ EFI_HANDLE *DeviceHandleBuffer;\r
+ UINTN Index;\r
+\r
+ //\r
+ // Try to disonnect the driver from the devices it's controlling.\r
+ //\r
+ Status = gBS->LocateHandleBuffer (\r
+ AllHandles,\r
+ NULL,\r
+ NULL,\r
+ &DeviceHandleCount,\r
+ &DeviceHandleBuffer\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ for (Index = 0; Index < DeviceHandleCount; Index++) {\r
+ Status = gBS->DisconnectController (\r
+ DeviceHandleBuffer[Index],\r
+ ImageHandle,\r
+ NULL\r
+ );\r
+ }\r
+\r
+ if (DeviceHandleBuffer != NULL) {\r
+ FreePool (DeviceHandleBuffer);\r
+ }\r
+ }\r
+ //\r
+ // Unload the iSCSI configuration form.\r
+ //\r
+ IScsiConfigFormUnload (gIScsiDriverBinding.DriverBindingHandle);\r
+\r
+ //\r
+ // Uninstall the protocols installed by iSCSI driver.\r
+ //\r
+ gBS->UninstallMultipleProtocolInterfaces (\r
+ ImageHandle,\r
+ &gEfiAuthenticationInfoProtocolGuid,\r
+ &gIScsiAuthenticationInfo,\r
+ NULL\r
+ );\r
+ \r
+ return gBS->UninstallMultipleProtocolInterfaces (\r
+ ImageHandle,\r
+ &gEfiDriverBindingProtocolGuid,\r
+ &gIScsiDriverBinding,\r
+ &gEfiComponentName2ProtocolGuid,\r
+ &gIScsiComponentName2,\r
+ &gEfiComponentNameProtocolGuid,\r
+ &gIScsiComponentName,\r
+ &gEfiIScsiInitiatorNameProtocolGuid,\r
+ &gIScsiInitiatorName,\r
+ NULL\r
+ );\r
+}\r
+\r
+/**\r
+ This is the declaration of an EFI image entry point. This entry point is\r
+ the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including\r
+ both device drivers and bus drivers.\r
+ \r
+ The entry point for iSCSI driver which initializes the global variables and\r
+ installs the driver binding, component name protocol, iSCSI initiator name\r
+ protocol and Authentication Info protocol on its image.\r
+ \r
+ @param[in] ImageHandle The firmware allocated handle for the UEFI image.\r
+ @param[in] SystemTable A pointer to the EFI System Table.\r
+\r
+ @retval EFI_SUCCESS The operation completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiDriverEntryPoint (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_ISCSI_INITIATOR_NAME_PROTOCOL *IScsiInitiatorName;\r
+ EFI_AUTHENTICATION_INFO_PROTOCOL *AuthenticationInfo;\r
+\r
+ //\r
+ // There should be only one EFI_ISCSI_INITIATOR_NAME_PROTOCOL.\r
+ //\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiIScsiInitiatorNameProtocolGuid,\r
+ NULL,\r
+ (VOID **) &IScsiInitiatorName\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ //\r
+ // Initialize the EFI Driver Library.\r
+ //\r
+ Status = EfiLibInstallDriverBindingComponentName2 (\r
+ ImageHandle,\r
+ SystemTable,\r
+ &gIScsiDriverBinding,\r
+ ImageHandle,\r
+ &gIScsiComponentName,\r
+ &gIScsiComponentName2\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Install the iSCSI Initiator Name Protocol.\r
+ //\r
+ Status = gBS->InstallProtocolInterface (\r
+ &ImageHandle,\r
+ &gEfiIScsiInitiatorNameProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &gIScsiInitiatorName\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error1;\r
+ } \r
+\r
+ //\r
+ // Create the private data structures.\r
+ //\r
+ mPrivate = AllocateZeroPool (sizeof (ISCSI_PRIVATE_DATA));\r
+ if (mPrivate == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error2;\r
+ }\r
+\r
+ InitializeListHead (&mPrivate->NicInfoList);\r
+ InitializeListHead (&mPrivate->AttemptConfigs);\r
+\r
+ //\r
+ // Initialize the configuration form of iSCSI.\r
+ //\r
+ Status = IScsiConfigFormInit (gIScsiDriverBinding.DriverBindingHandle);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error3;\r
+ }\r
+\r
+ //\r
+ // There should be only one EFI_AUTHENTICATION_INFO_PROTOCOL. If already exists,\r
+ // do not produce the protocol instance.\r
+ //\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiAuthenticationInfoProtocolGuid,\r
+ NULL,\r
+ (VOID **) &AuthenticationInfo\r
+ );\r
+ if (Status == EFI_NOT_FOUND) {\r
+ Status = gBS->InstallProtocolInterface (\r
+ &ImageHandle,\r
+ &gEfiAuthenticationInfoProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &gIScsiAuthenticationInfo\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error4;\r
+ } \r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+Error4:\r
+ IScsiConfigFormUnload (gIScsiDriverBinding.DriverBindingHandle);\r
+\r
+Error3:\r
+ FreePool (mPrivate);\r
+\r
+Error2:\r
+ gBS->UninstallMultipleProtocolInterfaces (\r
+ ImageHandle,\r
+ &gEfiIScsiInitiatorNameProtocolGuid,\r
+ &gIScsiInitiatorName,\r
+ NULL\r
+ );\r
+\r
+Error1:\r
+ gBS->UninstallMultipleProtocolInterfaces (\r
+ ImageHandle,\r
+ &gEfiDriverBindingProtocolGuid,\r
+ &gIScsiDriverBinding,\r
+ &gEfiComponentName2ProtocolGuid,\r
+ &gIScsiComponentName2,\r
+ &gEfiComponentNameProtocolGuid,\r
+ &gIScsiComponentName,\r
+ NULL\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+ The header file of IScsiDriver.c.\r
+\r
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _ISCSI_DRIVER_H_\r
+#define _ISCSI_DRIVER_H_\r
+\r
+#define ISCSI_V4_PRIVATE_GUID \\r
+ { \\r
+ 0xfa3cde4c, 0x87c2, 0x427d, { 0xae, 0xde, 0x7d, 0xd0, 0x96, 0xc8, 0x8c, 0x58 } \\r
+ }\r
+\r
+#define ISCSI_V6_PRIVATE_GUID \\r
+ { \\r
+ 0x28be27e5, 0x66cc, 0x4a31, { 0xa3, 0x15, 0xdb, 0x14, 0xc3, 0x74, 0x4d, 0x85 } \\r
+ }\r
+\r
+#define ISCSI_INITIATOR_NAME_VAR_NAME L"I_NAME"\r
+\r
+#define IP_MODE_AUTOCONFIG_IP4 3\r
+#define IP_MODE_AUTOCONFIG_IP6 4\r
+#define IP_MODE_AUTOCONFIG_SUCCESS 5\r
+\r
+extern EFI_COMPONENT_NAME2_PROTOCOL gIScsiComponentName2;\r
+extern EFI_COMPONENT_NAME_PROTOCOL gIScsiComponentName;\r
+extern EFI_ISCSI_INITIATOR_NAME_PROTOCOL gIScsiInitiatorName;\r
+extern EFI_AUTHENTICATION_INFO_PROTOCOL gIScsiAuthenticationInfo;\r
+extern EFI_EXT_SCSI_PASS_THRU_PROTOCOL gIScsiExtScsiPassThruProtocolTemplate;\r
+\r
+typedef struct {\r
+ CHAR16 PortString[ISCSI_NAME_IFR_MAX_SIZE];\r
+ LIST_ENTRY NicInfoList;\r
+ UINT8 NicCount;\r
+ UINT8 CurrentNic;\r
+ UINT8 MaxNic;\r
+ BOOLEAN Ipv6Flag;\r
+ BOOLEAN OneSessionEstablished;\r
+ BOOLEAN EnableMpio;\r
+ UINT8 MpioCount; // The number of attempts in MPIO.\r
+ UINT8 Krb5MpioCount; // The number of attempts login with KRB5 in MPIO.\r
+ UINT8 SinglePathCount; // The number of single path attempts.\r
+ UINT8 ValidSinglePathCount; // The number of valid single path attempts.\r
+ UINT8 BootSelectedIndex;\r
+ UINT8 AttemptCount;\r
+ LIST_ENTRY AttemptConfigs; // User configured Attempt list.\r
+ CHAR8 InitiatorName[ISCSI_NAME_MAX_SIZE];\r
+ UINTN InitiatorNameLength;\r
+} ISCSI_PRIVATE_DATA;\r
+\r
+extern ISCSI_PRIVATE_DATA *mPrivate;\r
+\r
+typedef struct {\r
+ LIST_ENTRY Link;\r
+ UINT32 HwAddressSize;\r
+ EFI_MAC_ADDRESS PermanentAddress;\r
+ UINT8 NicIndex;\r
+ UINT16 VlanId;\r
+ UINTN BusNumber;\r
+ UINTN DeviceNumber;\r
+ UINTN FunctionNumber;\r
+} ISCSI_NIC_INFO;\r
+\r
+typedef struct _ISCSI_PRIVATE_PROTOCOL {\r
+ UINT32 Reserved;\r
+} ISCSI_PRIVATE_PROTOCOL;\r
+\r
+//\r
+// EFI Driver Binding Protocol for iSCSI driver.\r
+//\r
+\r
+/**\r
+ Tests to see if this driver supports a given controller. If a child device is provided, \r
+ it tests to see if this driver supports creating a handle for the specified child device.\r
+\r
+ This function checks to see if the driver specified by This supports the device specified by \r
+ ControllerHandle. Drivers typically use the device path attached to \r
+ ControllerHandle and/or the services from the bus I/O abstraction attached to \r
+ ControllerHandle to determine if the driver supports ControllerHandle. This function \r
+ may be called many times during platform initialization. In order to reduce boot times, the tests \r
+ performed by this function must be very small and take as little time as possible to execute. This \r
+ function must not change the state of any hardware devices, and this function must be aware that the \r
+ device specified by ControllerHandle may already be managed by the same driver or a \r
+ different driver. This function must match its calls to AllocatePages() with FreePages(), \r
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol(). \r
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is \r
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required \r
+ to guarantee the state of ControllerHandle is not modified by this function.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle The handle of the controller to test. This handle \r
+ must support a protocol interface that supplies \r
+ an I/O abstraction to the driver.\r
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This \r
+ parameter is ignored by device drivers, and is optional for bus \r
+ drivers. For bus drivers, if this parameter is not NULL, then \r
+ the bus driver must determine if the bus controller specified \r
+ by ControllerHandle and the child controller specified \r
+ by RemainingDevicePath are both supported by this \r
+ bus driver.\r
+\r
+ @retval EFI_SUCCESS The device specified by ControllerHandle and\r
+ RemainingDevicePath is supported by the driver specified by This.\r
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and\r
+ RemainingDevicePath is already managed by the driver\r
+ specified by This.\r
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and\r
+ RemainingDevicePath is already managed by a different\r
+ driver or an application that requires exclusive access.\r
+ Currently not implemented.\r
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and\r
+ RemainingDevicePath is not supported by the driver specified by This.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiDriverBindingSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
+ );\r
+\r
+/**\r
+ Starts a device controller or a bus controller.\r
+\r
+ The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
+ As a result, much of the error checking on the parameters to Start() has been moved into this \r
+ common boot service. It is legal to call Start() from other locations, \r
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+ 1. ControllerHandle must be a valid EFI_HANDLE.\r
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
+ EFI_DEVICE_PATH_PROTOCOL.\r
+ 3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
+ have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS. \r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle The handle of the controller to start. This handle \r
+ must support a protocol interface that supplies \r
+ an I/O abstraction to the driver.\r
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This \r
+ parameter is ignored by device drivers, and is optional for bus \r
+ drivers. For a bus driver, if this parameter is NULL, then handles \r
+ for all the children of Controller are created by this driver. \r
+ If this parameter is not NULL and the first Device Path Node is \r
+ not the End of Device Path Node, then only the handle for the \r
+ child device specified by the first Device Path Node of \r
+ RemainingDevicePath is created by this driver.\r
+ If the first Device Path Node of RemainingDevicePath is \r
+ the End of Device Path Node, no child handle is created by this\r
+ driver.\r
+\r
+ @retval EFI_SUCCESS The device was started.\r
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error. Currently not implemented.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+ @retval Others The driver failed to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiDriverBindingStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
+ );\r
+\r
+/**\r
+ Stops a device controller or a bus controller.\r
+ \r
+ The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). \r
+ As a result, much of the error checking on the parameters to Stop() has been moved \r
+ into this common boot service. It is legal to call Stop() from other locations, \r
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
+ same driver's Start() function.\r
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
+ EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
+ Start() function, and the Start() function must have called OpenProtocol() on\r
+ ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+ \r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle A handle to the device being stopped. The handle must \r
+ support a bus specific I/O protocol for the driver \r
+ to use to stop the device.\r
+ @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.\r
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL \r
+ if NumberOfChildren is 0.\r
+\r
+ @retval EFI_SUCCESS The device was stopped.\r
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiDriverBindingStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL\r
+ );\r
+\r
+//\r
+// EFI Component Name(2) Protocol for iSCSI driver.\r
+//\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+ This function retrieves the user readable name of a driver in the form of a\r
+ Unicode string. If the driver specified by This has a user readable name in\r
+ the language specified by Language, then a pointer to the driver name is\r
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+ by This does not support the language specified by Language,\r
+ then EFI_UNSUPPORTED is returned.\r
+\r
+ @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param[in] Language A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified\r
+ in RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param[out] DriverName A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ driver specified by This in the language\r
+ specified by Language.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by\r
+ This and the language specified by Language was\r
+ returned in DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ );\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by a driver.\r
+\r
+ This function retrieves the user readable name of the controller specified by\r
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+ driver specified by This has a user readable name in the language specified by\r
+ Language, then a pointer to the controller name is returned in ControllerName,\r
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently\r
+ managing the controller specified by ControllerHandle and ChildHandle,\r
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not\r
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+ @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param[in] ControllerHandle The handle of a controller that the driver\r
+ specified by This is managing. This handle\r
+ specifies the controller whose name is to be\r
+ returned.\r
+\r
+ @param[in] ChildHandle The handle of the child controller to retrieve\r
+ the name of. This is an optional parameter that\r
+ may be NULL. It will be NULL for device\r
+ drivers. It will also be NULL for a bus drivers\r
+ that wish to retrieve the name of the bus\r
+ controller. It will not be NULL for a bus\r
+ driver that wishes to retrieve the name of a\r
+ child controller.\r
+\r
+ @param[in] Language A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is \r
+ determined by the driver writer. Language is \r
+ specified inRFC 4646 or ISO 639-2 language code \r
+ format.\r
+ \r
+ @param[out] ControllerName A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ controller specified by ControllerHandle and\r
+ ChildHandle in the language specified by\r
+ Language from the point of view of the driver\r
+ specified by This.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the user readable name in\r
+ the language specified by Language for the\r
+ driver specified by This was returned in\r
+ DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ );\r
+\r
+//\r
+// EFI iSCSI Initiator Name Protocol for iSCSI driver.\r
+//\r
+\r
+/**\r
+ Retrieves the current set value of iSCSI Initiator Name.\r
+\r
+ @param[in] This Pointer to the EFI_ISCSI_INITIATOR_NAME_PROTOCOL\r
+ instance.\r
+ @param[in, out] BufferSize Size of the buffer in bytes pointed to by Buffer /\r
+ Actual size of the variable data buffer.\r
+ @param[out] Buffer Pointer to the buffer for data to be read.\r
+\r
+ @retval EFI_SUCCESS Data was successfully retrieved into the provided\r
+ buffer and the BufferSize was sufficient to handle\r
+ the iSCSI initiator name.\r
+ @retval EFI_BUFFER_TOO_SMALL BufferSize is too small for the result. BufferSize\r
+ will be updated with the size required to complete\r
+ the request. Buffer will not be affected.\r
+ @retval EFI_INVALID_PARAMETER BufferSize is NULL. BufferSize and Buffer will not\r
+ be affected.\r
+ @retval EFI_INVALID_PARAMETER Buffer is NULL. BufferSize and Buffer will not be\r
+ affected.\r
+ @retval EFI_DEVICE_ERROR The iSCSI initiator name could not be retrieved\r
+ due to a hardware error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiGetInitiatorName (\r
+ IN EFI_ISCSI_INITIATOR_NAME_PROTOCOL *This,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+/**\r
+ Sets the iSSI Initiator Name.\r
+\r
+ @param[in] This Pointer to the EFI_ISCSI_INITIATOR_NAME_PROTOCOL\r
+ instance.\r
+ @param[in, out] BufferSize Size of the buffer in bytes pointed to by Buffer.\r
+ @param[in] Buffer Pointer to the buffer for data to be written.\r
+\r
+ @retval EFI_SUCCESS Data was successfully stored by the protocol.\r
+ @retval EFI_UNSUPPORTED Platform policies do not allow for data to be\r
+ written.\r
+ @retval EFI_INVALID_PARAMETER BufferSize exceeds the maximum allowed limit.\r
+ BufferSize will be updated with the maximum size\r
+ required to complete the request.\r
+ @retval EFI_INVALID_PARAMETER Buffersize is NULL. BufferSize and Buffer will not\r
+ be affected.\r
+ @retval EFI_INVALID_PARAMETER Buffer is NULL. BufferSize and Buffer will not be\r
+ affected.\r
+ @retval EFI_DEVICE_ERROR The data could not be stored due to a hardware\r
+ error.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the data\r
+ @retval EFI_PROTOCOL_ERROR Input iSCSI initiator name does not adhere to RFC\r
+ 3720\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiSetInitiatorName (\r
+ IN EFI_ISCSI_INITIATOR_NAME_PROTOCOL *This,\r
+ IN OUT UINTN *BufferSize,\r
+ IN VOID *Buffer\r
+ );\r
+\r
+//\r
+// EFI_AUTHENTICATION_INFO_PROTOCOL for iSCSI driver.\r
+//\r
+\r
+/**\r
+ Retrieves the authentication information associated with a particular controller handle.\r
+\r
+ @param[in] This Pointer to the EFI_AUTHENTICATION_INFO_PROTOCOL.\r
+ @param[in] ControllerHandle Handle to the Controller.\r
+ @param[out] Buffer Pointer to the authentication information. This function is\r
+ responsible for allocating the buffer and it is the caller's\r
+ responsibility to free buffer when the caller is finished with buffer.\r
+\r
+ @retval EFI_DEVICE_ERROR The authentication information could not be\r
+ retrieved due to a hardware error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiGetAuthenticationInfo (\r
+ IN EFI_AUTHENTICATION_INFO_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ OUT VOID **Buffer\r
+ );\r
+\r
+/**\r
+ Set the authentication information for a given controller handle.\r
+\r
+ @param[in] This Pointer to the EFI_AUTHENTICATION_INFO_PROTOCOL.\r
+ @param[in] ControllerHandle Handle to the Controller.\r
+ @param[in] Buffer Pointer to the authentication information.\r
+\r
+ @retval EFI_UNSUPPORTED If the platform policies do not allow setting of\r
+ the authentication information.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiSetAuthenticationInfo (\r
+ IN EFI_AUTHENTICATION_INFO_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN VOID *Buffer\r
+ );\r
+\r
+//\r
+// EFI_EXT_SCSI_PASS_THRU_PROTOCOL for iSCSI driver.\r
+//\r
+\r
+/**\r
+ Sends a SCSI Request Packet to a SCSI device that is attached to the SCSI channel.\r
+ This function supports both blocking I/O and nonblocking I/O. The blocking I/O\r
+ functionality is required, and the nonblocking I/O functionality is optional. \r
+\r
+ @param[in] This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Target The Target is an array of size TARGET_MAX_BYTES and it\r
+ represents the id of the SCSI device to send the SCSI\r
+ Request Packet. Each transport driver may choose to\r
+ utilize a subset of this size to suit the needs\r
+ of transport target representation. For example, a \r
+ Fibre Channel driver may use only 8 bytes (WWN)\r
+ to represent an FC target.\r
+ @param[in] Lun The LUN of the SCSI device to send the SCSI Request Packet.\r
+ @param[in, out] Packet A pointer to the SCSI Request Packet to send to the\r
+ SCSI device specified by Target and Lun. \r
+ @param[in] Event If nonblocking I/O is not supported then Event is ignored,\r
+ and blocking I/O is performed. If Event is NULL, then\r
+ blocking I/O is performed. If Event is not NULL and non\r
+ blocking I/O is supported, then nonblocking I/O is performed,\r
+ and Event will be signaled when the SCSI Request Packet\r
+ completes.\r
+\r
+ @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For\r
+ bi-directional commands, InTransferLength bytes \r
+ were transferred from InDataBuffer.\r
+ For write and bi-directional commands, OutTransferLength\r
+ bytes were transferred by OutDataBuffer.\r
+ @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was not executed.\r
+ The number of bytes that could be transferred is\r
+ returned in InTransferLength. For write and\r
+ bi-directional commands, OutTransferLength bytes\r
+ were transferred by OutDataBuffer.\r
+ @retval EFI_NOT_READY The SCSI Request Packet could not be sent because\r
+ there are too many SCSI Request Packets already\r
+ queued. The caller may retry later.\r
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send\r
+ the SCSI Request Packet. \r
+ @retval EFI_INVALID_PARAMETER Target, Lun, or the contents of ScsiRequestPacket\r
+ are invalid.\r
+ @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet\r
+ is not supported by the host adapter.\r
+ This includes the case of Bi-directional SCSI\r
+ commands not supported by the implementation.\r
+ The SCSI Request Packet was not sent,\r
+ so no additional status information is available.\r
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI\r
+ Request Packet to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiExtScsiPassThruFunction (\r
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
+ IN UINT8 *Target,\r
+ IN UINT64 Lun,\r
+ IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,\r
+ IN EFI_EVENT Event OPTIONAL\r
+ );\r
+\r
+/**\r
+ Used to retrieve the list of legal Target IDs and LUNs for SCSI devices on\r
+ a SCSI channel. These can either be the list SCSI devices that are actually\r
+ present on the SCSI channel, or the list of legal Target Ids and LUNs for the\r
+ SCSI channel. Regardless, the caller of this function must probe the Target ID \r
+ and LUN returned to see if a SCSI device is actually present at that location \r
+ on the SCSI channel. \r
+\r
+ @param[in] This The EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+ @param[in, out] Target On input, a pointer to the Target ID of a SCSI\r
+ device present on the SCSI channel. On output, a\r
+ pointer to the Target ID of the next SCSI device\r
+ present on a SCSI channel. An input value of\r
+ 0xFFFFFFFF retrieves the Target ID of the first\r
+ SCSI device present on a SCSI channel.\r
+ @param[in, out] Lun On input, a pointer to the LUN of a SCSI device\r
+ present on the SCSI channel. On output, a pointer\r
+ to the LUN of the next SCSI device present on a\r
+ SCSI channel.\r
+\r
+ @retval EFI_SUCCESS The Target ID and Lun of the next SCSI device on\r
+ the SCSI channel was returned in Target and Lun.\r
+ @retval EFI_NOT_FOUND There are no more SCSI devices on this SCSI\r
+ channel.\r
+ @retval EFI_INVALID_PARAMETER Target is not 0xFFFFFFFF,and Target and Lun were\r
+ not returned on a previous call to\r
+ GetNextDevice().\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiExtScsiPassThruGetNextTargetLun (\r
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
+ IN OUT UINT8 **Target,\r
+ IN OUT UINT64 *Lun\r
+ );\r
+\r
+/**\r
+ Allocate and build a device path node for a SCSI device on a SCSI channel.\r
+\r
+ @param[in] This Protocol instance pointer.\r
+ @param[in] Target The Target ID of the SCSI device for which a\r
+ device path node is to be allocated and built.\r
+ @param[in] Lun The LUN of the SCSI device for which a device\r
+ path node is to be allocated and built.\r
+ @param[in, out] DevicePath A pointer to a single device path node that\r
+ describes the SCSI device specified by Target and\r
+ Lun. This function is responsible for allocating\r
+ the buffer DevicePath with the boot service\r
+ AllocatePool(). It is the caller's\r
+ responsibility to free DevicePath when the caller\r
+ is finished with DevicePath.\r
+\r
+ @retval EFI_SUCCESS The device path node that describes the SCSI\r
+ device specified by Target and Lun was allocated\r
+ and returned in DevicePath.\r
+ @retval EFI_NOT_FOUND The SCSI devices specified by Target and Lun does\r
+ not exist on the SCSI channel.\r
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate\r
+ DevicePath.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiExtScsiPassThruBuildDevicePath (\r
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
+ IN UINT8 *Target,\r
+ IN UINT64 Lun,\r
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath\r
+ );\r
+\r
+/**\r
+ Translate a device path node to a Target ID and LUN.\r
+\r
+ @param[in] This Protocol instance pointer.\r
+ @param[in] DevicePath A pointer to the device path node that describes\r
+ a SCSI device on the SCSI channel.\r
+ @param[out] Target A pointer to the Target ID of a SCSI device on\r
+ the SCSI channel.\r
+ @param[out] Lun A pointer to the LUN of a SCSI device on the SCSI\r
+ channel.\r
+\r
+ @retval EFI_SUCCESS DevicePath was successfully translated to a\r
+ Target ID and LUN, and they were returned in\r
+ Target and Lun.\r
+ @retval EFI_INVALID_PARAMETER DevicePath/Target/Lun is NULL.\r
+ @retval EFI_UNSUPPORTED This driver does not support the device path node\r
+ type in DevicePath.\r
+ @retval EFI_NOT_FOUND A valid translation from DevicePath to a Target\r
+ ID and LUN does not exist.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiExtScsiPassThruGetTargetLun (\r
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ OUT UINT8 **Target,\r
+ OUT UINT64 *Lun\r
+ );\r
+\r
+/**\r
+ Resets a SCSI channel.This operation resets all the SCSI devices connected to\r
+ the SCSI channel.\r
+\r
+ @param[in] This Protocol instance pointer.\r
+\r
+ @retval EFI_UNSUPPORTED It is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiExtScsiPassThruResetChannel (\r
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This\r
+ );\r
+\r
+/**\r
+ Resets a SCSI device that is connected to a SCSI channel.\r
+\r
+ @param[in] This Protocol instance pointer.\r
+ @param[in] Target The Target ID of the SCSI device to reset.\r
+ @param[in] Lun The LUN of the SCSI device to reset.\r
+\r
+ @retval EFI_UNSUPPORTED It is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiExtScsiPassThruResetTargetLun (\r
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
+ IN UINT8 *Target,\r
+ IN UINT64 Lun\r
+ );\r
+\r
+/**\r
+ Retrieve the list of legal Target IDs for SCSI devices on a SCSI channel. \r
+\r
+ @param[in] This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL\r
+ instance.\r
+ @param[in, out] Target (TARGET_MAX_BYTES) of a SCSI device present on\r
+ the SCSI channel. On output, a pointer to the\r
+ Target ID (an array of TARGET_MAX_BYTES) of the\r
+ next SCSI device present on a SCSI channel.\r
+ An input value of 0xF(all bytes in the array are 0xF)\r
+ in the Target array retrieves the Target ID of the\r
+ first SCSI device present on a SCSI channel. \r
+\r
+ @retval EFI_SUCCESS The Target ID of the next SCSI device on the SCSI\r
+ channel was returned in Target.\r
+ @retval EFI_INVALID_PARAMETER Target or Lun is NULL.\r
+ @retval EFI_TIMEOUT Target array is not all 0xF, and Target was not\r
+ returned on a previous call to GetNextTarget().\r
+ @retval EFI_NOT_FOUND There are no more SCSI devices on this SCSI channel.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiExtScsiPassThruGetNextTarget (\r
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
+ IN OUT UINT8 **Target\r
+ );\r
+\r
+#endif\r
--- /dev/null
+## @file\r
+# Component description file for IScsi module.\r
+#\r
+# Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = IScsiDxe\r
+ FILE_GUID = 86CDDF93-4872-4597-8AF9-A35AE4D3725F\r
+ MODULE_TYPE = UEFI_DRIVER\r
+ VERSION_STRING = 1.0\r
+ ENTRY_POINT = IScsiDriverEntryPoint\r
+ UNLOAD_IMAGE = IScsiUnload\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF\r
+#\r
+# DRIVER_BINDING = gIScsiDriverBinding\r
+# COMPONENT_NAME = gIScsiComponentName\r
+# COMPONENT_NAME2 = gIScsiComponentName2\r
+#\r
+\r
+\r
+[Sources]\r
+ ComponentName.c\r
+ IScsiAuthenticationInfo.c\r
+ IScsiCHAP.h\r
+ IScsiCHAP.c\r
+ IScsiConfig.c\r
+ IScsiConfig.h\r
+ IScsiConfigNVDataStruc.h\r
+ IScsiConfigStrings.uni\r
+ IScsiConfigVfr.vfr\r
+ IScsiDhcp.c\r
+ IScsiDhcp.h\r
+ IScsiDhcp6.c\r
+ IScsiDhcp6.h\r
+ IScsiDriver.c\r
+ IScsiDriver.h\r
+ IScsiExtScsiPassThru.c\r
+ IScsiIbft.c\r
+ IScsiIbft.h\r
+ IScsiInitiatorName.c \r
+ IScsiImpl.h\r
+ IScsiMisc.c\r
+ IScsiMisc.h\r
+ IScsiProto.c\r
+ IScsiProto.h\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+ CryptoPkg/CryptoPkg.dec\r
+\r
+[LibraryClasses]\r
+ BaseLib\r
+ BaseMemoryLib\r
+ DebugLib\r
+ DevicePathLib\r
+ HiiLib\r
+ MemoryAllocationLib\r
+ NetLib\r
+ TcpIoLib\r
+ PrintLib\r
+ UefiBootServicesTableLib\r
+ UefiDriverEntryPoint\r
+ UefiLib \r
+ UefiRuntimeServicesTableLib\r
+ UefiHiiServicesLib\r
+ BaseCryptLib\r
+\r
+[Protocols]\r
+ gEfiAcpiTableProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiDriverBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiPciIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiDhcp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiDhcp6ProtocolGuid # PROTOCOL ALWAYS_CONSUMED \r
+ gEfiDhcp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiDhcp6ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED \r
+ gEfiTcp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiTcp6ProtocolGuid # PROTOCOL ALWAYS_CONSUMED \r
+ gEfiTcp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiTcp6ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED \r
+ gEfiExtScsiPassThruProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiHiiConfigAccessProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiIScsiInitiatorNameProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiAuthenticationInfoProtocolGuid # PROTOCOL ALWAYS_CONSUMED \r
+\r
+[Guids]\r
+ gEfiEventExitBootServicesGuid\r
+ gEfiIfrTianoGuid ## CONSUMES ## GUID\r
+ gEfiAcpiTableGuid ## CONSUMES ## GUID\r
+ gEfiAcpi10TableGuid ## CONSUMES ## GUID\r
+ gEfiAcpi20TableGuid ## CONSUMES ## GUID\r
--- /dev/null
+/** @file\r
+ The implementation of EFI_EXT_SCSI_PASS_THRU_PROTOCOL.\r
+\r
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "IScsiImpl.h"\r
+\r
+EFI_EXT_SCSI_PASS_THRU_PROTOCOL gIScsiExtScsiPassThruProtocolTemplate = {\r
+ NULL,\r
+ IScsiExtScsiPassThruFunction,\r
+ IScsiExtScsiPassThruGetNextTargetLun,\r
+ IScsiExtScsiPassThruBuildDevicePath,\r
+ IScsiExtScsiPassThruGetTargetLun,\r
+ IScsiExtScsiPassThruResetChannel,\r
+ IScsiExtScsiPassThruResetTargetLun,\r
+ IScsiExtScsiPassThruGetNextTarget\r
+};\r
+\r
+\r
+/**\r
+ Sends a SCSI Request Packet to a SCSI device that is attached to the SCSI channel.\r
+ This function supports both blocking I/O and nonblocking I/O. The blocking I/O\r
+ functionality is required, and the nonblocking I/O functionality is optional. \r
+\r
+ @param[in] This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Target The Target is an array of size TARGET_MAX_BYTES and it\r
+ represents the id of the SCSI device to send the SCSI\r
+ Request Packet. Each transport driver may choose to\r
+ utilize a subset of this size to suit the needs\r
+ of transport target representation. For example, a \r
+ Fibre Channel driver may use only 8 bytes (WWN)\r
+ to represent an FC target.\r
+ @param[in] Lun The LUN of the SCSI device to send the SCSI Request Packet.\r
+ @param[in, out] Packet A pointer to the SCSI Request Packet to send to the\r
+ SCSI device specified by Target and Lun. \r
+ @param[in] Event If nonblocking I/O is not supported then Event is ignored,\r
+ and blocking I/O is performed. If Event is NULL, then\r
+ blocking I/O is performed. If Event is not NULL and non\r
+ blocking I/O is supported, then nonblocking I/O is performed,\r
+ and Event will be signaled when the SCSI Request Packet\r
+ completes.\r
+\r
+ @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For\r
+ bi-directional commands, InTransferLength bytes \r
+ were transferred from InDataBuffer.\r
+ For write and bi-directional commands, OutTransferLength\r
+ bytes were transferred by OutDataBuffer.\r
+ @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was not executed.\r
+ The number of bytes that could be transferred is\r
+ returned in InTransferLength. For write and\r
+ bi-directional commands, OutTransferLength bytes\r
+ were transferred by OutDataBuffer.\r
+ @retval EFI_NOT_READY The SCSI Request Packet could not be sent because\r
+ there are too many SCSI Request Packets already\r
+ queued. The caller may retry later.\r
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send\r
+ the SCSI Request Packet. \r
+ @retval EFI_INVALID_PARAMETER Target, Lun, or the contents of ScsiRequestPacket,\r
+ are invalid.\r
+ @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet\r
+ is not supported by the host adapter.\r
+ This includes the case of Bi-directional SCSI\r
+ commands not supported by the implementation.\r
+ The SCSI Request Packet was not sent,\r
+ so no additional status information is available.\r
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI\r
+ Request Packet to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiExtScsiPassThruFunction (\r
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
+ IN UINT8 *Target,\r
+ IN UINT64 Lun,\r
+ IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,\r
+ IN EFI_EVENT Event OPTIONAL\r
+ )\r
+{\r
+ if (Target[0] != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Packet == NULL) || (Packet->Cdb == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return IScsiExecuteScsiCommand (This, Target, Lun, Packet);\r
+}\r
+\r
+\r
+/**\r
+ Used to retrieve the list of legal Target IDs and LUNs for SCSI devices on\r
+ a SCSI channel. These can either be the list SCSI devices that are actually\r
+ present on the SCSI channel, or the list of legal Target Ids and LUNs for the\r
+ SCSI channel. Regardless, the caller of this function must probe the Target ID \r
+ and LUN returned to see if a SCSI device is actually present at that location \r
+ on the SCSI channel. \r
+\r
+ @param[in] This The EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+ @param[in, out] Target On input, a pointer to the Target ID of a SCSI\r
+ device present on the SCSI channel. On output, a\r
+ pointer to the Target ID of the next SCSI device\r
+ present on a SCSI channel. An input value of\r
+ 0xFFFFFFFF retrieves the Target ID of the first\r
+ SCSI device present on a SCSI channel.\r
+ @param[in, out] Lun On input, a pointer to the LUN of a SCSI device\r
+ present on the SCSI channel. On output, a pointer\r
+ to the LUN of the next SCSI device present on a\r
+ SCSI channel.\r
+\r
+ @retval EFI_SUCCESS The Target ID and Lun of the next SCSI device on\r
+ the SCSI channel was returned in Target and Lun.\r
+ @retval EFI_NOT_FOUND There are no more SCSI devices on this SCSI\r
+ channel.\r
+ @retval EFI_INVALID_PARAMETER Target is not 0xFFFFFFFF,and Target and Lun were\r
+ not returned on a previous call to\r
+ GetNextDevice().\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiExtScsiPassThruGetNextTargetLun (\r
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
+ IN OUT UINT8 **Target,\r
+ IN OUT UINT64 *Lun\r
+ )\r
+{\r
+ ISCSI_DRIVER_DATA *Private;\r
+ ISCSI_SESSION_CONFIG_NVDATA *ConfigNvData;\r
+ UINT8 TargetId[TARGET_MAX_BYTES];\r
+\r
+ Private = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (This);\r
+ ConfigNvData = &Private->Session->ConfigData->SessionConfigData;\r
+\r
+ if ((*Target)[0] == 0 && (CompareMem (Lun, ConfigNvData->BootLun, sizeof (UINT64)) == 0)) {\r
+ //\r
+ // Only one <Target, Lun> pair per iSCSI Driver instance.\r
+ //\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ SetMem (TargetId, TARGET_MAX_BYTES, 0xFF);\r
+ if (CompareMem (*Target, TargetId, TARGET_MAX_BYTES) == 0) {\r
+ (*Target)[0] = 0;\r
+ CopyMem (Lun, ConfigNvData->BootLun, sizeof (UINT64));\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ return EFI_INVALID_PARAMETER;\r
+}\r
+\r
+\r
+/**\r
+ Allocate and build a device path node for a SCSI device on a SCSI channel.\r
+\r
+ @param[in] This Protocol instance pointer.\r
+ @param[in] Target The Target ID of the SCSI device for which a\r
+ device path node is to be allocated and built.\r
+ @param[in] Lun The LUN of the SCSI device for which a device\r
+ path node is to be allocated and built.\r
+ @param[in, out] DevicePath A pointer to a single device path node that\r
+ describes the SCSI device specified by Target and\r
+ Lun. This function is responsible for allocating\r
+ the buffer DevicePath with the boot service\r
+ AllocatePool(). It is the caller's\r
+ responsibility to free DevicePath when the caller\r
+ is finished with DevicePath.\r
+\r
+ @retval EFI_SUCCESS The device path node that describes the SCSI\r
+ device specified by Target and Lun was allocated\r
+ and returned in DevicePath.\r
+ @retval EFI_NOT_FOUND The SCSI devices specified by Target and Lun does\r
+ not exist on the SCSI channel.\r
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate\r
+ DevicePath.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiExtScsiPassThruBuildDevicePath (\r
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
+ IN UINT8 *Target,\r
+ IN UINT64 Lun,\r
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath\r
+ )\r
+{\r
+ ISCSI_DRIVER_DATA *Private;\r
+ ISCSI_SESSION *Session;\r
+ ISCSI_SESSION_CONFIG_NVDATA *ConfigNvData;\r
+ ISCSI_CHAP_AUTH_CONFIG_NVDATA *AuthConfig;\r
+ EFI_DEV_PATH *Node;\r
+ UINTN DevPathNodeLen;\r
+\r
+ if ((DevicePath == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Target[0] != 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ Private = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (This);\r
+ Session = Private->Session;\r
+ ConfigNvData = &Session->ConfigData->SessionConfigData;\r
+ AuthConfig = Session->AuthData.CHAP.AuthConfig;\r
+\r
+ if (CompareMem (&Lun, ConfigNvData->BootLun, sizeof (UINT64)) != 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ DevPathNodeLen = sizeof (ISCSI_DEVICE_PATH) + AsciiStrLen (ConfigNvData->TargetName) + 1;\r
+ Node = AllocateZeroPool (DevPathNodeLen);\r
+ if (Node == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Node->DevPath.Type = MESSAGING_DEVICE_PATH;\r
+ Node->DevPath.SubType = MSG_ISCSI_DP;\r
+ SetDevicePathNodeLength (&Node->DevPath, DevPathNodeLen);\r
+\r
+ //\r
+ // 0 for TCP, others are reserved.\r
+ //\r
+ Node->Iscsi.NetworkProtocol = 0;\r
+\r
+ Node->Iscsi.LoginOption = 0;\r
+\r
+ switch (Session->AuthType) {\r
+ case ISCSI_AUTH_TYPE_NONE:\r
+ Node->Iscsi.LoginOption |= 0x0800;\r
+ break;\r
+\r
+ case ISCSI_AUTH_TYPE_CHAP:\r
+ //\r
+ // Bit12: 0=CHAP_BI, 1=CHAP_UNI\r
+ //\r
+ if (AuthConfig->CHAPType == ISCSI_CHAP_UNI) {\r
+ Node->Iscsi.LoginOption |= 0x1000;\r
+ }\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+\r
+ CopyMem (&Node->Iscsi.Lun, ConfigNvData->BootLun, sizeof (UINT64));\r
+ Node->Iscsi.TargetPortalGroupTag = Session->TargetPortalGroupTag;\r
+ AsciiStrCpy ((CHAR8 *) Node + sizeof (ISCSI_DEVICE_PATH), ConfigNvData->TargetName);\r
+\r
+ *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Node;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Translate a device path node to a Target ID and LUN.\r
+\r
+ @param[in] This Protocol instance pointer.\r
+ @param[in] DevicePath A pointer to the device path node that describes\r
+ a SCSI device on the SCSI channel.\r
+ @param[out] Target A pointer to the Target ID of a SCSI device on\r
+ the SCSI channel.\r
+ @param[out] Lun A pointer to the LUN of a SCSI device on the SCSI\r
+ channel.\r
+\r
+ @retval EFI_SUCCESS DevicePath was successfully translated to a\r
+ Target ID and LUN, and they were returned in\r
+ Target and Lun.\r
+ @retval EFI_INVALID_PARAMETER DevicePath/Target/Lun is NULL.\r
+ @retval EFI_UNSUPPORTED This driver does not support the device path node\r
+ type in DevicePath.\r
+ @retval EFI_NOT_FOUND A valid translation does not exist from DevicePath \r
+ to a TargetID and LUN.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiExtScsiPassThruGetTargetLun (\r
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ OUT UINT8 **Target,\r
+ OUT UINT64 *Lun\r
+ )\r
+{\r
+ ISCSI_DRIVER_DATA *Private;\r
+ ISCSI_SESSION_CONFIG_NVDATA *ConfigNvData;\r
+\r
+ if ((DevicePath == NULL) || (Target == NULL) || (Lun == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||\r
+ (DevicePath->SubType != MSG_ISCSI_DP) ||\r
+ (DevicePathNodeLength (DevicePath) <= sizeof (ISCSI_DEVICE_PATH))\r
+ ) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Private = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (This);\r
+ ConfigNvData = &Private->Session->ConfigData->SessionConfigData;\r
+\r
+ SetMem (*Target, TARGET_MAX_BYTES, 0xFF);\r
+ (*Target)[0] = 0;\r
+\r
+ if (AsciiStrCmp (ConfigNvData->TargetName, (CHAR8 *) DevicePath + sizeof (ISCSI_DEVICE_PATH)) != 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ CopyMem (Lun, ConfigNvData->BootLun, sizeof (UINT64));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Resets a SCSI channel. This operation resets all the SCSI devices connected to\r
+ the SCSI channel.\r
+\r
+ @param[in] This Protocol instance pointer.\r
+\r
+ @retval EFI_UNSUPPORTED It is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiExtScsiPassThruResetChannel (\r
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This\r
+ )\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+\r
+/**\r
+ Resets a SCSI device that is connected to a SCSI channel.\r
+\r
+ @param[in] This Protocol instance pointer.\r
+ @param[in] Target The Target ID of the SCSI device to reset.\r
+ @param[in] Lun The LUN of the SCSI device to reset.\r
+\r
+ @retval EFI_UNSUPPORTED It is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiExtScsiPassThruResetTargetLun (\r
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
+ IN UINT8 *Target,\r
+ IN UINT64 Lun\r
+ )\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+ Retrieve the list of legal Target IDs for SCSI devices on a SCSI channel. \r
+\r
+ @param[in] This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL\r
+ instance.\r
+ @param[in, out] Target (TARGET_MAX_BYTES) of a SCSI device present on\r
+ the SCSI channel. On output, a pointer to the\r
+ Target ID (an array of TARGET_MAX_BYTES) of the\r
+ next SCSI device present on a SCSI channel.\r
+ An input value of 0xF(all bytes in the array are 0xF)\r
+ in the Target array retrieves the Target ID of the\r
+ first SCSI device present on a SCSI channel. \r
+\r
+ @retval EFI_SUCCESS The Target ID of the next SCSI device on the SCSI\r
+ channel was returned in Target.\r
+ @retval EFI_INVALID_PARAMETER Target or Lun is NULL.\r
+ @retval EFI_TIMEOUT Target array is not all 0xF, and Target was not\r
+ returned on a previous call to GetNextTarget().\r
+ @retval EFI_NOT_FOUND There are no more SCSI devices on this SCSI channel.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiExtScsiPassThruGetNextTarget (\r
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
+ IN OUT UINT8 **Target\r
+ )\r
+{\r
+ UINT8 TargetId[TARGET_MAX_BYTES];\r
+\r
+ SetMem (TargetId, TARGET_MAX_BYTES, 0xFF);\r
+\r
+ if (CompareMem (*Target, TargetId, TARGET_MAX_BYTES) == 0) {\r
+ (*Target)[0] = 0;\r
+ return EFI_SUCCESS;\r
+ } else if ((*Target)[0] == 0) {\r
+ return EFI_NOT_FOUND;\r
+ } else {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+}\r
+\r
--- /dev/null
+/** @file\r
+ Implementation for iSCSI Boot Firmware Table publication.\r
+\r
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "IScsiImpl.h"\r
+\r
+BOOLEAN mIbftInstalled = FALSE;\r
+UINTN mTableKey;\r
+\r
+/**\r
+ Initialize the header of the iSCSI Boot Firmware Table.\r
+ \r
+ @param[out] Header The header of the iSCSI Boot Firmware Table.\r
+ @param[in] OemId The OEM ID.\r
+ @param[in] OemTableId The OEM table ID for the iBFT.\r
+\r
+**/\r
+VOID\r
+IScsiInitIbfTableHeader (\r
+ OUT EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER *Header,\r
+ IN UINT8 *OemId,\r
+ IN UINT64 *OemTableId\r
+ )\r
+{\r
+ Header->Signature = EFI_ACPI_3_0_ISCSI_BOOT_FIRMWARE_TABLE_SIGNATURE;\r
+ Header->Length = IBFT_HEAP_OFFSET;\r
+ Header->Revision = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_REVISION;\r
+ Header->Checksum = 0;\r
+\r
+ CopyMem (Header->OemId, OemId, sizeof (Header->OemId));\r
+ CopyMem (&Header->OemTableId, OemTableId, sizeof (UINT64));\r
+}\r
+\r
+\r
+/**\r
+ Initialize the control section of the iSCSI Boot Firmware Table.\r
+\r
+ @param[in] Table The ACPI table.\r
+\r
+**/\r
+VOID\r
+IScsiInitControlSection (\r
+ IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER *Table\r
+ )\r
+{\r
+ EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *Control;\r
+ UINTN NumOffset;\r
+\r
+ Control = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *) (Table + 1);\r
+\r
+ Control->Header.StructureId = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE_ID;\r
+ Control->Header.Version = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE_VERSION;\r
+ Control->Header.Length = (UINT16) sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE);\r
+\r
+ //\r
+ // If in multipathing mode, enable the Boot Failover Flag.\r
+ // If in single path mode, disable it. Mix-model is not allowed.\r
+ //\r
+ // BUGBUG: if Boot Failover Flag is set to 1, the OS installer cannot\r
+ // find the iSCSI mapped disk. So still keep not set for single path mode.\r
+ //\r
+ if (mPrivate->EnableMpio) {\r
+ Control->Header.Flags = 0;\r
+ NumOffset = 2 * (mPrivate->MpioCount - mPrivate->Krb5MpioCount);\r
+ } else {\r
+ NumOffset = 2 * mPrivate->ValidSinglePathCount;\r
+ }\r
+\r
+ //\r
+ // Each attempt occupies two offsets: one for the NIC section;\r
+ // the other for the Target section.\r
+ //\r
+ if (NumOffset > 4) {\r
+ //\r
+ // Need expand the control section if more than 2 NIC/Target attempts\r
+ // exist.\r
+ //\r
+ Control->Header.Length = (UINT16) (Control->Header.Length + (NumOffset - 4) * sizeof (UINT16));\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Add one item into the heap.\r
+\r
+ @param[in, out] Heap On input, the current address of the heap. On output, the address of\r
+ the heap after the item is added.\r
+ @param[in] Data The data to add into the heap.\r
+ @param[in] Len Length of the Data in byte.\r
+\r
+**/\r
+VOID\r
+IScsiAddHeapItem (\r
+ IN OUT UINT8 **Heap,\r
+ IN VOID *Data,\r
+ IN UINTN Len\r
+ )\r
+{\r
+ //\r
+ // Add one byte for the NULL delimiter.\r
+ //\r
+ *Heap -= Len + 1;\r
+\r
+ CopyMem (*Heap, Data, Len);\r
+ *(*Heap + Len) = 0;\r
+}\r
+\r
+\r
+/**\r
+ Fill the Initiator section of the iSCSI Boot Firmware Table.\r
+\r
+ @param[in] Table The ACPI table.\r
+ @param[in, out] Heap The heap.\r
+\r
+**/\r
+VOID\r
+IScsiFillInitiatorSection (\r
+ IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER *Table,\r
+ IN OUT UINT8 **Heap\r
+ )\r
+{\r
+ EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *Control;\r
+ EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE *Initiator;\r
+\r
+ Control = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *) (Table + 1);\r
+\r
+ //\r
+ // Initiator section immediately follows the control section.\r
+ //\r
+ Initiator = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE *)\r
+ ((UINT8 *) Control + IBFT_ROUNDUP (Control->Header.Length));\r
+\r
+ Control->InitiatorOffset = (UINT16) ((UINTN) Initiator - (UINTN) Table);\r
+\r
+ Initiator->Header.StructureId = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_ID;\r
+ Initiator->Header.Version = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_VERSION;\r
+ Initiator->Header.Length = (UINT16) sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE);\r
+ Initiator->Header.Flags = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_FLAG_BLOCK_VALID |\r
+ EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_FLAG_BOOT_SELECTED;\r
+\r
+ //\r
+ // Fill the iSCSI Initiator Name into the heap.\r
+ //\r
+ IScsiAddHeapItem (Heap, mPrivate->InitiatorName, mPrivate->InitiatorNameLength - 1);\r
+\r
+ Initiator->IScsiNameLength = (UINT16) (mPrivate->InitiatorNameLength - 1);\r
+ Initiator->IScsiNameOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);\r
+}\r
+\r
+\r
+/**\r
+ Map the v4 IP address into v6 IP address.\r
+\r
+ @param[in] V4 The v4 IP address.\r
+ @param[out] V6 The v6 IP address.\r
+\r
+**/\r
+VOID\r
+IScsiMapV4ToV6Addr (\r
+ IN EFI_IPv4_ADDRESS *V4,\r
+ OUT EFI_IPv6_ADDRESS *V6\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ ZeroMem (V6, sizeof (EFI_IPv6_ADDRESS));\r
+\r
+ V6->Addr[10] = 0xff;\r
+ V6->Addr[11] = 0xff;\r
+\r
+ for (Index = 0; Index < 4; Index++) {\r
+ V6->Addr[12 + Index] = V4->Addr[Index];\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Fill the NIC and target sections in iSCSI Boot Firmware Table.\r
+\r
+ @param[in] Table The buffer of the ACPI table.\r
+ @param[in, out] Heap The heap buffer used to store the variable length\r
+ parameters such as iSCSI name.\r
+\r
+**/\r
+VOID\r
+IScsiFillNICAndTargetSections (\r
+ IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER *Table,\r
+ IN OUT UINT8 **Heap\r
+ )\r
+{\r
+ EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *Control;\r
+ EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE *Nic;\r
+ EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE *Target;\r
+ ISCSI_SESSION_CONFIG_NVDATA *NvData;\r
+ ISCSI_CHAP_AUTH_CONFIG_NVDATA *AuthConfig;\r
+ UINT16 *SectionOffset;\r
+ UINTN Index;\r
+ UINT16 Length;\r
+ LIST_ENTRY *Entry;\r
+ ISCSI_ATTEMPT_CONFIG_NVDATA *Attempt;\r
+ ISCSI_NIC_INFO *NicInfo;\r
+ BOOLEAN Flag;\r
+\r
+ //\r
+ // Get the offset of the first Nic and Target section.\r
+ //\r
+ Control = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *) (Table + 1);\r
+ Nic = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE *) ((UINTN) Table +\r
+ Control->InitiatorOffset + IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE)));\r
+ Target = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE *) ((UINTN) Nic +\r
+ IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE)));\r
+\r
+ SectionOffset = &Control->NIC0Offset;\r
+\r
+ Index = 0;\r
+ Flag = TRUE;\r
+\r
+ NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) {\r
+ if (Index == 0) {\r
+ //\r
+ // First entry should be boot selected entry.\r
+ //\r
+ Attempt = IScsiConfigGetAttemptByConfigIndex (mPrivate->BootSelectedIndex);\r
+ if (Attempt == NULL) {\r
+ //\r
+ // First boot selected entry can not be found.\r
+ //\r
+ break;\r
+ }\r
+\r
+ ASSERT (Attempt->SessionConfigData.Enabled != ISCSI_DISABLED);\r
+\r
+ } else {\r
+ if (Index == 1 && Flag) {\r
+ Entry = mPrivate->AttemptConfigs.ForwardLink;\r
+ Flag = FALSE;\r
+ }\r
+\r
+ Attempt = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);\r
+ if (Attempt->AttemptConfigIndex == mPrivate->BootSelectedIndex) {\r
+ continue;\r
+ }\r
+ }\r
+\r
+ if (Attempt->SessionConfigData.Enabled == ISCSI_DISABLED) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Krb5 attempt will not be recorded in iBFT.\r
+ //\r
+ if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_KRB) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // If multipath mode is enabled, only the attempts in MPIO will be recorded in iBFT.\r
+ //\r
+ if (mPrivate->EnableMpio && Attempt->SessionConfigData.Enabled != ISCSI_ENABLED_FOR_MPIO) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Only the valid attempts will be recorded.\r
+ //\r
+ if (!Attempt->ValidiBFTPath) {\r
+ continue;\r
+ }\r
+\r
+ NvData = &Attempt->SessionConfigData;\r
+ AuthConfig = &Attempt->AuthConfigData.CHAP;\r
+\r
+ //\r
+ // Fill the Nic section.\r
+ //\r
+\r
+ Nic->Header.StructureId = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_ID;\r
+ Nic->Header.Version = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_VERSION;\r
+ Nic->Header.Length = (UINT16) sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE);\r
+ Nic->Header.Index = (UINT8) Index;\r
+ Nic->Header.Flags = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_BLOCK_VALID |\r
+ EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_GLOBAL;\r
+\r
+ if (Index == 0) {\r
+ Nic->Header.Flags |= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_BOOT_SELECTED;\r
+ }\r
+\r
+ if (NvData->InitiatorInfoFromDhcp) {\r
+ Nic->Origin = IpPrefixOriginDhcp;\r
+ } else {\r
+ Nic->Origin = IpPrefixOriginManual;\r
+ }\r
+\r
+ if (NvData->IpMode == IP_MODE_IP4 || NvData->IpMode == IP_MODE_AUTOCONFIG) {\r
+ //\r
+ // Get the subnet mask prefix length.\r
+ //\r
+ Nic->SubnetMaskPrefixLength = IScsiGetSubnetMaskPrefixLength (&NvData->SubnetMask);\r
+\r
+ //\r
+ // Map the various v4 addresses into v6 addresses.\r
+ //\r
+ IScsiMapV4ToV6Addr (&NvData->LocalIp, &Nic->Ip);\r
+ IScsiMapV4ToV6Addr (&NvData->Gateway, &Nic->Gateway);\r
+ IScsiMapV4ToV6Addr (&Attempt->PrimaryDns.v4, &Nic->PrimaryDns);\r
+ IScsiMapV4ToV6Addr (&Attempt->SecondaryDns.v4, &Nic->SecondaryDns);\r
+ IScsiMapV4ToV6Addr (&Attempt->DhcpServer.v4, &Nic->DhcpServer);\r
+\r
+ } else if (NvData->IpMode == IP_MODE_IP6 || NvData->IpMode == IP_MODE_AUTOCONFIG) {\r
+ //\r
+ // TODO: The subnet mask/local ip/gateway/dhcpserver for iBFT-IPv6 needs to be \r
+ // confirmed with spec owner.\r
+ //\r
+\r
+ CopyMem (&Nic->PrimaryDns, &Attempt->PrimaryDns, sizeof (EFI_IPv6_ADDRESS));\r
+ CopyMem (&Nic->SecondaryDns, &Attempt->SecondaryDns, sizeof (EFI_IPv6_ADDRESS));\r
+ //\r
+ // TODO: DHCP server address cannot be retrieved by DHCPv6 process since \r
+ // DHCP server option is removed.\r
+ //CopyMem (&Nic->DhcpServer, &Attempt->DhcpServer, sizeof (EFI_IPv6_ADDRESS));\r
+ //\r
+ } else {\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ //\r
+ // Get Nic Info: VLAN tag, Mac address, PCI location.\r
+ //\r
+ NicInfo = IScsiGetNicInfoByIndex (Attempt->NicIndex);\r
+ ASSERT (NicInfo != NULL);\r
+\r
+ Nic->VLanTag = NicInfo->VlanId;\r
+ CopyMem (Nic->Mac, &NicInfo->PermanentAddress, sizeof (Nic->Mac));\r
+ Nic->PciLocation = (UINT16) ((NicInfo->BusNumber << 8) |\r
+ (NicInfo->DeviceNumber << 3) | NicInfo->FunctionNumber);\r
+ *SectionOffset = (UINT16) ((UINTN) Nic - (UINTN) Table);\r
+ SectionOffset++;\r
+\r
+ //\r
+ // Fill the Target section.\r
+ //\r
+\r
+ Target->Header.StructureId = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_ID;\r
+ Target->Header.Version = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_VERSION;\r
+ Target->Header.Length = (UINT16) sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE);\r
+ Target->Header.Index = (UINT8) Index;\r
+ Target->Header.Flags = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_FLAG_BLOCK_VALID;\r
+\r
+ if (Index == 0) {\r
+ Target->Header.Flags |= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_FLAG_BOOT_SELECTED;\r
+ }\r
+\r
+ Target->Port = NvData->TargetPort;\r
+\r
+ if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) {\r
+ Target->CHAPType = AuthConfig->CHAPType;\r
+ } else if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_NONE) {\r
+ Target->CHAPType = ISCSI_AUTH_TYPE_NONE;\r
+ }\r
+\r
+ Target->NicIndex = (UINT8) Index;\r
+\r
+ if (NvData->IpMode == IP_MODE_IP4 || NvData->IpMode == IP_MODE_AUTOCONFIG) {\r
+ IScsiMapV4ToV6Addr (&NvData->TargetIp.v4, &Target->Ip);\r
+ } else if (NvData->IpMode == IP_MODE_IP6 || NvData->IpMode == IP_MODE_AUTOCONFIG) {\r
+ CopyMem (&Target->Ip, &NvData->TargetIp, sizeof (EFI_IPv6_ADDRESS));\r
+ } else {\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ CopyMem (Target->BootLun, NvData->BootLun, sizeof (Target->BootLun));\r
+\r
+ //\r
+ // Target iSCSI Name, CHAP name/secret, reverse CHAP name/secret.\r
+ //\r
+ Length = (UINT16) AsciiStrLen (NvData->TargetName);\r
+ IScsiAddHeapItem (Heap, NvData->TargetName, Length);\r
+\r
+ Target->IScsiNameLength = Length;\r
+ Target->IScsiNameOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);\r
+\r
+ if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) {\r
+ //\r
+ // CHAP Name\r
+ //\r
+ Length = (UINT16) AsciiStrLen (AuthConfig->CHAPName);\r
+ IScsiAddHeapItem (Heap, AuthConfig->CHAPName, Length);\r
+ Target->CHAPNameLength = Length;\r
+ Target->CHAPNameOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);\r
+\r
+ //\r
+ // CHAP Secret\r
+ //\r
+ Length = (UINT16) AsciiStrLen (AuthConfig->CHAPSecret);\r
+ IScsiAddHeapItem (Heap, AuthConfig->CHAPSecret, Length);\r
+ Target->CHAPSecretLength = Length;\r
+ Target->CHAPSecretOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);\r
+\r
+ if (Target->CHAPType == ISCSI_CHAP_MUTUAL) {\r
+ //\r
+ // Reverse CHAP Name.\r
+ //\r
+ Length = (UINT16) AsciiStrLen (AuthConfig->ReverseCHAPName);\r
+ IScsiAddHeapItem (Heap, AuthConfig->ReverseCHAPName, Length);\r
+ Target->ReverseCHAPNameLength = Length;\r
+ Target->ReverseCHAPNameOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);\r
+\r
+ //\r
+ // Reverse CHAP Secret.\r
+ //\r
+ Length = (UINT16) AsciiStrLen (AuthConfig->ReverseCHAPSecret);\r
+ IScsiAddHeapItem (Heap, AuthConfig->ReverseCHAPSecret, Length);\r
+ Target->ReverseCHAPSecretLength = Length;\r
+ Target->ReverseCHAPSecretOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);\r
+ }\r
+ }\r
+\r
+ *SectionOffset = (UINT16) ((UINTN) Target - (UINTN) Table);\r
+ SectionOffset++;\r
+\r
+ //\r
+ // Advance to the next NIC/Target pair.\r
+ //\r
+ Nic = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE *) ((UINTN) Target +\r
+ IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE)));\r
+ Target = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE *) ((UINTN) Nic +\r
+ IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE)));\r
+\r
+ Index++;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Publish and remove the iSCSI Boot Firmware Table according to the iSCSI\r
+ session status.\r
+\r
+**/\r
+VOID\r
+IScsiPublishIbft (\r
+ IN VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;\r
+ EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER *Table;\r
+ EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;\r
+ EFI_ACPI_DESCRIPTION_HEADER *Rsdt;\r
+ UINT8 *Heap;\r
+ UINT8 Checksum;\r
+ UINTN Index;\r
+\r
+\r
+ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol);\r
+ if (EFI_ERROR (Status)) {\r
+ return ;\r
+ }\r
+\r
+ //\r
+ // Find ACPI table RSD_PTR from the system table.\r
+ //\r
+ for (Index = 0, Rsdp = NULL; Index < gST->NumberOfTableEntries; Index++) {\r
+ if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpi20TableGuid) ||\r
+ CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpi10TableGuid) ||\r
+ CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpiTableGuid)\r
+ ) {\r
+ //\r
+ // A match was found.\r
+ //\r
+ Rsdp = (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *) gST->ConfigurationTable[Index].VendorTable;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Rsdp == NULL) {\r
+ return ;\r
+ } else {\r
+ Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->RsdtAddress;\r
+ }\r
+\r
+ if (mIbftInstalled) {\r
+ Status = AcpiTableProtocol->UninstallAcpiTable (\r
+ AcpiTableProtocol,\r
+ mTableKey\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return ;\r
+ }\r
+ mIbftInstalled = FALSE;\r
+ }\r
+\r
+ //\r
+ // If there is no valid attempt configuration, just return.\r
+ //\r
+ if ((!mPrivate->EnableMpio && mPrivate->ValidSinglePathCount == 0) ||\r
+ (mPrivate->EnableMpio && mPrivate->MpioCount <= mPrivate->Krb5MpioCount)) {\r
+ return ;\r
+ }\r
+\r
+ //\r
+ // Allocate 4k bytes to hold the ACPI table.\r
+ //\r
+ Table = AllocateZeroPool (IBFT_MAX_SIZE);\r
+ if (Table == NULL) {\r
+ return ;\r
+ }\r
+\r
+ Heap = (UINT8 *) Table + IBFT_HEAP_OFFSET;\r
+\r
+ //\r
+ // Fill in the various section of the iSCSI Boot Firmware Table.\r
+ //\r
+ IScsiInitIbfTableHeader (Table, Rsdt->OemId, &Rsdt->OemTableId);\r
+ IScsiInitControlSection (Table);\r
+ IScsiFillInitiatorSection (Table, &Heap);\r
+ IScsiFillNICAndTargetSections (Table, &Heap);\r
+\r
+ Checksum = CalculateCheckSum8((UINT8 *)Table, Table->Length);\r
+ Table->Checksum = Checksum;\r
+\r
+ //\r
+ // Install or update the iBFT table.\r
+ //\r
+ Status = AcpiTableProtocol->InstallAcpiTable (\r
+ AcpiTableProtocol,\r
+ Table,\r
+ Table->Length,\r
+ &mTableKey\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ return;\r
+ }\r
+\r
+ mIbftInstalled = TRUE;\r
+ FreePool (Table);\r
+}\r
--- /dev/null
+/** @file\r
+ Some extra definitions for iBFT.\r
+\r
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _ISCSI_IBFT_H_\r
+#define _ISCSI_IBFT_H_\r
+\r
+#include <IndustryStandard/Acpi.h>\r
+#include <IndustryStandard/IScsiBootFirmwareTable.h> \r
+#include <Protocol/AcpiTable.h>\r
+#include <Protocol/PciIo.h>\r
+\r
+#define IBFT_TABLE_VAR_NAME L"iBFT"\r
+#define IBFT_MAX_SIZE 4096\r
+#define IBFT_HEAP_OFFSET 2048\r
+\r
+#define IBFT_ROUNDUP(size) NET_ROUNDUP ((size), EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_STRUCTURE_ALIGNMENT)\r
+\r
+/**\r
+ Publish and remove the iSCSI Boot Firmware Table according to the iSCSI\r
+ session status.\r
+\r
+**/\r
+VOID\r
+IScsiPublishIbft (\r
+ IN VOID\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+ The shared head file for iSCSI driver.\r
+\r
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _ISCSI_IMPL_H_\r
+#define _ISCSI_IMPL_H_\r
+\r
+#include <Uefi.h>\r
+\r
+#include <Protocol/ComponentName.h>\r
+#include <Protocol/ComponentName2.h>\r
+#include <Protocol/DriverBinding.h>\r
+#include <Protocol/DevicePath.h>\r
+#include <Protocol/HiiConfigAccess.h>\r
+\r
+#include <Protocol/Dhcp4.h>\r
+#include <Protocol/Dhcp6.h>\r
+#include <Protocol/Tcp4.h>\r
+#include <Protocol/Tcp6.h>\r
+\r
+#include <Protocol/AuthenticationInfo.h>\r
+#include <Protocol/IScsiInitiatorName.h>\r
+#include <Protocol/ScsiPassThruExt.h>\r
+\r
+#include <Library/HiiLib.h>\r
+#include <Library/UefiHiiServicesLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/DpcLib.h>\r
+#include <Library/NetLib.h>\r
+#include <Library/TcpIoLib.h>\r
+#include <Library/BaseCryptLib.h>\r
+\r
+#include <Guid/MdeModuleHii.h>\r
+#include <Guid/EventGroup.h>\r
+#include <Guid/Acpi.h>\r
+\r
+#include "IScsiConfigNVDataStruc.h"\r
+#include "IScsiDriver.h"\r
+#include "IScsiProto.h"\r
+#include "IScsiCHAP.h"\r
+#include "IScsiDhcp.h"\r
+#include "IScsiDhcp6.h"\r
+#include "IScsiIbft.h"\r
+#include "IScsiMisc.h"\r
+#include "IScsiConfig.h"\r
+\r
+#define ISCSI_AUTH_INITIAL 0\r
+\r
+#define ISCSI_SESSION_SIGNATURE SIGNATURE_32 ('I', 'S', 'S', 'N')\r
+///\r
+/// 10 seconds\r
+///\r
+#define ISCSI_GET_MAPPING_TIMEOUT 100000000U\r
+///\r
+/// 3 seconds\r
+///\r
+#define ISCSI_WAIT_IPSEC_TIMEOUT 30000000U\r
+\r
+struct _ISCSI_SESSION {\r
+ UINT32 Signature;\r
+\r
+ ISCSI_DRIVER_DATA *Private;\r
+ ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData;\r
+\r
+ UINT8 AuthType;\r
+ union {\r
+ ISCSI_CHAP_AUTH_DATA CHAP;\r
+ } AuthData;\r
+\r
+ UINT8 State;\r
+\r
+ UINT8 Isid[6];\r
+ UINT16 Tsih;\r
+\r
+ UINT32 CmdSN;\r
+ UINT32 ExpCmdSN;\r
+ UINT32 MaxCmdSN;\r
+\r
+ UINT32 InitiatorTaskTag;\r
+ UINT16 NextCid;\r
+\r
+ LIST_ENTRY Conns;\r
+ UINT32 NumConns;\r
+\r
+ LIST_ENTRY TcbList;\r
+\r
+ //\r
+ // Session-wide parameters\r
+ //\r
+ UINT16 TargetPortalGroupTag;\r
+ UINT32 MaxConnections;\r
+ BOOLEAN InitialR2T;\r
+ BOOLEAN ImmediateData;\r
+ UINT32 MaxBurstLength;\r
+ UINT32 FirstBurstLength;\r
+ UINT32 DefaultTime2Wait;\r
+ UINT32 DefaultTime2Retain;\r
+ UINT16 MaxOutstandingR2T;\r
+ BOOLEAN DataPDUInOrder;\r
+ BOOLEAN DataSequenceInOrder;\r
+ UINT8 ErrorRecoveryLevel;\r
+};\r
+\r
+#define ISCSI_CONNECTION_SIGNATURE SIGNATURE_32 ('I', 'S', 'C', 'N')\r
+\r
+struct _ISCSI_CONNECTION {\r
+ UINT32 Signature;\r
+ LIST_ENTRY Link;\r
+\r
+ EFI_EVENT TimeoutEvent;\r
+\r
+ ISCSI_SESSION *Session;\r
+\r
+ UINT8 State;\r
+ UINT8 CurrentStage;\r
+ UINT8 NextStage;\r
+\r
+ UINT8 AuthStep;\r
+\r
+ BOOLEAN PartialReqSent;\r
+ BOOLEAN PartialRspRcvd;\r
+\r
+ BOOLEAN TransitInitiated;\r
+ BOOLEAN ParamNegotiated;\r
+\r
+ UINT16 Cid;\r
+ UINT32 ExpStatSN;\r
+\r
+ //\r
+ // Queues...\r
+ //\r
+ NET_BUF_QUEUE RspQue;\r
+\r
+ BOOLEAN Ipv6Flag;\r
+ TCP_IO TcpIo;\r
+\r
+ //\r
+ // Connection-only parameters.\r
+ //\r
+ UINT32 MaxRecvDataSegmentLength;\r
+ ISCSI_DIGEST_TYPE HeaderDigest;\r
+ ISCSI_DIGEST_TYPE DataDigest;\r
+};\r
+\r
+#define ISCSI_DRIVER_DATA_SIGNATURE SIGNATURE_32 ('I', 'S', 'D', 'A')\r
+\r
+#define ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU(PassThru) \\r
+ CR ( \\r
+ PassThru, \\r
+ ISCSI_DRIVER_DATA, \\r
+ IScsiExtScsiPassThru, \\r
+ ISCSI_DRIVER_DATA_SIGNATURE \\r
+ )\r
+\r
+#define ISCSI_DRIVER_DATA_FROM_IDENTIFIER(Identifier) \\r
+ CR ( \\r
+ Identifier, \\r
+ ISCSI_DRIVER_DATA, \\r
+ IScsiIdentifier, \\r
+ ISCSI_DRIVER_DATA_SIGNATURE \\r
+ )\r
+\r
+struct _ISCSI_DRIVER_DATA {\r
+ UINT32 Signature;\r
+ EFI_HANDLE Image;\r
+ EFI_HANDLE Controller;\r
+ ISCSI_PRIVATE_PROTOCOL IScsiIdentifier;\r
+\r
+ EFI_EVENT ExitBootServiceEvent;\r
+\r
+ EFI_EXT_SCSI_PASS_THRU_PROTOCOL IScsiExtScsiPassThru;\r
+ EFI_EXT_SCSI_PASS_THRU_MODE ExtScsiPassThruMode;\r
+ EFI_HANDLE ExtScsiPassThruHandle;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ EFI_HANDLE ChildHandle; \r
+ ISCSI_SESSION *Session;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+ Implementation for EFI iSCSI Initiator Name Protocol.\r
+\r
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "IScsiImpl.h"\r
+\r
+EFI_ISCSI_INITIATOR_NAME_PROTOCOL gIScsiInitiatorName = {\r
+ IScsiGetInitiatorName,\r
+ IScsiSetInitiatorName\r
+};\r
+\r
+\r
+/**\r
+ Retrieves the current set value of iSCSI Initiator Name.\r
+\r
+ @param[in] This Pointer to the EFI_ISCSI_INITIATOR_NAME_PROTOCOL\r
+ instance.\r
+ @param[in, out] BufferSize Size of the buffer in bytes pointed to by Buffer /\r
+ Actual size of the variable data buffer.\r
+ @param[out] Buffer Pointer to the buffer for data to be read.\r
+ The data is a null-terminated UTF-8 encoded string.\r
+ The maximum length is 223 characters, including the null-terminator.\r
+\r
+ @retval EFI_SUCCESS Data was successfully retrieved into the provided\r
+ buffer and the BufferSize was sufficient to handle\r
+ the iSCSI initiator name.\r
+ @retval EFI_BUFFER_TOO_SMALL BufferSize is too small for the result. BufferSize\r
+ will be updated with the size required to complete\r
+ the request. Buffer will not be affected.\r
+ @retval EFI_INVALID_PARAMETER BufferSize is NULL. BufferSize and Buffer will not\r
+ be affected.\r
+ @retval EFI_INVALID_PARAMETER Buffer is NULL. BufferSize and Buffer will not be\r
+ affected.\r
+ @retval EFI_DEVICE_ERROR The iSCSI initiator name could not be retrieved\r
+ due to a hardware error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiGetInitiatorName (\r
+ IN EFI_ISCSI_INITIATOR_NAME_PROTOCOL *This,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ if ((BufferSize == NULL) || (Buffer == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = gRT->GetVariable (\r
+ ISCSI_INITIATOR_NAME_VAR_NAME,\r
+ &gEfiIScsiInitiatorNameProtocolGuid,\r
+ NULL,\r
+ BufferSize,\r
+ Buffer\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Sets the iSSI Initiator Name.\r
+\r
+ @param[in] This Pointer to the EFI_ISCSI_INITIATOR_NAME_PROTOCOL\r
+ instance.\r
+ @param[in, out] BufferSize Size of the buffer in bytes pointed to by Buffer.\r
+ @param[in] Buffer Pointer to the buffer for data to be written.\r
+ The data is a null-terminated UTF-8 encoded string.\r
+ The maximum length is 223 characters, including the null-terminator.\r
+\r
+ @retval EFI_SUCCESS Data was successfully stored by the protocol.\r
+ @retval EFI_UNSUPPORTED Platform policies do not allow for data to be\r
+ written.\r
+ @retval EFI_INVALID_PARAMETER BufferSize exceeds the maximum allowed limit.\r
+ BufferSize will be updated with the maximum size\r
+ required to complete the request.\r
+ @retval EFI_INVALID_PARAMETER Buffersize is NULL. BufferSize and Buffer will not\r
+ be affected.\r
+ @retval EFI_INVALID_PARAMETER Buffer is NULL. BufferSize and Buffer will not be\r
+ affected.\r
+ @retval EFI_DEVICE_ERROR The data could not be stored due to a hardware\r
+ error.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the data\r
+ @retval EFI_PROTOCOL_ERROR Input iSCSI initiator name does not adhere to RFC\r
+ 3720\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiSetInitiatorName (\r
+ IN EFI_ISCSI_INITIATOR_NAME_PROTOCOL *This,\r
+ IN OUT UINTN *BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ if ((BufferSize == NULL) || (Buffer == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (*BufferSize > ISCSI_NAME_MAX_SIZE) {\r
+ *BufferSize = ISCSI_NAME_MAX_SIZE;\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Only support iqn iSCSI names.\r
+ //\r
+ Status = IScsiNormalizeName ((CHAR8 *) Buffer, *BufferSize - 1);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = gRT->SetVariable (\r
+ ISCSI_INITIATOR_NAME_VAR_NAME,\r
+ &gEfiIScsiInitiatorNameProtocolGuid,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+ *BufferSize,\r
+ Buffer\r
+ );\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+ Miscellaneous routines for iSCSI driver.\r
+\r
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "IScsiImpl.h"\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 IScsiHexString[] = "0123456789ABCDEFabcdef";\r
+\r
+/**\r
+ Removes (trims) specified leading and trailing characters from a string.\r
+\r
+ @param[in, out] Str Pointer to the null-terminated string to be trimmed.\r
+ On return, Str will hold the trimmed string. \r
+\r
+ @param[in] CharC Character will be trimmed from str.\r
+\r
+**/\r
+VOID\r
+IScsiStrTrim (\r
+ IN OUT CHAR16 *Str,\r
+ IN CHAR16 CharC\r
+ )\r
+{\r
+ CHAR16 *Pointer1;\r
+ CHAR16 *Pointer2;\r
+ \r
+ if (*Str == 0) {\r
+ return ;\r
+ }\r
+ \r
+ //\r
+ // Trim off the leading and trailing characters c\r
+ //\r
+ for (Pointer1 = Str; (*Pointer1 != 0) && (*Pointer1 == CharC); Pointer1++) {\r
+ ;\r
+ }\r
+ \r
+ Pointer2 = Str;\r
+ if (Pointer2 == Pointer1) {\r
+ while (*Pointer1 != 0) {\r
+ Pointer2++;\r
+ Pointer1++;\r
+ }\r
+ } else {\r
+ while (*Pointer1 != 0) { \r
+ *Pointer2 = *Pointer1; \r
+ Pointer1++;\r
+ Pointer2++;\r
+ }\r
+ *Pointer2 = 0;\r
+ }\r
+ \r
+ \r
+ for (Pointer1 = Str + StrLen(Str) - 1; Pointer1 >= Str && *Pointer1 == CharC; Pointer1--) {\r
+ ;\r
+ }\r
+ if (Pointer1 != Str + StrLen(Str) - 1) { \r
+ *(Pointer1 + 1) = 0;\r
+ }\r
+}\r
+\r
+/**\r
+ Calculate the prefix length of the IPv4 subnet mask.\r
+\r
+ @param[in] SubnetMask The IPv4 subnet mask.\r
+\r
+ @return The prefix length of the subnet mask.\r
+ @retval 0 Other errors as indicated.\r
+\r
+**/\r
+UINT8\r
+IScsiGetSubnetMaskPrefixLength (\r
+ IN EFI_IPv4_ADDRESS *SubnetMask\r
+ )\r
+{\r
+ UINT8 Len;\r
+ UINT32 ReverseMask;\r
+\r
+ //\r
+ // The SubnetMask is in network byte order.\r
+ //\r
+ ReverseMask = (SubnetMask->Addr[0] << 24) | (SubnetMask->Addr[1] << 16) | (SubnetMask->Addr[2] << 8) | (SubnetMask->Addr[3]);\r
+\r
+ //\r
+ // Reverse it.\r
+ //\r
+ ReverseMask = ~ReverseMask;\r
+\r
+ if ((ReverseMask & (ReverseMask + 1)) != 0) {\r
+ return 0;\r
+ }\r
+\r
+ Len = 0;\r
+\r
+ while (ReverseMask != 0) {\r
+ ReverseMask = ReverseMask >> 1;\r
+ Len++;\r
+ }\r
+\r
+ return (UINT8) (32 - Len);\r
+}\r
+\r
+\r
+/**\r
+ Convert the hexadecimal encoded LUN string into the 64-bit LUN.\r
+\r
+ @param[in] Str The hexadecimal encoded LUN string.\r
+ @param[out] Lun Storage to return the 64-bit LUN.\r
+\r
+ @retval EFI_SUCCESS The 64-bit LUN is stored in Lun.\r
+ @retval EFI_INVALID_PARAMETER The string is malformatted.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiAsciiStrToLun (\r
+ IN CHAR8 *Str,\r
+ OUT UINT8 *Lun\r
+ )\r
+{\r
+ UINTN Index, IndexValue, IndexNum, SizeStr;\r
+ CHAR8 TemStr[2];\r
+ UINT8 TemValue;\r
+ UINT16 Value[4];\r
+ \r
+ ZeroMem (Lun, 8);\r
+ ZeroMem (TemStr, 2);\r
+ ZeroMem ((UINT8 *) Value, sizeof (Value));\r
+ SizeStr = AsciiStrLen (Str); \r
+ IndexValue = 0;\r
+ IndexNum = 0;\r
+\r
+ for (Index = 0; Index < SizeStr; Index ++) {\r
+ TemStr[0] = Str[Index];\r
+ TemValue = (UINT8) AsciiStrHexToUint64 (TemStr);\r
+ if (TemValue == 0 && TemStr[0] != '0') {\r
+ if ((TemStr[0] != '-') || (IndexNum == 0)) {\r
+ //\r
+ // Invalid Lun Char.\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ \r
+ if ((TemValue == 0) && (TemStr[0] == '-')) {\r
+ //\r
+ // Next Lun value.\r
+ //\r
+ if (++IndexValue >= 4) {\r
+ //\r
+ // Max 4 Lun value.\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Restart str index for the next lun value.\r
+ //\r
+ IndexNum = 0;\r
+ continue;\r
+ }\r
+ \r
+ if (++IndexNum > 4) {\r
+ // \r
+ // Each Lun Str can't exceed size 4, because it will be as UINT16 value.\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ \r
+ //\r
+ // Combine UINT16 value.\r
+ //\r
+ Value[IndexValue] = (UINT16) ((Value[IndexValue] << 4) + TemValue);\r
+ }\r
+ \r
+ for (Index = 0; Index <= IndexValue; Index ++) {\r
+ *((UINT16 *) &Lun[Index * 2]) = HTONS (Value[Index]);\r
+ }\r
+ \r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Convert the 64-bit LUN into the hexadecimal encoded LUN string.\r
+\r
+ @param[in] Lun The 64-bit LUN.\r
+ @param[out] Str The storage to return the hexadecimal encoded LUN string.\r
+\r
+**/\r
+VOID\r
+IScsiLunToUnicodeStr (\r
+ IN UINT8 *Lun,\r
+ OUT CHAR16 *Str\r
+ )\r
+{\r
+ UINTN Index;\r
+ CHAR16 *TempStr;\r
+\r
+ TempStr = Str;\r
+\r
+ for (Index = 0; Index < 4; Index++) {\r
+\r
+ if ((Lun[2 * Index] | Lun[2 * Index + 1]) == 0) {\r
+ StrCpy (TempStr, L"0-");\r
+ } else {\r
+ TempStr[0] = (CHAR16) IScsiHexString[Lun[2 * Index] >> 4];\r
+ TempStr[1] = (CHAR16) IScsiHexString[Lun[2 * Index] & 0x0F];\r
+ TempStr[2] = (CHAR16) IScsiHexString[Lun[2 * Index + 1] >> 4];\r
+ TempStr[3] = (CHAR16) IScsiHexString[Lun[2 * Index + 1] & 0x0F];\r
+ TempStr[4] = L'-';\r
+ TempStr[5] = 0;\r
+\r
+ IScsiStrTrim (TempStr, L'0');\r
+ }\r
+\r
+ TempStr += StrLen (TempStr);\r
+ }\r
+\r
+ Str[StrLen (Str) - 1] = 0;\r
+\r
+ for (Index = StrLen (Str) - 1; Index > 1; Index = Index - 2) {\r
+ if ((Str[Index] == L'0') && (Str[Index - 1] == L'-')) {\r
+ Str[Index - 1] = 0;\r
+ } else {\r
+ break;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Convert the formatted IP address into the binary IP address.\r
+\r
+ @param[in] Str The UNICODE string.\r
+ @param[in] IpMode Indicates whether the IP address is v4 or v6.\r
+ @param[out] Ip The storage to return the ASCII string.\r
+\r
+ @retval EFI_SUCCESS The binary IP address is returned in Ip.\r
+ @retval EFI_INVALID_PARAMETER The IP string is malformatted or IpMode is\r
+ invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiAsciiStrToIp (\r
+ IN CHAR8 *Str,\r
+ IN UINT8 IpMode,\r
+ OUT EFI_IP_ADDRESS *Ip\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ if (IpMode == IP_MODE_IP4 || IpMode == IP_MODE_AUTOCONFIG_IP4) {\r
+ return NetLibAsciiStrToIp4 (Str, &Ip->v4);\r
+\r
+ } else if (IpMode == IP_MODE_IP6 || IpMode == IP_MODE_AUTOCONFIG_IP6) {\r
+ return NetLibAsciiStrToIp6 (Str, &Ip->v6);\r
+\r
+ } else if (IpMode == IP_MODE_AUTOCONFIG) {\r
+ Status = NetLibAsciiStrToIp4 (Str, &Ip->v4);\r
+ if (!EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ return NetLibAsciiStrToIp6 (Str, &Ip->v6);\r
+\r
+ }\r
+\r
+ return EFI_INVALID_PARAMETER;\r
+}\r
+\r
+/**\r
+ Convert the mac address into a hexadecimal encoded "-" seperated string.\r
+\r
+ @param[in] Mac The mac address.\r
+ @param[in] Len Length in bytes of the mac address.\r
+ @param[in] VlanId VLAN ID of the network device.\r
+ @param[out] Str The storage to return the mac string.\r
+\r
+**/\r
+VOID\r
+IScsiMacAddrToStr (\r
+ IN EFI_MAC_ADDRESS *Mac,\r
+ IN UINT32 Len,\r
+ IN UINT16 VlanId,\r
+ OUT CHAR16 *Str\r
+ )\r
+{\r
+ UINT32 Index;\r
+ CHAR16 *String;\r
+\r
+ for (Index = 0; Index < Len; Index++) {\r
+ Str[3 * Index] = (CHAR16) IScsiHexString[(Mac->Addr[Index] >> 4) & 0x0F];\r
+ Str[3 * Index + 1] = (CHAR16) IScsiHexString[Mac->Addr[Index] & 0x0F];\r
+ Str[3 * Index + 2] = L'-';\r
+ }\r
+\r
+ String = &Str[3 * Index - 1] ;\r
+ if (VlanId != 0) {\r
+ String += UnicodeSPrint (String, 6 * sizeof (CHAR16), L"\\%04x", (UINTN) VlanId);\r
+ }\r
+\r
+ *String = L'\0';\r
+}\r
+\r
+/**\r
+ Convert the binary encoded buffer into a hexadecimal encoded string.\r
+\r
+ @param[in] BinBuffer The buffer containing the binary data.\r
+ @param[in] BinLength Length of the binary buffer.\r
+ @param[in, out] HexStr Pointer to the string.\r
+ @param[in, out] HexLength The length of the string.\r
+\r
+ @retval EFI_SUCCESS The binary data is converted to the hexadecimal string \r
+ and the length of the string is updated.\r
+ @retval EFI_BUFFER_TOO_SMALL The string is too small.\r
+ @retval EFI_INVALID_PARAMETER The IP string is malformatted.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiBinToHex (\r
+ IN UINT8 *BinBuffer,\r
+ IN UINT32 BinLength,\r
+ IN OUT CHAR8 *HexStr,\r
+ IN OUT UINT32 *HexLength\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ if ((HexStr == NULL) || (BinBuffer == NULL) || (BinLength == 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (((*HexLength) - 3) < BinLength * 2) {\r
+ *HexLength = BinLength * 2 + 3;\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ *HexLength = BinLength * 2 + 3;\r
+ //\r
+ // Prefix for Hex String.\r
+ //\r
+ HexStr[0] = '0';\r
+ HexStr[1] = 'x';\r
+\r
+ for (Index = 0; Index < BinLength; Index++) {\r
+ HexStr[Index * 2 + 2] = IScsiHexString[BinBuffer[Index] >> 4];\r
+ HexStr[Index * 2 + 3] = IScsiHexString[BinBuffer[Index] & 0xf];\r
+ }\r
+\r
+ HexStr[Index * 2 + 2] = '\0';\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Convert the hexadecimal string into a binary encoded buffer.\r
+\r
+ @param[in, out] BinBuffer The binary buffer.\r
+ @param[in, out] BinLength Length of the binary buffer.\r
+ @param[in] HexStr The hexadecimal string.\r
+\r
+ @retval EFI_SUCCESS The hexadecimal string is converted into a binary\r
+ encoded buffer.\r
+ @retval EFI_BUFFER_TOO_SMALL The binary buffer is too small to hold the converted data.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiHexToBin (\r
+ IN OUT UINT8 *BinBuffer,\r
+ IN OUT UINT32 *BinLength,\r
+ IN CHAR8 *HexStr\r
+ )\r
+{\r
+ UINTN Index;\r
+ UINTN Length;\r
+ UINT8 Digit;\r
+ CHAR8 TemStr[2];\r
+ \r
+ ZeroMem (TemStr, sizeof (TemStr));\r
+\r
+ //\r
+ // Find out how many hex characters the string has.\r
+ //\r
+ if ((HexStr[0] == '0') && ((HexStr[1] == 'x') || (HexStr[1] == 'X'))) {\r
+ HexStr += 2;\r
+ }\r
+ \r
+ Length = AsciiStrLen (HexStr);\r
+\r
+ for (Index = 0; Index < Length; Index ++) {\r
+ TemStr[0] = HexStr[Index];\r
+ Digit = (UINT8) AsciiStrHexToUint64 (TemStr);\r
+ if (Digit == 0 && TemStr[0] != '0') {\r
+ //\r
+ // Invalid Lun Char.\r
+ //\r
+ break;\r
+ }\r
+ if ((Index & 1) == 0) {\r
+ BinBuffer [Index/2] = Digit;\r
+ } else {\r
+ BinBuffer [Index/2] = (UINT8) ((BinBuffer [Index/2] << 4) + Digit);\r
+ }\r
+ }\r
+ \r
+ *BinLength = (UINT32) ((Index + 1)/2);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Convert the decimal-constant string or hex-constant string into a numerical value.\r
+\r
+ @param[in] Str String in decimal or hex.\r
+\r
+ @return The numerical value.\r
+\r
+**/\r
+UINTN\r
+IScsiNetNtoi (\r
+ IN CHAR8 *Str\r
+ )\r
+{\r
+ if ((Str[0] == '0') && ((Str[1] == 'x') || (Str[1] == 'X'))) {\r
+ Str += 2;\r
+\r
+ return AsciiStrHexToUintn (Str);\r
+ }\r
+\r
+ return AsciiStrDecimalToUintn (Str);\r
+}\r
+\r
+\r
+/**\r
+ Generate random numbers.\r
+\r
+ @param[in, out] Rand The buffer to contain random numbers.\r
+ @param[in] RandLength The length of the Rand buffer.\r
+\r
+**/\r
+VOID\r
+IScsiGenRandom (\r
+ IN OUT UINT8 *Rand,\r
+ IN UINTN RandLength\r
+ )\r
+{\r
+ UINT32 Random;\r
+\r
+ while (RandLength > 0) {\r
+ Random = NET_RANDOM (NetRandomInitSeed ());\r
+ *Rand++ = (UINT8) (Random);\r
+ RandLength--;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Record the NIC info in global structure.\r
+\r
+ @param[in] Controller The handle of the controller.\r
+\r
+ @retval EFI_SUCCESS The operation is completed.\r
+ @retval EFI_OUT_OF_RESOURCES Do not have sufficient resources to finish this\r
+ operation.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiAddNic (\r
+ IN EFI_HANDLE Controller\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ ISCSI_NIC_INFO *NicInfo;\r
+ LIST_ENTRY *Entry;\r
+ EFI_MAC_ADDRESS MacAddr;\r
+ UINTN HwAddressSize;\r
+ UINT16 VlanId;\r
+\r
+ //\r
+ // Get MAC address of this network device.\r
+ //\r
+ Status = NetLibGetMacAddress (Controller, &MacAddr, &HwAddressSize);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Get VLAN ID of this network device.\r
+ //\r
+ VlanId = NetLibGetVlanId (Controller);\r
+\r
+ //\r
+ // Check whether the NIC info already exists. Return directly if so.\r
+ //\r
+ NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {\r
+ NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);\r
+ if (NicInfo->HwAddressSize == HwAddressSize &&\r
+ CompareMem (&NicInfo->PermanentAddress, MacAddr.Addr, HwAddressSize) == 0 &&\r
+ NicInfo->VlanId == VlanId) {\r
+ mPrivate->CurrentNic = NicInfo->NicIndex;\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (mPrivate->MaxNic < NicInfo->NicIndex) {\r
+ mPrivate->MaxNic = NicInfo->NicIndex;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Record the NIC info in private structure.\r
+ //\r
+ NicInfo = AllocateZeroPool (sizeof (ISCSI_NIC_INFO));\r
+ if (NicInfo == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ CopyMem (&NicInfo->PermanentAddress, MacAddr.Addr, HwAddressSize);\r
+ NicInfo->HwAddressSize = (UINT32) HwAddressSize;\r
+ NicInfo->VlanId = VlanId;\r
+ NicInfo->NicIndex = (UINT8) (mPrivate->MaxNic + 1);\r
+ mPrivate->MaxNic = NicInfo->NicIndex;\r
+\r
+ //\r
+ // Get the PCI location.\r
+ //\r
+ IScsiGetNICPciLocation (\r
+ Controller,\r
+ &NicInfo->BusNumber,\r
+ &NicInfo->DeviceNumber,\r
+ &NicInfo->FunctionNumber\r
+ );\r
+\r
+ InsertTailList (&mPrivate->NicInfoList, &NicInfo->Link);\r
+ mPrivate->NicCount++;\r
+\r
+ mPrivate->CurrentNic = NicInfo->NicIndex;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Delete the recorded NIC info from global structure. Also delete corresponding\r
+ attempts.\r
+\r
+ @param[in] Controller The handle of the controller.\r
+\r
+ @retval EFI_SUCCESS The operation is completed.\r
+ @retval EFI_NOT_FOUND The NIC info to be deleted is not recorded.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiRemoveNic (\r
+ IN EFI_HANDLE Controller\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ ISCSI_NIC_INFO *NicInfo;\r
+ LIST_ENTRY *Entry;\r
+ LIST_ENTRY *NextEntry;\r
+ ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;\r
+ ISCSI_NIC_INFO *ThisNic;\r
+ EFI_MAC_ADDRESS MacAddr;\r
+ UINTN HwAddressSize;\r
+ UINT16 VlanId;\r
+\r
+ //\r
+ // Get MAC address of this network device.\r
+ //\r
+ Status = NetLibGetMacAddress (Controller, &MacAddr, &HwAddressSize);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Get VLAN ID of this network device.\r
+ //\r
+ VlanId = NetLibGetVlanId (Controller);\r
+\r
+ //\r
+ // Check whether the NIC information exists.\r
+ //\r
+ ThisNic = NULL;\r
+\r
+ NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {\r
+ NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);\r
+ if (NicInfo->HwAddressSize == HwAddressSize &&\r
+ CompareMem (&NicInfo->PermanentAddress, MacAddr.Addr, HwAddressSize) == 0 &&\r
+ NicInfo->VlanId == VlanId) {\r
+\r
+ ThisNic = NicInfo;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (ThisNic == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ mPrivate->CurrentNic = ThisNic->NicIndex;\r
+\r
+ RemoveEntryList (&ThisNic->Link);\r
+ FreePool (ThisNic);\r
+ mPrivate->NicCount--;\r
+\r
+ //\r
+ // Remove all attempts related to this NIC.\r
+ //\r
+ NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &mPrivate->AttemptConfigs) {\r
+ AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);\r
+ if (AttemptConfigData->NicIndex == mPrivate->CurrentNic) {\r
+ RemoveEntryList (&AttemptConfigData->Link);\r
+ mPrivate->AttemptCount--;\r
+\r
+ if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO && mPrivate->MpioCount > 0) {\r
+ if (--mPrivate->MpioCount == 0) {\r
+ mPrivate->EnableMpio = FALSE;\r
+ }\r
+\r
+ if (AttemptConfigData->AuthenticationType == ISCSI_AUTH_TYPE_KRB && mPrivate->Krb5MpioCount > 0) {\r
+ mPrivate->Krb5MpioCount--;\r
+ }\r
+\r
+ } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED && mPrivate->SinglePathCount > 0) {\r
+ mPrivate->SinglePathCount--;\r
+\r
+ if (mPrivate->ValidSinglePathCount > 0) {\r
+ mPrivate->ValidSinglePathCount--;\r
+ }\r
+ }\r
+\r
+ FreePool (AttemptConfigData);\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Get the recorded NIC info from global structure by the Index.\r
+\r
+ @param[in] NicIndex The index indicates the position of NIC info.\r
+\r
+ @return Pointer to the NIC info, or NULL if not found.\r
+\r
+**/\r
+ISCSI_NIC_INFO *\r
+IScsiGetNicInfoByIndex (\r
+ IN UINT8 NicIndex\r
+ )\r
+{\r
+ LIST_ENTRY *Entry;\r
+ ISCSI_NIC_INFO *NicInfo;\r
+\r
+ NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {\r
+ NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);\r
+ if (NicInfo->NicIndex == NicIndex) {\r
+ return NicInfo;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Get the NIC's PCI location and return it accroding to the composited\r
+ format defined in iSCSI Boot Firmware Table.\r
+\r
+ @param[in] Controller The handle of the controller.\r
+ @param[out] Bus The bus number.\r
+ @param[out] Device The device number.\r
+ @param[out] Function The function number.\r
+\r
+ @return The composited representation of the NIC PCI location.\r
+\r
+**/\r
+UINT16\r
+IScsiGetNICPciLocation (\r
+ IN EFI_HANDLE Controller,\r
+ OUT UINTN *Bus,\r
+ OUT UINTN *Device,\r
+ OUT UINTN *Function\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ EFI_HANDLE PciIoHandle;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINTN Segment;\r
+\r
+ Status = gBS->HandleProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &DevicePath\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return 0;\r
+ }\r
+\r
+ Status = gBS->LocateDevicePath (\r
+ &gEfiPciIoProtocolGuid,\r
+ &DevicePath,\r
+ &PciIoHandle\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return 0;\r
+ }\r
+\r
+ Status = gBS->HandleProtocol (PciIoHandle, &gEfiPciIoProtocolGuid, (VOID **) &PciIo);\r
+ if (EFI_ERROR (Status)) {\r
+ return 0;\r
+ }\r
+\r
+ Status = PciIo->GetLocation (PciIo, &Segment, Bus, Device, Function);\r
+ if (EFI_ERROR (Status)) {\r
+ return 0;\r
+ }\r
+\r
+ return (UINT16) ((*Bus << 8) | (*Device << 3) | *Function);\r
+}\r
+\r
+\r
+/**\r
+ Read the EFI variable (VendorGuid/Name) and return a dynamically allocated\r
+ buffer, and the size of the buffer. If failure, return NULL.\r
+\r
+ @param[in] Name String part of EFI variable name.\r
+ @param[in] VendorGuid GUID part of EFI variable name.\r
+ @param[out] VariableSize Returns the size of the EFI variable that was read.\r
+\r
+ @return Dynamically allocated memory that contains a copy of the EFI variable.\r
+ @return Caller is responsible freeing the buffer.\r
+ @retval NULL Variable was not read.\r
+\r
+**/\r
+VOID *\r
+IScsiGetVariableAndSize (\r
+ IN CHAR16 *Name,\r
+ IN EFI_GUID *VendorGuid,\r
+ OUT UINTN *VariableSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN BufferSize;\r
+ VOID *Buffer;\r
+\r
+ Buffer = NULL;\r
+\r
+ //\r
+ // Pass in a zero size buffer to find the required buffer size.\r
+ //\r
+ BufferSize = 0;\r
+ Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ //\r
+ // Allocate the buffer to return\r
+ //\r
+ Buffer = AllocateZeroPool (BufferSize);\r
+ if (Buffer == NULL) {\r
+ return NULL;\r
+ }\r
+ //\r
+ // Read variable into the allocated buffer.\r
+ //\r
+ Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);\r
+ if (EFI_ERROR (Status)) {\r
+ BufferSize = 0;\r
+ }\r
+ }\r
+\r
+ *VariableSize = BufferSize;\r
+ return Buffer;\r
+}\r
+\r
+\r
+/**\r
+ Create the iSCSI driver data.\r
+\r
+ @param[in] Image The handle of the driver image.\r
+ @param[in] Controller The handle of the controller.\r
+\r
+ @return The iSCSI driver data created.\r
+ @retval NULL Other errors as indicated.\r
+\r
+**/\r
+ISCSI_DRIVER_DATA *\r
+IScsiCreateDriverData (\r
+ IN EFI_HANDLE Image,\r
+ IN EFI_HANDLE Controller\r
+ )\r
+{\r
+ ISCSI_DRIVER_DATA *Private;\r
+ EFI_STATUS Status;\r
+\r
+ Private = AllocateZeroPool (sizeof (ISCSI_DRIVER_DATA));\r
+ if (Private == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ Private->Signature = ISCSI_DRIVER_DATA_SIGNATURE;\r
+ Private->Image = Image;\r
+ Private->Controller = Controller;\r
+ Private->Session = NULL;\r
+\r
+ //\r
+ // Create an event to be signaled when the BS to RT transition is triggerd so\r
+ // as to abort the iSCSI session.\r
+ //\r
+ Status = gBS->CreateEventEx (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ IScsiOnExitBootService,\r
+ Private,\r
+ &gEfiEventExitBootServicesGuid,\r
+ &Private->ExitBootServiceEvent\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (Private);\r
+ return NULL;\r
+ }\r
+\r
+ Private->ExtScsiPassThruHandle = NULL;\r
+ CopyMem(&Private->IScsiExtScsiPassThru, &gIScsiExtScsiPassThruProtocolTemplate, sizeof(EFI_EXT_SCSI_PASS_THRU_PROTOCOL));\r
+\r
+ //\r
+ // 0 is designated to the TargetId, so use another value for the AdapterId.\r
+ //\r
+ Private->ExtScsiPassThruMode.AdapterId = 2;\r
+ Private->ExtScsiPassThruMode.Attributes = EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;\r
+ Private->ExtScsiPassThruMode.IoAlign = 4;\r
+ Private->IScsiExtScsiPassThru.Mode = &Private->ExtScsiPassThruMode;\r
+\r
+ return Private;\r
+}\r
+\r
+\r
+/**\r
+ Clean the iSCSI driver data.\r
+\r
+ @param[in] Private The iSCSI driver data.\r
+\r
+**/\r
+VOID\r
+IScsiCleanDriverData (\r
+ IN ISCSI_DRIVER_DATA *Private\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ if (Private->DevicePath != NULL) {\r
+ gBS->UninstallProtocolInterface (\r
+ Private->ExtScsiPassThruHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ Private->DevicePath\r
+ );\r
+\r
+ FreePool (Private->DevicePath);\r
+ }\r
+\r
+ if (Private->ExtScsiPassThruHandle != NULL) {\r
+ Status = gBS->UninstallProtocolInterface (\r
+ Private->ExtScsiPassThruHandle,\r
+ &gEfiExtScsiPassThruProtocolGuid,\r
+ &Private->IScsiExtScsiPassThru\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ mPrivate->OneSessionEstablished = FALSE;\r
+ }\r
+ }\r
+\r
+ gBS->CloseEvent (Private->ExitBootServiceEvent);\r
+\r
+ FreePool (Private);\r
+}\r
+\r
+\r
+/**\r
+ Get the various configuration data.\r
+\r
+ @param[in] Private The iSCSI driver data.\r
+\r
+ @retval EFI_SUCCESS The configuration data is retrieved.\r
+ @retval EFI_NOT_FOUND This iSCSI driver is not configured yet.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiGetConfigData (\r
+ IN ISCSI_DRIVER_DATA *Private\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CHAR16 MacString[ISCSI_MAX_MAC_STRING_LEN];\r
+ UINTN Index;\r
+ ISCSI_NIC_INFO *NicInfo;\r
+ ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;\r
+ ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptTmp;\r
+ UINT8 *AttemptConfigOrder;\r
+ UINTN AttemptConfigOrderSize;\r
+ CHAR16 IScsiMode[64];\r
+ CHAR16 IpMode[64];\r
+\r
+ //\r
+ // There should be at least one attempt configured.\r
+ //\r
+ AttemptConfigOrder = IScsiGetVariableAndSize (\r
+ L"AttemptOrder",\r
+ &mVendorGuid,\r
+ &AttemptConfigOrderSize\r
+ );\r
+ if (AttemptConfigOrder == NULL || AttemptConfigOrderSize == 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // Get the iSCSI Initiator Name.\r
+ //\r
+ mPrivate->InitiatorNameLength = ISCSI_NAME_MAX_SIZE;\r
+ Status = gIScsiInitiatorName.Get (\r
+ &gIScsiInitiatorName,\r
+ &mPrivate->InitiatorNameLength,\r
+ mPrivate->InitiatorName\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Get the normal configuration.\r
+ //\r
+ for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {\r
+\r
+ //\r
+ // Check whether the attempt exists in AttemptConfig.\r
+ //\r
+ AttemptTmp = IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder[Index]); \r
+ if (AttemptTmp != NULL && AttemptTmp->SessionConfigData.Enabled == ISCSI_DISABLED) {\r
+ continue;\r
+ } else if (AttemptTmp != NULL && AttemptTmp->SessionConfigData.Enabled != ISCSI_DISABLED) {\r
+ //\r
+ // Check the autoconfig path to see whether it should be retried.\r
+ //\r
+ if (AttemptTmp->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG &&\r
+ AttemptTmp->AutoConfigureMode != IP_MODE_AUTOCONFIG_SUCCESS) {\r
+ if (mPrivate->Ipv6Flag &&\r
+ AttemptTmp->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6) {\r
+ //\r
+ // Autoconfigure for IP6 already attempted but failed. Do not try again.\r
+ //\r
+ continue;\r
+ } else if (!mPrivate->Ipv6Flag &&\r
+ AttemptTmp->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4) {\r
+ //\r
+ // Autoconfigure for IP4 already attempted but failed. Do not try again.\r
+ //\r
+ continue;\r
+ } else {\r
+ //\r
+ // Try another approach for this autoconfigure path.\r
+ //\r
+ AttemptTmp->AutoConfigureMode =\r
+ (UINT8) (mPrivate->Ipv6Flag ? IP_MODE_AUTOCONFIG_IP6 : IP_MODE_AUTOCONFIG_IP4);\r
+ AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp = TRUE;\r
+ AttemptTmp->SessionConfigData.TargetInfoFromDhcp = TRUE;\r
+ AttemptTmp->DhcpSuccess = FALSE;\r
+\r
+ //\r
+ // Get some information from the dhcp server.\r
+ //\r
+ if (!mPrivate->Ipv6Flag) {\r
+ Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptTmp);\r
+ if (!EFI_ERROR (Status)) {\r
+ AttemptTmp->DhcpSuccess = TRUE;\r
+ }\r
+ } else {\r
+ Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptTmp);\r
+ if (!EFI_ERROR (Status)) {\r
+ AttemptTmp->DhcpSuccess = TRUE;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Refresh the state of this attempt to NVR.\r
+ //\r
+ AsciiStrToUnicodeStr (AttemptTmp->MacString, MacString);\r
+ UnicodeSPrint (\r
+ mPrivate->PortString,\r
+ (UINTN) ISCSI_NAME_IFR_MAX_SIZE,\r
+ L"%s%d",\r
+ MacString,\r
+ (UINTN) AttemptTmp->AttemptConfigIndex\r
+ );\r
+\r
+ gRT->SetVariable (\r
+ mPrivate->PortString,\r
+ &gEfiIScsiInitiatorNameProtocolGuid,\r
+ ISCSI_CONFIG_VAR_ATTR,\r
+ sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),\r
+ AttemptTmp\r
+ );\r
+\r
+ continue;\r
+ }\r
+ } else if (AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp && !AttemptTmp->ValidPath) {\r
+ //\r
+ // Get DHCP information for already added, but failed, attempt.\r
+ //\r
+ AttemptTmp->DhcpSuccess = FALSE;\r
+ if (!mPrivate->Ipv6Flag && (AttemptTmp->SessionConfigData.IpMode == IP_MODE_IP4)) {\r
+ Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptTmp);\r
+ if (!EFI_ERROR (Status)) {\r
+ AttemptTmp->DhcpSuccess = TRUE;\r
+ }\r
+ } else if (mPrivate->Ipv6Flag && (AttemptTmp->SessionConfigData.IpMode == IP_MODE_IP6)) {\r
+ Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptTmp);\r
+ if (!EFI_ERROR (Status)) {\r
+ AttemptTmp->DhcpSuccess = TRUE;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Refresh the state of this attempt to NVR.\r
+ //\r
+ AsciiStrToUnicodeStr (AttemptTmp->MacString, MacString);\r
+ UnicodeSPrint (\r
+ mPrivate->PortString,\r
+ (UINTN) ISCSI_NAME_IFR_MAX_SIZE,\r
+ L"%s%d",\r
+ MacString,\r
+ (UINTN) AttemptTmp->AttemptConfigIndex\r
+ );\r
+\r
+ gRT->SetVariable (\r
+ mPrivate->PortString,\r
+ &gEfiIScsiInitiatorNameProtocolGuid,\r
+ ISCSI_CONFIG_VAR_ATTR,\r
+ sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),\r
+ AttemptTmp\r
+ );\r
+\r
+ continue;\r
+\r
+ } else {\r
+ continue;\r
+ }\r
+ }\r
+\r
+ //\r
+ // This attempt does not exist in AttemptConfig. Try to add a new one.\r
+ //\r
+\r
+ NicInfo = IScsiGetNicInfoByIndex (mPrivate->CurrentNic);\r
+ ASSERT (NicInfo != NULL);\r
+ IScsiMacAddrToStr (&NicInfo->PermanentAddress, NicInfo->HwAddressSize, NicInfo->VlanId, MacString);\r
+ UnicodeSPrint (\r
+ mPrivate->PortString,\r
+ (UINTN) 128,\r
+ L"%s%d",\r
+ MacString,\r
+ (UINTN) AttemptConfigOrder[Index]\r
+ );\r
+\r
+ AttemptConfigData = (ISCSI_ATTEMPT_CONFIG_NVDATA *) GetVariable (\r
+ mPrivate->PortString,\r
+ &gEfiIScsiInitiatorNameProtocolGuid\r
+ );\r
+\r
+ if (AttemptConfigData == NULL) {\r
+ continue;\r
+ }\r
+\r
+ ASSERT (AttemptConfigOrder[Index] == AttemptConfigData->AttemptConfigIndex);\r
+\r
+ AttemptConfigData->NicIndex = NicInfo->NicIndex;\r
+ AttemptConfigData->DhcpSuccess = FALSE;\r
+ AttemptConfigData->ValidiBFTPath = (BOOLEAN) (mPrivate->EnableMpio ? TRUE : FALSE);\r
+ AttemptConfigData->ValidPath = FALSE;\r
+\r
+ if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) {\r
+ AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp = TRUE;\r
+ AttemptConfigData->SessionConfigData.TargetInfoFromDhcp = TRUE;\r
+\r
+ AttemptConfigData->AutoConfigureMode =\r
+ (UINT8) (mPrivate->Ipv6Flag ? IP_MODE_AUTOCONFIG_IP6 : IP_MODE_AUTOCONFIG_IP4);\r
+ }\r
+ \r
+ //\r
+ // Get some information from dhcp server.\r
+ //\r
+ if (AttemptConfigData->SessionConfigData.Enabled != ISCSI_DISABLED &&\r
+ AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp) {\r
+\r
+ if (!mPrivate->Ipv6Flag &&\r
+ (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4 ||\r
+ AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4)) {\r
+ Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptConfigData);\r
+ if (!EFI_ERROR (Status)) {\r
+ AttemptConfigData->DhcpSuccess = TRUE;\r
+ }\r
+ } else if (mPrivate->Ipv6Flag &&\r
+ (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6 ||\r
+ AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6)) {\r
+ Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptConfigData);\r
+ if (!EFI_ERROR (Status)) {\r
+ AttemptConfigData->DhcpSuccess = TRUE;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Refresh the state of this attempt to NVR.\r
+ //\r
+ AsciiStrToUnicodeStr (AttemptConfigData->MacString, MacString);\r
+ UnicodeSPrint (\r
+ mPrivate->PortString,\r
+ (UINTN) ISCSI_NAME_IFR_MAX_SIZE,\r
+ L"%s%d",\r
+ MacString,\r
+ (UINTN) AttemptConfigData->AttemptConfigIndex\r
+ );\r
+\r
+ gRT->SetVariable (\r
+ mPrivate->PortString,\r
+ &gEfiIScsiInitiatorNameProtocolGuid,\r
+ ISCSI_CONFIG_VAR_ATTR,\r
+ sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),\r
+ AttemptConfigData\r
+ );\r
+ }\r
+\r
+ //\r
+ // Update Attempt Help Info.\r
+ //\r
+\r
+ if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_DISABLED) {\r
+ UnicodeSPrint (IScsiMode, 64, L"Disabled");\r
+ } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) {\r
+ UnicodeSPrint (IScsiMode, 64, L"Enabled");\r
+ } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {\r
+ UnicodeSPrint (IScsiMode, 64, L"Enabled for MPIO");\r
+ }\r
+\r
+ if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4) {\r
+ UnicodeSPrint (IpMode, 64, L"IP4");\r
+ } else if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6) {\r
+ UnicodeSPrint (IpMode, 64, L"IP6");\r
+ } else if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) {\r
+ UnicodeSPrint (IpMode, 64, L"Autoconfigure");\r
+ }\r
+\r
+ UnicodeSPrint (\r
+ mPrivate->PortString,\r
+ (UINTN) ISCSI_NAME_IFR_MAX_SIZE,\r
+ L"MAC: %s, PFA: Bus %d | Dev %d | Func %d, iSCSI mode: %s, IP version: %s",\r
+ MacString,\r
+ NicInfo->BusNumber,\r
+ NicInfo->DeviceNumber,\r
+ NicInfo->FunctionNumber,\r
+ IScsiMode,\r
+ IpMode\r
+ );\r
+\r
+ AttemptConfigData->AttemptTitleHelpToken = HiiSetString (\r
+ mCallbackInfo->RegisteredHandle,\r
+ 0,\r
+ mPrivate->PortString,\r
+ NULL\r
+ );\r
+ ASSERT (AttemptConfigData->AttemptTitleHelpToken != 0);\r
+\r
+ //\r
+ // Record the attempt in global link list.\r
+ //\r
+ InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);\r
+ mPrivate->AttemptCount++;\r
+\r
+ if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {\r
+ mPrivate->MpioCount++;\r
+ mPrivate->EnableMpio = TRUE;\r
+\r
+ if (AttemptConfigData->AuthenticationType == ISCSI_AUTH_TYPE_KRB) {\r
+ mPrivate->Krb5MpioCount++;\r
+ }\r
+ } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) {\r
+ mPrivate->SinglePathCount++;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Reorder the AttemptConfig by the configured order.\r
+ //\r
+ for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {\r
+ AttemptConfigData = IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder[Index]);\r
+ if (AttemptConfigData == NULL) {\r
+ continue;\r
+ }\r
+\r
+ RemoveEntryList (&AttemptConfigData->Link);\r
+ InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);\r
+ }\r
+\r
+ //\r
+ // Update the Main Form.\r
+ //\r
+ IScsiConfigUpdateAttempt ();\r
+\r
+ FreePool (AttemptConfigOrder);\r
+\r
+ //\r
+ // There should be at least one attempt configuration.\r
+ //\r
+ if (!mPrivate->EnableMpio) {\r
+ if (mPrivate->SinglePathCount == 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ mPrivate->ValidSinglePathCount = mPrivate->SinglePathCount;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Get the device path of the iSCSI tcp connection and update it.\r
+\r
+ @param Session The iSCSI session.\r
+\r
+ @return The updated device path.\r
+ @retval NULL Other errors as indicated.\r
+\r
+**/\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+IScsiGetTcpConnDevicePath (\r
+ IN ISCSI_SESSION *Session\r
+ )\r
+{\r
+ ISCSI_CONNECTION *Conn;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ EFI_STATUS Status;\r
+ EFI_DEV_PATH *DPathNode;\r
+\r
+ if (Session->State != SESSION_STATE_LOGGED_IN) {\r
+ return NULL;\r
+ }\r
+\r
+ Conn = NET_LIST_USER_STRUCT_S (\r
+ Session->Conns.ForwardLink,\r
+ ISCSI_CONNECTION,\r
+ Link,\r
+ ISCSI_CONNECTION_SIGNATURE\r
+ );\r
+\r
+ Status = gBS->HandleProtocol (\r
+ Conn->TcpIo.Handle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &DevicePath\r
+ ); \r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+ //\r
+ // Duplicate it.\r
+ //\r
+ DevicePath = DuplicateDevicePath (DevicePath);\r
+ if (DevicePath == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ DPathNode = (EFI_DEV_PATH *) DevicePath;\r
+\r
+ while (!IsDevicePathEnd (&DPathNode->DevPath)) {\r
+ if (DevicePathType (&DPathNode->DevPath) == MESSAGING_DEVICE_PATH) {\r
+ if (!Conn->Ipv6Flag && DevicePathSubType (&DPathNode->DevPath) == MSG_IPv4_DP) {\r
+ DPathNode->Ipv4.LocalPort = 0;\r
+ DPathNode->Ipv4.StaticIpAddress = (BOOLEAN) !Session->ConfigData->SessionConfigData.InitiatorInfoFromDhcp;\r
+ break;\r
+ } else if (Conn->Ipv6Flag && DevicePathSubType (&DPathNode->DevPath) == MSG_IPv6_DP) {\r
+ DPathNode->Ipv6.LocalPort = 0;\r
+ DPathNode->Ipv6.StaticIpAddress = (BOOLEAN) !Session->ConfigData->SessionConfigData.InitiatorInfoFromDhcp;\r
+ break;\r
+ }\r
+ }\r
+\r
+ DPathNode = (EFI_DEV_PATH *) NextDevicePathNode (&DPathNode->DevPath);\r
+ }\r
+\r
+ return DevicePath;\r
+}\r
+\r
+\r
+/**\r
+ Abort the session when the transition from BS to RT is initiated.\r
+\r
+ @param[in] Event The event signaled.\r
+ @param[in] Context The iSCSI driver data.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+IScsiOnExitBootService (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ ISCSI_DRIVER_DATA *Private;\r
+\r
+ Private = (ISCSI_DRIVER_DATA *) Context;\r
+ gBS->CloseEvent (Private->ExitBootServiceEvent);\r
+\r
+ if (Private->Session != NULL) {\r
+ IScsiSessionAbort (Private->Session);\r
+ }\r
+}\r
--- /dev/null
+/** @file\r
+ Miscellaneous definitions for iSCSI driver.\r
+\r
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _ISCSI_MISC_H_\r
+#define _ISCSI_MISC_H_\r
+\r
+typedef struct _ISCSI_DRIVER_DATA ISCSI_DRIVER_DATA;\r
+\r
+#pragma pack(1)\r
+typedef struct _ISCSI_SESSION_CONFIG_NVDATA {\r
+ UINT16 TargetPort;\r
+ UINT8 Enabled;\r
+ UINT8 IpMode;\r
+\r
+ EFI_IPv4_ADDRESS LocalIp;\r
+ EFI_IPv4_ADDRESS SubnetMask;\r
+ EFI_IPv4_ADDRESS Gateway;\r
+\r
+ BOOLEAN InitiatorInfoFromDhcp;\r
+ BOOLEAN TargetInfoFromDhcp;\r
+ CHAR8 TargetName[ISCSI_NAME_MAX_SIZE];\r
+ EFI_IP_ADDRESS TargetIp;\r
+ UINT8 BootLun[8];\r
+\r
+ UINT16 ConnectTimeout; ///< timout value in milliseconds\r
+ UINT8 ConnectRetryCount;\r
+ UINT8 IsId[6];\r
+} ISCSI_SESSION_CONFIG_NVDATA;\r
+#pragma pack()\r
+\r
+/**\r
+ Calculate the prefix length of the IPv4 subnet mask.\r
+\r
+ @param[in] SubnetMask The IPv4 subnet mask.\r
+\r
+ @return The prefix length of the subnet mask.\r
+ @retval 0 Other errors as indicated.\r
+\r
+**/\r
+UINT8\r
+IScsiGetSubnetMaskPrefixLength (\r
+ IN EFI_IPv4_ADDRESS *SubnetMask\r
+ );\r
+\r
+/**\r
+ Convert the hexadecimal encoded LUN string into the 64-bit LUN. \r
+\r
+ @param[in] Str The hexadecimal encoded LUN string.\r
+ @param[out] Lun Storage to return the 64-bit LUN.\r
+\r
+ @retval EFI_SUCCESS The 64-bit LUN is stored in Lun.\r
+ @retval EFI_INVALID_PARAMETER The string is malformatted.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiAsciiStrToLun (\r
+ IN CHAR8 *Str,\r
+ OUT UINT8 *Lun\r
+ );\r
+\r
+/**\r
+ Convert the 64-bit LUN into the hexadecimal encoded LUN string.\r
+\r
+ @param[in] Lun The 64-bit LUN.\r
+ @param[out] String The storage to return the hexadecimal encoded LUN string.\r
+\r
+**/\r
+VOID\r
+IScsiLunToUnicodeStr (\r
+ IN UINT8 *Lun,\r
+ OUT CHAR16 *String\r
+ );\r
+\r
+/**\r
+ Convert the mac address into a hexadecimal encoded "-" seperated string.\r
+\r
+ @param[in] Mac The mac address.\r
+ @param[in] Len Length in bytes of the mac address.\r
+ @param[in] VlanId VLAN ID of the network device.\r
+ @param[out] Str The storage to return the mac string.\r
+\r
+**/\r
+VOID\r
+IScsiMacAddrToStr (\r
+ IN EFI_MAC_ADDRESS *Mac,\r
+ IN UINT32 Len,\r
+ IN UINT16 VlanId,\r
+ OUT CHAR16 *Str\r
+ );\r
+\r
+/**\r
+ Convert the formatted IP address into the binary IP address.\r
+\r
+ @param[in] Str The UNICODE string.\r
+ @param[in] IpMode Indicates whether the IP address is v4 or v6.\r
+ @param[out] Ip The storage to return the ASCII string.\r
+\r
+ @retval EFI_SUCCESS The binary IP address is returned in Ip.\r
+ @retval EFI_INVALID_PARAMETER The IP string is malformatted or IpMode is\r
+ invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiAsciiStrToIp (\r
+ IN CHAR8 *Str,\r
+ IN UINT8 IpMode,\r
+ OUT EFI_IP_ADDRESS *Ip\r
+ );\r
+\r
+/**\r
+ Convert the binary encoded buffer into a hexadecimal encoded string.\r
+\r
+ @param[in] BinBuffer The buffer containing the binary data.\r
+ @param[in] BinLength Length of the binary buffer.\r
+ @param[in, out] HexStr Pointer to the string.\r
+ @param[in, out] HexLength The length of the string.\r
+\r
+ @retval EFI_SUCCESS The binary data is converted to the hexadecimal string \r
+ and the length of the string is updated.\r
+ @retval EFI_BUFFER_TOO_SMALL The string is too small.\r
+ @retval EFI_INVALID_PARAMETER The IP string is malformatted.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiBinToHex (\r
+ IN UINT8 *BinBuffer,\r
+ IN UINT32 BinLength,\r
+ IN OUT CHAR8 *HexStr,\r
+ IN OUT UINT32 *HexLength\r
+ );\r
+\r
+/**\r
+ Convert the hexadecimal string into a binary encoded buffer.\r
+\r
+ @param[in, out] BinBuffer The binary buffer.\r
+ @param[in, out] BinLength Length of the binary buffer.\r
+ @param[in] HexStr The hexadecimal string.\r
+\r
+ @retval EFI_SUCCESS The hexadecimal string is converted into a binary\r
+ encoded buffer.\r
+ @retval EFI_BUFFER_TOO_SMALL The binary buffer is too small to hold the converted data.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiHexToBin (\r
+ IN OUT UINT8 *BinBuffer,\r
+ IN OUT UINT32 *BinLength,\r
+ IN CHAR8 *HexStr\r
+ );\r
+\r
+\r
+/**\r
+ Convert the decimal-constant string or hex-constant string into a numerical value.\r
+\r
+ @param[in] Str String in decimal or hex.\r
+\r
+ @return The numerical value.\r
+\r
+**/\r
+UINTN\r
+IScsiNetNtoi (\r
+ IN CHAR8 *Str\r
+ );\r
+\r
+/**\r
+ Generate random numbers.\r
+\r
+ @param[in, out] Rand The buffer to contain random numbers.\r
+ @param[in] RandLength The length of the Rand buffer.\r
+\r
+**/\r
+VOID\r
+IScsiGenRandom (\r
+ IN OUT UINT8 *Rand,\r
+ IN UINTN RandLength\r
+ );\r
+\r
+/**\r
+ Record the NIC information in a global structure.\r
+\r
+ @param[in] Controller The handle of the controller.\r
+\r
+ @retval EFI_SUCCESS The operation is completed.\r
+ @retval EFI_OUT_OF_RESOURCES Do not have sufficient resource to finish this\r
+ operation.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiAddNic (\r
+ IN EFI_HANDLE Controller\r
+ );\r
+\r
+/**\r
+ Delete the recorded NIC information from a global structure. Also delete corresponding\r
+ attempts.\r
+\r
+ @param[in] Controller The handle of the controller.\r
+\r
+ @retval EFI_SUCCESS The operation completed.\r
+ @retval EFI_NOT_FOUND The NIC information to be deleted is not recorded.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiRemoveNic (\r
+ IN EFI_HANDLE Controller\r
+ );\r
+\r
+/**\r
+ Get the recorded NIC information from a global structure by the Index.\r
+\r
+ @param[in] NicIndex The index indicates the position of NIC info.\r
+\r
+ @return Pointer to the NIC info or NULL if not found.\r
+\r
+**/\r
+ISCSI_NIC_INFO *\r
+IScsiGetNicInfoByIndex (\r
+ IN UINT8 NicIndex\r
+ );\r
+\r
+\r
+/**\r
+ Get the NIC's PCI location and return it accroding to the composited\r
+ format defined in iSCSI Boot Firmware Table.\r
+\r
+ @param[in] Controller The handle of the controller.\r
+ @param[out] Bus The bus number.\r
+ @param[out] Device The device number.\r
+ @param[out] Function The function number.\r
+\r
+ @return The composited representation of the NIC PCI location.\r
+\r
+**/\r
+UINT16\r
+IScsiGetNICPciLocation (\r
+ IN EFI_HANDLE Controller,\r
+ OUT UINTN *Bus,\r
+ OUT UINTN *Device,\r
+ OUT UINTN *Function\r
+ );\r
+\r
+/**\r
+ Read the EFI variable (VendorGuid/Name) and return a dynamically allocated\r
+ buffer, and the size of the buffer. If failure, return NULL.\r
+\r
+ @param[in] Name String part of EFI variable name.\r
+ @param[in] VendorGuid GUID part of EFI variable name.\r
+ @param[out] VariableSize Returns the size of the EFI variable that was read.\r
+\r
+ @return Dynamically allocated memory that contains a copy of the EFI variable.\r
+ @return Caller is responsible freeing the buffer.\r
+ @retval NULL Variable was not read.\r
+\r
+**/\r
+VOID *\r
+IScsiGetVariableAndSize (\r
+ IN CHAR16 *Name,\r
+ IN EFI_GUID *VendorGuid,\r
+ OUT UINTN *VariableSize\r
+ );\r
+\r
+/**\r
+ Create the iSCSI driver data.\r
+\r
+ @param[in] Image The handle of the driver image.\r
+ @param[in] Controller The handle of the controller.\r
+\r
+ @return The iSCSI driver data created.\r
+ @retval NULL Other errors as indicated.\r
+\r
+**/\r
+ISCSI_DRIVER_DATA *\r
+IScsiCreateDriverData (\r
+ IN EFI_HANDLE Image,\r
+ IN EFI_HANDLE Controller\r
+ );\r
+\r
+/**\r
+ Clean the iSCSI driver data.\r
+\r
+ @param[in] Private The iSCSI driver data.\r
+\r
+**/\r
+VOID\r
+IScsiCleanDriverData (\r
+ IN ISCSI_DRIVER_DATA *Private\r
+ );\r
+\r
+/**\r
+ Get the various configuration data of this iSCSI instance.\r
+\r
+ @param[in] Private The iSCSI driver data.\r
+\r
+ @retval EFI_SUCCESS Obtained the configuration of this instance.\r
+ @retval EFI_ABORTED The operation was aborted.\r
+ @retval Others Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiGetConfigData (\r
+ IN ISCSI_DRIVER_DATA *Private\r
+ );\r
+\r
+/**\r
+ Get the device path of the iSCSI tcp connection and update it.\r
+\r
+ @param[in] Session The iSCSI session data.\r
+\r
+ @return The updated device path.\r
+ @retval NULL Other errors as indicated.\r
+\r
+**/\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+IScsiGetTcpConnDevicePath (\r
+ IN ISCSI_SESSION *Session\r
+ );\r
+\r
+/**\r
+ Abort the session when the transition from BS to RT is initiated.\r
+\r
+ @param[in] Event The event signaled.\r
+ @param[in] Context The iSCSI driver data.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+IScsiOnExitBootService (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+ The implementation of iSCSI protocol based on RFC3720.\r
+\r
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "IScsiImpl.h"\r
+\r
+UINT32 mDataSegPad = 0;\r
+\r
+/**\r
+ Attach the iSCSI connection to the iSCSI session. \r
+\r
+ @param[in, out] Session The iSCSI session.\r
+ @param[in, out] Conn The iSCSI connection.\r
+\r
+**/\r
+VOID\r
+IScsiAttatchConnection (\r
+ IN OUT ISCSI_SESSION *Session,\r
+ IN OUT ISCSI_CONNECTION *Conn\r
+ )\r
+{\r
+ InsertTailList (&Session->Conns, &Conn->Link);\r
+ Conn->Session = Session;\r
+ Session->NumConns++;\r
+}\r
+\r
+/**\r
+ Detach the iSCSI connection from the session it belongs to. \r
+\r
+ @param[in, out] Conn The iSCSI connection.\r
+\r
+**/\r
+VOID\r
+IScsiDetatchConnection (\r
+ IN OUT ISCSI_CONNECTION *Conn\r
+ )\r
+{\r
+ RemoveEntryList (&Conn->Link);\r
+ Conn->Session->NumConns--;\r
+ Conn->Session = NULL;\r
+}\r
+\r
+\r
+/**\r
+ Check the sequence number according to RFC3720. \r
+\r
+ @param[in, out] ExpSN The currently expected sequence number.\r
+ @param[in] NewSN The sequence number to check.\r
+\r
+ @retval EFI_SUCCESS The check passed and the ExpSN is increased.\r
+ @retval EFI_NOT_READY Response was sent due to a retransmission request.\r
+ @retval EFI_PROTOCOL_ERROR Some kind of iSCSI protocol error occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiCheckSN (\r
+ IN OUT UINT32 *ExpSN,\r
+ IN UINT32 NewSN\r
+ )\r
+{\r
+ if (!ISCSI_SEQ_EQ (NewSN, *ExpSN)) {\r
+ if (ISCSI_SEQ_LT (NewSN, *ExpSN)) {\r
+ //\r
+ // Duplicate\r
+ //\r
+ return EFI_NOT_READY;\r
+ } else {\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+ } else {\r
+ //\r
+ // Advance the ExpSN\r
+ //\r
+ (*ExpSN)++;\r
+ return EFI_SUCCESS;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Update the sequence numbers for the iSCSI command.\r
+\r
+ @param[in, out] Session The iSCSI session.\r
+ @param[in] MaxCmdSN Maximum CmdSN from the target.\r
+ @param[in] ExpCmdSN Next expected CmdSN from the target.\r
+\r
+**/\r
+VOID\r
+IScsiUpdateCmdSN (\r
+ IN OUT ISCSI_SESSION *Session,\r
+ IN UINT32 MaxCmdSN,\r
+ IN UINT32 ExpCmdSN\r
+ )\r
+{\r
+ if (ISCSI_SEQ_LT (MaxCmdSN, ExpCmdSN - 1)) {\r
+ return ;\r
+ }\r
+\r
+ if (ISCSI_SEQ_GT (MaxCmdSN, Session->MaxCmdSN)) {\r
+ Session->MaxCmdSN = MaxCmdSN;\r
+ }\r
+\r
+ if (ISCSI_SEQ_GT (ExpCmdSN, Session->ExpCmdSN)) {\r
+ Session->ExpCmdSN = ExpCmdSN;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ This function does the iSCSI connection login.\r
+\r
+ @param[in, out] Conn The iSCSI connection to login.\r
+ @param Timeout The timeout value in millisecond.\r
+\r
+ @retval EFI_SUCCESS The iSCSI connection is logged into the iSCSI target.\r
+ @retval EFI_TIMEOUT Timeout occurred during the login procedure.\r
+ @retval Others Other errors as indicated. \r
+\r
+**/\r
+EFI_STATUS\r
+IScsiConnLogin (\r
+ IN OUT ISCSI_CONNECTION *Conn,\r
+ IN UINT16 Timeout\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Start the timer, and wait Timeout seconds to establish the TCP connection.\r
+ //\r
+ Status = gBS->SetTimer (Conn->TimeoutEvent, TimerRelative, Timeout * TICKS_PER_MS);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Try to establish the tcp connection.\r
+ //\r
+ Status = TcpIoConnect (&Conn->TcpIo, Conn->TimeoutEvent);\r
+ gBS->SetTimer (Conn->TimeoutEvent, TimerCancel, 0);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Conn->State = CONN_STATE_IN_LOGIN;\r
+\r
+ //\r
+ // Connection is established, start the iSCSI Login.\r
+ //\r
+ do {\r
+ Status = IScsiSendLoginReq (Conn);\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+\r
+ Status = IScsiReceiveLoginRsp (Conn);\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ } while (Conn->CurrentStage != ISCSI_FULL_FEATURE_PHASE);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Reset the iSCSI connection.\r
+\r
+ @param[in, out] Conn The iSCSI connection to reset.\r
+\r
+**/\r
+VOID\r
+IScsiConnReset (\r
+ IN OUT ISCSI_CONNECTION *Conn\r
+ )\r
+{\r
+ TcpIoReset (&Conn->TcpIo);\r
+}\r
+\r
+\r
+/**\r
+ Create a TCP connection for the iSCSI session.\r
+\r
+ @param[in] Session Points to the iSCSI session.\r
+\r
+ @return The newly created iSCSI connection.\r
+\r
+**/\r
+ISCSI_CONNECTION *\r
+IScsiCreateConnection (\r
+ IN ISCSI_SESSION *Session\r
+ )\r
+{\r
+ ISCSI_DRIVER_DATA *Private;\r
+ ISCSI_SESSION_CONFIG_NVDATA *NvData;\r
+ ISCSI_CONNECTION *Conn;\r
+ TCP_IO_CONFIG_DATA TcpIoConfig;\r
+ TCP4_IO_CONFIG_DATA *Tcp4IoConfig;\r
+ TCP6_IO_CONFIG_DATA *Tcp6IoConfig;\r
+ EFI_STATUS Status;\r
+\r
+ Private = Session->Private;\r
+ NvData = &Session->ConfigData->SessionConfigData;\r
+\r
+ Conn = AllocateZeroPool (sizeof (ISCSI_CONNECTION));\r
+ if (Conn == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ Conn->Signature = ISCSI_CONNECTION_SIGNATURE;\r
+ Conn->State = CONN_STATE_FREE;\r
+ Conn->CurrentStage = ISCSI_SECURITY_NEGOTIATION;\r
+ Conn->NextStage = ISCSI_LOGIN_OPERATIONAL_NEGOTIATION;\r
+ Conn->AuthStep = ISCSI_AUTH_INITIAL;\r
+ Conn->ExpStatSN = 0;\r
+ Conn->PartialReqSent = FALSE;\r
+ Conn->PartialRspRcvd = FALSE;\r
+ Conn->ParamNegotiated = FALSE;\r
+ Conn->Cid = Session->NextCid++;\r
+ Conn->Ipv6Flag = mPrivate->Ipv6Flag;\r
+\r
+ Status = gBS->CreateEvent (\r
+ EVT_TIMER,\r
+ TPL_CALLBACK,\r
+ NULL,\r
+ NULL,\r
+ &Conn->TimeoutEvent\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (Conn);\r
+ return NULL;\r
+ }\r
+\r
+ NetbufQueInit (&Conn->RspQue);\r
+\r
+ //\r
+ // Set the default connection-only parameters.\r
+ //\r
+ Conn->MaxRecvDataSegmentLength = DEFAULT_MAX_RECV_DATA_SEG_LEN;\r
+ Conn->HeaderDigest = IScsiDigestNone;\r
+ Conn->DataDigest = IScsiDigestNone;\r
+\r
+ if (!Conn->Ipv6Flag) {\r
+ Tcp4IoConfig = &TcpIoConfig.Tcp4IoConfigData;\r
+ \r
+ CopyMem (&Tcp4IoConfig->LocalIp, &NvData->LocalIp, sizeof (EFI_IPv4_ADDRESS));\r
+ CopyMem (&Tcp4IoConfig->SubnetMask, &NvData->SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
+ CopyMem (&Tcp4IoConfig->Gateway, &NvData->Gateway, sizeof (EFI_IPv4_ADDRESS));\r
+ CopyMem (&Tcp4IoConfig->RemoteIp, &NvData->TargetIp, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+ Tcp4IoConfig->RemotePort = NvData->TargetPort;\r
+ Tcp4IoConfig->ActiveFlag = TRUE;\r
+\r
+ } else {\r
+ Tcp6IoConfig = &TcpIoConfig.Tcp6IoConfigData;\r
+ \r
+ CopyMem (&Tcp6IoConfig->RemoteIp, &NvData->TargetIp, sizeof (EFI_IPv6_ADDRESS));\r
+ Tcp6IoConfig->RemotePort = NvData->TargetPort;\r
+ Tcp6IoConfig->ActiveFlag = TRUE;\r
+ }\r
+\r
+ //\r
+ // Create the TCP IO for this connection.\r
+ //\r
+ Status = TcpIoCreateSocket (\r
+ Private->Image,\r
+ Private->Controller,\r
+ (UINT8) (!Conn->Ipv6Flag ? TCP_VERSION_4: TCP_VERSION_6),\r
+ &TcpIoConfig,\r
+ &Conn->TcpIo\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->CloseEvent (Conn->TimeoutEvent);\r
+ FreePool (Conn);\r
+ Conn = NULL;\r
+ }\r
+\r
+ return Conn;\r
+}\r
+\r
+\r
+/**\r
+ Destroy an iSCSI connection.\r
+\r
+ @param[in] Conn The connection to destroy.\r
+\r
+**/\r
+VOID\r
+IScsiDestroyConnection (\r
+ IN ISCSI_CONNECTION *Conn\r
+ )\r
+{\r
+ TcpIoDestroySocket (&Conn->TcpIo);\r
+\r
+ NetbufQueFlush (&Conn->RspQue);\r
+ gBS->CloseEvent (Conn->TimeoutEvent);\r
+ FreePool (Conn);\r
+}\r
+\r
+\r
+/**\r
+ Login the iSCSI session.\r
+\r
+ @param[in] Session The iSCSI session.\r
+\r
+ @retval EFI_SUCCESS The iSCSI session login procedure finished.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+ @retval EFI_NO_MEDIA There was a media error.\r
+ @retval Others Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiSessionLogin (\r
+ IN ISCSI_SESSION *Session\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ ISCSI_CONNECTION *Conn;\r
+ VOID *Tcp;\r
+ EFI_GUID *ProtocolGuid;\r
+ UINT8 RetryCount;\r
+ BOOLEAN MediaPresent;\r
+\r
+ //\r
+ // Check media status before session login.\r
+ //\r
+ MediaPresent = TRUE;\r
+ NetLibDetectMedia (Session->Private->Controller, &MediaPresent);\r
+ if (!MediaPresent) {\r
+ return EFI_NO_MEDIA;\r
+ }\r
+\r
+ //\r
+ // Set session identifier\r
+ //\r
+ CopyMem (Session->Isid, Session->ConfigData->SessionConfigData.IsId, 6);\r
+\r
+ RetryCount = 0;\r
+\r
+ do {\r
+ //\r
+ // Create a connection for the session.\r
+ //\r
+ Conn = IScsiCreateConnection (Session);\r
+ if (Conn == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ IScsiAttatchConnection (Session, Conn);\r
+\r
+ //\r
+ // Login througth the newly created connection.\r
+ //\r
+ Status = IScsiConnLogin (Conn, Session->ConfigData->SessionConfigData.ConnectTimeout);\r
+ if (EFI_ERROR (Status)) {\r
+ IScsiConnReset (Conn);\r
+ IScsiDetatchConnection (Conn);\r
+ IScsiDestroyConnection (Conn);\r
+ }\r
+\r
+ if (Status != EFI_TIMEOUT) {\r
+ break;\r
+ }\r
+\r
+ RetryCount++;\r
+ } while (RetryCount <= Session->ConfigData->SessionConfigData.ConnectRetryCount);\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ Session->State = SESSION_STATE_LOGGED_IN;\r
+\r
+ if (!mPrivate->Ipv6Flag) {\r
+ ProtocolGuid = &gEfiTcp4ProtocolGuid; \r
+ } else {\r
+ ProtocolGuid = &gEfiTcp6ProtocolGuid;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Conn->TcpIo.Handle,\r
+ ProtocolGuid,\r
+ (VOID **) &Tcp,\r
+ Session->Private->Image,\r
+ Session->Private->ExtScsiPassThruHandle,\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER \r
+ );\r
+\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Wait for IPsec negotiation, then try to login the iSCSI session again.\r
+\r
+ @param[in] Session The iSCSI session.\r
+\r
+ @retval EFI_SUCCESS The iSCSI session login procedure finished.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+ @retval EFI_PROTOCOL_ERROR Some kind of iSCSI protocol error occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiSessionReLogin (\r
+ IN ISCSI_SESSION *Session\r
+ )\r
+{\r
+\r
+ EFI_STATUS Status;\r
+ EFI_STATUS TimerStatus;\r
+ EFI_EVENT Timer;\r
+\r
+ Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = gBS->SetTimer (\r
+ Timer,\r
+ TimerRelative,\r
+ ISCSI_WAIT_IPSEC_TIMEOUT\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->CloseEvent (Timer);\r
+ return Status;\r
+ }\r
+\r
+ do {\r
+\r
+ TimerStatus = gBS->CheckEvent (Timer);\r
+\r
+ if (!EFI_ERROR (TimerStatus)) {\r
+ Status = IScsiSessionLogin (Session);\r
+ }\r
+\r
+ } while (TimerStatus == EFI_NOT_READY);\r
+\r
+ gBS->CloseEvent (Timer);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Build and send the iSCSI login request to the iSCSI target according to\r
+ the current login stage.\r
+\r
+ @param[in] Conn The connection in the iSCSI login phase.\r
+\r
+ @retval EFI_SUCCESS The iSCSI login request PDU is built and sent on this\r
+ connection.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+ @retval EFI_DEVICE_ERROR Some kind of device error occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiSendLoginReq (\r
+ IN ISCSI_CONNECTION *Conn\r
+ )\r
+{\r
+ NET_BUF *Pdu;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Build the Login Request PDU.\r
+ //\r
+ Pdu = IScsiPrepareLoginReq (Conn);\r
+ if (Pdu == NULL) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Send it to the iSCSI target.\r
+ //\r
+ Status = TcpIoTransmit (&Conn->TcpIo, Pdu);\r
+\r
+ NetbufFree (Pdu);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Receive and process the iSCSI login response.\r
+\r
+ @param[in] Conn The connection in the iSCSI login phase.\r
+ \r
+ @retval EFI_SUCCESS The iSCSI login response PDU is received and processed.\r
+ @retval Others Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiReceiveLoginRsp (\r
+ IN ISCSI_CONNECTION *Conn\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ NET_BUF *Pdu;\r
+\r
+ //\r
+ // Receive the iSCSI login response.\r
+ //\r
+ Status = IScsiReceivePdu (Conn, &Pdu, NULL, FALSE, FALSE, NULL);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // A Login Response is received; process it.\r
+ //\r
+ Status = IScsiProcessLoginRsp (Conn, Pdu);\r
+\r
+ NetbufFree (Pdu);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Add an iSCSI key-value pair as a string into the data segment of the Login Request PDU.\r
+ The DataSegmentLength and the actual size of the net buffer containing this PDU will be\r
+ updated.\r
+\r
+ @param[in, out] Pdu The iSCSI PDU whose data segment the key-value pair will\r
+ be added to.\r
+ @param[in] Key The key name string.\r
+ @param[in] Value The value string.\r
+\r
+ @retval EFI_SUCCESS The key-value pair is added to the PDU's data segment and\r
+ the correspondence length fields are updated.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough space in the PDU to add the key-value\r
+ pair.\r
+**/\r
+EFI_STATUS\r
+IScsiAddKeyValuePair (\r
+ IN OUT NET_BUF *Pdu,\r
+ IN CHAR8 *Key,\r
+ IN CHAR8 *Value\r
+ )\r
+{\r
+ UINT32 DataSegLen;\r
+ UINT32 KeyLen;\r
+ UINT32 ValueLen;\r
+ UINT32 TotalLen;\r
+ ISCSI_LOGIN_REQUEST *LoginReq;\r
+ CHAR8 *Data;\r
+\r
+ LoginReq = (ISCSI_LOGIN_REQUEST *) NetbufGetByte (Pdu, 0, NULL);\r
+ DataSegLen = NTOH24 (LoginReq->DataSegmentLength);\r
+\r
+ KeyLen = (UINT32) AsciiStrLen (Key);\r
+ ValueLen = (UINT32) AsciiStrLen (Value);\r
+\r
+ //\r
+ // 1 byte for the key value separator '=' and 1 byte for the null\r
+ // delimiter after the value.\r
+ //\r
+ TotalLen = KeyLen + 1 + ValueLen + 1;\r
+\r
+ //\r
+ // Allocate the space for the key-value pair.\r
+ //\r
+ Data = (CHAR8 *) NetbufAllocSpace (Pdu, TotalLen, NET_BUF_TAIL);\r
+ if (Data == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // Add the key.\r
+ //\r
+ CopyMem (Data, Key, KeyLen);\r
+ Data += KeyLen;\r
+\r
+ *Data = '=';\r
+ Data++;\r
+\r
+ //\r
+ // Add the value.\r
+ //\r
+ CopyMem (Data, Value, ValueLen);\r
+ Data += ValueLen;\r
+\r
+ *Data = '\0';\r
+\r
+ //\r
+ // Update the DataSegmentLength\r
+ //\r
+ ISCSI_SET_DATASEG_LEN (LoginReq, DataSegLen + TotalLen);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Prepare the iSCSI login request to be sent according to the current login status.\r
+\r
+ @param[in, out] Conn The connection in the iSCSI login phase.\r
+\r
+ @return The pointer to the net buffer containing the iSCSI login request built.\r
+ @retval NULL Other errors as indicated.\r
+\r
+**/\r
+NET_BUF *\r
+IScsiPrepareLoginReq (\r
+ IN OUT ISCSI_CONNECTION *Conn\r
+ )\r
+{\r
+ ISCSI_SESSION *Session;\r
+ NET_BUF *Nbuf;\r
+ ISCSI_LOGIN_REQUEST *LoginReq;\r
+ EFI_STATUS Status;\r
+\r
+ Session = Conn->Session;\r
+\r
+ Nbuf = NetbufAlloc (sizeof (ISCSI_LOGIN_REQUEST) + DEFAULT_MAX_RECV_DATA_SEG_LEN);\r
+ if (Nbuf == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ LoginReq = (ISCSI_LOGIN_REQUEST *) NetbufAllocSpace (Nbuf, sizeof (ISCSI_LOGIN_REQUEST), NET_BUF_TAIL);\r
+ ASSERT (LoginReq != NULL);\r
+ ZeroMem (LoginReq, sizeof (ISCSI_LOGIN_REQUEST));\r
+\r
+ //\r
+ // Init the login request pdu\r
+ //\r
+ ISCSI_SET_OPCODE (LoginReq, ISCSI_OPCODE_LOGIN_REQ, ISCSI_REQ_IMMEDIATE);\r
+ ISCSI_SET_STAGES (LoginReq, Conn->CurrentStage, Conn->NextStage);\r
+ LoginReq->VersionMax = ISCSI_VERSION_MAX;\r
+ LoginReq->VersionMin = ISCSI_VERSION_MIN;\r
+ LoginReq->Tsih = HTONS (Session->Tsih);\r
+ LoginReq->InitiatorTaskTag = HTONL (Session->InitiatorTaskTag);\r
+ LoginReq->Cid = HTONS (Conn->Cid);\r
+ LoginReq->CmdSN = HTONL (Session->CmdSN);\r
+\r
+ //\r
+ // For the first Login Request on a coonection this is ExpStatSN for the\r
+ // old connection, and this field is only valid if the Login Request restarts\r
+ // a connection.\r
+ // For subsequent Login Requests it is used to acknowledge the Login Responses\r
+ // with their increasing StatSN values.\r
+ //\r
+ LoginReq->ExpStatSN = HTONL (Conn->ExpStatSN);\r
+ CopyMem (LoginReq->Isid, Session->Isid, sizeof (LoginReq->Isid));\r
+\r
+ if (Conn->PartialRspRcvd) {\r
+ //\r
+ // A partial response. The initiator must send an empty Login Request.\r
+ //\r
+ return Nbuf;\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ switch (Conn->CurrentStage) {\r
+ case ISCSI_SECURITY_NEGOTIATION:\r
+ //\r
+ // Both none authentication and CHAP authentication share the CHAP path.\r
+ // \r
+ //\r
+ if (Session->AuthType != ISCSI_AUTH_TYPE_KRB) {\r
+ Status = IScsiCHAPToSendReq (Conn, Nbuf);\r
+ }\r
+\r
+ break;\r
+\r
+ case ISCSI_LOGIN_OPERATIONAL_NEGOTIATION:\r
+ //\r
+ // Only negotiate the paramter once.\r
+ //\r
+ if (!Conn->ParamNegotiated) {\r
+ IScsiFillOpParams (Conn, Nbuf);\r
+ }\r
+ \r
+ ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);\r
+ break;\r
+\r
+ default:\r
+ //\r
+ // An error occurs...\r
+ //\r
+ Status = EFI_DEVICE_ERROR;\r
+ break;\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ NetbufFree (Nbuf);\r
+ Nbuf = NULL;\r
+ } else {\r
+ //\r
+ // Pad the data segment if needed.\r
+ //\r
+ IScsiPadSegment (Nbuf, ISCSI_GET_DATASEG_LEN (LoginReq));\r
+ //\r
+ // Check whether we will issue the stage transition signal?\r
+ //\r
+ Conn->TransitInitiated = ISCSI_FLAG_ON (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);\r
+ }\r
+\r
+ return Nbuf;\r
+}\r
+\r
+\r
+/**\r
+ Process the iSCSI Login Response.\r
+\r
+ @param[in, out] Conn The connection on which the iSCSI login response is received.\r
+ @param[in, out] Pdu The iSCSI login response PDU.\r
+\r
+ @retval EFI_SUCCESS The iSCSI login response PDU is processed, and all checks are passed.\r
+ @retval EFI_PROTOCOL_ERROR Some kind of iSCSI protocol error occurred.\r
+ @retval EFI_MEDIA_CHANGED Target is redirected.\r
+ @retval Others Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiProcessLoginRsp (\r
+ IN OUT ISCSI_CONNECTION *Conn,\r
+ IN OUT NET_BUF *Pdu\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ ISCSI_SESSION *Session;\r
+ ISCSI_LOGIN_RESPONSE *LoginRsp;\r
+ BOOLEAN Transit;\r
+ BOOLEAN Continue;\r
+ UINT8 CurrentStage;\r
+ UINT8 NextStage;\r
+ UINT8 *DataSeg;\r
+ UINT32 DataSegLen;\r
+\r
+ Status = EFI_SUCCESS;\r
+ Session = Conn->Session;\r
+\r
+ LoginRsp = (ISCSI_LOGIN_RESPONSE *) NetbufGetByte (Pdu, 0, NULL);\r
+ if (!ISCSI_CHECK_OPCODE (LoginRsp, ISCSI_OPCODE_LOGIN_RSP)) {\r
+ //\r
+ // It is not a Login Response.\r
+ //\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+ //\r
+ // Get the data segment, if any.\r
+ //\r
+ DataSegLen = ISCSI_GET_DATASEG_LEN (LoginRsp);\r
+ if (DataSegLen != 0) {\r
+ DataSeg = NetbufGetByte (Pdu, sizeof (ISCSI_LOGIN_RESPONSE), NULL);\r
+ } else {\r
+ DataSeg = NULL;\r
+ }\r
+ //\r
+ // Check the status class in the login response PDU.\r
+ //\r
+ switch (LoginRsp->StatusClass) {\r
+ case ISCSI_LOGIN_STATUS_SUCCESS:\r
+ //\r
+ // Just break here; the response and the data segment will be processed later.\r
+ //\r
+ break;\r
+\r
+ case ISCSI_LOGIN_STATUS_REDIRECTION:\r
+ //\r
+ // The target may be moved to a different address.\r
+ //\r
+ if (DataSeg == NULL) {\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+ //\r
+ // Process the TargetAddress key-value strings in the data segment to update the\r
+ // target address info.\r
+ //\r
+ Status = IScsiUpdateTargetAddress (Session, (CHAR8 *) DataSeg, DataSegLen);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Session will be restarted on this error status because the Target is\r
+ // redirected by this Login Response.\r
+ //\r
+ return EFI_MEDIA_CHANGED;\r
+\r
+ default:\r
+ //\r
+ // Initiator Error, Target Error, or any other undefined error code.\r
+ //\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+ //\r
+ // The status is success; extract the wanted fields from the header segment.\r
+ //\r
+ Transit = ISCSI_FLAG_ON (LoginRsp, ISCSI_LOGIN_RSP_PDU_FLAG_TRANSIT);\r
+ Continue = ISCSI_FLAG_ON (LoginRsp, ISCSI_LOGIN_RSP_PDU_FLAG_CONTINUE);\r
+\r
+ CurrentStage = ISCSI_GET_CURRENT_STAGE (LoginRsp);\r
+ NextStage = ISCSI_GET_NEXT_STAGE (LoginRsp);\r
+\r
+ LoginRsp->InitiatorTaskTag = NTOHL (LoginRsp->InitiatorTaskTag);\r
+\r
+ if ((Transit && Continue) ||\r
+ (CurrentStage != Conn->CurrentStage) ||\r
+ (!Conn->TransitInitiated && Transit) ||\r
+ (Transit && (NextStage != Conn->NextStage)) ||\r
+ (CompareMem (Session->Isid, LoginRsp->Isid, sizeof (LoginRsp->Isid)) != 0) ||\r
+ (LoginRsp->InitiatorTaskTag != Session->InitiatorTaskTag)\r
+ ) {\r
+ //\r
+ // A Login Response with the C bit set to 1 MUST have the T bit set to 0.\r
+ // The CSG in the Login Response MUST be the same with the I-end of this connection.\r
+ // The T bit can't be 1 if the last Login Response sent by the initiator doesn't\r
+ // initiate the transistion.\r
+ // The NSG MUST be the same with the I-end of this connection if Transit is required.\r
+ // The ISID in the Login Response MUST be the same with this session.\r
+ //\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+\r
+ LoginRsp->StatSN = NTOHL (LoginRsp->StatSN);\r
+ LoginRsp->ExpCmdSN = NTOHL (LoginRsp->ExpCmdSN);\r
+ LoginRsp->MaxCmdSN = NTOHL (LoginRsp->MaxCmdSN);\r
+\r
+ if ((Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION) && (Conn->AuthStep == ISCSI_AUTH_INITIAL)) {\r
+ //\r
+ // If the Login Request is a leading Login Request, the target MUST use\r
+ // the value presented in CmdSN as the target value for ExpCmdSN.\r
+ //\r
+ if ((Session->State == SESSION_STATE_FREE) && (Session->CmdSN != LoginRsp->ExpCmdSN)) {\r
+ return EFI_PROTOCOL_ERROR; \r
+ }\r
+\r
+ //\r
+ // It's the initial Login Response, initialize the local ExpStatSN, MaxCmdSN\r
+ // and ExpCmdSN.\r
+ //\r
+ Conn->ExpStatSN = LoginRsp->StatSN + 1;\r
+ Session->MaxCmdSN = LoginRsp->MaxCmdSN;\r
+ Session->ExpCmdSN = LoginRsp->ExpCmdSN;\r
+ } else {\r
+ //\r
+ // Check the StatSN of this PDU.\r
+ //\r
+ Status = IScsiCheckSN (&Conn->ExpStatSN, LoginRsp->StatSN);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Update the MaxCmdSN and ExpCmdSN.\r
+ //\r
+ IScsiUpdateCmdSN (Session, LoginRsp->MaxCmdSN, LoginRsp->ExpCmdSN);\r
+ } else {\r
+ return Status;\r
+ }\r
+ }\r
+ //\r
+ // Trim off the header segment.\r
+ //\r
+ NetbufTrim (Pdu, sizeof (ISCSI_LOGIN_RESPONSE), NET_BUF_HEAD);\r
+\r
+ //\r
+ // Queue this login response first in case it's a partial response so that\r
+ // later when the full response list is received we can combine these scattered\r
+ // responses' data segment and then process it.\r
+ //\r
+ NET_GET_REF (Pdu);\r
+ NetbufQueAppend (&Conn->RspQue, Pdu);\r
+\r
+ Conn->PartialRspRcvd = Continue;\r
+ if (Continue) {\r
+ //\r
+ // It is a partial response; must wait for another or more Request/Response\r
+ // conversations to get the full response.\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ switch (CurrentStage) {\r
+ case ISCSI_SECURITY_NEGOTIATION:\r
+ //\r
+ // In security negotiation stage, let CHAP module handle it.\r
+ //\r
+ if (Session->AuthType != ISCSI_AUTH_TYPE_KRB) {\r
+ Status = IScsiCHAPOnRspReceived (Conn);\r
+ }\r
+ break;\r
+\r
+ case ISCSI_LOGIN_OPERATIONAL_NEGOTIATION:\r
+ //\r
+ // Response received with negotiation response on iSCSI parameters: check them.\r
+ //\r
+ Status = IScsiCheckOpParams (Conn);\r
+ if (!EFI_ERROR (Status)) {\r
+ Conn->ParamNegotiated = TRUE;\r
+ }\r
+\r
+ break;\r
+\r
+ default:\r
+ //\r
+ // Should never get here.\r
+ //\r
+ Status = EFI_PROTOCOL_ERROR;\r
+ break;\r
+ }\r
+\r
+ if (Transit && (Status == EFI_SUCCESS)) {\r
+ //\r
+ // Do the state transition.\r
+ //\r
+ Conn->CurrentStage = Conn->NextStage;\r
+\r
+ if (Conn->CurrentStage == ISCSI_LOGIN_OPERATIONAL_NEGOTIATION) {\r
+ Conn->NextStage = ISCSI_FULL_FEATURE_PHASE;\r
+ } else {\r
+ //\r
+ // CurrentStage is iSCSI Full Feature. It is the Login-Final Response;\r
+ // get the TSIH from the Login Response.\r
+ //\r
+ Session->Tsih = NTOHS (LoginRsp->Tsih);\r
+ }\r
+ }\r
+ //\r
+ // Flush the response(s) received.\r
+ //\r
+ NetbufQueFlush (&Conn->RspQue);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Updated the target information according the data received in the iSCSI\r
+ login response with an target redirection status.\r
+\r
+ @param[in, out] Session The iSCSI session.\r
+ @param[in] Data The data segment that should contain the\r
+ TargetAddress key-value list.\r
+ @param[in] Len Length of the data.\r
+ \r
+ @retval EFI_SUCCESS The target address is updated.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+ @retval EFI_NOT_FOUND The TargetAddress key is not found.\r
+ @retval Others Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiUpdateTargetAddress (\r
+ IN OUT ISCSI_SESSION *Session,\r
+ IN CHAR8 *Data,\r
+ IN UINT32 Len\r
+ )\r
+{\r
+ LIST_ENTRY *KeyValueList;\r
+ CHAR8 *TargetAddress;\r
+ CHAR8 *IpStr;\r
+ EFI_STATUS Status;\r
+ UINTN Number;\r
+ UINT8 IpMode;\r
+\r
+ KeyValueList = IScsiBuildKeyValueList (Data, Len);\r
+ if (KeyValueList == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = EFI_NOT_FOUND;\r
+\r
+ while (TRUE) {\r
+ TargetAddress = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_TARGET_ADDRESS);\r
+ if (TargetAddress == NULL) {\r
+ break;\r
+ }\r
+\r
+ if (!NET_IS_DIGIT (TargetAddress[0])) {\r
+ //\r
+ // The domainname of the target may be presented in three formats: a DNS host name,\r
+ // a dotted-decimal IPv4 address, or a bracketed IPv6 address. Only accept dotted\r
+ // IPv4 address.\r
+ //\r
+ continue;\r
+ }\r
+\r
+ IpStr = TargetAddress;\r
+\r
+ while ((*TargetAddress != 0) && (*TargetAddress != ':') && (*TargetAddress != ',')) {\r
+ //\r
+ // NULL, ':', or ',' ends the IPv4 string.\r
+ //\r
+ TargetAddress++;\r
+ }\r
+\r
+ if (*TargetAddress == ',') {\r
+ //\r
+ // Comma and the portal group tag MUST be ommitted if the TargetAddress is sent\r
+ // as the result of a redirection.\r
+ //\r
+ continue;\r
+ } else if (*TargetAddress == ':') {\r
+ *TargetAddress = '\0';\r
+\r
+ TargetAddress++;\r
+\r
+ Number = AsciiStrDecimalToUintn (TargetAddress);\r
+ if (Number > 0xFFFF) {\r
+ continue;\r
+ } else {\r
+ Session->ConfigData->SessionConfigData.TargetPort = (UINT16) Number;\r
+ }\r
+ } else {\r
+ //\r
+ // The string only contains the IPv4 address. Use the well-known port.\r
+ //\r
+ Session->ConfigData->SessionConfigData.TargetPort = ISCSI_WELL_KNOWN_PORT;\r
+ }\r
+ //\r
+ // Update the target IP address.\r
+ //\r
+ if (Session->ConfigData->SessionConfigData.IpMode < IP_MODE_AUTOCONFIG) {\r
+ IpMode = Session->ConfigData->SessionConfigData.IpMode;\r
+ } else {\r
+ IpMode = Session->ConfigData->AutoConfigureMode;\r
+ }\r
+\r
+ Status = IScsiAsciiStrToIp (\r
+ IpStr,\r
+ IpMode,\r
+ &Session->ConfigData->SessionConfigData.TargetIp\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ } else {\r
+ break;\r
+ }\r
+ }\r
+\r
+ IScsiFreeKeyValueList (KeyValueList);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ The callback function to free the net buffer list.\r
+\r
+ @param[in] Arg The opaque parameter.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+IScsiFreeNbufList (\r
+ VOID *Arg\r
+ )\r
+{\r
+ ASSERT (Arg != NULL);\r
+\r
+ NetbufFreeList ((LIST_ENTRY *) Arg);\r
+ FreePool (Arg);\r
+}\r
+\r
+\r
+/**\r
+ The callback function called in NetBufFree; it does nothing.\r
+\r
+ @param[in] Arg The opaque parameter.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+IScsiNbufExtFree (\r
+ VOID *Arg\r
+ )\r
+{\r
+}\r
+\r
+\r
+/**\r
+ Receive an iSCSI response PDU. An iSCSI response PDU contains an iSCSI PDU header and\r
+ an optional data segment. The two parts will be put into two blocks of buffers in the\r
+ net buffer. The digest check will be conducted in this function if needed and the digests\r
+ will be trimmed from the PDU buffer.\r
+\r
+ @param[in] Conn The iSCSI connection to receive data from.\r
+ @param[out] Pdu The received iSCSI pdu.\r
+ @param[in] Context The context used to describe information on the caller provided\r
+ buffer to receive data segment of the iSCSI pdu. It is optional.\r
+ @param[in] HeaderDigest Whether there will be header digest received.\r
+ @param[in] DataDigest Whether there will be data digest.\r
+ @param[in] TimeoutEvent The timeout event. It is optional.\r
+\r
+ @retval EFI_SUCCESS An iSCSI pdu is received.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+ @retval EFI_PROTOCOL_ERROR Some kind of iSCSI protocol error occurred.\r
+ @retval Others Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiReceivePdu (\r
+ IN ISCSI_CONNECTION *Conn,\r
+ OUT NET_BUF **Pdu,\r
+ IN ISCSI_IN_BUFFER_CONTEXT *Context, OPTIONAL\r
+ IN BOOLEAN HeaderDigest,\r
+ IN BOOLEAN DataDigest,\r
+ IN EFI_EVENT TimeoutEvent OPTIONAL\r
+ )\r
+{\r
+ LIST_ENTRY *NbufList;\r
+ UINT32 Len;\r
+ NET_BUF *PduHdr;\r
+ UINT8 *Header;\r
+ EFI_STATUS Status;\r
+ UINT32 PadLen;\r
+ UINT32 InDataOffset;\r
+ NET_FRAGMENT Fragment[2];\r
+ UINT32 FragmentCount;\r
+ NET_BUF *DataSeg;\r
+ UINT32 PadAndCRC32[2];\r
+\r
+ NbufList = AllocatePool (sizeof (LIST_ENTRY));\r
+ if (NbufList == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ InitializeListHead (NbufList);\r
+\r
+ //\r
+ // The header digest will be received together with the PDU header, if exists.\r
+ //\r
+ Len = sizeof (ISCSI_BASIC_HEADER) + (HeaderDigest ? sizeof (UINT32) : 0);\r
+ PduHdr = NetbufAlloc (Len);\r
+ if (PduHdr == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Header = NetbufAllocSpace (PduHdr, Len, NET_BUF_TAIL);\r
+ ASSERT (Header != NULL);\r
+ InsertTailList (NbufList, &PduHdr->List);\r
+\r
+ //\r
+ // First step, receive the BHS of the PDU.\r
+ //\r
+ Status = TcpIoReceive (&Conn->TcpIo, PduHdr, FALSE, TimeoutEvent);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (HeaderDigest) {\r
+ //\r
+ // TODO: check the header-digest.\r
+ //\r
+ //\r
+ // Trim off the digest.\r
+ //\r
+ NetbufTrim (PduHdr, sizeof (UINT32), NET_BUF_TAIL);\r
+ }\r
+\r
+ Len = ISCSI_GET_DATASEG_LEN (Header);\r
+ if (Len == 0) {\r
+ //\r
+ // No data segment.\r
+ //\r
+ goto FORM_PDU;\r
+ }\r
+ //\r
+ // Get the length of the padding bytes of the data segment.\r
+ //\r
+ PadLen = ISCSI_GET_PAD_LEN (Len);\r
+\r
+ switch (ISCSI_GET_OPCODE (Header)) {\r
+ case ISCSI_OPCODE_SCSI_DATA_IN:\r
+ //\r
+ // To reduce memory copy overhead, try to use the buffer described by Context \r
+ // if the PDU is an iSCSI SCSI data.\r
+ //\r
+ InDataOffset = ISCSI_GET_BUFFER_OFFSET (Header);\r
+ if ((Context == NULL) || ((InDataOffset + Len) > Context->InDataLen)) {\r
+ Status = EFI_PROTOCOL_ERROR;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Fragment[0].Len = Len;\r
+ Fragment[0].Bulk = Context->InData + InDataOffset;\r
+\r
+ if (DataDigest || (PadLen != 0)) {\r
+ //\r
+ // The data segment is padded. Use two fragments to receive it:\r
+ // the first to receive the useful data; the second to receive the padding.\r
+ //\r
+ Fragment[1].Len = PadLen + (DataDigest ? sizeof (UINT32) : 0);\r
+ Fragment[1].Bulk = (UINT8 *)PadAndCRC32 + (4 - PadLen);\r
+\r
+ FragmentCount = 2;\r
+ } else {\r
+ FragmentCount = 1;\r
+ }\r
+\r
+ DataSeg = NetbufFromExt (&Fragment[0], FragmentCount, 0, 0, IScsiNbufExtFree, NULL);\r
+ if (DataSeg == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ break;\r
+\r
+ case ISCSI_OPCODE_SCSI_RSP:\r
+ case ISCSI_OPCODE_NOP_IN:\r
+ case ISCSI_OPCODE_LOGIN_RSP:\r
+ case ISCSI_OPCODE_TEXT_RSP:\r
+ case ISCSI_OPCODE_ASYNC_MSG:\r
+ case ISCSI_OPCODE_REJECT:\r
+ case ISCSI_OPCODE_VENDOR_T0:\r
+ case ISCSI_OPCODE_VENDOR_T1:\r
+ case ISCSI_OPCODE_VENDOR_T2:\r
+ //\r
+ // Allocate buffer to receive the data segment.\r
+ //\r
+ Len += PadLen + (DataDigest ? sizeof (UINT32) : 0);\r
+ DataSeg = NetbufAlloc (Len);\r
+ if (DataSeg == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ NetbufAllocSpace (DataSeg, Len, NET_BUF_TAIL);\r
+ break;\r
+\r
+ default:\r
+ Status = EFI_PROTOCOL_ERROR;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ InsertTailList (NbufList, &DataSeg->List);\r
+\r
+ //\r
+ // Receive the data segment with the data digest, if any.\r
+ //\r
+ Status = TcpIoReceive (&Conn->TcpIo, DataSeg, FALSE, TimeoutEvent);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (DataDigest) {\r
+ //\r
+ // TODO: Check the data digest.\r
+ //\r
+ NetbufTrim (DataSeg, sizeof (UINT32), NET_BUF_TAIL);\r
+ }\r
+\r
+ if (PadLen != 0) {\r
+ //\r
+ // Trim off the padding bytes in the data segment.\r
+ //\r
+ NetbufTrim (DataSeg, PadLen, NET_BUF_TAIL);\r
+ }\r
+\r
+FORM_PDU:\r
+ //\r
+ // Form the pdu from a list of pdu segments.\r
+ //\r
+ *Pdu = NetbufFromBufList (NbufList, 0, 0, IScsiFreeNbufList, NbufList);\r
+ if (*Pdu == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ON_EXIT:\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Free the Nbufs in this NbufList and the NbufList itself.\r
+ //\r
+ IScsiFreeNbufList (NbufList);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Check and get the result of the prameter negotiation.\r
+\r
+ @param[in, out] Conn The connection in iSCSI login.\r
+\r
+ @retval EFI_SUCCESS The parmeter check is passed and negotiation is finished.\r
+ @retval EFI_PROTOCOL_ERROR Some kind of iSCSI protocol error occurred.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiCheckOpParams (\r
+ IN OUT ISCSI_CONNECTION *Conn\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ LIST_ENTRY *KeyValueList;\r
+ CHAR8 *Data;\r
+ UINT32 Len;\r
+ ISCSI_SESSION *Session;\r
+ CHAR8 *Value;\r
+ UINTN NumericValue;\r
+\r
+ ASSERT (Conn->RspQue.BufNum != 0);\r
+\r
+ Session = Conn->Session;\r
+\r
+ Len = Conn->RspQue.BufSize;\r
+ Data = AllocatePool (Len);\r
+ if (Data == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ NetbufQueCopy (&Conn->RspQue, 0, Len, (UINT8 *) Data);\r
+\r
+ Status = EFI_PROTOCOL_ERROR;\r
+\r
+ //\r
+ // Extract the Key-Value pairs into a list.\r
+ //\r
+ KeyValueList = IScsiBuildKeyValueList (Data, Len);\r
+ if (KeyValueList == NULL) {\r
+ FreePool (Data);\r
+ return Status;\r
+ }\r
+ //\r
+ // HeaderDigest\r
+ //\r
+ Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_HEADER_DIGEST);\r
+ if (Value == NULL) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ if (AsciiStrCmp (Value, "CRC32") == 0) {\r
+ if (Conn->HeaderDigest != IScsiDigestCRC32) {\r
+ goto ON_ERROR;\r
+ }\r
+ } else if (AsciiStrCmp (Value, ISCSI_KEY_VALUE_NONE) == 0) {\r
+ Conn->HeaderDigest = IScsiDigestNone;\r
+ } else {\r
+ goto ON_ERROR;\r
+ }\r
+ //\r
+ // DataDigest\r
+ //\r
+ Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_DATA_DIGEST);\r
+ if (Value == NULL) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ if (AsciiStrCmp (Value, "CRC32") == 0) {\r
+ if (Conn->DataDigest != IScsiDigestCRC32) {\r
+ goto ON_ERROR;\r
+ }\r
+ } else if (AsciiStrCmp (Value, ISCSI_KEY_VALUE_NONE) == 0) {\r
+ Conn->DataDigest = IScsiDigestNone;\r
+ } else {\r
+ goto ON_ERROR;\r
+ }\r
+ //\r
+ // ErrorRecoveryLevel: result fuction is Minimum.\r
+ //\r
+ Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_ERROR_RECOVERY_LEVEL);\r
+ if (Value == NULL) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ NumericValue = IScsiNetNtoi (Value);\r
+ if (NumericValue > 2) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Session->ErrorRecoveryLevel = (UINT8) MIN (Session->ErrorRecoveryLevel, NumericValue);\r
+\r
+ //\r
+ // InitialR2T: result function is OR.\r
+ //\r
+ if (!Session->InitialR2T) {\r
+ Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_INITIAL_R2T);\r
+ if (Value == NULL) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Session->InitialR2T = (BOOLEAN) (AsciiStrCmp (Value, "Yes") == 0);\r
+ }\r
+\r
+ //\r
+ // ImmediateData: result function is AND.\r
+ //\r
+ Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_IMMEDIATE_DATA);\r
+ if (Value == NULL) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Session->ImmediateData = (BOOLEAN) (Session->ImmediateData && (BOOLEAN) (AsciiStrCmp (Value, "Yes") == 0));\r
+\r
+ //\r
+ // MaxRecvDataSegmentLength is declarative.\r
+ //\r
+ Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_MAX_RECV_DATA_SEGMENT_LENGTH);\r
+ if (Value != NULL) {\r
+ Conn->MaxRecvDataSegmentLength = (UINT32) IScsiNetNtoi (Value);\r
+ }\r
+ //\r
+ // MaxBurstLength: result funtion is Mininum.\r
+ //\r
+ Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_MAX_BURST_LENGTH);\r
+ if (Value == NULL) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ NumericValue = IScsiNetNtoi (Value);\r
+ Session->MaxBurstLength = (UINT32) MIN (Session->MaxBurstLength, NumericValue);\r
+\r
+ //\r
+ // FirstBurstLength: result function is Minimum. Irrelevant when InitialR2T=Yes and\r
+ // ImmediateData=No.\r
+ //\r
+ if (!(Session->InitialR2T && !Session->ImmediateData)) {\r
+ Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_FIRST_BURST_LENGTH);\r
+ if (Value == NULL) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ NumericValue = IScsiNetNtoi (Value);\r
+ Session->FirstBurstLength = (UINT32) MIN (Session->FirstBurstLength, NumericValue);\r
+ }\r
+\r
+ //\r
+ // MaxConnections: result function is Minimum.\r
+ //\r
+ Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_MAX_CONNECTIONS);\r
+ if (Value == NULL) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ NumericValue = IScsiNetNtoi (Value);\r
+ if ((NumericValue == 0) || (NumericValue > 65535)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Session->MaxConnections = (UINT32) MIN (Session->MaxConnections, NumericValue);\r
+\r
+ //\r
+ // DataPDUInOrder: result function is OR.\r
+ //\r
+ if (!Session->DataPDUInOrder) {\r
+ Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_DATA_PDU_IN_ORDER);\r
+ if (Value == NULL) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Session->DataPDUInOrder = (BOOLEAN) (AsciiStrCmp (Value, "Yes") == 0);\r
+ }\r
+\r
+ //\r
+ // DataSequenceInorder: result function is OR.\r
+ //\r
+ if (!Session->DataSequenceInOrder) {\r
+ Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_DATA_SEQUENCE_IN_ORDER);\r
+ if (Value == NULL) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Session->DataSequenceInOrder = (BOOLEAN) (AsciiStrCmp (Value, "Yes") == 0);\r
+ }\r
+\r
+ //\r
+ // DefaultTime2Wait: result function is Maximum.\r
+ //\r
+ Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_DEFAULT_TIME2WAIT);\r
+ if (Value == NULL) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ NumericValue = IScsiNetNtoi (Value);\r
+ if (NumericValue == 0) {\r
+ Session->DefaultTime2Wait = 0;\r
+ } else if (NumericValue > 3600) {\r
+ goto ON_ERROR;\r
+ } else {\r
+ Session->DefaultTime2Wait = (UINT32) MAX (Session->DefaultTime2Wait, NumericValue);\r
+ }\r
+ //\r
+ // DefaultTime2Retain: result function is Minimum.\r
+ //\r
+ Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_DEFAULT_TIME2RETAIN);\r
+ if (Value == NULL) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ NumericValue = IScsiNetNtoi (Value);\r
+ if (NumericValue == 0) {\r
+ Session->DefaultTime2Retain = 0;\r
+ } else if (NumericValue > 3600) {\r
+ goto ON_ERROR;\r
+ } else {\r
+ Session->DefaultTime2Retain = (UINT32) MIN (Session->DefaultTime2Retain, NumericValue);\r
+ }\r
+ //\r
+ // MaxOutstandingR2T: result function is Minimum.\r
+ //\r
+ Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_MAX_OUTSTANDING_R2T);\r
+ if (Value == NULL) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ NumericValue = IScsiNetNtoi (Value);\r
+ if ((NumericValue == 0) || (NumericValue > 65535)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Session->MaxOutstandingR2T = (UINT16) MIN (Session->MaxOutstandingR2T, NumericValue);\r
+\r
+ //\r
+ // Remove declarative key-value pairs, if any.\r
+ //\r
+ IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_SESSION_TYPE);\r
+ IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_TARGET_ALIAS);\r
+ IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_TARGET_PORTAL_GROUP_TAG);\r
+\r
+ \r
+ //\r
+ // Remove the key-value that may not needed for result function is OR.\r
+ //\r
+ IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_INITIAL_R2T);\r
+ IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_DATA_PDU_IN_ORDER);\r
+ IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_DATA_SEQUENCE_IN_ORDER);\r
+\r
+\r
+ if (IsListEmpty (KeyValueList)) {\r
+ //\r
+ // Succeed if no more keys in the list.\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ }\r
+\r
+ON_ERROR:\r
+\r
+ IScsiFreeKeyValueList (KeyValueList);\r
+\r
+ FreePool (Data);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Fill the oprational parameters.\r
+\r
+ @param[in] Conn The connection in iSCSI login.\r
+ @param[in, out] Pdu The iSCSI login request PDU to fill the parameters.\r
+\r
+**/\r
+VOID\r
+IScsiFillOpParams (\r
+ IN ISCSI_CONNECTION *Conn,\r
+ IN OUT NET_BUF *Pdu\r
+ )\r
+{\r
+ ISCSI_SESSION *Session;\r
+ CHAR8 Value[256];\r
+\r
+ Session = Conn->Session;\r
+\r
+ AsciiSPrint (Value, sizeof (Value), "%a", (Conn->HeaderDigest == IScsiDigestCRC32) ? "None,CRC32" : "None");\r
+ IScsiAddKeyValuePair (Pdu, ISCSI_KEY_HEADER_DIGEST, Value);\r
+\r
+ AsciiSPrint (Value, sizeof (Value), "%a", (Conn->DataDigest == IScsiDigestCRC32) ? "None,CRC32" : "None");\r
+ IScsiAddKeyValuePair (Pdu, ISCSI_KEY_DATA_DIGEST, Value);\r
+\r
+ AsciiSPrint (Value, sizeof (Value), "%d", Session->ErrorRecoveryLevel);\r
+ IScsiAddKeyValuePair (Pdu, ISCSI_KEY_ERROR_RECOVERY_LEVEL, Value);\r
+\r
+ AsciiSPrint (Value, sizeof (Value), "%a", Session->InitialR2T ? "Yes" : "No");\r
+ IScsiAddKeyValuePair (Pdu, ISCSI_KEY_INITIAL_R2T, Value);\r
+\r
+ AsciiSPrint (Value, sizeof (Value), "%a", Session->ImmediateData ? "Yes" : "No");\r
+ IScsiAddKeyValuePair (Pdu, ISCSI_KEY_IMMEDIATE_DATA, Value);\r
+\r
+ AsciiSPrint (Value, sizeof (Value), "%d", MAX_RECV_DATA_SEG_LEN_IN_FFP);\r
+ IScsiAddKeyValuePair (Pdu, ISCSI_KEY_MAX_RECV_DATA_SEGMENT_LENGTH, Value);\r
+\r
+ AsciiSPrint (Value, sizeof (Value), "%d", Session->MaxBurstLength);\r
+ IScsiAddKeyValuePair (Pdu, ISCSI_KEY_MAX_BURST_LENGTH, Value);\r
+\r
+ AsciiSPrint (Value, sizeof (Value), "%d", Session->FirstBurstLength);\r
+ IScsiAddKeyValuePair (Pdu, ISCSI_KEY_FIRST_BURST_LENGTH, Value);\r
+\r
+ AsciiSPrint (Value, sizeof (Value), "%d", Session->MaxConnections);\r
+ IScsiAddKeyValuePair (Pdu, ISCSI_KEY_MAX_CONNECTIONS, Value);\r
+\r
+ AsciiSPrint (Value, sizeof (Value), "%a", Session->DataPDUInOrder ? "Yes" : "No");\r
+ IScsiAddKeyValuePair (Pdu, ISCSI_KEY_DATA_PDU_IN_ORDER, Value);\r
+\r
+ AsciiSPrint (Value, sizeof (Value), "%a", Session->DataSequenceInOrder ? "Yes" : "No");\r
+ IScsiAddKeyValuePair (Pdu, ISCSI_KEY_DATA_SEQUENCE_IN_ORDER, Value);\r
+\r
+ AsciiSPrint (Value, sizeof (Value), "%d", Session->DefaultTime2Wait);\r
+ IScsiAddKeyValuePair (Pdu, ISCSI_KEY_DEFAULT_TIME2WAIT, Value);\r
+\r
+ AsciiSPrint (Value, sizeof (Value), "%d", Session->DefaultTime2Retain);\r
+ IScsiAddKeyValuePair (Pdu, ISCSI_KEY_DEFAULT_TIME2RETAIN, Value);\r
+\r
+ AsciiSPrint (Value, sizeof (Value), "%d", Session->MaxOutstandingR2T);\r
+ IScsiAddKeyValuePair (Pdu, ISCSI_KEY_MAX_OUTSTANDING_R2T, Value);\r
+}\r
+\r
+\r
+/**\r
+ Pad the iSCSI AHS or data segment to an integer number of 4 byte words.\r
+\r
+ @param[in, out] Pdu The iSCSI pdu which contains segments to pad.\r
+ @param[in] Len The length of the last segment in the PDU.\r
+\r
+ @retval EFI_SUCCESS The segment is padded or there is no need to pad it.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough remaining free space to add the\r
+ padding bytes.\r
+**/\r
+EFI_STATUS\r
+IScsiPadSegment (\r
+ IN OUT NET_BUF *Pdu,\r
+ IN UINT32 Len\r
+ )\r
+{\r
+ UINT32 PadLen;\r
+ UINT8 *Data;\r
+\r
+ PadLen = ISCSI_GET_PAD_LEN (Len);\r
+\r
+ if (PadLen != 0) {\r
+ Data = NetbufAllocSpace (Pdu, PadLen, NET_BUF_TAIL);\r
+ if (Data == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ ZeroMem (Data, PadLen);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Build a key-value list from the data segment.\r
+\r
+ @param[in] Data The data segment containing the key-value pairs.\r
+ @param[in] Len Length of the data segment.\r
+\r
+ @return The key-value list.\r
+ @retval NULL Other errors as indicated.\r
+\r
+**/\r
+LIST_ENTRY *\r
+IScsiBuildKeyValueList (\r
+ IN CHAR8 *Data,\r
+ IN UINT32 Len\r
+ )\r
+{\r
+ LIST_ENTRY *ListHead;\r
+ ISCSI_KEY_VALUE_PAIR *KeyValuePair;\r
+\r
+ ListHead = AllocatePool (sizeof (LIST_ENTRY));\r
+ if (ListHead == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ InitializeListHead (ListHead);\r
+\r
+ while (Len > 0) {\r
+ KeyValuePair = AllocatePool (sizeof (ISCSI_KEY_VALUE_PAIR));\r
+ if (KeyValuePair == NULL) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ InitializeListHead (&KeyValuePair->List);\r
+\r
+ KeyValuePair->Key = Data;\r
+\r
+ while ((Len > 0) && (*Data != '=')) {\r
+ Len--;\r
+ Data++;\r
+ }\r
+\r
+ if (*Data == '=') {\r
+ *Data = '\0';\r
+\r
+ Data++;\r
+ Len--;\r
+ } else {\r
+ FreePool (KeyValuePair);\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ KeyValuePair->Value = Data;\r
+\r
+ InsertTailList (ListHead, &KeyValuePair->List);;\r
+\r
+ Data += AsciiStrLen (KeyValuePair->Value) + 1;\r
+ Len -= (UINT32) AsciiStrLen (KeyValuePair->Value) + 1;\r
+ }\r
+\r
+ return ListHead;\r
+\r
+ON_ERROR:\r
+\r
+ IScsiFreeKeyValueList (ListHead);\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Get the value string by the key name from the key-value list. If found,\r
+ the key-value entry will be removed from the list.\r
+\r
+ @param[in, out] KeyValueList The key-value list.\r
+ @param[in] Key The key name to find.\r
+\r
+ @return The value string.\r
+ @retval NULL The key value pair cannot be found.\r
+\r
+**/\r
+CHAR8 *\r
+IScsiGetValueByKeyFromList (\r
+ IN OUT LIST_ENTRY *KeyValueList,\r
+ IN CHAR8 *Key\r
+ )\r
+{\r
+ LIST_ENTRY *Entry;\r
+ ISCSI_KEY_VALUE_PAIR *KeyValuePair;\r
+ CHAR8 *Value;\r
+\r
+ Value = NULL;\r
+\r
+ NET_LIST_FOR_EACH (Entry, KeyValueList) {\r
+ KeyValuePair = NET_LIST_USER_STRUCT (Entry, ISCSI_KEY_VALUE_PAIR, List);\r
+\r
+ if (AsciiStrCmp (KeyValuePair->Key, Key) == 0) {\r
+ Value = KeyValuePair->Value;\r
+\r
+ RemoveEntryList (&KeyValuePair->List);\r
+ FreePool (KeyValuePair);\r
+ break;\r
+ }\r
+ }\r
+\r
+ return Value;\r
+}\r
+\r
+\r
+/**\r
+ Free the key-value list.\r
+\r
+ @param[in] KeyValueList The key-value list.\r
+\r
+**/\r
+VOID\r
+IScsiFreeKeyValueList (\r
+ IN LIST_ENTRY *KeyValueList\r
+ )\r
+{\r
+ LIST_ENTRY *Entry;\r
+ ISCSI_KEY_VALUE_PAIR *KeyValuePair;\r
+\r
+ while (!IsListEmpty (KeyValueList)) {\r
+ Entry = NetListRemoveHead (KeyValueList);\r
+ KeyValuePair = NET_LIST_USER_STRUCT (Entry, ISCSI_KEY_VALUE_PAIR, List);\r
+\r
+ FreePool (KeyValuePair);\r
+ }\r
+\r
+ FreePool (KeyValueList);\r
+}\r
+\r
+\r
+/**\r
+ Normalize the iSCSI name according to RFC.\r
+\r
+ @param[in, out] Name The iSCSI name.\r
+ @param[in] Len Length of the iSCSI name.\r
+\r
+ @retval EFI_SUCCESS The iSCSI name is valid and normalized.\r
+ @retval EFI_PROTOCOL_ERROR The iSCSI name is malformatted or not in the IQN format.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiNormalizeName (\r
+ IN OUT CHAR8 *Name,\r
+ IN UINTN Len\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ for (Index = 0; Index < Len; Index++) {\r
+ if (NET_IS_UPPER_CASE_CHAR (Name[Index])) {\r
+ //\r
+ // Convert the upper-case characters to lower-case ones.\r
+ //\r
+ Name[Index] = (CHAR8) (Name[Index] - 'A' + 'a');\r
+ }\r
+\r
+ if (!NET_IS_LOWER_CASE_CHAR (Name[Index]) &&\r
+ !NET_IS_DIGIT (Name[Index]) &&\r
+ (Name[Index] != '-') &&\r
+ (Name[Index] != '.') &&\r
+ (Name[Index] != ':')\r
+ ) {\r
+ //\r
+ // ASCII dash, dot, colon lower-case characters and digit characters\r
+ // are allowed.\r
+ //\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+ }\r
+\r
+ if ((Len < 4) || (CompareMem (Name, "iqn.", 4) != 0)) {\r
+ //\r
+ // Only IQN format is accepted now.\r
+ //\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Create an iSCSI task control block.\r
+\r
+ @param[in] Conn The connection on which the task control block will be created.\r
+ @param[out] Tcb The newly created task control block.\r
+\r
+ @retval EFI_SUCCESS The task control block is created.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+ @retval EFI_NOT_READY The target cannot accept new commands.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiNewTcb (\r
+ IN ISCSI_CONNECTION *Conn,\r
+ OUT ISCSI_TCB **Tcb\r
+ )\r
+{\r
+ ISCSI_SESSION *Session;\r
+ ISCSI_TCB *NewTcb;\r
+\r
+ ASSERT (Tcb != NULL);\r
+\r
+ Session = Conn->Session;\r
+\r
+ if (ISCSI_SEQ_GT (Session->CmdSN, Session->MaxCmdSN)) {\r
+ return EFI_NOT_READY;\r
+ }\r
+\r
+ NewTcb = AllocateZeroPool (sizeof (ISCSI_TCB));\r
+ if (NewTcb == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ InitializeListHead (&NewTcb->Link);\r
+\r
+ NewTcb->SoFarInOrder = TRUE;\r
+ NewTcb->InitiatorTaskTag = Session->InitiatorTaskTag;\r
+ NewTcb->CmdSN = Session->CmdSN;\r
+ NewTcb->Conn = Conn;\r
+\r
+ InsertTailList (&Session->TcbList, &NewTcb->Link);\r
+\r
+ //\r
+ // Advance the initiator task tag.\r
+ //\r
+ Session->InitiatorTaskTag++;\r
+ Session->CmdSN++;\r
+\r
+ *Tcb = NewTcb;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Delete the tcb from the connection and destroy it.\r
+\r
+ @param[in] Tcb The tcb to delete.\r
+\r
+**/\r
+VOID\r
+IScsiDelTcb (\r
+ IN ISCSI_TCB *Tcb\r
+ )\r
+{\r
+ RemoveEntryList (&Tcb->Link);\r
+\r
+ FreePool (Tcb);\r
+}\r
+\r
+\r
+/**\r
+ Find the task control block by the initator task tag.\r
+\r
+ @param[in] TcbList The tcb list.\r
+ @param[in] InitiatorTaskTag The initiator task tag.\r
+\r
+ @return The task control block found.\r
+ @retval NULL The task control block cannot be found.\r
+\r
+**/\r
+ISCSI_TCB *\r
+IScsiFindTcbByITT (\r
+ IN LIST_ENTRY *TcbList,\r
+ IN UINT32 InitiatorTaskTag\r
+ )\r
+{\r
+ ISCSI_TCB *Tcb;\r
+ LIST_ENTRY *Entry;\r
+\r
+ Tcb = NULL;\r
+\r
+ NET_LIST_FOR_EACH (Entry, TcbList) {\r
+ Tcb = NET_LIST_USER_STRUCT (Entry, ISCSI_TCB, Link);\r
+\r
+ if (Tcb->InitiatorTaskTag == InitiatorTaskTag) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ return Tcb;\r
+}\r
+\r
+\r
+/**\r
+ Create a data segment, pad it, and calculate the CRC if needed.\r
+\r
+ @param[in] Data The data to fill into the data segment.\r
+ @param[in] Len Length of the data.\r
+ @param[in] DataDigest Whether to calculate CRC for this data segment.\r
+\r
+ @return The net buffer wrapping the data segment.\r
+\r
+**/\r
+NET_BUF *\r
+IScsiNewDataSegment (\r
+ IN UINT8 *Data,\r
+ IN UINT32 Len,\r
+ IN BOOLEAN DataDigest\r
+ )\r
+{\r
+ NET_FRAGMENT Fragment[2];\r
+ UINT32 FragmentCount;\r
+ UINT32 PadLen;\r
+ NET_BUF *DataSeg;\r
+\r
+ Fragment[0].Len = Len;\r
+ Fragment[0].Bulk = Data;\r
+\r
+ PadLen = ISCSI_GET_PAD_LEN (Len);\r
+ if (PadLen != 0) {\r
+ Fragment[1].Len = PadLen;\r
+ Fragment[1].Bulk = (UINT8 *) &mDataSegPad;\r
+\r
+ FragmentCount = 2;\r
+ } else {\r
+ FragmentCount = 1;\r
+ }\r
+\r
+ DataSeg = NetbufFromExt (&Fragment[0], FragmentCount, 0, 0, IScsiNbufExtFree, NULL);\r
+\r
+ return DataSeg;\r
+}\r
+\r
+\r
+/**\r
+ Create a iSCSI SCSI command PDU to encapsulate the command issued\r
+ by SCSI through the EXT SCSI PASS THRU Protocol.\r
+\r
+ @param[in] Packet The EXT SCSI PASS THRU request packet containing the SCSI command.\r
+ @param[in] Lun The LUN.\r
+ @param[in] Tcb The tcb assocated with this SCSI command.\r
+\r
+ @return The created iSCSI SCSI command PDU.\r
+ @retval NULL Other errors as indicated.\r
+\r
+**/\r
+NET_BUF *\r
+IScsiNewScsiCmdPdu (\r
+ IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,\r
+ IN UINT64 Lun,\r
+ IN ISCSI_TCB *Tcb\r
+ )\r
+{\r
+ LIST_ENTRY *NbufList;\r
+ NET_BUF *Pdu;\r
+ NET_BUF *PduHeader;\r
+ NET_BUF *DataSeg;\r
+ SCSI_COMMAND *ScsiCmd;\r
+ UINT8 AHSLength;\r
+ UINT32 Length;\r
+ ISCSI_ADDITIONAL_HEADER *Header;\r
+ ISCSI_BI_EXP_READ_DATA_LEN_AHS *BiExpReadDataLenAHS;\r
+ ISCSI_SESSION *Session;\r
+ UINT32 ImmediateDataLen;\r
+\r
+ AHSLength = 0;\r
+\r
+ if (Packet->DataDirection == DataBi) {\r
+ //\r
+ // Bidirectional Read/Write command, the bidirectional expected\r
+ // read data length AHS is required.\r
+ //\r
+ AHSLength += sizeof (ISCSI_BI_EXP_READ_DATA_LEN_AHS);\r
+ }\r
+\r
+ if (Packet->CdbLength > 16) {\r
+ //\r
+ // The CDB exceeds 16 bytes. An extended CDB AHS is required.\r
+ //\r
+ AHSLength = (UINT8) (AHSLength + ISCSI_ROUNDUP (Packet->CdbLength - 16) + sizeof (ISCSI_ADDITIONAL_HEADER));\r
+ }\r
+\r
+ Length = sizeof (SCSI_COMMAND) + AHSLength;\r
+ PduHeader = NetbufAlloc (Length);\r
+ if (PduHeader == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ ScsiCmd = (SCSI_COMMAND *) NetbufAllocSpace (PduHeader, Length, NET_BUF_TAIL);\r
+ if (ScsiCmd == NULL) {\r
+ NetbufFree (PduHeader);\r
+ return NULL;\r
+ } \r
+ Header = (ISCSI_ADDITIONAL_HEADER *) (ScsiCmd + 1);\r
+\r
+ ZeroMem (ScsiCmd, Length);\r
+\r
+ ISCSI_SET_OPCODE (ScsiCmd, ISCSI_OPCODE_SCSI_CMD, 0);\r
+ ISCSI_SET_FLAG (ScsiCmd, ISCSI_TASK_ATTR_SIMPLE);\r
+\r
+ //\r
+ // Set the READ/WRITE flags according to the IO type of this request.\r
+ //\r
+ switch (Packet->DataDirection) {\r
+ case DataIn:\r
+ ISCSI_SET_FLAG (ScsiCmd, SCSI_CMD_PDU_FLAG_READ);\r
+ ScsiCmd->ExpDataXferLength = NTOHL (Packet->InTransferLength);\r
+ break;\r
+\r
+ case DataOut:\r
+ ISCSI_SET_FLAG (ScsiCmd, SCSI_CMD_PDU_FLAG_WRITE);\r
+ ScsiCmd->ExpDataXferLength = NTOHL (Packet->OutTransferLength);\r
+ break;\r
+\r
+ case DataBi:\r
+ ISCSI_SET_FLAG (ScsiCmd, SCSI_CMD_PDU_FLAG_READ | SCSI_CMD_PDU_FLAG_WRITE);\r
+ ScsiCmd->ExpDataXferLength = NTOHL (Packet->OutTransferLength);\r
+\r
+ //\r
+ // Fill the bidirectional expected read data length AHS.\r
+ //\r
+ BiExpReadDataLenAHS = (ISCSI_BI_EXP_READ_DATA_LEN_AHS *) Header;\r
+ Header = (ISCSI_ADDITIONAL_HEADER *) (BiExpReadDataLenAHS + 1);\r
+\r
+ BiExpReadDataLenAHS->Length = NTOHS (5);\r
+ BiExpReadDataLenAHS->Type = ISCSI_AHS_TYPE_BI_EXP_READ_DATA_LEN;\r
+ BiExpReadDataLenAHS->ExpReadDataLength = NTOHL (Packet->InTransferLength);\r
+\r
+ break;\r
+ }\r
+\r
+ ScsiCmd->TotalAHSLength = AHSLength;\r
+ CopyMem (ScsiCmd->Lun, &Lun, sizeof (ScsiCmd->Lun));\r
+ ScsiCmd->InitiatorTaskTag = NTOHL (Tcb->InitiatorTaskTag);\r
+ ScsiCmd->CmdSN = NTOHL (Tcb->CmdSN);\r
+ ScsiCmd->ExpStatSN = NTOHL (Tcb->Conn->ExpStatSN);\r
+\r
+ CopyMem (ScsiCmd->Cdb, Packet->Cdb, sizeof (ScsiCmd->Cdb));\r
+\r
+ if (Packet->CdbLength > 16) {\r
+ Header->Length = NTOHS ((UINT16) (Packet->CdbLength - 15));\r
+ Header->Type = ISCSI_AHS_TYPE_EXT_CDB;\r
+\r
+ CopyMem (Header + 1, (UINT8 *) Packet->Cdb + 16, Packet->CdbLength - 16);\r
+ }\r
+\r
+ Pdu = PduHeader;\r
+ Session = Tcb->Conn->Session;\r
+ ImmediateDataLen = 0;\r
+\r
+ if (Session->ImmediateData && (Packet->OutTransferLength != 0)) {\r
+ //\r
+ // Send immediate data in this SCSI Command PDU. The length of the immeidate\r
+ // data is the minimum of FirstBurstLength, the data length to be xfered, and\r
+ // the MaxRecvdataSegmentLength on this connection.\r
+ //\r
+ ImmediateDataLen = MIN (Session->FirstBurstLength, Packet->OutTransferLength);\r
+ ImmediateDataLen = MIN (ImmediateDataLen, Tcb->Conn->MaxRecvDataSegmentLength);\r
+\r
+ //\r
+ // Update the data segment length in the PDU header.\r
+ //\r
+ ISCSI_SET_DATASEG_LEN (ScsiCmd, ImmediateDataLen);\r
+\r
+ //\r
+ // Create the data segment.\r
+ //\r
+ DataSeg = IScsiNewDataSegment ((UINT8 *) Packet->OutDataBuffer, ImmediateDataLen, FALSE);\r
+ if (DataSeg == NULL) {\r
+ NetbufFree (PduHeader);\r
+ Pdu = NULL;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ NbufList = AllocatePool (sizeof (LIST_ENTRY));\r
+ if (NbufList == NULL) {\r
+ NetbufFree (PduHeader);\r
+ NetbufFree (DataSeg);\r
+\r
+ Pdu = NULL;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ InitializeListHead (NbufList);\r
+ InsertTailList (NbufList, &PduHeader->List);\r
+ InsertTailList (NbufList, &DataSeg->List);\r
+\r
+ Pdu = NetbufFromBufList (NbufList, 0, 0, IScsiFreeNbufList, NbufList);\r
+ if (Pdu == NULL) {\r
+ IScsiFreeNbufList (NbufList);\r
+ }\r
+ }\r
+\r
+ if (Session->InitialR2T ||\r
+ (ImmediateDataLen == Session->FirstBurstLength) ||\r
+ (ImmediateDataLen == Packet->OutTransferLength)\r
+ ) {\r
+ //\r
+ // Unsolicited data out sequence is not allowed,\r
+ // or FirstBustLength data is already sent out by immediate data,\r
+ // or all the OUT data accompany this SCSI packet are sent as\r
+ // immediate data. The final flag should be set on this SCSI Command\r
+ // PDU.\r
+ //\r
+ ISCSI_SET_FLAG (ScsiCmd, ISCSI_BHS_FLAG_FINAL);\r
+ }\r
+\r
+ON_EXIT:\r
+\r
+ return Pdu;\r
+}\r
+\r
+\r
+/**\r
+ Create a new iSCSI SCSI Data Out PDU.\r
+\r
+ @param[in] Data The data to put into the Data Out PDU.\r
+ @param[in] Len Length of the data.\r
+ @param[in] DataSN The DataSN of the Data Out PDU.\r
+ @param[in] Tcb The task control block of this Data Out PDU.\r
+ @param[in] Lun The LUN.\r
+\r
+ @return The net buffer wrapping the Data Out PDU.\r
+ @retval NULL Other errors as indicated.\r
+\r
+**/\r
+NET_BUF *\r
+IScsiNewDataOutPdu (\r
+ IN UINT8 *Data,\r
+ IN UINT32 Len,\r
+ IN UINT32 DataSN,\r
+ IN ISCSI_TCB *Tcb,\r
+ IN UINT64 Lun\r
+ )\r
+{\r
+ LIST_ENTRY *NbufList;\r
+ NET_BUF *PduHdr;\r
+ NET_BUF *DataSeg;\r
+ NET_BUF *Pdu;\r
+ ISCSI_SCSI_DATA_OUT *DataOutHdr;\r
+ ISCSI_XFER_CONTEXT *XferContext;\r
+\r
+ NbufList = AllocatePool (sizeof (LIST_ENTRY));\r
+ if (NbufList == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ InitializeListHead (NbufList);\r
+\r
+ //\r
+ // Allocate memory for the BHS.\r
+ //\r
+ PduHdr = NetbufAlloc (sizeof (ISCSI_SCSI_DATA_OUT));\r
+ if (PduHdr == NULL) {\r
+ FreePool (NbufList);\r
+ return NULL;\r
+ }\r
+ //\r
+ // Insert the BHS into the buffer list.\r
+ //\r
+ InsertTailList (NbufList, &PduHdr->List);\r
+\r
+ DataOutHdr = (ISCSI_SCSI_DATA_OUT *) NetbufAllocSpace (PduHdr, sizeof (ISCSI_SCSI_DATA_OUT), NET_BUF_TAIL);\r
+ ASSERT (DataOutHdr != NULL);\r
+ XferContext = &Tcb->XferContext;\r
+\r
+ ZeroMem (DataOutHdr, sizeof (ISCSI_SCSI_DATA_OUT));\r
+\r
+ //\r
+ // Set the flags and fields of the Data Out PDU BHS.\r
+ //\r
+ ISCSI_SET_OPCODE (DataOutHdr, ISCSI_OPCODE_SCSI_DATA_OUT, 0);\r
+ ISCSI_SET_DATASEG_LEN (DataOutHdr, Len);\r
+\r
+ DataOutHdr->InitiatorTaskTag = HTONL (Tcb->InitiatorTaskTag);\r
+ DataOutHdr->TargetTransferTag = HTONL (XferContext->TargetTransferTag);\r
+ DataOutHdr->ExpStatSN = HTONL (Tcb->Conn->ExpStatSN);\r
+ DataOutHdr->DataSN = HTONL (DataSN);\r
+ DataOutHdr->BufferOffset = HTONL (XferContext->Offset);\r
+\r
+ if (XferContext->TargetTransferTag != ISCSI_RESERVED_TAG) {\r
+ CopyMem (&DataOutHdr->Lun, &Lun, sizeof (DataOutHdr->Lun));\r
+ }\r
+ //\r
+ // Build the data segment for this Data Out PDU.\r
+ //\r
+ DataSeg = IScsiNewDataSegment (Data, Len, FALSE);\r
+ if (DataSeg == NULL) {\r
+ IScsiFreeNbufList (NbufList);\r
+ return NULL;\r
+ }\r
+ //\r
+ // Put the data segment into the buffer list and combine it with the BHS\r
+ // into a full Data Out PDU.\r
+ //\r
+ InsertTailList (NbufList, &DataSeg->List);\r
+ Pdu = NetbufFromBufList (NbufList, 0, 0, IScsiFreeNbufList, NbufList);\r
+ if (Pdu == NULL) {\r
+ IScsiFreeNbufList (NbufList);\r
+ }\r
+\r
+ return Pdu;\r
+}\r
+\r
+\r
+/**\r
+ Generate a consecutive sequence of iSCSI SCSI Data Out PDUs.\r
+\r
+ @param[in] Data The data which will be carried by the sequence of iSCSI SCSI Data Out PDUs.\r
+ @param[in] Tcb The task control block of the data to send out.\r
+ @param[in] Lun The LUN the data will be sent to.\r
+\r
+ @return A list of net buffers with each of them wrapping an iSCSI SCSI Data Out PDU.\r
+ @retval NULL Other errors as indicated.\r
+\r
+**/\r
+LIST_ENTRY *\r
+IScsiGenerateDataOutPduSequence (\r
+ IN UINT8 *Data,\r
+ IN ISCSI_TCB *Tcb,\r
+ IN UINT64 Lun\r
+ )\r
+{\r
+ LIST_ENTRY *PduList;\r
+ UINT32 DataSN;\r
+ UINT32 DataLen;\r
+ NET_BUF *DataOutPdu;\r
+ ISCSI_CONNECTION *Conn;\r
+ ISCSI_XFER_CONTEXT *XferContext;\r
+\r
+ PduList = AllocatePool (sizeof (LIST_ENTRY));\r
+ if (PduList == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ InitializeListHead (PduList);\r
+\r
+ DataSN = 0;\r
+ Conn = Tcb->Conn;\r
+ DataOutPdu = NULL;\r
+ XferContext = &Tcb->XferContext;\r
+\r
+ while (XferContext->DesiredLength > 0) {\r
+ //\r
+ // Determine the length of data this Data Out PDU can carry.\r
+ //\r
+ DataLen = MIN (XferContext->DesiredLength, Conn->MaxRecvDataSegmentLength);\r
+\r
+ //\r
+ // Create a Data Out PDU.\r
+ //\r
+ DataOutPdu = IScsiNewDataOutPdu (Data, DataLen, DataSN, Tcb, Lun);\r
+ if (DataOutPdu == NULL) {\r
+ IScsiFreeNbufList (PduList);\r
+ PduList = NULL;\r
+\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ InsertTailList (PduList, &DataOutPdu->List);\r
+\r
+ //\r
+ // Update the context and DataSN.\r
+ //\r
+ Data += DataLen;\r
+ XferContext->Offset += DataLen;\r
+ XferContext->DesiredLength -= DataLen;\r
+ DataSN++;\r
+ }\r
+ //\r
+ // Set the F bit for the last data out PDU in this sequence.\r
+ //\r
+ ISCSI_SET_FLAG (NetbufGetByte (DataOutPdu, 0, NULL), ISCSI_BHS_FLAG_FINAL);\r
+\r
+ON_EXIT:\r
+\r
+ return PduList;\r
+}\r
+\r
+/**\r
+ Send the Data in a sequence of Data Out PDUs one by one.\r
+\r
+ @param[in] Data The data to carry by Data Out PDUs.\r
+ @param[in] Lun The LUN the data will be sent to.\r
+ @param[in] Tcb The task control block.\r
+\r
+ @retval EFI_SUCCES The data is sent out to the LUN.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+ @retval Others Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiSendDataOutPduSequence (\r
+ IN UINT8 *Data,\r
+ IN UINT64 Lun,\r
+ IN ISCSI_TCB *Tcb\r
+ )\r
+{\r
+ LIST_ENTRY *DataOutPduList;\r
+ LIST_ENTRY *Entry;\r
+ NET_BUF *Pdu;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Generate the Data Out PDU sequence.\r
+ //\r
+ DataOutPduList = IScsiGenerateDataOutPduSequence (Data, Tcb, Lun);\r
+ if (DataOutPduList == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // Send the Data Out PDU's one by one.\r
+ //\r
+ NET_LIST_FOR_EACH (Entry, DataOutPduList) {\r
+ Pdu = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
+\r
+ Status = TcpIoTransmit (&Tcb->Conn->TcpIo, Pdu);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ IScsiFreeNbufList (DataOutPduList);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Process the received iSCSI SCSI Data In PDU.\r
+\r
+ @param[in] Pdu The Data In PDU received.\r
+ @param[in] Tcb The task control block.\r
+ @param[in, out] Packet The EXT SCSI PASS THRU request packet.\r
+\r
+ @retval EFI_SUCCES The check on the Data IN PDU is passed and some update\r
+ actions are taken.\r
+ @retval EFI_PROTOCOL_ERROR Some kind of iSCSI protocol errror occurred.\r
+ @retval EFI_BAD_BUFFER_SIZEE The buffer was not the proper size for the request.\r
+ @retval Others Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiOnDataInRcvd (\r
+ IN NET_BUF *Pdu,\r
+ IN ISCSI_TCB *Tcb,\r
+ IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet\r
+ )\r
+{\r
+ ISCSI_SCSI_DATA_IN *DataInHdr;\r
+ EFI_STATUS Status;\r
+\r
+ DataInHdr = (ISCSI_SCSI_DATA_IN *) NetbufGetByte (Pdu, 0, NULL);\r
+\r
+ DataInHdr->InitiatorTaskTag = NTOHL (DataInHdr->InitiatorTaskTag);\r
+ DataInHdr->ExpCmdSN = NTOHL (DataInHdr->ExpCmdSN);\r
+ DataInHdr->MaxCmdSN = NTOHL (DataInHdr->MaxCmdSN);\r
+ DataInHdr->DataSN = NTOHL (DataInHdr->DataSN);\r
+\r
+ //\r
+ // Check the DataSN.\r
+ //\r
+ Status = IScsiCheckSN (&Tcb->ExpDataSN, DataInHdr->DataSN);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (DataInHdr->InitiatorTaskTag != Tcb->InitiatorTaskTag) {\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+ //\r
+ // Update the command related sequence numbers.\r
+ //\r
+ IScsiUpdateCmdSN (Tcb->Conn->Session, DataInHdr->MaxCmdSN, DataInHdr->ExpCmdSN);\r
+\r
+ if (ISCSI_FLAG_ON (DataInHdr, SCSI_DATA_IN_PDU_FLAG_STATUS_VALID)) {\r
+ if (!ISCSI_FLAG_ON (DataInHdr, ISCSI_BHS_FLAG_FINAL)) {\r
+ //\r
+ // The S bit is on but the F bit is off.\r
+ //\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+\r
+ Tcb->StatusXferd = TRUE;\r
+\r
+ if (ISCSI_FLAG_ON (DataInHdr, SCSI_DATA_IN_PDU_FLAG_OVERFLOW | SCSI_DATA_IN_PDU_FLAG_UNDERFLOW)) {\r
+ //\r
+ // Underflow and Overflow are mutual flags.\r
+ //\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+ //\r
+ // S bit is on, the StatSN is valid.\r
+ //\r
+ Status = IScsiCheckSN (&Tcb->Conn->ExpStatSN, NTOHL (DataInHdr->StatSN));\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Packet->HostAdapterStatus = 0;\r
+ Packet->TargetStatus = DataInHdr->Status;\r
+\r
+ if (ISCSI_FLAG_ON (DataInHdr, SCSI_RSP_PDU_FLAG_OVERFLOW)) {\r
+ Packet->InTransferLength += NTOHL (DataInHdr->ResidualCount);\r
+ Status = EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ if (ISCSI_FLAG_ON (DataInHdr, SCSI_RSP_PDU_FLAG_UNDERFLOW)) {\r
+ Packet->InTransferLength -= NTOHL (DataInHdr->ResidualCount);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Process the received iSCSI R2T PDU.\r
+\r
+ @param[in] Pdu The R2T PDU received.\r
+ @param[in] Tcb The task control block.\r
+ @param[in] Lun The Lun.\r
+ @param[in, out] Packet The EXT SCSI PASS THRU request packet.\r
+\r
+ @retval EFI_SUCCES The R2T PDU is valid and the solicited data is sent out.\r
+ @retval EFI_PROTOCOL_ERROR Some kind of iSCSI protocol errror occurred.\r
+ @retval Others Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiOnR2TRcvd (\r
+ IN NET_BUF *Pdu,\r
+ IN ISCSI_TCB *Tcb,\r
+ IN UINT64 Lun,\r
+ IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet\r
+ )\r
+{\r
+ ISCSI_READY_TO_TRANSFER *R2THdr;\r
+ EFI_STATUS Status;\r
+ ISCSI_XFER_CONTEXT *XferContext;\r
+ UINT8 *Data;\r
+\r
+ R2THdr = (ISCSI_READY_TO_TRANSFER *) NetbufGetByte (Pdu, 0, NULL);\r
+\r
+ R2THdr->InitiatorTaskTag = NTOHL (R2THdr->InitiatorTaskTag);\r
+ R2THdr->TargetTransferTag = NTOHL (R2THdr->TargetTransferTag);\r
+ R2THdr->StatSN = NTOHL (R2THdr->StatSN);\r
+ R2THdr->R2TSeqNum = NTOHL (R2THdr->R2TSeqNum);\r
+ R2THdr->BufferOffset = NTOHL (R2THdr->BufferOffset);\r
+ R2THdr->DesiredDataTransferLength = NTOHL (R2THdr->DesiredDataTransferLength);\r
+\r
+ if ((R2THdr->InitiatorTaskTag != Tcb->InitiatorTaskTag) || !ISCSI_SEQ_EQ (R2THdr->StatSN, Tcb->Conn->ExpStatSN)) {\r
+ return EFI_PROTOCOL_ERROR;;\r
+ }\r
+ //\r
+ // Check the sequence number.\r
+ //\r
+ Status = IScsiCheckSN (&Tcb->ExpDataSN, R2THdr->R2TSeqNum);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ XferContext = &Tcb->XferContext;\r
+ XferContext->TargetTransferTag = R2THdr->TargetTransferTag;\r
+ XferContext->Offset = R2THdr->BufferOffset;\r
+ XferContext->DesiredLength = R2THdr->DesiredDataTransferLength;\r
+\r
+ if (((XferContext->Offset + XferContext->DesiredLength) > Packet->OutTransferLength) ||\r
+ (XferContext->DesiredLength > Tcb->Conn->Session->MaxBurstLength)\r
+ ) {\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+ //\r
+ // Send the data solicited by this R2T.\r
+ //\r
+ Data = (UINT8 *) Packet->OutDataBuffer + XferContext->Offset;\r
+ Status = IScsiSendDataOutPduSequence (Data, Lun, Tcb);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Process the received iSCSI SCSI Response PDU.\r
+\r
+ @param[in] Pdu The Response PDU received.\r
+ @param[in] Tcb The task control block.\r
+ @param[in, out] Packet The EXT SCSI PASS THRU request packet.\r
+\r
+ @retval EFI_SUCCES The Response PDU is processed.\r
+ @retval EFI_PROTOCOL_ERROR Some kind of iSCSI protocol errror occurred.\r
+ @retval EFI_BAD_BUFFER_SIZEE The buffer was not the proper size for the request.\r
+ @retval Others Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiOnScsiRspRcvd (\r
+ IN NET_BUF *Pdu,\r
+ IN ISCSI_TCB *Tcb,\r
+ IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet\r
+ )\r
+{\r
+ SCSI_RESPONSE *ScsiRspHdr;\r
+ ISCSI_SENSE_DATA *SenseData;\r
+ EFI_STATUS Status;\r
+ UINT32 DataSegLen;\r
+\r
+ ScsiRspHdr = (SCSI_RESPONSE *) NetbufGetByte (Pdu, 0, NULL);\r
+\r
+ ScsiRspHdr->InitiatorTaskTag = NTOHL (ScsiRspHdr->InitiatorTaskTag);\r
+ if (ScsiRspHdr->InitiatorTaskTag != Tcb->InitiatorTaskTag) {\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+\r
+ ScsiRspHdr->StatSN = NTOHL (ScsiRspHdr->StatSN);\r
+\r
+ Status = IScsiCheckSN (&Tcb->Conn->ExpStatSN, ScsiRspHdr->StatSN);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ ScsiRspHdr->MaxCmdSN = NTOHL (ScsiRspHdr->MaxCmdSN);\r
+ ScsiRspHdr->ExpCmdSN = NTOHL (ScsiRspHdr->ExpCmdSN);\r
+ IScsiUpdateCmdSN (Tcb->Conn->Session, ScsiRspHdr->MaxCmdSN, ScsiRspHdr->ExpCmdSN);\r
+\r
+ Tcb->StatusXferd = TRUE;\r
+\r
+ Packet->HostAdapterStatus = ScsiRspHdr->Response;\r
+ if (Packet->HostAdapterStatus != ISCSI_SERVICE_RSP_COMMAND_COMPLETE_AT_TARGET) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Packet->TargetStatus = ScsiRspHdr->Status;\r
+\r
+ if (ISCSI_FLAG_ON (ScsiRspHdr, SCSI_RSP_PDU_FLAG_BI_READ_OVERFLOW | SCSI_RSP_PDU_FLAG_BI_READ_UNDERFLOW) ||\r
+ ISCSI_FLAG_ON (ScsiRspHdr, SCSI_RSP_PDU_FLAG_OVERFLOW | SCSI_RSP_PDU_FLAG_UNDERFLOW)\r
+ ) {\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+\r
+ if (ISCSI_FLAG_ON (ScsiRspHdr, SCSI_RSP_PDU_FLAG_BI_READ_OVERFLOW)) {\r
+ Packet->InTransferLength += NTOHL (ScsiRspHdr->BiReadResidualCount);\r
+ Status = EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ if (ISCSI_FLAG_ON (ScsiRspHdr, SCSI_RSP_PDU_FLAG_BI_READ_UNDERFLOW)) {\r
+ Packet->InTransferLength -= NTOHL (ScsiRspHdr->BiReadResidualCount);\r
+ }\r
+\r
+ if (ISCSI_FLAG_ON (ScsiRspHdr, SCSI_RSP_PDU_FLAG_OVERFLOW)) {\r
+ if (Packet->DataDirection == DataIn) {\r
+ Packet->InTransferLength += NTOHL (ScsiRspHdr->ResidualCount);\r
+ } else {\r
+ Packet->OutTransferLength += NTOHL (ScsiRspHdr->ResidualCount);\r
+ }\r
+\r
+ Status = EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ if (ISCSI_FLAG_ON (ScsiRspHdr, SCSI_RSP_PDU_FLAG_UNDERFLOW)) {\r
+ if (Packet->DataDirection == DataIn) {\r
+ Packet->InTransferLength -= NTOHL (ScsiRspHdr->ResidualCount);\r
+ } else {\r
+ Packet->OutTransferLength -= NTOHL (ScsiRspHdr->ResidualCount);\r
+ }\r
+ }\r
+\r
+ DataSegLen = ISCSI_GET_DATASEG_LEN (ScsiRspHdr);\r
+ if (DataSegLen != 0) {\r
+ SenseData = (ISCSI_SENSE_DATA *) NetbufGetByte (Pdu, sizeof (SCSI_RESPONSE), NULL);\r
+\r
+ SenseData->Length = NTOHS (SenseData->Length);\r
+\r
+ Packet->SenseDataLength = (UINT8) MIN (SenseData->Length, Packet->SenseDataLength);\r
+ if (Packet->SenseDataLength != 0) {\r
+ CopyMem (Packet->SenseData, &SenseData->Data[0], Packet->SenseDataLength);\r
+ }\r
+ } else {\r
+ Packet->SenseDataLength = 0;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Process the received NOP In PDU.\r
+\r
+ @param[in] Pdu The NOP In PDU received.\r
+ @param[in] Tcb The task control block.\r
+\r
+ @retval EFI_SUCCES The NOP In PDU is processed and the related sequence\r
+ numbers are updated.\r
+ @retval EFI_PROTOCOL_ERROR Some kind of iSCSI protocol errror occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiOnNopInRcvd (\r
+ IN NET_BUF *Pdu,\r
+ IN ISCSI_TCB *Tcb\r
+ )\r
+{\r
+ ISCSI_NOP_IN *NopInHdr;\r
+ EFI_STATUS Status;\r
+\r
+ NopInHdr = (ISCSI_NOP_IN *) NetbufGetByte (Pdu, 0, NULL);\r
+\r
+ NopInHdr->StatSN = NTOHL (NopInHdr->StatSN);\r
+ NopInHdr->ExpCmdSN = NTOHL (NopInHdr->ExpCmdSN);\r
+ NopInHdr->MaxCmdSN = NTOHL (NopInHdr->MaxCmdSN);\r
+\r
+ if (NopInHdr->InitiatorTaskTag == ISCSI_RESERVED_TAG) {\r
+ if (NopInHdr->StatSN != Tcb->Conn->ExpStatSN) {\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+ } else {\r
+ Status = IScsiCheckSN (&Tcb->Conn->ExpStatSN, NopInHdr->StatSN);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ IScsiUpdateCmdSN (Tcb->Conn->Session, NopInHdr->MaxCmdSN, NopInHdr->ExpCmdSN);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Execute the SCSI command issued through the EXT SCSI PASS THRU protocol.\r
+\r
+ @param[in] PassThru The EXT SCSI PASS THRU protocol.\r
+ @param[in] Target The target ID.\r
+ @param[in] Lun The LUN.\r
+ @param[in, out] Packet The request packet containing IO request, SCSI command\r
+ buffer and buffers to read/write.\r
+ \r
+ @retval EFI_SUCCES The SCSI command is executed and the result is updated to \r
+ the Packet.\r
+ @retval EFI_DEVICE_ERROR Session state was not as required.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+ @retval Others Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiExecuteScsiCommand (\r
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 *Target,\r
+ IN UINT64 Lun,\r
+ IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ ISCSI_DRIVER_DATA *Private;\r
+ ISCSI_SESSION *Session;\r
+ EFI_EVENT TimeoutEvent;\r
+ ISCSI_CONNECTION *Conn;\r
+ ISCSI_TCB *Tcb;\r
+ NET_BUF *Pdu;\r
+ ISCSI_XFER_CONTEXT *XferContext;\r
+ UINT8 *Data;\r
+ ISCSI_IN_BUFFER_CONTEXT InBufferContext;\r
+ UINT64 Timeout;\r
+ UINT8 *PduHdr;\r
+\r
+ Private = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (PassThru);\r
+ Session = Private->Session;\r
+ Status = EFI_SUCCESS;\r
+ Tcb = NULL;\r
+ TimeoutEvent = NULL;\r
+ Timeout = 0;\r
+\r
+ if (Session->State != SESSION_STATE_LOGGED_IN) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Conn = NET_LIST_USER_STRUCT_S (\r
+ Session->Conns.ForwardLink,\r
+ ISCSI_CONNECTION,\r
+ Link,\r
+ ISCSI_CONNECTION_SIGNATURE\r
+ );\r
+\r
+ if (Packet->Timeout != 0) {\r
+ Timeout = MultU64x32 (Packet->Timeout, 4);\r
+ }\r
+\r
+ Status = IScsiNewTcb (Conn, &Tcb);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // Encapsulate the SCSI request packet into an iSCSI SCSI Command PDU.\r
+ //\r
+ Pdu = IScsiNewScsiCmdPdu (Packet, Lun, Tcb);\r
+ if (Pdu == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ XferContext = &Tcb->XferContext;\r
+ PduHdr = NetbufGetByte (Pdu, 0, NULL);\r
+ XferContext->Offset = ISCSI_GET_DATASEG_LEN (PduHdr);\r
+\r
+ //\r
+ // Transmit the SCSI Command PDU.\r
+ //\r
+ Status = TcpIoTransmit (&Conn->TcpIo, Pdu);\r
+\r
+ NetbufFree (Pdu);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (!Session->InitialR2T &&\r
+ (XferContext->Offset < Session->FirstBurstLength) &&\r
+ (XferContext->Offset < Packet->OutTransferLength)\r
+ ) {\r
+ //\r
+ // Unsolicited Data-Out sequence is allowed. There is remaining SCSI\r
+ // OUT data, and the limit of FirstBurstLength is not reached.\r
+ //\r
+ XferContext->TargetTransferTag = ISCSI_RESERVED_TAG;\r
+ XferContext->DesiredLength = MIN (\r
+ Session->FirstBurstLength,\r
+ Packet->OutTransferLength - XferContext->Offset\r
+ );\r
+\r
+ Data = (UINT8 *) Packet->OutDataBuffer + XferContext->Offset;\r
+ Status = IScsiSendDataOutPduSequence (Data, Lun, Tcb);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+ }\r
+\r
+ InBufferContext.InData = (UINT8 *) Packet->InDataBuffer;\r
+ InBufferContext.InDataLen = Packet->InTransferLength;\r
+\r
+ while (!Tcb->StatusXferd) {\r
+ //\r
+ // Start the timeout timer.\r
+ //\r
+ if (Timeout != 0) {\r
+ Status = gBS->SetTimer (Conn->TimeoutEvent, TimerRelative, Timeout);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ TimeoutEvent = Conn->TimeoutEvent;\r
+ }\r
+\r
+ //\r
+ // Try to receive PDU from target.\r
+ //\r
+ Status = IScsiReceivePdu (Conn, &Pdu, &InBufferContext, FALSE, FALSE, TimeoutEvent);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ switch (ISCSI_GET_OPCODE (NetbufGetByte (Pdu, 0, NULL))) {\r
+ case ISCSI_OPCODE_SCSI_DATA_IN:\r
+ Status = IScsiOnDataInRcvd (Pdu, Tcb, Packet);\r
+ break;\r
+\r
+ case ISCSI_OPCODE_R2T:\r
+ Status = IScsiOnR2TRcvd (Pdu, Tcb, Lun, Packet);\r
+ break;\r
+\r
+ case ISCSI_OPCODE_SCSI_RSP:\r
+ Status = IScsiOnScsiRspRcvd (Pdu, Tcb, Packet);\r
+ break;\r
+\r
+ case ISCSI_OPCODE_NOP_IN:\r
+ Status = IScsiOnNopInRcvd (Pdu, Tcb);\r
+ break;\r
+\r
+ case ISCSI_OPCODE_VENDOR_T0:\r
+ case ISCSI_OPCODE_VENDOR_T1:\r
+ case ISCSI_OPCODE_VENDOR_T2:\r
+ //\r
+ // These messages are vendor specific. Skip them.\r
+ //\r
+ break;\r
+\r
+ default:\r
+ Status = EFI_PROTOCOL_ERROR;\r
+ break;\r
+ }\r
+\r
+ NetbufFree (Pdu);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ON_EXIT:\r
+\r
+ if (TimeoutEvent != NULL) {\r
+ gBS->SetTimer (TimeoutEvent, TimerCancel, 0);\r
+ }\r
+\r
+ if (Tcb != NULL) {\r
+ IScsiDelTcb (Tcb);\r
+ }\r
+\r
+ if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_READY)) {\r
+ //\r
+ // Reinstate the session.\r
+ //\r
+ if (EFI_ERROR (IScsiSessionReinstatement (Session))) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Reinstate the session on some error.\r
+\r
+ @param[in] Session The iSCSI session\r
+\r
+ @retval EFI_SUCCESS The session is reinstated from some error.\r
+ @retval Other Reinstatement failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiSessionReinstatement (\r
+ IN ISCSI_SESSION *Session\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ ASSERT (Session->State == SESSION_STATE_LOGGED_IN);\r
+\r
+ //\r
+ // Abort the session and re-init it.\r
+ //\r
+ IScsiSessionAbort (Session);\r
+ IScsiSessionInit (Session, TRUE);\r
+\r
+ //\r
+ // Login again.\r
+ //\r
+ Status = IScsiSessionLogin (Session);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Initialize some session parameters before login.\r
+\r
+ @param[in, out] Session The iSCSI session.\r
+ @param[in] Recovery Whether the request is from a fresh new start or recovery.\r
+\r
+**/\r
+VOID\r
+IScsiSessionInit (\r
+ IN OUT ISCSI_SESSION *Session,\r
+ IN BOOLEAN Recovery\r
+ )\r
+{\r
+ if (!Recovery) {\r
+ Session->Signature = ISCSI_SESSION_SIGNATURE;\r
+ Session->State = SESSION_STATE_FREE;\r
+\r
+ InitializeListHead (&Session->Conns);\r
+ InitializeListHead (&Session->TcbList);\r
+ }\r
+\r
+ Session->Tsih = 0;\r
+\r
+ Session->CmdSN = 1;\r
+ Session->InitiatorTaskTag = 1;\r
+ Session->NextCid = 1;\r
+\r
+ Session->TargetPortalGroupTag = 0;\r
+ Session->MaxConnections = ISCSI_MAX_CONNS_PER_SESSION;\r
+ Session->InitialR2T = FALSE;\r
+ Session->ImmediateData = TRUE;\r
+ Session->MaxBurstLength = 262144;\r
+ Session->FirstBurstLength = MAX_RECV_DATA_SEG_LEN_IN_FFP;\r
+ Session->DefaultTime2Wait = 2;\r
+ Session->DefaultTime2Retain = 20;\r
+ Session->MaxOutstandingR2T = DEFAULT_MAX_OUTSTANDING_R2T;\r
+ Session->DataPDUInOrder = TRUE;\r
+ Session->DataSequenceInOrder = TRUE;\r
+ Session->ErrorRecoveryLevel = 0;\r
+}\r
+\r
+\r
+/**\r
+ Abort the iSCSI session. That is, reset all the connection(s), and free the\r
+ resources.\r
+\r
+ @param[in, out] Session The iSCSI session.\r
+\r
+**/\r
+VOID\r
+IScsiSessionAbort (\r
+ IN OUT ISCSI_SESSION *Session\r
+ )\r
+{\r
+ ISCSI_CONNECTION *Conn;\r
+ EFI_GUID *ProtocolGuid;\r
+\r
+ if (Session->State != SESSION_STATE_LOGGED_IN) {\r
+ return ;\r
+ }\r
+\r
+ ASSERT (!IsListEmpty (&Session->Conns));\r
+\r
+ while (!IsListEmpty (&Session->Conns)) {\r
+ Conn = NET_LIST_USER_STRUCT_S (\r
+ Session->Conns.ForwardLink,\r
+ ISCSI_CONNECTION,\r
+ Link,\r
+ ISCSI_CONNECTION_SIGNATURE\r
+ );\r
+ if (!Conn->Ipv6Flag) {\r
+ ProtocolGuid = &gEfiTcp4ProtocolGuid;\r
+ } else {\r
+ ProtocolGuid = &gEfiTcp6ProtocolGuid; \r
+ }\r
+\r
+ gBS->CloseProtocol (\r
+ Conn->TcpIo.Handle,\r
+ ProtocolGuid,\r
+ Session->Private->Image,\r
+ Session->Private->ExtScsiPassThruHandle\r
+ );\r
+\r
+ IScsiConnReset (Conn);\r
+\r
+ IScsiDetatchConnection (Conn);\r
+ IScsiDestroyConnection (Conn);\r
+ }\r
+\r
+ Session->State = SESSION_STATE_FAILED;\r
+\r
+ return ;\r
+}\r
--- /dev/null
+/** @file\r
+ The header file of iSCSI Protocol that defines many specific data structures.\r
+\r
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _ISCSI_PROTO_H_\r
+#define _ISCSI_PROTO_H_\r
+\r
+//\r
+// RFC 1982 Serial Number Arithmetic, SERIAL_BITS = 32\r
+//\r
+#define ISCSI_SEQ_EQ(s1, s2) ((s1) == (s2))\r
+#define ISCSI_SEQ_LT(s1, s2) \\r
+ ( \\r
+ (((INT32) (s1) < (INT32) (s2)) && (s2 - s1) < ((UINT32) 1 << 31)) || \\r
+ (((INT32) (s1) > (INT32) (s2)) && (s1 - s2) > ((UINT32) 1 << 31)) \\r
+ )\r
+#define ISCSI_SEQ_GT(s1, s2) \\r
+ ( \\r
+ (((INT32) (s1) < (INT32) (s2)) && (s2 - s1) > ((UINT32) 1 << 31)) || \\r
+ (((INT32) (s1) > (INT32) (s2)) && (s1 - s2) < ((UINT32) 1 << 31)) \\r
+ )\r
+\r
+#define ISCSI_WELL_KNOWN_PORT 3260\r
+#define ISCSI_MAX_CONNS_PER_SESSION 1\r
+\r
+#define DEFAULT_MAX_RECV_DATA_SEG_LEN 8192\r
+#define MAX_RECV_DATA_SEG_LEN_IN_FFP 65536\r
+#define DEFAULT_MAX_OUTSTANDING_R2T 1\r
+\r
+#define ISCSI_VERSION_MAX 0x00\r
+#define ISCSI_VERSION_MIN 0x00\r
+\r
+#define ISCSI_KEY_AUTH_METHOD "AuthMethod"\r
+#define ISCSI_KEY_HEADER_DIGEST "HeaderDigest"\r
+#define ISCSI_KEY_DATA_DIGEST "DataDigest"\r
+#define ISCSI_KEY_MAX_CONNECTIONS "MaxConnections"\r
+#define ISCSI_KEY_TARGET_NAME "TargetName"\r
+#define ISCSI_KEY_INITIATOR_NAME "InitiatorName"\r
+#define ISCSI_KEY_TARGET_ALIAS "TargetAlias"\r
+#define ISCSI_KEY_INITIATOR_ALIAS "InitiatorAlias"\r
+#define ISCSI_KEY_TARGET_ADDRESS "TargetAddress"\r
+#define ISCSI_KEY_INITIAL_R2T "InitialR2T"\r
+#define ISCSI_KEY_IMMEDIATE_DATA "ImmediateData"\r
+#define ISCSI_KEY_TARGET_PORTAL_GROUP_TAG "TargetPortalGroupTag"\r
+#define ISCSI_KEY_MAX_BURST_LENGTH "MaxBurstLength"\r
+#define ISCSI_KEY_FIRST_BURST_LENGTH "FirstBurstLength"\r
+#define ISCSI_KEY_DEFAULT_TIME2WAIT "DefaultTime2Wait"\r
+#define ISCSI_KEY_DEFAULT_TIME2RETAIN "DefaultTime2Retain"\r
+#define ISCSI_KEY_MAX_OUTSTANDING_R2T "MaxOutstandingR2T"\r
+#define ISCSI_KEY_DATA_PDU_IN_ORDER "DataPDUInOrder"\r
+#define ISCSI_KEY_DATA_SEQUENCE_IN_ORDER "DataSequenceInOrder"\r
+#define ISCSI_KEY_ERROR_RECOVERY_LEVEL "ErrorRecoveryLevel"\r
+#define ISCSI_KEY_SESSION_TYPE "SessionType"\r
+#define ISCSI_KEY_MAX_RECV_DATA_SEGMENT_LENGTH "MaxRecvDataSegmentLength"\r
+\r
+#define ISCSI_KEY_VALUE_NONE "None"\r
+\r
+///\r
+/// connection state for initiator\r
+///\r
+\r
+#define CONN_STATE_FREE 0\r
+#define CONN_STATE_XPT_WAIT 1\r
+#define CONN_STATE_IN_LOGIN 2\r
+#define CONN_STATE_LOGGED_IN 3\r
+#define CONN_STATE_IN_LOGOUT 4\r
+#define CONN_STATE_LOGOUT_REQUESTED 5\r
+#define CONN_STATE_CLEANUP_WAIT 6\r
+#define CONN_STATE_IN_CLEANUP 7\r
+\r
+///\r
+/// session state for initiator\r
+///\r
+#define SESSION_STATE_FREE 0\r
+#define SESSION_STATE_LOGGED_IN 1\r
+#define SESSION_STATE_FAILED 2\r
+\r
+#define ISCSI_RESERVED_TAG 0xffffffff\r
+\r
+#define ISCSI_REQ_IMMEDIATE 0x40\r
+#define ISCSI_OPCODE_MASK 0x3F\r
+\r
+#define ISCSI_SET_OPCODE(PduHdr, Op, Flgs) ((((ISCSI_BASIC_HEADER *) (PduHdr))->OpCode) = ((Op) | (Flgs)))\r
+#define ISCSI_GET_OPCODE(PduHdr) ((((ISCSI_BASIC_HEADER *) (PduHdr))->OpCode) & ISCSI_OPCODE_MASK)\r
+#define ISCSI_CHECK_OPCODE(PduHdr, Op) ((((PduHdr)->OpCode) & ISCSI_OPCODE_MASK) == (Op))\r
+#define ISCSI_IMMEDIATE_ON(PduHdr) ((PduHdr)->OpCode & ISCSI_REQ_IMMEDIATE)\r
+#define ISCSI_SET_FLAG(PduHdr, Flag) (((ISCSI_BASIC_HEADER *) (PduHdr))->Flags |= (BOOLEAN)(Flag))\r
+#define ISCSI_CLEAR_FLAG(PduHdr, Flag) (((ISCSI_BASIC_HEADER *) (PduHdr))->Flags &= ~(Flag))\r
+#define ISCSI_FLAG_ON(PduHdr, Flag) ((BOOLEAN) ((((ISCSI_BASIC_HEADER *) (PduHdr))->Flags & (Flag)) == (Flag)))\r
+#define ISCSI_SET_STAGES(PduHdr, Cur, Nxt) ((PduHdr)->Flags = (UINT8) ((PduHdr)->Flags | ((Cur) << 2 | (Nxt))))\r
+#define ISCSI_GET_CURRENT_STAGE(PduHdr) ((UINT8) (((PduHdr)->Flags >> 2) & 0x3))\r
+#define ISCSI_GET_NEXT_STAGE(PduHdr) ((UINT8) (((PduHdr)->Flags) & 0x3))\r
+\r
+#define ISCSI_GET_PAD_LEN(DataLen) ((~(DataLen) + 1) & 0x3)\r
+#define ISCSI_ROUNDUP(DataLen) (((DataLen) + 3) &~(0x3))\r
+\r
+#define HTON24(Dst, Src) \\r
+ do { \\r
+ (Dst)[0] = (UINT8) ((UINT8) ((Src) >> 16) & 0xFF); \\r
+ (Dst)[1] = (UINT8) ((UINT8) ((Src) >> 8) & 0xFF); \\r
+ (Dst)[2] = (UINT8) ((UINT8) (Src) & 0xFF); \\r
+ } while (0);\r
+\r
+#define NTOH24(src) (((src)[0] << 16) | ((src)[1] << 8) | ((src)[2]))\r
+\r
+#define ISCSI_GET_DATASEG_LEN(PduHdr) NTOH24 (((ISCSI_BASIC_HEADER *) (PduHdr))->DataSegmentLength)\r
+#define ISCSI_SET_DATASEG_LEN(PduHdr, Len) HTON24 (((ISCSI_BASIC_HEADER *) (PduHdr))->DataSegmentLength, (Len))\r
+#define ISCSI_GET_BUFFER_OFFSET(PduHdr) NTOHL (((ISCSI_SCSI_DATA_IN *) (PduHdr))->BufferOffset)\r
+\r
+//\r
+// Initiator opcodes.\r
+//\r
+#define ISCSI_OPCODE_NOP_OUT 0x00\r
+#define ISCSI_OPCODE_SCSI_CMD 0x01\r
+#define ISCSI_OPCODE_SCSI_TMF_REQ 0x02\r
+#define ISCSI_OPCODE_LOGIN_REQ 0x03\r
+#define ISCSI_OPCODE_TEXT_REQ 0x04\r
+#define ISCSI_OPCODE_SCSI_DATA_OUT 0x05\r
+#define ISCSI_OPCODE_LOGOUT_REQ 0x06\r
+#define ISCSI_OPCODE_SNACK_REQ 0x10\r
+#define ISCSI_OPCODE_VENDOR_I0 0x1c\r
+#define ISCSI_OPCODE_VENDOR_I1 0x1d\r
+#define ISCSI_OPCODE_VENDOR_I2 0x1e\r
+\r
+//\r
+// Target opcodes.\r
+//\r
+#define ISCSI_OPCODE_NOP_IN 0x20\r
+#define ISCSI_OPCODE_SCSI_RSP 0x21\r
+#define ISCSI_OPCODE_SCSI_TMF_RSP 0x22\r
+#define ISCSI_OPCODE_LOGIN_RSP 0x23\r
+#define ISCSI_OPCODE_TEXT_RSP 0x24\r
+#define ISCSI_OPCODE_SCSI_DATA_IN 0x25\r
+#define ISCSI_OPCODE_LOGOUT_RSP 0x26\r
+#define ISCSI_OPCODE_R2T 0x31\r
+#define ISCSI_OPCODE_ASYNC_MSG 0x32\r
+#define ISCSI_OPCODE_VENDOR_T0 0x3c\r
+#define ISCSI_OPCODE_VENDOR_T1 0x3d\r
+#define ISCSI_OPCODE_VENDOR_T2 0x3e\r
+#define ISCSI_OPCODE_REJECT 0x3f\r
+\r
+#define ISCSI_BHS_FLAG_FINAL 0x80\r
+\r
+//\r
+// Defined AHS types, others are reserved.\r
+//\r
+#define ISCSI_AHS_TYPE_EXT_CDB 0x1\r
+#define ISCSI_AHS_TYPE_BI_EXP_READ_DATA_LEN 0x2\r
+\r
+#define SCSI_CMD_PDU_FLAG_READ 0x40\r
+#define SCSI_CMD_PDU_FLAG_WRITE 0x20\r
+\r
+#define ISCSI_CMD_PDU_TASK_ATTR_MASK 0x07\r
+\r
+//\r
+// task attributes\r
+//\r
+#define ISCSI_TASK_ATTR_UNTAGGED 0x00\r
+#define ISCSI_TASK_ATTR_SIMPLE 0x01\r
+#define ISCSI_TASK_ATTR_ORDERD 0x02\r
+#define ISCSI_TASK_ATTR_HOQ 0x03\r
+#define ISCSI_TASK_ATTR_ACA 0x04\r
+\r
+//\r
+// Flag bit definitions in SCSI response.\r
+//\r
+#define SCSI_RSP_PDU_FLAG_BI_READ_OVERFLOW 0x10\r
+#define SCSI_RSP_PDU_FLAG_BI_READ_UNDERFLOW 0x08\r
+#define SCSI_RSP_PDU_FLAG_OVERFLOW 0x04\r
+#define SCSI_RSP_PDU_FLAG_UNDERFLOW 0x02\r
+\r
+//\r
+// iSCSI service response codes.\r
+//\r
+#define ISCSI_SERVICE_RSP_COMMAND_COMPLETE_AT_TARGET 0x00\r
+#define ISCSI_SERVICE_RSP_TARGET_FAILURE 0x01\r
+\r
+#define ISCSI_TMF_RSP_PDU_RSP_FUNCTION_COMPLETE 0\r
+#define ISCSI_TMF_RSP_PDU_RSP_TASK_NOT_EXIST 1\r
+#define ISCSI_TMF_RSP_PDU_RSP_LUN_NOT_EXIST 2\r
+#define ISCSI_TMF_RSP_PDU_RSP_TASK_STILL_ALLEGIANT 3\r
+#define ISCSI_TMF_RSP_PDU_RSP_TASK_REASSGIN_NOT_SUPPORTED 4\r
+#define ISCSI_TMF_RSP_PDU_RSP_NOT_SUPPORTED 5\r
+#define ISCSI_TMF_RSP_PDU_RSP_FUNCTION_AHTH_FAILED 6\r
+#define ISCSI_TMF_RSP_PDU_RSP_FUNCTION_REJECTED 255\r
+\r
+#define SCSI_DATA_IN_PDU_FLAG_ACKKNOWLEDGE 0x40\r
+#define SCSI_DATA_IN_PDU_FLAG_OVERFLOW SCSI_RSP_PDU_FLAG_OVERFLOW\r
+#define SCSI_DATA_IN_PDU_FLAG_UNDERFLOW SCSI_RSP_PDU_FLAG_UNDERFLOW\r
+#define SCSI_DATA_IN_PDU_FLAG_STATUS_VALID 0x01\r
+\r
+#define ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT 0x80\r
+#define ISCSI_LOGIN_REQ_PDU_FLAG_CONTINUE 0x40\r
+\r
+#define ISCSI_LOGIN_RSP_PDU_FLAG_TRANSIT ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT\r
+#define ISCSI_LOGIN_RSP_PDU_FLAG_CONTINUE ISCSI_LOGIN_REQ_PDU_FLAG_CONTINUE\r
+\r
+#define ISCSI_LOGIN_STATUS_SUCCESS 0\r
+#define ISCSI_LOGIN_STATUS_REDIRECTION 1\r
+#define ISCSI_LOGIN_STATUS_INITIATOR_ERROR 2\r
+#define ISCSI_LOGIN_STATUS_TARGET_ERROR 3\r
+\r
+#define ISCSI_LOGOUT_REASON_CLOSE_SESSION 0\r
+#define ISCSI_LOGOUT_REASON_CLOSE_CONNECTION 1\r
+#define ISCSI_LOGOUT_REASON_REMOVE_CONNECTION_FOR_RECOVERY 2\r
+\r
+#define ISCSI_LOGOUT_RESPONSE_SESSION_CLOSED_SUCCESS 0\r
+#define ISCSI_LOGOUT_RESPONSE_CID_NOT_FOUND 1\r
+#define ISCSI_LOGOUT_RESPONSE_RECOVERY_NOT_SUPPORTED 2\r
+#define ISCSI_LOGOUT_RESPONSE_CLEANUP_FAILED 3\r
+\r
+#define ISCSI_SNACK_REQUEST_TYPE_DATA_OR_R2T 0\r
+#define ISCSI_SNACK_REQUEST_TYPE_STATUS 1\r
+#define ISCSI_SNACK_REQUEST_TYPE_DATA_ACK 2\r
+#define ISCSI_SNACK_REQUEST_TYPE_RDATA 3\r
+\r
+#define ISCSI_SECURITY_NEGOTIATION 0\r
+#define ISCSI_LOGIN_OPERATIONAL_NEGOTIATION 1\r
+#define ISCSI_FULL_FEATURE_PHASE 3\r
+\r
+typedef struct _ISCSI_SESSION ISCSI_SESSION;\r
+typedef struct _ISCSI_CONNECTION ISCSI_CONNECTION;\r
+\r
+typedef enum {\r
+ DataIn = 0,\r
+ DataOut = 1,\r
+ DataBi = 2\r
+} DATA_DIRECTION;\r
+\r
+///\r
+/// iSCSI Basic Header Segment\r
+///\r
+typedef struct _ISCSI_BASIC_HEADER {\r
+ UINT8 OpCode;\r
+ UINT8 Flags;\r
+ UINT16 OpCodeSpecific1;\r
+ UINT8 TotalAHSLength;\r
+ UINT8 DataSegmentLength[3];\r
+ UINT8 Lun[8];\r
+ UINT32 InitiatorTaskTag;\r
+ UINT32 OpCodeSpecific2[7];\r
+} ISCSI_BASIC_HEADER;\r
+\r
+typedef struct _ISCSI_ADDTIONAL_HEADER {\r
+ UINT16 Length;\r
+ UINT8 Type;\r
+ UINT8 TypeSpecific[1];\r
+} ISCSI_ADDITIONAL_HEADER;\r
+\r
+typedef struct _ISCSI_BI_EXP_READ_DATA_LEN_AHS {\r
+ UINT16 Length;\r
+ UINT8 Type;\r
+ UINT8 Reserved;\r
+ UINT32 ExpReadDataLength;\r
+} ISCSI_BI_EXP_READ_DATA_LEN_AHS;\r
+\r
+///\r
+/// SCSI Command\r
+///\r
+typedef struct _SCSI_COMMAND {\r
+ UINT8 OpCode;\r
+ UINT8 Flags;\r
+ UINT16 Reserved;\r
+ UINT8 TotalAHSLength;\r
+ UINT8 DataSegmentLength[3];\r
+ UINT8 Lun[8];\r
+ UINT32 InitiatorTaskTag;\r
+ UINT32 ExpDataXferLength;\r
+ UINT32 CmdSN;\r
+ UINT32 ExpStatSN;\r
+ UINT8 Cdb[16];\r
+} SCSI_COMMAND;\r
+\r
+///\r
+/// SCSI Response\r
+///\r
+typedef struct _SCSI_RESPONSE {\r
+ UINT8 OpCode;\r
+ UINT8 Flags;\r
+ UINT8 Response;\r
+ UINT8 Status;\r
+ UINT8 TotalAHSLength;\r
+ UINT8 DataSegmentLength[3];\r
+ UINT8 Reserved[8];\r
+ UINT32 InitiatorTaskTag;\r
+ UINT32 SNACKTag;\r
+ UINT32 StatSN;\r
+ UINT32 ExpCmdSN;\r
+ UINT32 MaxCmdSN;\r
+ UINT32 ExpDataSN;\r
+ UINT32 BiReadResidualCount;\r
+ UINT32 ResidualCount;\r
+} SCSI_RESPONSE;\r
+\r
+typedef struct _ISCSI_SENSE_DATA {\r
+ UINT16 Length;\r
+ UINT8 Data[2];\r
+} ISCSI_SENSE_DATA;\r
+\r
+///\r
+/// iSCSI Task Managment Function Request.\r
+///\r
+typedef struct _ISCSI_TMF_REQUEST {\r
+ UINT8 OpCode;\r
+ UINT8 Fuction;\r
+ UINT16 Reserved1;\r
+ UINT8 TotalAHSLength;\r
+ UINT8 DataSegmentLength[3];\r
+ UINT8 Lun[8];\r
+ UINT32 InitiatorTaskTag;\r
+ UINT32 ReferencedTaskTag;\r
+ UINT32 CmdSN;\r
+ UINT32 ExpStatSN;\r
+ UINT32 RefCmdSN;\r
+ UINT32 ExpDataSN;\r
+ UINT32 Reserved2[2];\r
+} ISCSI_TMF_REQUEST;\r
+\r
+///\r
+/// iSCSI Task Management Function Response.\r
+///\r
+typedef struct _ISCSI_TMF_RESPONSE {\r
+ UINT8 OpCode;\r
+ UINT8 Reserved1;\r
+ UINT8 Response;\r
+ UINT8 Reserved2;\r
+ UINT8 TotalAHSLength;\r
+ UINT8 DataSegmentLength[3];\r
+ UINT32 Reserver3[2];\r
+ UINT32 InitiatorTaskTag;\r
+ UINT32 Reserved4;\r
+ UINT32 StatSN;\r
+ UINT32 ExpCmdSN;\r
+ UINT32 MaxCmdSN;\r
+ UINT32 Reserved[3];\r
+} ISCSI_TMF_RESPONSE;\r
+\r
+///\r
+/// SCSI Data-Out\r
+///\r
+typedef struct _ISCSI_SCSI_DATA_OUT {\r
+ UINT8 OpCode;\r
+ UINT8 Reserved1[3];\r
+ UINT8 TotalAHSLength;\r
+ UINT8 DataSegmentLength[3];\r
+ UINT8 Lun[8];\r
+ UINT32 InitiatorTaskTag;\r
+ UINT32 TargetTransferTag;\r
+ UINT32 Reserved2;\r
+ UINT32 ExpStatSN;\r
+ UINT32 Reserved3;\r
+ UINT32 DataSN;\r
+ UINT32 BufferOffset;\r
+ UINT32 Reserved4;\r
+} ISCSI_SCSI_DATA_OUT;\r
+\r
+///\r
+/// SCSI Data-In\r
+///\r
+typedef struct _ISCSI_SCSI_DATA_IN {\r
+ UINT8 OpCode;\r
+ UINT8 Flags;\r
+ UINT8 Reserved1;\r
+ UINT8 Status;\r
+ UINT8 TotalAHSLength;\r
+ UINT8 DataSegmentLength[3];\r
+ UINT8 Lun[8];\r
+ UINT32 InitiatorTaskTag;\r
+ UINT32 TargetTransferTag;\r
+ UINT32 StatSN;\r
+ UINT32 ExpCmdSN;\r
+ UINT32 MaxCmdSN;\r
+ UINT32 DataSN;\r
+ UINT32 BufferOffset;\r
+ UINT32 ResidualCount;\r
+} ISCSI_SCSI_DATA_IN;\r
+\r
+///\r
+/// Ready To Transfer.\r
+///\r
+typedef struct _ISCSI_READY_TO_TRANSFER {\r
+ UINT8 OpCode;\r
+ UINT8 Reserved1[3];\r
+ UINT8 TotalAHSLength;\r
+ UINT8 DataSegmentLength[3];\r
+ UINT8 Lun[8];\r
+ UINT32 InitiatorTaskTag;\r
+ UINT32 TargetTransferTag;\r
+ UINT32 StatSN;\r
+ UINT32 ExpCmdSN;\r
+ UINT32 MaxCmdSN;\r
+ UINT32 R2TSeqNum;\r
+ UINT32 BufferOffset;\r
+ UINT32 DesiredDataTransferLength;\r
+} ISCSI_READY_TO_TRANSFER;\r
+\r
+typedef struct _ISCSI_ASYNC_MESSAGE {\r
+ UINT8 OpCode;\r
+ UINT8 Reserved1[8];\r
+ UINT8 TotalAHSLength;\r
+ UINT8 DataSegmentLength[3];\r
+ UINT8 Lun[8];\r
+ UINT32 InitiatorTaskTag;\r
+ UINT32 Reserved2;\r
+ UINT32 StatSN;\r
+ UINT32 ExpCmdSN;\r
+ UINT32 MaxCmdSN;\r
+ UINT8 AsyncEvent;\r
+ UINT8 AsyncVCode;\r
+ UINT16 Parameter1;\r
+ UINT16 Parameter2;\r
+ UINT16 Parameter3;\r
+ UINT32 Reserved3;\r
+} ISCSI_ASYNC_MESSAGE;\r
+\r
+///\r
+/// Login Request.\r
+///\r
+typedef struct _ISCSI_LOGIN_REQUEST {\r
+ UINT8 OpCode;\r
+ UINT8 Flags;\r
+ UINT8 VersionMax;\r
+ UINT8 VersionMin;\r
+ UINT8 TotalAHSLength;\r
+ UINT8 DataSegmentLength[3];\r
+ UINT8 Isid[6];\r
+ UINT16 Tsih;\r
+ UINT32 InitiatorTaskTag;\r
+ UINT16 Cid;\r
+ UINT16 Reserved1;\r
+ UINT32 CmdSN;\r
+ UINT32 ExpStatSN;\r
+ UINT32 Reserved2[4];\r
+} ISCSI_LOGIN_REQUEST;\r
+\r
+///\r
+/// Login Response.\r
+///\r
+typedef struct _ISCSI_LOGIN_RESPONSE {\r
+ UINT8 OpCode;\r
+ UINT8 Flags;\r
+ UINT8 VersionMax;\r
+ UINT8 VersionActive;\r
+ UINT8 TotalAHSLength;\r
+ UINT8 DataSegmentLength[3];\r
+ UINT8 Isid[6];\r
+ UINT16 Tsih;\r
+ UINT32 InitiatorTaskTag;\r
+ UINT32 Reserved1;\r
+ UINT32 StatSN;\r
+ UINT32 ExpCmdSN;\r
+ UINT32 MaxCmdSN;\r
+ UINT8 StatusClass;\r
+ UINT8 StatusDetail;\r
+ UINT8 Reserved2[10];\r
+} ISCSI_LOGIN_RESPONSE;\r
+\r
+///\r
+/// Logout Request.\r
+///\r
+typedef struct _ISCSI_LOGOUT_REQUEST {\r
+ UINT8 OpCode;\r
+ UINT8 ReasonCode;\r
+ UINT16 Reserved1;\r
+ UINT8 TotalAHSLength;\r
+ UINT8 DataSegmentLength[3];\r
+ UINT32 Reserved2[2];\r
+ UINT32 InitiatorTaskTag;\r
+ UINT16 Cid;\r
+ UINT16 Reserved3;\r
+ UINT32 CmdSN;\r
+ UINT32 ExpStatSN;\r
+ UINT32 Reserved4[4];\r
+} ISCSI_LOGOUT_REQUEST;\r
+\r
+///\r
+/// Logout Response.\r
+///\r
+typedef struct _ISCSI_LOGOUT_RESPONSE {\r
+ UINT8 OpCode;\r
+ UINT8 Reserved1;\r
+ UINT8 Response;\r
+ UINT8 Reserved2;\r
+ UINT8 TotalAHSLength;\r
+ UINT8 DataSegmentLength[3];\r
+ UINT32 Reserved3[2];\r
+ UINT32 InitiatorTaskTag;\r
+ UINT32 Reserved4;\r
+ UINT32 StatSN;\r
+ UINT32 ExpCmdSN;\r
+ UINT32 MaxCmdSN;\r
+ UINT32 Reserved5;\r
+ UINT16 Time2Wait;\r
+ UINT16 Time2Retain;\r
+ UINT32 Reserved6;\r
+} ISCSI_LOGOUT_RESPONSE;\r
+\r
+///\r
+/// SNACK Request.\r
+///\r
+typedef struct _ISCSI_SNACK_REQUEST {\r
+ UINT8 OpCode;\r
+ UINT8 Type;\r
+ UINT16 Reserved1;\r
+ UINT8 TotalAHSLength;\r
+ UINT8 DataSegmentLength[3];\r
+ UINT8 Lun[8];\r
+ UINT32 InitiatorTaskTag;\r
+ UINT32 TargetTransferTag;\r
+ UINT32 Reserved2;\r
+ UINT32 ExpStatSN;\r
+ UINT32 Reserved[2];\r
+ UINT32 BegRun;\r
+ UINT32 RunLength;\r
+} ISCSI_SNACK_REQUEST;\r
+\r
+///\r
+/// Reject.\r
+///\r
+typedef struct _ISCSI_REJECT {\r
+ UINT8 OpCode;\r
+ UINT8 Reserved1;\r
+ UINT8 Reason;\r
+ UINT8 Reserved2;\r
+ UINT8 TotalAHSLength;\r
+ UINT8 DataSegmentLength[3];\r
+ UINT32 Reserved3[2];\r
+ UINT32 InitiatorTaskTag;\r
+ UINT32 Reserved4;\r
+ UINT32 StatSN;\r
+ UINT32 ExpCmdSN;\r
+ UINT32 MaxCmdSN;\r
+ UINT32 DataSN;\r
+ UINT32 Reserved5[2];\r
+} ISCSI_REJECT;\r
+\r
+///\r
+/// NOP-Out.\r
+///\r
+typedef struct _ISCSI_NOP_OUT {\r
+ UINT8 OpCode;\r
+ UINT8 Reserved1[3];\r
+ UINT8 TotalAHSLength;\r
+ UINT8 DataSegmentLength[3];\r
+ UINT8 Lun[8];\r
+ UINT32 InitiatorTaskTag;\r
+ UINT32 TargetTransferTag;\r
+ UINT32 CmdSN;\r
+ UINT32 ExpStatSN;\r
+ UINT32 Reserved2[4];\r
+} ISCSI_NOP_OUT;\r
+\r
+///\r
+/// NOP-In.\r
+///\r
+typedef struct _ISCSI_NOP_IN {\r
+ UINT8 OpCode;\r
+ UINT8 Reserved1[3];\r
+ UINT8 TotalAHSLength;\r
+ UINT8 DataSegmentLength[3];\r
+ UINT8 Lun[8];\r
+ UINT32 InitiatorTaskTag;\r
+ UINT32 TargetTransferTag;\r
+ UINT32 StatSN;\r
+ UINT32 ExpCmdSN;\r
+ UINT32 MaxCmdSN;\r
+ UINT32 Reserved2[3];\r
+} ISCSI_NOP_IN;\r
+\r
+typedef enum {\r
+ IScsiDigestNone,\r
+ IScsiDigestCRC32\r
+} ISCSI_DIGEST_TYPE;\r
+\r
+typedef struct _ISCSI_XFER_CONTEXT {\r
+ UINT32 TargetTransferTag;\r
+ UINT32 Offset;\r
+ UINT32 DesiredLength;\r
+ UINT32 ExpDataSN;\r
+} ISCSI_XFER_CONTEXT;\r
+\r
+typedef struct _ISCSI_IN_BUFFER_CONTEXT {\r
+ UINT8 *InData;\r
+ UINT32 InDataLen;\r
+} ISCSI_IN_BUFFER_CONTEXT;\r
+\r
+typedef struct _ISCSI_TCB {\r
+ LIST_ENTRY Link;\r
+\r
+ BOOLEAN SoFarInOrder;\r
+ UINT32 ExpDataSN;\r
+ BOOLEAN FbitReceived;\r
+ BOOLEAN StatusXferd;\r
+ UINT32 ActiveR2Ts;\r
+ UINT32 Response;\r
+ CHAR8 *Reason;\r
+ UINT32 InitiatorTaskTag;\r
+ UINT32 CmdSN;\r
+ UINT32 SNACKTag;\r
+\r
+ ISCSI_XFER_CONTEXT XferContext;\r
+\r
+ ISCSI_CONNECTION *Conn;\r
+} ISCSI_TCB;\r
+\r
+typedef struct _ISCSI_KEY_VALUE_PAIR {\r
+ LIST_ENTRY List;\r
+\r
+ CHAR8 *Key;\r
+ CHAR8 *Value;\r
+} ISCSI_KEY_VALUE_PAIR;\r
+\r
+/**\r
+ Attach the iSCSI connection to the iSCSI session. \r
+\r
+ @param[in, out] Session The iSCSI session.\r
+ @param[in, out] Conn The iSCSI connection.\r
+\r
+**/\r
+VOID\r
+IScsiAttatchConnection (\r
+ IN OUT ISCSI_SESSION *Session,\r
+ IN OUT ISCSI_CONNECTION *Conn\r
+ );\r
+\r
+/**\r
+ Detach the iSCSI connection from the session it belongs to. \r
+\r
+ @param[in, out] Conn The iSCSI connection.\r
+\r
+**/\r
+VOID\r
+IScsiDetatchConnection (\r
+ IN OUT ISCSI_CONNECTION *Conn\r
+ );\r
+\r
+/**\r
+ This function performs the iSCSI connection login.\r
+\r
+ @param[in, out] Conn The iSCSI connection to login.\r
+ @param Timeout The timeout value in milliseconds.\r
+\r
+ @retval EFI_SUCCESS The iSCSI connection is logged into the iSCSI target.\r
+ @retval EFI_TIMEOUT Timeout occurred during the login procedure.\r
+ @retval Others Other errors as indicated. \r
+\r
+**/\r
+EFI_STATUS\r
+IScsiConnLogin (\r
+ IN OUT ISCSI_CONNECTION *Conn,\r
+ IN UINT16 Timeout\r
+ );\r
+\r
+/**\r
+ Create a TCP connection for the iSCSI session.\r
+\r
+ @param[in] Session Points to the iSCSI session.\r
+\r
+ @return The newly created iSCSI connection.\r
+\r
+**/\r
+ISCSI_CONNECTION *\r
+IScsiCreateConnection (\r
+ IN ISCSI_SESSION *Session\r
+ );\r
+\r
+/**\r
+ Destroy an iSCSI connection.\r
+\r
+ @param[in] Conn The connection to destroy.\r
+\r
+**/\r
+VOID\r
+IScsiDestroyConnection (\r
+ IN ISCSI_CONNECTION *Conn\r
+ );\r
+\r
+/**\r
+ Login the iSCSI session.\r
+\r
+ @param[in] Session The iSCSI session\r
+\r
+ @retval EFI_SUCCESS The iSCSI session login procedure finished.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+ @retval EFI_NO_MEDIA There was a media error.\r
+ @retval Others Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiSessionLogin (\r
+ IN ISCSI_SESSION *Session\r
+ );\r
+\r
+/**\r
+ Wait for IPsec negotiation, then try to login the iSCSI session again.\r
+\r
+ @param[in] Session The iSCSI session\r
+\r
+ @retval EFI_SUCCESS The iSCSI session login procedure finished.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+ @retval EFI_PROTOCOL_ERROR Some kind of iSCSI protocol error happened.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiSessionReLogin (\r
+ IN ISCSI_SESSION *Session\r
+ );\r
+\r
+/**\r
+ Build and send the iSCSI login request to the iSCSI target according to\r
+ the current login stage.\r
+\r
+ @param[in] Conn The connection in the iSCSI login phase.\r
+\r
+ @retval EFI_SUCCESS The iSCSI login request PDU is built and sent on this\r
+ connection.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+ @retval EFI_DEVICE_ERROR Some kind of device error happened.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiSendLoginReq (\r
+ IN ISCSI_CONNECTION *Conn\r
+ );\r
+\r
+/**\r
+ Receive and process the iSCSI login response.\r
+\r
+ @param[in] Conn The connection in the iSCSI login phase.\r
+ \r
+ @retval EFI_SUCCESS The iSCSI login response PDU is received and processed.\r
+ @retval Others Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiReceiveLoginRsp (\r
+ IN ISCSI_CONNECTION *Conn\r
+ );\r
+\r
+/**\r
+ Add an iSCSI key-value pair as a string into the data segment of the Login Request PDU.\r
+ The DataSegmentLength and the actual size of the net buffer containing this PDU will be\r
+ updated.\r
+\r
+ @param[in, out] Pdu The iSCSI PDU whose data segment the key-value pair will\r
+ be added to.\r
+ @param[in] Key The key name string.\r
+ @param[in] Value The value string.\r
+\r
+ @retval EFI_SUCCESS The key-valu pair is added to the PDU's datasegment and\r
+ the correspondence length fields are updated.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough space in the PDU to add the key-value\r
+ pair.\r
+**/\r
+EFI_STATUS\r
+IScsiAddKeyValuePair (\r
+ IN OUT NET_BUF *Pdu,\r
+ IN CHAR8 *Key,\r
+ IN CHAR8 *Value\r
+ );\r
+\r
+/**\r
+ Prepare the iSCSI login request to be sent according to the current login status.\r
+\r
+ @param[in, out] Conn The connection in the iSCSI login phase.\r
+\r
+ @return The pointer to the net buffer containing the iSCSI login request built.\r
+ @retval NULL Other errors as indicated.\r
+\r
+**/\r
+NET_BUF *\r
+IScsiPrepareLoginReq (\r
+ IN OUT ISCSI_CONNECTION *Conn\r
+ );\r
+\r
+/**\r
+ Process the iSCSI Login Response.\r
+\r
+ @param[in, out] Conn The connection on which the iSCSI login response is received.\r
+ @param[in, out] Pdu The iSCSI login response PDU.\r
+\r
+ @retval EFI_SUCCESS The iSCSI login response PDU is processed and all check are passed.\r
+ @retval EFI_PROTOCOL_ERROR Some kind of iSCSI protocol error happened.\r
+ @retval EFI_MEDIA_CHANGED Target is redirected.\r
+ @retval Others Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiProcessLoginRsp (\r
+ IN OUT ISCSI_CONNECTION *Conn,\r
+ IN OUT NET_BUF *Pdu\r
+ );\r
+\r
+/**\r
+ Updated the target information according the data received in the iSCSI\r
+ login response with an target redirection status.\r
+\r
+ @param[in, out] Session The iSCSI session.\r
+ @param[in] Data The data segment which should contain the\r
+ TargetAddress key-value list.\r
+ @param[in] Len Length of the data.\r
+ \r
+ @retval EFI_SUCCESS The target address is updated.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+ @retval EFI_NOT_FOUND The TargetAddress key is not found.\r
+ @retval Others Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiUpdateTargetAddress (\r
+ IN OUT ISCSI_SESSION *Session,\r
+ IN CHAR8 *Data,\r
+ IN UINT32 Len\r
+ );\r
+\r
+/**\r
+ The callback function to free the net buffer list.\r
+\r
+ @param[in] Arg The opaque parameter.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+IScsiFreeNbufList (\r
+ VOID *Arg\r
+ );\r
+\r
+/**\r
+ Receive an iSCSI response PDU. An iSCSI response PDU contains an iSCSI PDU header and\r
+ an optional data segment. The two parts will be put into two blocks of buffers in the\r
+ net buffer. The digest check will be conducted in this function if needed and the digests\r
+ will be trimmed from the PDU buffer.\r
+\r
+ @param[in] Conn The iSCSI connection to receive data from.\r
+ @param[out] Pdu The received iSCSI pdu.\r
+ @param[in] Context The context used to describe information on the caller provided\r
+ buffer to receive data segment of the iSCSI pdu, it's optional.\r
+ @param[in] HeaderDigest Whether there will be header digest received.\r
+ @param[in] DataDigest Whether there will be data digest.\r
+ @param[in] TimeoutEvent The timeout event, it's optional.\r
+\r
+ @retval EFI_SUCCESS An iSCSI pdu is received.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+ @retval EFI_PROTOCOL_ERROR Some kind of iSCSI protocol error occurred.\r
+ @retval Others Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiReceivePdu (\r
+ IN ISCSI_CONNECTION *Conn,\r
+ OUT NET_BUF **Pdu,\r
+ IN ISCSI_IN_BUFFER_CONTEXT *Context, OPTIONAL\r
+ IN BOOLEAN HeaderDigest,\r
+ IN BOOLEAN DataDigest,\r
+ IN EFI_EVENT TimeoutEvent OPTIONAL\r
+ );\r
+\r
+/**\r
+ Check and get the result of the prameter negotiation.\r
+\r
+ @param[in, out] Conn The connection in iSCSI login.\r
+\r
+ @retval EFI_SUCCESS The parmeter check is passed and negotiation is finished.\r
+ @retval EFI_PROTOCOL_ERROR Some kind of iSCSI protocol error occurred.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiCheckOpParams (\r
+ IN OUT ISCSI_CONNECTION *Conn\r
+ );\r
+\r
+/**\r
+ Fill the oprational prameters.\r
+\r
+ @param[in] Conn The connection in iSCSI login.\r
+ @param[in, out] Pdu The iSCSI login request PDU to fill the parameters.\r
+\r
+**/\r
+VOID\r
+IScsiFillOpParams (\r
+ IN ISCSI_CONNECTION *Conn,\r
+ IN OUT NET_BUF *Pdu\r
+ );\r
+\r
+/**\r
+ Pad the iSCSI AHS or data segment to an integer number of 4 byte words.\r
+\r
+ @param[in, out] Pdu The iSCSI pdu which contains segments to pad.\r
+ @param[in] Len The length of the last semgnet in the PDU.\r
+\r
+ @retval EFI_SUCCESS The segment is padded or no need to pad it.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough remaining free space to add the\r
+ padding bytes.\r
+**/\r
+EFI_STATUS\r
+IScsiPadSegment (\r
+ IN OUT NET_BUF *Pdu,\r
+ IN UINT32 Len\r
+ );\r
+\r
+/**\r
+ Build a key-value list from the data segment.\r
+\r
+ @param[in] Data The data segment containing the key-value pairs.\r
+ @param[in] Len Length of the data segment.\r
+\r
+ @return The key-value list.\r
+ @retval NULL Other errors as indicated.\r
+\r
+**/\r
+LIST_ENTRY *\r
+IScsiBuildKeyValueList (\r
+ IN CHAR8 *Data,\r
+ IN UINT32 Len\r
+ );\r
+\r
+/**\r
+ Get the value string by the key name from the key-value list. If found,\r
+ the key-value entry will be removed from the list.\r
+\r
+ @param[in, out] KeyValueList The key-value list.\r
+ @param[in] Key The key name to find.\r
+\r
+ @return The value string.\r
+ @retval NULL The key value pair can not be found.\r
+\r
+**/\r
+CHAR8 *\r
+IScsiGetValueByKeyFromList (\r
+ IN OUT LIST_ENTRY *KeyValueList,\r
+ IN CHAR8 *Key\r
+ );\r
+\r
+/**\r
+ Free the key-value list.\r
+\r
+ @param[in] KeyValueList The key-value list.\r
+\r
+**/\r
+VOID\r
+IScsiFreeKeyValueList (\r
+ IN LIST_ENTRY *KeyValueList\r
+ );\r
+\r
+/**\r
+ Normalize the iSCSI name according to RFC.\r
+\r
+ @param[in, out] Name The iSCSI name.\r
+ @param[in] Len length of the iSCSI name.\r
+\r
+ @retval EFI_SUCCESS The iSCSI name is valid and normalized.\r
+ @retval EFI_PROTOCOL_ERROR The iSCSI name is mal-formatted or not in the IQN format.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiNormalizeName (\r
+ IN OUT CHAR8 *Name,\r
+ IN UINTN Len\r
+ );\r
+\r
+/**\r
+ Execute the SCSI command issued through the EXT SCSI PASS THRU protocol.\r
+\r
+ @param[in] PassThru The EXT SCSI PASS THRU protocol.\r
+ @param[in] Target The target ID.\r
+ @param[in] Lun The LUN.\r
+ @param[in, out] Packet The request packet containing IO request, SCSI command\r
+ buffer and buffers to read/write.\r
+ \r
+ @retval EFI_SUCCES The SCSI command is executed and the result is updated to \r
+ the Packet.\r
+ @retval EFI_DEVICE_ERROR Session state was not as required.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+ @retval Others Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiExecuteScsiCommand (\r
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 *Target,\r
+ IN UINT64 Lun,\r
+ IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet\r
+ );\r
+\r
+/**\r
+ Reinstate the session on some error.\r
+\r
+ @param[in] Session The iSCSI session\r
+\r
+ @retval EFI_SUCCES The session is reinstated from some error.\r
+ @retval Other Reinstatement failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiSessionReinstatement (\r
+ IN ISCSI_SESSION *Session\r
+ );\r
+\r
+/**\r
+ Initialize some session parameters before login.\r
+\r
+ @param[in, out] Session The iSCSI session.\r
+ @param[in] Recovery Whether the request is from a fresh new start or recovery.\r
+\r
+**/\r
+VOID\r
+IScsiSessionInit (\r
+ IN OUT ISCSI_SESSION *Session,\r
+ IN BOOLEAN Recovery\r
+ );\r
+ \r
+/**\r
+ Abort the iSCSI session, that is, reset all the connection and free the\r
+ resources.\r
+\r
+ @param[in, out] Session The iSCSI session.\r
+\r
+**/\r
+VOID\r
+IScsiSessionAbort (\r
+ IN OUT ISCSI_SESSION *Session\r
+ );\r
+\r
+#endif\r
NetLib|MdeModulePkg/Library/DxeNetLib/DxeNetLib.inf\r
IpIoLib|MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.inf\r
UdpIoLib|MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf\r
+ TcpIoLib|MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.inf\r
BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf\r
OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf\r
IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf\r
NetworkPkg/Dhcp6Dxe/Dhcp6Dxe.inf\r
NetworkPkg/Mtftp6Dxe/Mtftp6Dxe.inf\r
\r
-\r
[Components.IA32, Components.X64, Components.IPF]\r
+ NetworkPkg/IScsiDxe/IScsiDxe.inf\r
NetworkPkg/UefiPxeBcDxe/UefiPxeBcDxe.inf\r
NetworkPkg/Application/Ping6/Ping6.inf\r
NetworkPkg/Application/IfConfig6/IfConfig6.inf\r