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

Reply via email to