IpmiBmc.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. /** @file
  2. IPMI Transport common layer driver
  3. @copyright
  4. Copyright 1999 - 2021 Intel Corporation. <BR>
  5. SPDX-License-Identifier: BSD-2-Clause-Patent
  6. **/
  7. #include "IpmiBmc.h"
  8. EFI_STATUS
  9. UpdateErrorStatus (
  10. IN UINT8 BmcError,
  11. 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. EFIAPI
  44. IpmiSendCommandToBmc (
  45. IN IPMI_TRANSPORT *This,
  46. IN UINT8 NetFunction,
  47. IN UINT8 Lun,
  48. IN UINT8 Command,
  49. IN UINT8 *CommandData,
  50. IN UINT8 CommandDataSize,
  51. IN OUT UINT8 *ResponseData,
  52. IN OUT UINT8 *ResponseDataSize,
  53. IN VOID *Context
  54. )
  55. /*++
  56. Routine Description:
  57. Send IPMI command to BMC
  58. Arguments:
  59. This - Pointer to IPMI protocol instance
  60. NetFunction - Net Function of command to send
  61. Lun - LUN of command to send
  62. Command - IPMI command to send
  63. CommandData - Pointer to command data buffer, if needed
  64. CommandDataSize - Size of command data buffer
  65. ResponseData - Pointer to response data buffer
  66. ResponseDataSize - Pointer to response data buffer size
  67. Context - Context
  68. Returns:
  69. EFI_INVALID_PARAMETER - One of the input values is bad
  70. EFI_DEVICE_ERROR - IPMI command failed
  71. EFI_BUFFER_TOO_SMALL - Response buffer is too small
  72. EFI_UNSUPPORTED - Command is not supported by BMC
  73. EFI_SUCCESS - Command completed successfully
  74. --*/
  75. {
  76. IPMI_BMC_INSTANCE_DATA *IpmiInstance;
  77. UINT8 DataSize;
  78. EFI_STATUS Status;
  79. IPMI_COMMAND *IpmiCommand;
  80. IPMI_RESPONSE *IpmiResponse;
  81. UINT8 RetryCnt = IPMI_SEND_COMMAND_MAX_RETRY;
  82. UINT8 Index;
  83. UINT8 TempData[MAX_TEMP_DATA];
  84. IpmiInstance = INSTANCE_FROM_SM_IPMI_BMC_THIS (This);
  85. while (RetryCnt--) {
  86. //
  87. // The TempData buffer is used for both sending command data and receiving
  88. // response data. Since the command format is different from the response
  89. // format, the buffer is cast to both structure definitions.
  90. //
  91. IpmiCommand = (IPMI_COMMAND*) TempData;
  92. IpmiResponse = (IPMI_RESPONSE*) TempData;
  93. //
  94. // Send IPMI command to BMC
  95. //
  96. IpmiCommand->Lun = Lun;
  97. IpmiCommand->NetFunction = NetFunction;
  98. IpmiCommand->Command = Command;
  99. //
  100. // Ensure that the buffer is valid before attempting to copy the command data
  101. // buffer into the IpmiCommand structure.
  102. //
  103. if (CommandDataSize > 0) {
  104. if (CommandData == NULL) {
  105. return EFI_INVALID_PARAMETER;
  106. }
  107. CopyMem (
  108. IpmiCommand->CommandData,
  109. CommandData,
  110. CommandDataSize
  111. );
  112. }
  113. Status = SendDataToBmcPort (
  114. IpmiInstance->KcsTimeoutPeriod,
  115. IpmiInstance->IpmiIoBase,
  116. Context,
  117. (UINT8 *) IpmiCommand,
  118. (CommandDataSize + IPMI_COMMAND_HEADER_SIZE)
  119. );
  120. if (Status != EFI_SUCCESS) {
  121. IpmiInstance->BmcStatus = BMC_SOFTFAIL;
  122. IpmiInstance->SoftErrorCount++;
  123. return Status;
  124. }
  125. //
  126. // Get Response to IPMI Command from BMC.
  127. // Subtract 1 from DataSize so memory past the end of the buffer can't be written
  128. //
  129. DataSize = MAX_TEMP_DATA - 1;
  130. Status = ReceiveBmcDataFromPort (
  131. IpmiInstance->KcsTimeoutPeriod,
  132. IpmiInstance->IpmiIoBase,
  133. Context,
  134. (UINT8 *) IpmiResponse,
  135. &DataSize
  136. );
  137. if (Status != EFI_SUCCESS) {
  138. IpmiInstance->BmcStatus = BMC_SOFTFAIL;
  139. IpmiInstance->SoftErrorCount++;
  140. return Status;
  141. }
  142. //
  143. // If we got this far without any error codes, but the DataSize less than IPMI_RESPONSE_HEADER_SIZE, then the
  144. // command response failed, so do not continue.
  145. //
  146. if (DataSize < IPMI_RESPONSE_HEADER_SIZE) {
  147. return EFI_DEVICE_ERROR;
  148. }
  149. if ((IpmiResponse->CompletionCode != COMP_CODE_NORMAL) &&
  150. (IpmiInstance->BmcStatus == BMC_UPDATE_IN_PROGRESS)) {
  151. //
  152. // If the completion code is not normal and the BMC is in Force Update
  153. // mode, then update the error status and return EFI_UNSUPPORTED.
  154. //
  155. UpdateErrorStatus (
  156. IpmiResponse->CompletionCode,
  157. IpmiInstance
  158. );
  159. return EFI_UNSUPPORTED;
  160. } else if (IpmiResponse->CompletionCode != COMP_CODE_NORMAL) {
  161. //
  162. // Otherwise if the BMC is in normal mode, but the completion code
  163. // is not normal, then update the error status and return device error.
  164. //
  165. UpdateErrorStatus (
  166. IpmiResponse->CompletionCode,
  167. IpmiInstance
  168. );
  169. //
  170. // Intel Server System Integrated Baseboard Management Controller (BMC) Firmware v0.62
  171. // D4h C Insufficient privilege, in KCS channel this indicates KCS Policy Control Mode is Deny All.
  172. // In authenticated channels this indicates invalid authentication/privilege.
  173. //
  174. if (IpmiResponse->CompletionCode == COMP_INSUFFICIENT_PRIVILEGE) {
  175. return EFI_SECURITY_VIOLATION;
  176. } else {
  177. return EFI_DEVICE_ERROR;
  178. }
  179. }
  180. //
  181. // Verify the response data buffer passed in is big enough.
  182. //
  183. if ((DataSize - IPMI_RESPONSE_HEADER_SIZE) > *ResponseDataSize) {
  184. //
  185. //Verify the response data matched with the cmd sent.
  186. //
  187. if ((IpmiResponse->NetFunction != (NetFunction | 0x1)) || (IpmiResponse->Command != Command)) {
  188. if (0 == RetryCnt) {
  189. return EFI_DEVICE_ERROR;
  190. } else {
  191. continue;
  192. }
  193. }
  194. return EFI_BUFFER_TOO_SMALL;
  195. }
  196. break;
  197. }
  198. //
  199. // Copy data over to the response data buffer.
  200. //
  201. *ResponseDataSize = DataSize - IPMI_RESPONSE_HEADER_SIZE;
  202. CopyMem (
  203. ResponseData,
  204. IpmiResponse->ResponseData,
  205. *ResponseDataSize
  206. );
  207. //
  208. // Add completion code in response data to meet the requirement of IPMI spec 2.0
  209. //
  210. *ResponseDataSize += 1; // Add one byte for Completion Code
  211. for (Index = 1; Index < *ResponseDataSize; Index++) {
  212. ResponseData [*ResponseDataSize - Index] = ResponseData [*ResponseDataSize - (Index + 1)];
  213. }
  214. ResponseData [0] = IpmiResponse->CompletionCode;
  215. IpmiInstance->BmcStatus = BMC_OK;
  216. return EFI_SUCCESS;
  217. }
  218. EFI_STATUS
  219. EFIAPI
  220. IpmiBmcStatus (
  221. IN IPMI_TRANSPORT *This,
  222. OUT BMC_STATUS *BmcStatus,
  223. OUT SM_COM_ADDRESS *ComAddress,
  224. IN VOID *Context
  225. )
  226. /*++
  227. Routine Description:
  228. Updates the BMC status and returns the Com Address
  229. Arguments:
  230. This - Pointer to IPMI protocol instance
  231. BmcStatus - BMC status
  232. ComAddress - Com Address
  233. Context - Context
  234. Returns:
  235. EFI_SUCCESS - Success
  236. --*/
  237. {
  238. IPMI_BMC_INSTANCE_DATA *IpmiInstance;
  239. IpmiInstance = INSTANCE_FROM_SM_IPMI_BMC_THIS (This);
  240. if ((IpmiInstance->BmcStatus == BMC_SOFTFAIL) && (IpmiInstance->SoftErrorCount >= MAX_SOFT_COUNT)) {
  241. IpmiInstance->BmcStatus = BMC_HARDFAIL;
  242. }
  243. *BmcStatus = IpmiInstance->BmcStatus;
  244. ComAddress->ChannelType = SmBmc;
  245. ComAddress->Address.BmcAddress.LunAddress = 0x0;
  246. ComAddress->Address.BmcAddress.SlaveAddress = IpmiInstance->SlaveAddress;
  247. ComAddress->Address.BmcAddress.ChannelAddress = 0x0;
  248. return EFI_SUCCESS;
  249. }