PeiIpmiBmc.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. /** @file
  2. Generic IPMI transport layer during PEI phase
  3. @copyright
  4. Copyright 2016 - 2021 Intel Corporation. <BR>
  5. SPDX-License-Identifier: BSD-2-Clause-Patent
  6. **/
  7. #include "PeiIpmiBmc.h"
  8. EFI_STATUS
  9. UpdateErrorStatus (
  10. IN UINT8 BmcError,
  11. PEI_IPMI_BMC_INSTANCE_DATA *IpmiInstance
  12. )
  13. /*++
  14. Routine Description:
  15. Check if the completion code is a Soft Error and increment the count. The count
  16. is not updated if the BMC is in Force Update Mode.
  17. Arguments:
  18. BmcError - Completion code to check
  19. IpmiInstance - BMC instance data
  20. Returns:
  21. EFI_SUCCESS - Status
  22. --*/
  23. {
  24. UINT8 Errors[] = COMPLETION_CODES;
  25. UINT16 CodeCount;
  26. UINT8 i;
  27. CodeCount = sizeof (Errors) / sizeof (Errors[0]);
  28. for (i = 0; i < CodeCount; i++) {
  29. if (BmcError == Errors[i]) {
  30. //
  31. // Don't change Bmc Status flag if the BMC is in Force Update Mode.
  32. //
  33. if (IpmiInstance->BmcStatus != BMC_UPDATE_IN_PROGRESS) {
  34. IpmiInstance->BmcStatus = BMC_SOFTFAIL;
  35. }
  36. IpmiInstance->SoftErrorCount++;
  37. break;
  38. }
  39. }
  40. return EFI_SUCCESS;
  41. }
  42. EFI_STATUS
  43. PeiIpmiSendCommandToBmc (
  44. IN PEI_IPMI_TRANSPORT_PPI *This,
  45. IN UINT8 NetFunction,
  46. IN UINT8 Lun,
  47. IN UINT8 Command,
  48. IN UINT8 *CommandData,
  49. IN UINT8 CommandDataSize,
  50. IN OUT UINT8 *ResponseData,
  51. IN OUT UINT8 *ResponseDataSize,
  52. IN VOID *Context
  53. )
  54. /*++
  55. Routine Description:
  56. Send IPMI command to BMC
  57. Arguments:
  58. This - Pointer to IPMI protocol instance
  59. NetFunction - Net Function of command to send
  60. Lun - LUN of command to send
  61. Command - IPMI command to send
  62. CommandData - Pointer to command data buffer, if needed
  63. CommandDataSize - Size of command data buffer
  64. ResponseData - Pointer to response data buffer
  65. ResponseDataSize - Pointer to response data buffer size
  66. Context - Context
  67. Returns:
  68. EFI_INVALID_PARAMETER - One of the input values is bad
  69. EFI_DEVICE_ERROR - IPMI command failed
  70. EFI_BUFFER_TOO_SMALL - Response buffer is too small
  71. EFI_UNSUPPORTED - Command is not supported by BMC
  72. EFI_SUCCESS - Command completed successfully
  73. --*/
  74. {
  75. PEI_IPMI_BMC_INSTANCE_DATA *IpmiInstance;
  76. UINT8 DataSize;
  77. EFI_STATUS Status;
  78. IPMI_COMMAND *IpmiCommand;
  79. IPMI_RESPONSE *IpmiResponse;
  80. UINT8 Index;
  81. UINT8 TempData[MAX_TEMP_DATA];
  82. IpmiInstance = INSTANCE_FROM_PEI_SM_IPMI_BMC_THIS (This);
  83. //
  84. // The TempData buffer is used for both sending command data and receiving
  85. // response data. Since the command format is different from the response
  86. // format, the buffer is cast to both structure definitions.
  87. //
  88. IpmiCommand = (IPMI_COMMAND*) TempData;
  89. IpmiResponse = (IPMI_RESPONSE*) TempData;
  90. //
  91. // Send IPMI command to BMC
  92. //
  93. IpmiCommand->Lun = Lun;
  94. IpmiCommand->NetFunction = NetFunction;
  95. IpmiCommand->Command = Command;
  96. //
  97. // Ensure that the buffer is valid before attempting to copy the command data
  98. // buffer into the IpmiCommand structure.
  99. //
  100. if (CommandDataSize > 0) {
  101. if (CommandData == NULL) {
  102. return EFI_INVALID_PARAMETER;
  103. }
  104. CopyMem (
  105. IpmiCommand->CommandData,
  106. CommandData,
  107. CommandDataSize
  108. );
  109. }
  110. Status = SendDataToBmcPort (
  111. IpmiInstance->KcsTimeoutPeriod,
  112. IpmiInstance->IpmiIoBase,
  113. Context,
  114. (UINT8 *) IpmiCommand,
  115. (CommandDataSize + IPMI_COMMAND_HEADER_SIZE)
  116. );
  117. if (Status != EFI_SUCCESS) {
  118. IpmiInstance->BmcStatus = BMC_SOFTFAIL;
  119. IpmiInstance->SoftErrorCount++;
  120. DEBUG ((EFI_D_ERROR, "PEI Phase SendDataToBmcPort failed Status:%r\n", Status));
  121. return Status;
  122. }
  123. //
  124. // Get Response to IPMI Command from BMC.
  125. //
  126. DataSize = MAX_TEMP_DATA;
  127. Status = ReceiveBmcDataFromPort (
  128. IpmiInstance->KcsTimeoutPeriod,
  129. IpmiInstance->IpmiIoBase,
  130. Context,
  131. (UINT8 *) IpmiResponse,
  132. &DataSize
  133. );
  134. if (Status != EFI_SUCCESS) {
  135. IpmiInstance->BmcStatus = BMC_SOFTFAIL;
  136. IpmiInstance->SoftErrorCount++;
  137. DEBUG ((EFI_D_ERROR, "PEI Phase ReceiveBmcDataFromPort failed Status:%r\n", Status));
  138. return Status;
  139. }
  140. if ((IpmiResponse->CompletionCode != COMP_CODE_NORMAL) &&
  141. (IpmiInstance->BmcStatus == BMC_UPDATE_IN_PROGRESS)) {
  142. //
  143. // If the completion code is not normal and the BMC is in Force Update
  144. // mode, then update the error status and return EFI_UNSUPPORTED.
  145. //
  146. UpdateErrorStatus (
  147. IpmiResponse->CompletionCode,
  148. IpmiInstance
  149. );
  150. return EFI_UNSUPPORTED;
  151. } else if (IpmiResponse->CompletionCode != COMP_CODE_NORMAL) {
  152. //
  153. // Otherwise if the BMC is in normal mode, but the completion code
  154. // is not normal, then update the error status and return device error.
  155. //
  156. UpdateErrorStatus (
  157. IpmiResponse->CompletionCode,
  158. IpmiInstance
  159. );
  160. return EFI_DEVICE_ERROR;
  161. }
  162. //
  163. // If we got this far without any error codes, but the DataSize is 0 then the
  164. // command response failed, so do not continue.
  165. //
  166. //
  167. // Some abnormal case, in order to avoid that BMC sent illegal data size.
  168. // If we got this far without any error codes, but the DataSize less than IPMI_RESPONSE_HEADER_SIZE, then the
  169. // command response failed, so do not continue.
  170. if (DataSize < IPMI_RESPONSE_HEADER_SIZE) {
  171. return EFI_DEVICE_ERROR;
  172. }
  173. //
  174. // Verify the response data buffer passed in is big enough.
  175. //
  176. if ((DataSize - IPMI_RESPONSE_HEADER_SIZE) > *ResponseDataSize) {
  177. return EFI_BUFFER_TOO_SMALL;
  178. }
  179. //
  180. // Copy data over to the response data buffer.
  181. //
  182. *ResponseDataSize = DataSize - IPMI_RESPONSE_HEADER_SIZE;
  183. CopyMem (
  184. ResponseData,
  185. IpmiResponse->ResponseData,
  186. *ResponseDataSize
  187. );
  188. //
  189. // Add completion code in response data to meet the requirement of IPMI spec 2.0
  190. //
  191. *ResponseDataSize += 1; // Add one byte for Completion Code
  192. for (Index = 1; Index < *ResponseDataSize; Index++) {
  193. ResponseData [*ResponseDataSize - Index] = ResponseData [*ResponseDataSize - (Index + 1)];
  194. }
  195. ResponseData [0] = IpmiResponse->CompletionCode;
  196. IpmiInstance->BmcStatus = BMC_OK;
  197. return EFI_SUCCESS;
  198. }
  199. EFI_STATUS
  200. PeiIpmiBmcStatus (
  201. IN PEI_IPMI_TRANSPORT_PPI *This,
  202. OUT BMC_STATUS *BmcStatus,
  203. OUT SM_COM_ADDRESS *ComAddress,
  204. IN VOID *Context
  205. )
  206. /*++
  207. Routine Description:
  208. Updates the BMC status and returns the Com Address
  209. Arguments:
  210. This - Pointer to IPMI protocol instance
  211. BmcStatus - BMC status
  212. ComAddress - Com Address
  213. Context - Context
  214. Returns:
  215. EFI_SUCCESS - Success
  216. --*/
  217. {
  218. PEI_IPMI_BMC_INSTANCE_DATA *IpmiInstance;
  219. IpmiInstance = INSTANCE_FROM_PEI_SM_IPMI_BMC_THIS (This);
  220. if ((IpmiInstance->BmcStatus == BMC_SOFTFAIL) && (IpmiInstance->SoftErrorCount >= MAX_SOFT_COUNT)) {
  221. IpmiInstance->BmcStatus = BMC_HARDFAIL;
  222. }
  223. *BmcStatus = IpmiInstance->BmcStatus;
  224. ComAddress->ChannelType = SmBmc;
  225. ComAddress->Address.BmcAddress.LunAddress = 0x0;
  226. ComAddress->Address.BmcAddress.SlaveAddress = IpmiInstance->SlaveAddress;
  227. ComAddress->Address.BmcAddress.ChannelAddress = 0x0;
  228. return EFI_SUCCESS;
  229. }