| Matthew Barth | 70dbc58 | 2016-09-20 10:16:52 -0500 | [diff] [blame] | 1 | #include "oemhandler.hpp" | 
| Vishwanatha Subbanna | 0765506 | 2017-07-14 20:31:57 +0530 | [diff] [blame^] | 2 | #include "config.h" | 
| Chris Austen | 4d98c1e | 2015-10-13 14:33:50 -0500 | [diff] [blame] | 3 | #include <host-ipmid/ipmid-api.h> | 
| Vishwanatha Subbanna | 0765506 | 2017-07-14 20:31:57 +0530 | [diff] [blame^] | 4 | #include <host-ipmid/ipmid-host-cmd.hpp> | 
| Adriana Kobylak | 187bfce | 2016-03-04 11:55:43 -0600 | [diff] [blame] | 5 | #include <fstream> | 
| Chris Austen | 4d98c1e | 2015-10-13 14:33:50 -0500 | [diff] [blame] | 6 | #include <stdio.h> | 
|  | 7 | #include <string.h> | 
| Nan Li | 8a0807a | 2016-05-24 16:59:24 +0800 | [diff] [blame] | 8 | #include <endian.h> | 
| Vishwanatha Subbanna | 0765506 | 2017-07-14 20:31:57 +0530 | [diff] [blame^] | 9 | #include <functional> | 
|  | 10 | #include <systemd/sd-bus.h> | 
|  | 11 | #include <sdbusplus/bus.hpp> | 
|  | 12 | #include <host-interface.hpp> | 
| Chris Austen | 4d98c1e | 2015-10-13 14:33:50 -0500 | [diff] [blame] | 13 |  | 
|  | 14 | void register_netfn_oem_partial_esel() __attribute__((constructor)); | 
|  | 15 |  | 
| Chris Austen | fcafccf | 2016-02-19 23:15:57 -0600 | [diff] [blame] | 16 | const char *g_esel_path = "/tmp/esel"; | 
| Chris Austen | 29a8e0f | 2015-10-30 11:44:38 -0500 | [diff] [blame] | 17 | uint16_t g_record_id = 0x0001; | 
| Chris Austen | 4d98c1e | 2015-10-13 14:33:50 -0500 | [diff] [blame] | 18 |  | 
| Chris Austen | 4d98c1e | 2015-10-13 14:33:50 -0500 | [diff] [blame] | 19 | /////////////////////////////////////////////////////////////////////////////// | 
| Patrick Williams | 24fa5a9 | 2015-10-30 14:53:57 -0500 | [diff] [blame] | 20 | // For the First partial add eSEL the SEL Record ID and offset | 
|  | 21 | // value should be 0x0000. The extended data needs to be in | 
|  | 22 | // the form of an IPMI SEL Event Record, with Event sensor type | 
|  | 23 | // of 0xDF and Event Message format of 0x04. The returned | 
| Chris Austen | 4d98c1e | 2015-10-13 14:33:50 -0500 | [diff] [blame] | 24 | // Record ID should be used for all partial eSEL adds. | 
|  | 25 | // | 
| Chris Austen | ba54afb | 2016-02-19 23:18:42 -0600 | [diff] [blame] | 26 | // This function creates a /tmp/esel file to store the | 
| Chris Austen | 4d98c1e | 2015-10-13 14:33:50 -0500 | [diff] [blame] | 27 | // incoming partial esel.  It is the role of some other | 
| Patrick Williams | 24fa5a9 | 2015-10-30 14:53:57 -0500 | [diff] [blame] | 28 | // function to commit the error log in to long term | 
|  | 29 | // storage.  Likely via the ipmi add_sel command. | 
| Chris Austen | 4d98c1e | 2015-10-13 14:33:50 -0500 | [diff] [blame] | 30 | /////////////////////////////////////////////////////////////////////////////// | 
| Patrick Williams | 24fa5a9 | 2015-10-30 14:53:57 -0500 | [diff] [blame] | 31 | ipmi_ret_t ipmi_ibm_oem_partial_esel(ipmi_netfn_t netfn, ipmi_cmd_t cmd, | 
| Chris Austen | 17160ce | 2015-10-30 11:44:38 -0500 | [diff] [blame] | 32 | ipmi_request_t request, ipmi_response_t response, | 
|  | 33 | ipmi_data_len_t data_len, ipmi_context_t context) | 
| Chris Austen | 4d98c1e | 2015-10-13 14:33:50 -0500 | [diff] [blame] | 34 | { | 
| Nan Li | 8a0807a | 2016-05-24 16:59:24 +0800 | [diff] [blame] | 35 | uint8_t *reqptr = (uint8_t *) request; | 
|  | 36 | esel_request_t esel_req; | 
| Chris Austen | ba54afb | 2016-02-19 23:18:42 -0600 | [diff] [blame] | 37 | FILE *fp; | 
| Nan Li | b6c4c56 | 2016-03-30 17:06:13 +0800 | [diff] [blame] | 38 | int r = 0; | 
| Chris Austen | ba54afb | 2016-02-19 23:18:42 -0600 | [diff] [blame] | 39 | uint8_t rlen; | 
|  | 40 | ipmi_ret_t rc = IPMI_CC_OK; | 
|  | 41 | const char *pio; | 
| Chris Austen | 4d98c1e | 2015-10-13 14:33:50 -0500 | [diff] [blame] | 42 |  | 
| Nan Li | 8a0807a | 2016-05-24 16:59:24 +0800 | [diff] [blame] | 43 | esel_req.resid     = le16toh((((uint16_t) reqptr[1]) << 8) + reqptr[0]); | 
|  | 44 | esel_req.selrecord = le16toh((((uint16_t) reqptr[3]) << 8) + reqptr[2]); | 
|  | 45 | esel_req.offset    = le16toh((((uint16_t) reqptr[5]) << 8) + reqptr[4]); | 
|  | 46 | esel_req.progress  = reqptr[6]; | 
| Nan Li | b6c4c56 | 2016-03-30 17:06:13 +0800 | [diff] [blame] | 47 |  | 
| Nan Li | 8a0807a | 2016-05-24 16:59:24 +0800 | [diff] [blame] | 48 | uint16_t used_res_id = get_sel_reserve_id(); | 
| Nan Li | b6c4c56 | 2016-03-30 17:06:13 +0800 | [diff] [blame] | 49 |  | 
|  | 50 | // According to IPMI spec, Reservation ID must be checked. | 
| Nan Li | 8a0807a | 2016-05-24 16:59:24 +0800 | [diff] [blame] | 51 | if ( used_res_id != esel_req.resid ) { | 
| Nan Li | b6c4c56 | 2016-03-30 17:06:13 +0800 | [diff] [blame] | 52 | // 0xc5 means Reservation Cancelled or Invalid Reservation ID. | 
|  | 53 | printf("Used Reservation ID = %d\n", used_res_id); | 
|  | 54 | rc = IPMI_CC_INVALID_RESERVATION_ID; | 
|  | 55 |  | 
| Andrew Geissler | d929605 | 2017-06-15 14:57:25 -0500 | [diff] [blame] | 56 | // clean g_esel_path. | 
| Nan Li | b6c4c56 | 2016-03-30 17:06:13 +0800 | [diff] [blame] | 57 | r = remove(g_esel_path); | 
|  | 58 | if(r < 0) | 
|  | 59 | fprintf(stderr, "Error deleting %s\n", g_esel_path); | 
|  | 60 |  | 
|  | 61 | return rc; | 
|  | 62 | } | 
|  | 63 |  | 
|  | 64 | // OpenPOWER Host Interface spec says if RecordID and Offset are | 
| Chris Austen | ba54afb | 2016-02-19 23:18:42 -0600 | [diff] [blame] | 65 | // 0 then then this is a new request | 
| Nan Li | 8a0807a | 2016-05-24 16:59:24 +0800 | [diff] [blame] | 66 | if (!esel_req.selrecord && !esel_req.offset) | 
| Chris Austen | ba54afb | 2016-02-19 23:18:42 -0600 | [diff] [blame] | 67 | pio = "wb"; | 
|  | 68 | else | 
|  | 69 | pio = "rb+"; | 
| Chris Austen | 4d98c1e | 2015-10-13 14:33:50 -0500 | [diff] [blame] | 70 |  | 
| Chris Austen | ba54afb | 2016-02-19 23:18:42 -0600 | [diff] [blame] | 71 | rlen = (*data_len) - (uint8_t) (sizeof(esel_request_t)); | 
| Chris Austen | 4d98c1e | 2015-10-13 14:33:50 -0500 | [diff] [blame] | 72 |  | 
| Chris Austen | ba54afb | 2016-02-19 23:18:42 -0600 | [diff] [blame] | 73 | if ((fp = fopen(g_esel_path, pio)) != NULL) { | 
| Nan Li | 8a0807a | 2016-05-24 16:59:24 +0800 | [diff] [blame] | 74 | fseek(fp, esel_req.offset, SEEK_SET); | 
|  | 75 | fwrite(reqptr+(uint8_t) (sizeof(esel_request_t)), rlen, 1, fp); | 
| Chris Austen | ba54afb | 2016-02-19 23:18:42 -0600 | [diff] [blame] | 76 | fclose(fp); | 
| Chris Austen | 4d98c1e | 2015-10-13 14:33:50 -0500 | [diff] [blame] | 77 |  | 
| Chris Austen | ba54afb | 2016-02-19 23:18:42 -0600 | [diff] [blame] | 78 | *data_len = sizeof(g_record_id); | 
|  | 79 | memcpy(response, &g_record_id, *data_len); | 
|  | 80 | } else { | 
|  | 81 | fprintf(stderr, "Error trying to perform %s for esel%s\n",pio, g_esel_path); | 
|  | 82 | rc = IPMI_CC_INVALID; | 
|  | 83 | *data_len     = 0; | 
|  | 84 | } | 
| Chris Austen | 4d98c1e | 2015-10-13 14:33:50 -0500 | [diff] [blame] | 85 |  | 
| Chris Austen | ba54afb | 2016-02-19 23:18:42 -0600 | [diff] [blame] | 86 | // The first bit prepresents that this is the last partial packet | 
|  | 87 | // coming down.  If that is the case advance the record id so we | 
|  | 88 | // don't overlap logs.  This allows anyone to establish a log | 
|  | 89 | // directory system. | 
| Nan Li | 8a0807a | 2016-05-24 16:59:24 +0800 | [diff] [blame] | 90 | if (esel_req.progress & 1 ) { | 
| Chris Austen | ba54afb | 2016-02-19 23:18:42 -0600 | [diff] [blame] | 91 | g_record_id++; | 
|  | 92 | } | 
| Chris Austen | 4d98c1e | 2015-10-13 14:33:50 -0500 | [diff] [blame] | 93 |  | 
| Chris Austen | ba54afb | 2016-02-19 23:18:42 -0600 | [diff] [blame] | 94 | return rc; | 
| Chris Austen | 4d98c1e | 2015-10-13 14:33:50 -0500 | [diff] [blame] | 95 | } | 
|  | 96 |  | 
| Adriana Kobylak | 187bfce | 2016-03-04 11:55:43 -0600 | [diff] [blame] | 97 | // Prepare for FW Update. | 
|  | 98 | // Execute needed commands to prepare the system for a fw update from the host. | 
|  | 99 | ipmi_ret_t ipmi_ibm_oem_prep_fw_update(ipmi_netfn_t netfn, ipmi_cmd_t cmd, | 
|  | 100 | ipmi_request_t request, ipmi_response_t response, | 
|  | 101 | ipmi_data_len_t data_len, ipmi_context_t context) | 
|  | 102 | { | 
|  | 103 | ipmi_ret_t ipmi_rc = IPMI_CC_OK; | 
|  | 104 | *data_len = 0; | 
|  | 105 |  | 
|  | 106 | int rc = 0; | 
|  | 107 | std::ofstream rwfs_file; | 
|  | 108 | const char  *busname = "org.openbmc.control.Bmc"; | 
|  | 109 | const char  *objname = "/org/openbmc/control/bmc0"; | 
|  | 110 | const char  *iface = "org.openbmc.control.Bmc"; | 
|  | 111 | sd_bus *bus = ipmid_get_sd_bus_connection(); | 
|  | 112 | sd_bus_message *reply = NULL; | 
|  | 113 | sd_bus_error error = SD_BUS_ERROR_NULL; | 
|  | 114 | int r = 0; | 
|  | 115 |  | 
|  | 116 | // Set one time flag | 
|  | 117 | rc = system("fw_setenv openbmconce copy-files-to-ram copy-base-filesystem-to-ram"); | 
|  | 118 | rc = WEXITSTATUS(rc); | 
|  | 119 | if (rc != 0) { | 
|  | 120 | fprintf(stderr, "fw_setenv openbmconce failed with rc=%d\n", rc); | 
| Andrew Geissler | d929605 | 2017-06-15 14:57:25 -0500 | [diff] [blame] | 121 | return IPMI_CC_UNSPECIFIED_ERROR; | 
| Adriana Kobylak | 187bfce | 2016-03-04 11:55:43 -0600 | [diff] [blame] | 122 | } | 
|  | 123 |  | 
|  | 124 | // Touch the image-rwfs file to perform an empty update to force the save | 
|  | 125 | // in case we're already in ram and the flash is the same causing the ram files | 
|  | 126 | // to not be copied back to flash | 
|  | 127 | rwfs_file.open("/run/initramfs/image-rwfs", std::ofstream::out | std::ofstream::app); | 
|  | 128 | rwfs_file.close(); | 
|  | 129 |  | 
|  | 130 | // Reboot the BMC for settings to take effect | 
|  | 131 | r = sd_bus_call_method(bus, busname, objname, iface, | 
|  | 132 | "warmReset", &error, &reply, NULL); | 
|  | 133 | if (r < 0) { | 
|  | 134 | fprintf(stderr, "Failed to reset BMC: %s\n", strerror(-r)); | 
|  | 135 | return -1; | 
|  | 136 | } | 
|  | 137 | printf("Warning: BMC is going down for reboot!\n"); | 
|  | 138 | sd_bus_error_free(&error); | 
|  | 139 | reply = sd_bus_message_unref(reply); | 
|  | 140 |  | 
|  | 141 | return ipmi_rc; | 
|  | 142 | } | 
| Chris Austen | 4d98c1e | 2015-10-13 14:33:50 -0500 | [diff] [blame] | 143 |  | 
| Vishwanatha Subbanna | 0765506 | 2017-07-14 20:31:57 +0530 | [diff] [blame^] | 144 | namespace { | 
|  | 145 | // Storage to keep the object alive during process life | 
|  | 146 | std::unique_ptr<open_power::host::command::Host> opHost | 
|  | 147 | __attribute__((init_priority(101))); | 
|  | 148 | std::unique_ptr<sdbusplus::server::manager::manager> objManager | 
|  | 149 | __attribute__((init_priority(101))); | 
|  | 150 | } | 
|  | 151 |  | 
| Chris Austen | 4d98c1e | 2015-10-13 14:33:50 -0500 | [diff] [blame] | 152 | void register_netfn_oem_partial_esel() | 
|  | 153 | { | 
| Tom | cbfd6ec | 2016-09-14 17:45:55 +0530 | [diff] [blame] | 154 | printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_OEM, IPMI_CMD_PESEL); | 
|  | 155 | ipmi_register_callback(NETFUN_OEM, IPMI_CMD_PESEL, NULL, ipmi_ibm_oem_partial_esel, | 
|  | 156 | SYSTEM_INTERFACE); | 
| Adriana Kobylak | 187bfce | 2016-03-04 11:55:43 -0600 | [diff] [blame] | 157 |  | 
|  | 158 | printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", NETFUN_OEM, IPMI_CMD_PREP_FW_UPDATE); | 
| Tom | cbfd6ec | 2016-09-14 17:45:55 +0530 | [diff] [blame] | 159 | ipmi_register_callback(NETFUN_OEM, IPMI_CMD_PREP_FW_UPDATE, NULL, ipmi_ibm_oem_prep_fw_update, | 
|  | 160 | SYSTEM_INTERFACE); | 
| Adriana Kobylak | 187bfce | 2016-03-04 11:55:43 -0600 | [diff] [blame] | 161 |  | 
| Vishwanatha Subbanna | 0765506 | 2017-07-14 20:31:57 +0530 | [diff] [blame^] | 162 | // Create new object on the bus | 
|  | 163 | auto objPath = std::string{CONTROL_HOST_OBJ_MGR} + '/' + HOST_NAME + '0'; | 
|  | 164 |  | 
|  | 165 | // Add sdbusplus ObjectManager. | 
|  | 166 | auto& sdbusPlusHandler = ipmid_get_sdbus_plus_handler(); | 
|  | 167 | objManager = std::make_unique<sdbusplus::server::manager::manager>( | 
|  | 168 | *sdbusPlusHandler, | 
|  | 169 | CONTROL_HOST_OBJ_MGR); | 
|  | 170 |  | 
|  | 171 | opHost = std::make_unique<open_power::host::command::Host>( | 
|  | 172 | *sdbusPlusHandler, objPath.c_str()); | 
|  | 173 |  | 
|  | 174 | // Service for this is provided by phosphor layer systemcmdintf | 
|  | 175 | // and this will be as part of that. | 
| Tom | cbfd6ec | 2016-09-14 17:45:55 +0530 | [diff] [blame] | 176 | return; | 
| Chris Austen | 4d98c1e | 2015-10-13 14:33:50 -0500 | [diff] [blame] | 177 | } |