On 08/17/10 23:10, Albert Chu:
Attached is my reworked patch for ipmi-oem. Can you give it a shot and
LMK if it works?
Done. Some notes:
1. --------------
if user call for record id >= 65536 the number record ID is silently
changed to something else. I recommend not to allow out-of-range values
at all.
2. --------------
bytes_rq[8] = UCHAR_MAX;
Requests with MaxResponseDataSize>100 will fail.
Also response packet can't be larger than IPMI_OEM_MAX_BYTES
So you can't ask for more than min(IPMI_OEM_MAX_BYTES-17,100) bytes.
3. --------------
component_length = (rs_len - 16);
I prefer more safe approach - I assume that string may end before packet
end (e.g. len is obtained by strlen). And I doesn't assume that string
is '\0' terminated in response also.
The so-called documentation from Fujitsu is so vague to be trusted so
much, IMHO ...
4. ----------------
... in advance, you count the length including the trailing '\0' (which
is present in every response - not only the last part of string), so the
concatenation doesn't work (off-by-one bug)
5. ----------------
while (offset < data_length)
... will be neverending loop when
IPMI_OEM_FUJITSU_SEL_ENTRY_LONG_TEXT_MAX_STRING_LENGTH < data_length
You should replace
offset = IPMI_OEM_FUJITSU_SEL_ENTRY_LONG_TEXT_MAX_STRING_LENGTH
with
offset = data_length
to resolve the issue. Or use "break;" ...
6. ----------------
bytes_rq array need not to be intialized every round (only offset is
changing). Also, most of results needs to be extracted from bytes_rs
only once.
7. ----------------
If user asked for 'first' or 'last' record then use actual_record id for
subsequent (looped) requests to obtain consistent results as last SEL
may become non-last in meantime.
======================
I did (atleast try) to implement the code to loop if there was more text
to retrieve. Hopefully I implemented it right.
See [4], [5] and [7]
Also, I slightly tweaked the output to more similarly match ipmi-sel
output, adding in semi-colons and stuff. I admit, I'm not entirely sure
of the output. You may have specifically chosen your output
I tried to follow output format of ipmi-sel.
I attached the another iteration of patch.
Dan
--- ipmi-oem-fujitsu.c.orig 2010-08-18 00:30:00.000000000 +0200
+++ ipmi-oem-fujitsu.c 2010-08-18 01:15:30.000000000 +0200
@@ -223,6 +223,23 @@
#define IPMI_OEM_FUJITSU_ERROR_LED_CSS_BLINK_GEL_ON 7
#define IPMI_OEM_FUJITSU_ERROR_LED_CSS_BLINK_GEL_BLINK 8
+/* achu: one byte field, so max is 255 */
+#define IPMI_OEM_FUJITSU_SEL_ENTRY_LONG_TEXT_MAX_STRING_LENGTH 255
+
+#define IPMI_OEM_FUJITSU_CSS_BITMASK 0x80
+#define IPMI_OEM_FUJITSU_CSS_SHIFT 7
+
+#define IPMI_OEM_FUJITSU_SEVERITY_BITMASK 0x70
+#define IPMI_OEM_FUJITSU_SEVERITY_SHIFT 4
+
+#define IPMI_OEM_FUJITSU_CSS_COMPONENT 1
+#define IPMI_OEM_FUJITSU_NO_CSS_COMPONENT 0
+
+#define IPMI_OEM_FUJITSU_SEVERITY_INFORMATIONAL 0
+#define IPMI_OEM_FUJITSU_SEVERITY_MINOR 1
+#define IPMI_OEM_FUJITSU_SEVERITY_MAJOR 2
+#define IPMI_OEM_FUJITSU_SEVERITY_CRITICAL 3
+
static int
_ipmi_oem_get_power_source (ipmi_oem_state_data_t *state_data,
uint8_t command_specifier,
@@ -1290,3 +1307,235 @@
cleanup:
return (rv);
}
+
+int
+ipmi_oem_fujitsu_get_sel_entry_long_text (ipmi_oem_state_data_t *state_data)
+{
+ uint8_t bytes_rq[IPMI_OEM_MAX_BYTES];
+ uint8_t bytes_rs[IPMI_OEM_MAX_BYTES];
+ int rs_len, tmp;
+ uint16_t sel_record_id;
+ uint16_t actual_record_id = 0;
+ uint32_t timestamp = 0;
+ uint8_t css = 0;
+ uint8_t severity = 0;
+ time_t timetmp;
+ struct tm time_tm;
+ char time_buf[IPMI_OEM_TIME_BUFLEN + 1];
+ char string_buf[IPMI_OEM_FUJITSU_SEL_ENTRY_LONG_TEXT_MAX_STRING_LENGTH + 1];
+ uint8_t data_length = UCHAR_MAX;
+ uint8_t offset = 0;
+ uint8_t component_length = 0;
+ char *css_str = NULL;
+ char *severity_str = NULL;
+ char *ptr = NULL;
+ int rv = -1;
+
+ assert (state_data);
+ assert (state_data->prog_data->args->oem_options_count == 1);
+
+ errno = 0;
+
+ tmp = strtoul (state_data->prog_data->args->oem_options[0], &ptr, 0);
+ if (errno || ptr[0] != '\0')
+ {
+ pstdout_fprintf (state_data->pstate,
+ stderr,
+ "%s:%s invalid OEM option argument '%s'\n",
+ state_data->prog_data->args->oem_id,
+ state_data->prog_data->args->oem_command,
+ state_data->prog_data->args->oem_options[0]);
+ goto cleanup;
+ }
+
+ if (tmp > 0xFFFF)
+ {
+ pstdout_fprintf (state_data->pstate,
+ stderr,
+ "%s:%s invalid OEM option argument '%s' : out of
range\n",
+ state_data->prog_data->args->oem_id,
+ state_data->prog_data->args->oem_command,
+ state_data->prog_data->args->oem_options[0]);
+ goto cleanup;
+ }
+
+ sel_record_id = tmp;
+
+ memset (string_buf, '\0',
IPMI_OEM_FUJITSU_SEL_ENTRY_LONG_TEXT_MAX_STRING_LENGTH + 1);
+
+ /* Fujitsu OEM
+ *
+ * http://manuals.ts.fujitsu.com/file/4390/irmc_s2-ug-en.pdf
+ *
+ * Request
+ *
+ * 0x2E - OEM network function
+ * 0xF5 - OEM cmd
+ * 0x?? - Fujitsu IANA (LSB first)
+ * 0x?? - Fujitsu IANA
+ * 0x?? - Fujitsu IANA
+ * 0x43 - Command Specifier
+ * 0x?? - Record ID (LSB first)
+ * 0x?? - Record ID ; 0x0000 = "first record", 0xFFFF = "last record"
+ * 0x?? - Offset (in response SEL text)
+ * 0x?? - MaxResponseDataSize (size of converted SEL data 16:n in response,
maximum is 100)
+ *
+ * Response
+ *
+ * 0xF5 - OEM cmd
+ * 0x?? - Completion code
+ * 0x?? - Fujitsu IANA (LSB first)
+ * 0x?? - Fujitsu IANA
+ * 0x?? - Fujitsu IANA
+ * 0x?? - Next Record ID (LSB)
+ * 0x?? - Next Record ID (MSB)
+ * 0x?? - Actual Record ID (LSB)
+ * 0x?? - Actual Record ID (MSB)
+ * 0x?? - Record type
+ * 0x?? - timestamp (LSB first)
+ * 0x?? - timestamp
+ * 0x?? - timestamp
+ * 0x?? - timestamp
+ * 0x?? - severity
+ * bit 7 - CSS component
+ * - 0 - No CSS component
+ * - 1 - CSS component
+ * bit 6-4 - 000 = INFORMATIONAL
+ * 001 = MINOR
+ * 010 = MAJOR
+ * 011 = CRITICAL
+ * 1xx = unknown
+ * bit 3-0 - reserved
+ * 0x?? - data length (of the whole text)
+ * 0x?? - converted SEL data
+ * - requested number of bytes starting at requested offset
(MaxResponseDataSize-1 bytes of data)
+ * 0x00 - trailing '\0' character
+ */
+
+#define min(a,b) ((a)<(b) ? (a) : (b))
+ bytes_rq[0] = IPMI_CMD_OEM_FUJITSU_SYSTEM;
+ bytes_rq[1] = (IPMI_IANA_ENTERPRISE_ID_FUJITSU & 0x0000FF);
+ bytes_rq[2] = (IPMI_IANA_ENTERPRISE_ID_FUJITSU & 0x00FF00) >> 8;
+ bytes_rq[3] = (IPMI_IANA_ENTERPRISE_ID_FUJITSU & 0xFF0000) >> 16;
+ bytes_rq[4] = IPMI_OEM_FUJITSU_COMMAND_SPECIFIER_GET_SEL_ENTRY_LONG_TEXT;
+ bytes_rq[8] = min(IPMI_OEM_MAX_BYTES-17,100);
+ bytes_rq[5] = (sel_record_id & 0x00FF);
+ bytes_rq[6] = (sel_record_id & 0xFF00) >> 8;
+
+ while (offset < data_length)
+ {
+ bytes_rq[7] = offset;
+
+ if ((rs_len = ipmi_cmd_raw (state_data->ipmi_ctx,
+ 0, /* lun */
+ IPMI_NET_FN_OEM_GROUP_RQ, /* network
function */
+ bytes_rq, /* data */
+ 9, /* num bytes */
+ bytes_rs,
+ IPMI_OEM_MAX_BYTES)) < 0)
+ {
+ pstdout_fprintf (state_data->pstate,
+ stderr,
+ "ipmi_cmd_raw: %s\n",
+ ipmi_ctx_errormsg (state_data->ipmi_ctx));
+ goto cleanup;
+ }
+
+ if (ipmi_oem_check_response_and_completion_code (state_data,
+ bytes_rs,
+ rs_len,
+ 17,
+
IPMI_CMD_OEM_FUJITSU_SYSTEM,
+
IPMI_NET_FN_OEM_GROUP_RS,
+ NULL) < 0)
+ goto cleanup;
+
+ /* achu: assume a lot of this will be the same not matter how many times
we loop */
+ if (offset == 0) {
+ actual_record_id = bytes_rs[7];
+ actual_record_id |= (bytes_rs[8] << 8);
+
+ /* if user asked for 'first' or 'last' then use actual_record_id for
subsekvent request to obtain consistent results */
+ bytes_rq[5] = bytes_rs[7];
+ bytes_rq[6] = bytes_rs[8];
+
+ timestamp = bytes_rs[10];
+ timestamp |= (bytes_rs[11] << 8);
+ timestamp |= (bytes_rs[12] << 16);
+ timestamp |= (bytes_rs[13] << 24);
+
+ css = (bytes_rs[14] & IPMI_OEM_FUJITSU_CSS_BITMASK);
+ css >>= IPMI_OEM_FUJITSU_CSS_SHIFT;
+
+ severity = (bytes_rs[14] & IPMI_OEM_FUJITSU_SEVERITY_BITMASK);
+ severity >>= IPMI_OEM_FUJITSU_SEVERITY_SHIFT;
+ };
+
+ data_length = bytes_rs[15];
+
+ bytes_rs[rs_len-1]='\0'; /* just to be sure it's terminated */
+ component_length = strlen((char *)bytes_rs + 16);
+
+ /* achu: truncate if there is overflow */
+ if (offset + component_length >
IPMI_OEM_FUJITSU_SEL_ENTRY_LONG_TEXT_MAX_STRING_LENGTH)
+ {
+ memcpy (string_buf + offset,
+ &bytes_rs[16],
+ IPMI_OEM_FUJITSU_SEL_ENTRY_LONG_TEXT_MAX_STRING_LENGTH -
offset);
+ offset = data_length;
+ }
+ else
+ {
+ memcpy (string_buf + offset,
+ &bytes_rs[16],
+ component_length);
+ offset += component_length;
+ }
+ }
+
+ if (css == IPMI_OEM_FUJITSU_CSS_COMPONENT)
+ css_str = "CSS Component";
+
+ if (severity == IPMI_OEM_FUJITSU_SEVERITY_INFORMATIONAL)
+ severity_str = "INFORMATIONAL";
+ else if (severity == IPMI_OEM_FUJITSU_SEVERITY_MINOR)
+ severity_str = "MINOR";
+ else if (severity == IPMI_OEM_FUJITSU_SEVERITY_MAJOR)
+ severity_str = "MAJOR";
+ else if (severity == IPMI_OEM_FUJITSU_SEVERITY_CRITICAL)
+ severity_str = "CRITICAL";
+ else
+ severity_str = "Unknown Severity";
+
+ /* Posix says individual calls need not clear/set all portions of
+ * 'struct tm', thus passing 'struct tm' between functions could
+ * have issues. So we need to memset.
+ */
+ memset (&time_tm, '\0', sizeof(struct tm));
+
+ timetmp = timestamp;
+ localtime_r (&timetmp, &time_tm);
+ memset (time_buf, '\0', IPMI_OEM_TIME_BUFLEN + 1);
+ strftime (time_buf, IPMI_OEM_TIME_BUFLEN, "%b-%d-%Y | %H:%M:%S", &time_tm);
+
+ if (css_str)
+ pstdout_printf (state_data->pstate,
+ "%u | %s | %s ; %s ; %s\n",
+ actual_record_id,
+ time_buf,
+ css_str,
+ severity_str,
+ string_buf);
+ else
+ pstdout_printf (state_data->pstate,
+ "%u | %s | %s ; %s\n",
+ actual_record_id,
+ time_buf,
+ severity_str,
+ string_buf);
+
+ rv = 0;
+ cleanup:
+ return (rv);
+}
+
_______________________________________________
Freeipmi-devel mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/freeipmi-devel