/* * cmd_sel.c * * A command interpreter for OpenIPMI * * Author: MontaVista Software, Inc. * Corey Minyard * source@mvista.com * * Copyright 2004 MontaVista Software Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include /* Internal includes, do not use in your programs */ #include static int discrete_event_handler(ipmi_sensor_t *sensor, enum ipmi_event_dir_e dir, int offset, int severity, int prev_severity, void *cb_data, ipmi_event_t *event) { ipmi_cmd_info_t *cmd_info = cb_data; char sensor_name[IPMI_SENSOR_NAME_LEN]; ipmi_sensor_get_name(sensor, sensor_name, sizeof(sensor_name)); ipmi_cmdlang_out(cmd_info, "Object Type", "Sensor"); ipmi_cmdlang_out(cmd_info, "Name", sensor_name); ipmi_cmdlang_out(cmd_info, "Operation", "Event"); ipmi_cmdlang_out_int(cmd_info, "Offset", offset); ipmi_cmdlang_out(cmd_info, "Direction", ipmi_get_event_dir_string(dir)); ipmi_cmdlang_out_int(cmd_info, "Severity", severity); ipmi_cmdlang_out_int(cmd_info, "Previous Severity", prev_severity); return IPMI_EVENT_NOT_HANDLED; } static int threshold_event_handler(ipmi_sensor_t *sensor, enum ipmi_event_dir_e dir, enum ipmi_thresh_e threshold, enum ipmi_event_value_dir_e high_low, enum ipmi_value_present_e value_present, unsigned int raw_value, double value, void *cb_data, ipmi_event_t *event) { ipmi_cmd_info_t *cmd_info = cb_data; char sensor_name[IPMI_SENSOR_NAME_LEN]; ipmi_sensor_get_name(sensor, sensor_name, sizeof(sensor_name)); ipmi_cmdlang_out(cmd_info, "Object Type", "Sensor"); ipmi_cmdlang_out(cmd_info, "Name", sensor_name); ipmi_cmdlang_out(cmd_info, "Operation", "Event"); ipmi_cmdlang_out(cmd_info, "Threshold", ipmi_get_threshold_string(threshold)); ipmi_cmdlang_out(cmd_info, "High/Low", ipmi_get_value_dir_string(high_low)); ipmi_cmdlang_out(cmd_info, "Direction", ipmi_get_event_dir_string(dir)); switch (value_present) { case IPMI_BOTH_VALUES_PRESENT: ipmi_cmdlang_out_double(cmd_info, "Value", value); /* FALLTHRU */ case IPMI_RAW_VALUE_PRESENT: ipmi_cmdlang_out_int(cmd_info, "Raw Value", raw_value); break; default: break; } return IPMI_EVENT_NOT_HANDLED; } static void sel_list(ipmi_domain_t *domain, void *cb_data) { ipmi_cmd_info_t *cmd_info = cb_data; char domain_name[IPMI_DOMAIN_NAME_LEN]; int rv; unsigned int count1, count2; ipmi_event_t *event, *event2; ipmi_cmdlang_t *cmdlang = ipmi_cmdinfo_get_cmdlang(cmd_info); int curr_arg = ipmi_cmdlang_get_curr_arg(cmd_info); int argc = ipmi_cmdlang_get_argc(cmd_info); char **argv = ipmi_cmdlang_get_argv(cmd_info); int interp = 0; ipmi_event_handlers_t *h = NULL; ipmi_domain_get_name(domain, domain_name, sizeof(domain_name)); if ((argc - curr_arg) >= 1) { if (strcmp(argv[curr_arg], "interp") == 0) interp = 1; else { cmdlang->errstr = "Invalid parameter"; cmdlang->err = EINVAL; goto out_err; } } if (interp) { h = ipmi_event_handlers_alloc(); if (!h) { cmdlang->errstr = "Out of memory"; cmdlang->err = ENOMEM; goto out_err; } ipmi_event_handlers_set_threshold(h, threshold_event_handler); ipmi_event_handlers_set_discrete(h, discrete_event_handler); } ipmi_cmdlang_out(cmd_info, "Domain", NULL); ipmi_cmdlang_down(cmd_info); ipmi_cmdlang_out(cmd_info, "Name", domain_name); rv = ipmi_domain_sel_count(domain, &count1); if (rv) return; rv = ipmi_domain_sel_entries_used(domain, &count2); if (rv) return; ipmi_cmdlang_out_int(cmd_info, "Entries", count1); ipmi_cmdlang_out_int(cmd_info, "Slots in use", count2); event = ipmi_domain_first_event(domain); while (event) { ipmi_cmdlang_out(cmd_info, "Event", NULL); ipmi_cmdlang_down(cmd_info); ipmi_cmdlang_event_out(event, cmd_info); if (h) ipmi_event_call_handler(domain, h, event, cmd_info); ipmi_cmdlang_up(cmd_info); event2 = ipmi_domain_next_event(domain, event); ipmi_event_free(event); event = event2; } ipmi_cmdlang_up(cmd_info); if (h) ipmi_event_handlers_free(h); return; out_err: ipmi_domain_get_name(domain, cmdlang->objstr, cmdlang->objstr_len); cmdlang->location = "cmd_sel.c(sel_list)"; if (h) ipmi_event_handlers_free(h); } static void mc_sel_list(ipmi_mc_t *mc, void *cb_data) { ipmi_cmd_info_t *cmd_info = cb_data; char mc_name[IPMI_MC_NAME_LEN]; ipmi_event_t *event, *event2; ipmi_cmdlang_t *cmdlang = ipmi_cmdinfo_get_cmdlang(cmd_info); int curr_arg = ipmi_cmdlang_get_curr_arg(cmd_info); int argc = ipmi_cmdlang_get_argc(cmd_info); char **argv = ipmi_cmdlang_get_argv(cmd_info); int interp = 0; ipmi_event_handlers_t *h = NULL; ipmi_domain_t *domain = ipmi_mc_get_domain(mc); ipmi_mc_get_name(mc, mc_name, sizeof(mc_name)); if ((argc - curr_arg) >= 1) { if (strcmp(argv[curr_arg], "interp") == 0) interp = 1; else { cmdlang->errstr = "Invalid parameter"; cmdlang->err = EINVAL; goto out_err; } } if (interp) { h = ipmi_event_handlers_alloc(); if (!h) { cmdlang->errstr = "Out of memory"; cmdlang->err = ENOMEM; goto out_err; } ipmi_event_handlers_set_threshold(h, threshold_event_handler); ipmi_event_handlers_set_discrete(h, discrete_event_handler); } ipmi_cmdlang_out(cmd_info, "MC", NULL); ipmi_cmdlang_down(cmd_info); ipmi_cmdlang_out(cmd_info, "Name", mc_name); ipmi_cmdlang_out_int(cmd_info, "Entries", ipmi_mc_sel_count(mc)); ipmi_cmdlang_out_int(cmd_info, "Slots in use", ipmi_mc_sel_entries_used(mc)); event = ipmi_mc_first_event(mc); while (event) { ipmi_cmdlang_out(cmd_info, "Event", NULL); ipmi_cmdlang_down(cmd_info); ipmi_cmdlang_event_out(event, cmd_info); if (h) ipmi_event_call_handler(domain, h, event, cmd_info); ipmi_cmdlang_up(cmd_info); event2 = ipmi_mc_next_event(mc, event); ipmi_event_free(event); event = event2; } ipmi_cmdlang_up(cmd_info); if (h) ipmi_event_handlers_free(h); return; out_err: ipmi_mc_get_name(mc, cmdlang->objstr, cmdlang->objstr_len); cmdlang->location = "cmd_sel.c(mc_sel_list)"; if (h) ipmi_event_handlers_free(h); } typedef struct sel_delete_s { ipmi_cmd_info_t *cmd_info; int record; char mc_name[IPMI_MC_NAME_LEN]; } sel_delete_t; static void sel_delete_done(ipmi_domain_t *domain, int err, void *cb_data) { sel_delete_t *info = cb_data; ipmi_cmd_info_t *cmd_info = info->cmd_info; ipmi_cmdlang_t *cmdlang = ipmi_cmdinfo_get_cmdlang(cmd_info); ipmi_cmdlang_lock(cmd_info); if (err) { cmdlang->errstr = "Error deleting SEL entry"; cmdlang->err = err; ipmi_domain_get_name(domain, cmdlang->objstr, cmdlang->objstr_len); cmdlang->location = "cmd_sel.c(sel_delete_done)"; goto out; } ipmi_cmdlang_out(cmd_info, "Event deleted", NULL); ipmi_cmdlang_down(cmd_info); ipmi_cmdlang_out(cmd_info, "MC", info->mc_name); ipmi_cmdlang_out_int(cmd_info, "Record", info->record); ipmi_cmdlang_up(cmd_info); out: ipmi_mem_free(info); ipmi_cmdlang_unlock(cmd_info); ipmi_cmdlang_cmd_info_put(cmd_info); } static void sel_delete(ipmi_mc_t *mc, void *cb_data) { ipmi_cmd_info_t *cmd_info = cb_data; ipmi_cmdlang_t *cmdlang = ipmi_cmdinfo_get_cmdlang(cmd_info); int rv; int curr_arg = ipmi_cmdlang_get_curr_arg(cmd_info); int argc = ipmi_cmdlang_get_argc(cmd_info); char **argv = ipmi_cmdlang_get_argv(cmd_info); ipmi_event_t *event = NULL; int record_id; sel_delete_t *info; if ((argc - curr_arg) < 1) { cmdlang->errstr = "Not enough parameters"; cmdlang->err = EINVAL; goto out_err; } ipmi_cmdlang_get_int(argv[curr_arg], &record_id, cmd_info); if (cmdlang->err) { cmdlang->errstr = "Record id invalid"; goto out_err; } curr_arg++; event = ipmi_mc_event_by_recid(mc, record_id); if (!event) { cmdlang->errstr = "Event not found"; cmdlang->err = EINVAL; goto out_err; } info = ipmi_mem_alloc(sizeof(*info)); if (!info) { cmdlang->errstr = "Out of memory"; cmdlang->err = ENOMEM; goto out_err; } info->cmd_info = cmd_info; info->record = record_id; ipmi_mc_get_name(mc, info->mc_name, sizeof(info->mc_name)); ipmi_cmdlang_cmd_info_get(cmd_info); rv = ipmi_event_delete(event, sel_delete_done, info); if (rv) { ipmi_cmdlang_cmd_info_put(cmd_info); cmdlang->errstr = "Error deleting event"; cmdlang->err = rv; ipmi_mem_free(info); goto out_err; } ipmi_event_free(event); return; out_err: ipmi_mc_get_name(mc, cmdlang->objstr, cmdlang->objstr_len); cmdlang->location = "cmd_sel.c(sel_delete)"; if (event) ipmi_event_free(event); } static void sel_add_done(ipmi_mc_t *mc, unsigned int record_id, int err, void *cb_data) { ipmi_cmd_info_t *cmd_info = cb_data; ipmi_cmdlang_t *cmdlang = ipmi_cmdinfo_get_cmdlang(cmd_info); ipmi_cmdlang_lock(cmd_info); if (err) { cmdlang->errstr = "Error adding SEL entry"; cmdlang->err = err; ipmi_mc_get_name(mc, cmdlang->objstr, cmdlang->objstr_len); cmdlang->location = "cmd_sel.c(sel_add_done)"; } else { char mc_name[IPMI_MC_NAME_LEN]; ipmi_mc_get_name(mc, mc_name, sizeof(mc_name)); ipmi_cmdlang_out(cmd_info, "MC", NULL); ipmi_cmdlang_down(cmd_info); ipmi_cmdlang_out(cmd_info, "Name", mc_name); ipmi_cmdlang_out_int(cmd_info, "Record ID", record_id); ipmi_cmdlang_up(cmd_info); } ipmi_cmdlang_unlock(cmd_info); ipmi_cmdlang_cmd_info_put(cmd_info); } static void sel_add(ipmi_mc_t *mc, void *cb_data) { ipmi_cmd_info_t *cmd_info = cb_data; ipmi_cmdlang_t *cmdlang = ipmi_cmdinfo_get_cmdlang(cmd_info); int rv; int curr_arg = ipmi_cmdlang_get_curr_arg(cmd_info); int argc = ipmi_cmdlang_get_argc(cmd_info); char **argv = ipmi_cmdlang_get_argv(cmd_info); ipmi_event_t *event = NULL; int type; unsigned char data[13]; int i; if ((argc - curr_arg) < 14) { cmdlang->errstr = "Not enough parameters"; cmdlang->err = EINVAL; goto out_err; } ipmi_cmdlang_get_int(argv[curr_arg], &type, cmd_info); if (cmdlang->err) { cmdlang->errstr = "Record type invalid"; goto out_err; } curr_arg++; i = 0; while (curr_arg < argc) { ipmi_cmdlang_get_uchar(argv[curr_arg], &data[i], cmd_info); if (cmdlang->err) { cmdlang->errstr = "data invalid"; goto out_err; } curr_arg++; i++; } event = ipmi_event_alloc(ipmi_mc_convert_to_id(mc), 0, type, 0, data, 13); if (!event) { cmdlang->errstr = "Out of memory"; cmdlang->err = ENOMEM; goto out_err; } ipmi_cmdlang_cmd_info_get(cmd_info); rv = ipmi_mc_add_event_to_sel(mc, event, sel_add_done, cmd_info); if (rv) { ipmi_cmdlang_cmd_info_put(cmd_info); cmdlang->errstr = "Error adding event"; cmdlang->err = rv; goto out_err; } ipmi_event_free(event); return; out_err: ipmi_mc_get_name(mc, cmdlang->objstr, cmdlang->objstr_len); cmdlang->location = "cmd_sel.c(sel_add)"; if (event) ipmi_event_free(event); } static void sel_clear(ipmi_domain_t *domain, void *cb_data) { ipmi_cmd_info_t *cmd_info = cb_data; ipmi_event_t *event, *event2; char domain_name[IPMI_DOMAIN_NAME_LEN]; ipmi_domain_get_name(domain, domain_name, sizeof(domain_name)); event = ipmi_domain_first_event(domain); while (event) { event2 = event; event = ipmi_domain_next_event(domain, event2); ipmi_domain_del_event(domain, event2, NULL, NULL); ipmi_event_free(event2); } ipmi_cmdlang_out(cmd_info, "SEL Clear done", domain_name); return; } static void sel_force_clear_done(ipmi_mc_t *mc, int err, void *cb_data) { ipmi_cmd_info_t *cmd_info = cb_data; ipmi_cmdlang_t *cmdlang = ipmi_cmdinfo_get_cmdlang(cmd_info); ipmi_cmdlang_lock(cmd_info); if (err) { cmdlang->errstr = "Error forcing SEL clear"; cmdlang->err = err; ipmi_mc_get_name(mc, cmdlang->objstr, cmdlang->objstr_len); cmdlang->location = "cmd_sel.c(sel_force_clear_done)"; } else { char mc_name[IPMI_MC_NAME_LEN]; ipmi_mc_get_name(mc, mc_name, sizeof(mc_name)); ipmi_cmdlang_out(cmd_info, "MC force clear done", mc_name); } ipmi_cmdlang_unlock(cmd_info); ipmi_cmdlang_cmd_info_put(cmd_info); } static void sel_force_clear(ipmi_mc_t *mc, void *cb_data) { ipmi_cmd_info_t *cmd_info = cb_data; ipmi_cmdlang_t *cmdlang = ipmi_cmdinfo_get_cmdlang(cmd_info); int curr_arg = ipmi_cmdlang_get_curr_arg(cmd_info); int argc = ipmi_cmdlang_get_argc(cmd_info); char **argv = ipmi_cmdlang_get_argv(cmd_info); ipmi_event_t *event = NULL; char mc_name[IPMI_MC_NAME_LEN]; int rv; int force = 0; if (curr_arg < argc) { if (strcmp(argv[curr_arg], "nocheck") == 0) force = 1; else { cmdlang->err = EINVAL; cmdlang->errstr = "Invalid parameter"; goto out_err; } curr_arg++; } ipmi_mc_get_name(mc, mc_name, sizeof(mc_name)); if (force) event = NULL; else { event = ipmi_mc_last_event(mc); if (!event) { ipmi_cmdlang_out(cmd_info, "SEL force clear done, SEL already empty", mc_name); return; } } ipmi_cmdlang_cmd_info_get(cmd_info); rv = ipmi_mc_sel_clear(mc, event, sel_force_clear_done, cmd_info); if (rv) { ipmi_cmdlang_cmd_info_put(cmd_info); cmdlang->errstr = "Error forcing clear"; cmdlang->err = rv; goto out_err; } if (event) ipmi_event_free(event); return; out_err: ipmi_mc_get_name(mc, cmdlang->objstr, cmdlang->objstr_len); cmdlang->location = "cmd_sel.c(mc_force_clear)"; if (event) ipmi_event_free(event); } static ipmi_cmdlang_cmd_t *sel_cmds; static ipmi_cmdlang_init_t cmds_sel[] = { { "sel", NULL, "- Commands dealing with the SEL", NULL, NULL, &sel_cmds}, { "list", &sel_cmds, " [interp] - List all the events in the domain. If interp is" " specified, then interpret the event data if possible", ipmi_cmdlang_domain_handler, sel_list, NULL }, { "mc_list", &sel_cmds, " - List all the events in the given MC's SEL", ipmi_cmdlang_mc_handler, mc_sel_list, NULL }, { "delete", &sel_cmds, " - Delete the given event.", ipmi_cmdlang_mc_handler, sel_delete, NULL }, { "add", &sel_cmds, " <13 data bytes> - add the given event to the" " MC's sel.", ipmi_cmdlang_mc_handler, sel_add, NULL }, { "clear", &sel_cmds, " - Delete all events in the domain.", ipmi_cmdlang_domain_handler, sel_clear, NULL }, { "force_clear", &sel_cmds, " [nocheck] - Force a clear of the SEL in the MC. nocheck means" " don't check that any events were added during the clear, just force a" " clear.", ipmi_cmdlang_mc_handler, sel_force_clear, NULL }, }; #define CMDS_SEL_LEN (sizeof(cmds_sel)/sizeof(ipmi_cmdlang_init_t)) int ipmi_cmdlang_sel_init(os_handler_t *os_hnd) { return ipmi_cmdlang_reg_table(cmds_sel, CMDS_SEL_LEN); }