blob: 013bf94accc8ed8ff9f5e7cba033a263046c20f2 [file] [log] [blame]
Matthew Barth70dbc582016-09-20 10:16:52 -05001#include "oemhandler.hpp"
Chris Austen4d98c1e2015-10-13 14:33:50 -05002#include <host-ipmid/ipmid-api.h>
Adriana Kobylak187bfce2016-03-04 11:55:43 -06003#include <fstream>
Chris Austen4d98c1e2015-10-13 14:33:50 -05004#include <stdio.h>
5#include <string.h>
Adriana Kobylak187bfce2016-03-04 11:55:43 -06006#include <systemd/sd-bus.h>
Nan Li8a0807a2016-05-24 16:59:24 +08007#include <endian.h>
Chris Austen4d98c1e2015-10-13 14:33:50 -05008
9void register_netfn_oem_partial_esel() __attribute__((constructor));
10
Chris Austenfcafccf2016-02-19 23:15:57 -060011const char *g_esel_path = "/tmp/esel";
Chris Austen29a8e0f2015-10-30 11:44:38 -050012uint16_t g_record_id = 0x0001;
Chris Austen4d98c1e2015-10-13 14:33:50 -050013
Chris Austen4d98c1e2015-10-13 14:33:50 -050014///////////////////////////////////////////////////////////////////////////////
Patrick Williams24fa5a92015-10-30 14:53:57 -050015// For the First partial add eSEL the SEL Record ID and offset
16// value should be 0x0000. The extended data needs to be in
17// the form of an IPMI SEL Event Record, with Event sensor type
18// of 0xDF and Event Message format of 0x04. The returned
Chris Austen4d98c1e2015-10-13 14:33:50 -050019// Record ID should be used for all partial eSEL adds.
20//
Chris Austenba54afb2016-02-19 23:18:42 -060021// This function creates a /tmp/esel file to store the
Chris Austen4d98c1e2015-10-13 14:33:50 -050022// incoming partial esel. It is the role of some other
Patrick Williams24fa5a92015-10-30 14:53:57 -050023// function to commit the error log in to long term
24// storage. Likely via the ipmi add_sel command.
Chris Austen4d98c1e2015-10-13 14:33:50 -050025///////////////////////////////////////////////////////////////////////////////
Patrick Williams24fa5a92015-10-30 14:53:57 -050026ipmi_ret_t ipmi_ibm_oem_partial_esel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Chris Austen17160ce2015-10-30 11:44:38 -050027 ipmi_request_t request, ipmi_response_t response,
28 ipmi_data_len_t data_len, ipmi_context_t context)
Chris Austen4d98c1e2015-10-13 14:33:50 -050029{
Nan Li8a0807a2016-05-24 16:59:24 +080030 uint8_t *reqptr = (uint8_t *) request;
31 esel_request_t esel_req;
Chris Austenba54afb2016-02-19 23:18:42 -060032 FILE *fp;
Nan Lib6c4c562016-03-30 17:06:13 +080033 int r = 0;
Chris Austenba54afb2016-02-19 23:18:42 -060034 uint8_t rlen;
35 ipmi_ret_t rc = IPMI_CC_OK;
36 const char *pio;
Chris Austen4d98c1e2015-10-13 14:33:50 -050037
Nan Li8a0807a2016-05-24 16:59:24 +080038 esel_req.resid = le16toh((((uint16_t) reqptr[1]) << 8) + reqptr[0]);
39 esel_req.selrecord = le16toh((((uint16_t) reqptr[3]) << 8) + reqptr[2]);
40 esel_req.offset = le16toh((((uint16_t) reqptr[5]) << 8) + reqptr[4]);
41 esel_req.progress = reqptr[6];
Nan Lib6c4c562016-03-30 17:06:13 +080042
Nan Li8a0807a2016-05-24 16:59:24 +080043 uint16_t used_res_id = get_sel_reserve_id();
Nan Lib6c4c562016-03-30 17:06:13 +080044
45 // According to IPMI spec, Reservation ID must be checked.
Nan Li8a0807a2016-05-24 16:59:24 +080046 if ( used_res_id != esel_req.resid ) {
Nan Lib6c4c562016-03-30 17:06:13 +080047 // 0xc5 means Reservation Cancelled or Invalid Reservation ID.
48 printf("Used Reservation ID = %d\n", used_res_id);
49 rc = IPMI_CC_INVALID_RESERVATION_ID;
50
51 // clean g_esel_path.
52 r = remove(g_esel_path);
53 if(r < 0)
54 fprintf(stderr, "Error deleting %s\n", g_esel_path);
55
56 return rc;
57 }
58
59 // OpenPOWER Host Interface spec says if RecordID and Offset are
Chris Austenba54afb2016-02-19 23:18:42 -060060 // 0 then then this is a new request
Nan Li8a0807a2016-05-24 16:59:24 +080061 if (!esel_req.selrecord && !esel_req.offset)
Chris Austenba54afb2016-02-19 23:18:42 -060062 pio = "wb";
63 else
64 pio = "rb+";
Chris Austen4d98c1e2015-10-13 14:33:50 -050065
Chris Austenba54afb2016-02-19 23:18:42 -060066 rlen = (*data_len) - (uint8_t) (sizeof(esel_request_t));
Chris Austen4d98c1e2015-10-13 14:33:50 -050067
Chris Austenba54afb2016-02-19 23:18:42 -060068 printf("IPMI PARTIAL ESEL for %s Offset = %d Length = %d\n",
Nan Li8a0807a2016-05-24 16:59:24 +080069 g_esel_path, esel_req.offset, rlen);
Chris Austen4d98c1e2015-10-13 14:33:50 -050070
Chris Austenba54afb2016-02-19 23:18:42 -060071 if ((fp = fopen(g_esel_path, pio)) != NULL) {
Nan Li8a0807a2016-05-24 16:59:24 +080072 fseek(fp, esel_req.offset, SEEK_SET);
73 fwrite(reqptr+(uint8_t) (sizeof(esel_request_t)), rlen, 1, fp);
Chris Austenba54afb2016-02-19 23:18:42 -060074 fclose(fp);
Chris Austen4d98c1e2015-10-13 14:33:50 -050075
Chris Austenba54afb2016-02-19 23:18:42 -060076 *data_len = sizeof(g_record_id);
77 memcpy(response, &g_record_id, *data_len);
78 } else {
79 fprintf(stderr, "Error trying to perform %s for esel%s\n",pio, g_esel_path);
80 rc = IPMI_CC_INVALID;
81 *data_len = 0;
82 }
Chris Austen4d98c1e2015-10-13 14:33:50 -050083
Chris Austenba54afb2016-02-19 23:18:42 -060084 // The first bit prepresents that this is the last partial packet
85 // coming down. If that is the case advance the record id so we
86 // don't overlap logs. This allows anyone to establish a log
87 // directory system.
Nan Li8a0807a2016-05-24 16:59:24 +080088 if (esel_req.progress & 1 ) {
Chris Austenba54afb2016-02-19 23:18:42 -060089 g_record_id++;
90 }
Chris Austen4d98c1e2015-10-13 14:33:50 -050091
Chris Austenba54afb2016-02-19 23:18:42 -060092 return rc;
Chris Austen4d98c1e2015-10-13 14:33:50 -050093}
94
Adriana Kobylak187bfce2016-03-04 11:55:43 -060095// Prepare for FW Update.
96// Execute needed commands to prepare the system for a fw update from the host.
97ipmi_ret_t ipmi_ibm_oem_prep_fw_update(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
98 ipmi_request_t request, ipmi_response_t response,
99 ipmi_data_len_t data_len, ipmi_context_t context)
100{
101 ipmi_ret_t ipmi_rc = IPMI_CC_OK;
102 *data_len = 0;
103
104 int rc = 0;
105 std::ofstream rwfs_file;
106 const char *busname = "org.openbmc.control.Bmc";
107 const char *objname = "/org/openbmc/control/bmc0";
108 const char *iface = "org.openbmc.control.Bmc";
109 sd_bus *bus = ipmid_get_sd_bus_connection();
110 sd_bus_message *reply = NULL;
111 sd_bus_error error = SD_BUS_ERROR_NULL;
112 int r = 0;
113
114 // Set one time flag
115 rc = system("fw_setenv openbmconce copy-files-to-ram copy-base-filesystem-to-ram");
116 rc = WEXITSTATUS(rc);
117 if (rc != 0) {
118 fprintf(stderr, "fw_setenv openbmconce failed with rc=%d\n", rc);
119 return IPMI_CC_UNSPECIFIED_ERROR;
120 }
121
122 // Touch the image-rwfs file to perform an empty update to force the save
123 // in case we're already in ram and the flash is the same causing the ram files
124 // to not be copied back to flash
125 rwfs_file.open("/run/initramfs/image-rwfs", std::ofstream::out | std::ofstream::app);
126 rwfs_file.close();
127
128 // Reboot the BMC for settings to take effect
129 r = sd_bus_call_method(bus, busname, objname, iface,
130 "warmReset", &error, &reply, NULL);
131 if (r < 0) {
132 fprintf(stderr, "Failed to reset BMC: %s\n", strerror(-r));
133 return -1;
134 }
135 printf("Warning: BMC is going down for reboot!\n");
136 sd_bus_error_free(&error);
137 reply = sd_bus_message_unref(reply);
138
139 return ipmi_rc;
140}
Chris Austen4d98c1e2015-10-13 14:33:50 -0500141
142void register_netfn_oem_partial_esel()
143{
Tomcbfd6ec2016-09-14 17:45:55 +0530144 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_OEM, IPMI_CMD_PESEL);
145 ipmi_register_callback(NETFUN_OEM, IPMI_CMD_PESEL, NULL, ipmi_ibm_oem_partial_esel,
146 SYSTEM_INTERFACE);
Adriana Kobylak187bfce2016-03-04 11:55:43 -0600147
148 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", NETFUN_OEM, IPMI_CMD_PREP_FW_UPDATE);
Tomcbfd6ec2016-09-14 17:45:55 +0530149 ipmi_register_callback(NETFUN_OEM, IPMI_CMD_PREP_FW_UPDATE, NULL, ipmi_ibm_oem_prep_fw_update,
150 SYSTEM_INTERFACE);
Adriana Kobylak187bfce2016-03-04 11:55:43 -0600151
Tomcbfd6ec2016-09-14 17:45:55 +0530152 return;
Chris Austen4d98c1e2015-10-13 14:33:50 -0500153}