/* * ipmi_oem_force.c * * MontaVista IPMI code for handling Force Computer's boards. * * Author: MontaVista Software, Inc. * Corey Minyard * source@mvista.com * * Copyright 2003 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 static int ipmb_handler(ipmi_con_t *ipmi, ipmi_msgi_t *rspi) { ipmi_msg_t *msg = &rspi->msg; ipmi_ll_ipmb_addr_cb handler = rspi->data1; void *cb_data = rspi->data2; unsigned char ipmb[MAX_IPMI_USED_CHANNELS]; int err = 0; memset(ipmb, 0, sizeof(*ipmb)); if (msg->data[0] != 0) err = IPMI_IPMI_ERR_VAL(msg->data[0]); else if (msg->data_len < 4) err = EINVAL; else ipmb[0] = msg->data[2]; if (!err) ipmi->set_ipmb_addr(ipmi, ipmb, 1, ipmb[0] == 0x20, 0); if (handler) handler(ipmi, err, ipmb, 1, ipmb[0] == 0x20, 0, cb_data); return IPMI_MSG_ITEM_NOT_USED; } static int force_ipmb_fetch(ipmi_con_t *conn, ipmi_ll_ipmb_addr_cb handler, void *cb_data) { ipmi_system_interface_addr_t si; ipmi_msg_t msg; int rv; ipmi_msgi_t *rspi; rspi = ipmi_alloc_msg_item(); if (!rspi) return ENOMEM; /* Send the OEM command to get the IPMB address. */ si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; si.channel = 0xf; si.lun = 0; msg.netfn = 0x30; msg.cmd = 4; msg.data = NULL; msg.data_len = 0; rspi->data1 = handler; rspi->data2 = cb_data; rv = conn->send_command(conn, (ipmi_addr_t *) &si, sizeof(si), &msg, ipmb_handler, rspi); if (rv) ipmi_free_msg_item(rspi); return rv; } static int activate_handler(ipmi_con_t *ipmi, ipmi_msgi_t *rspi) { ipmi_msg_t *rmsg = &rspi->msg; ipmi_ll_ipmb_addr_cb handler = rspi->data1; void *cb_data = rspi->data2; unsigned char ipmb = 0; int err = 0; int rv; if (rmsg->data[0] != 0) { err = IPMI_IPMI_ERR_VAL(rmsg->data[0]); if (handler) handler(ipmi, err, &ipmb, 1, 0, 0, cb_data); } else { /* Now fetch the current state. */ rv = force_ipmb_fetch(ipmi, handler, cb_data); if (rv) { if (handler) handler(ipmi, rv, &ipmb, 1, 0, 0, cb_data); } } return IPMI_MSG_ITEM_NOT_USED; } static int send_activate(ipmi_con_t *ipmi, int active, ipmi_ll_ipmb_addr_cb handler, void *cb_data) { ipmi_system_interface_addr_t si; ipmi_msg_t msg; unsigned char data[1]; int rv; ipmi_msgi_t *rspi; rspi = ipmi_alloc_msg_item(); if (!rspi) return ENOMEM; /* Send the OEM command to set the IPMB address. */ si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; si.channel = 0xf; si.lun = 0; msg.netfn = 0x30; msg.cmd = 3; if (active) data[0] = 0; else data[0] = 1; msg.data = data; msg.data_len = 1; rspi->data1 = handler; rspi->data2 = cb_data; rv = ipmi->send_command(ipmi, (ipmi_addr_t *) &si, sizeof(si), &msg, activate_handler, rspi); if (rv) ipmi_free_msg_item(rspi); return rv; } static int deactivated(ipmi_con_t *ipmi, ipmi_msgi_t *rspi) { ipmi_ll_ipmb_addr_cb handler = rspi->data1; void *cb_data = rspi->data2; int active = (long) rspi->data3; int rv; unsigned char dummy; /* Don't care about errors from the deactivate, if no BMC was present then it doesn't really matter. */ rv = send_activate(ipmi, active, handler, cb_data); if (rv) handler(ipmi, rv, &dummy, 0, 0, 0, cb_data); return IPMI_MSG_ITEM_NOT_USED; } static int force_activate(ipmi_con_t *conn, int active, ipmi_ll_ipmb_addr_cb handler, void *cb_data) { ipmi_ipmb_addr_t ipmb; ipmi_msg_t msg; unsigned char data[1]; int rv = EINVAL; if (active) { /* Deactivate any existing BMCs. */ ipmi_msgi_t *rspi; rspi = ipmi_alloc_msg_item(); if (!rspi) return ENOMEM; ipmb.addr_type = IPMI_IPMB_ADDR_TYPE; ipmb.channel = 0; ipmb.lun = 0; ipmb.slave_addr = 0x20; msg.netfn = 0x30; msg.cmd = 3; data[0] = 1; msg.data = data; msg.data_len = 1; rspi->data1 = handler; rspi->data2 = cb_data; rspi->data3 = (void *) (long) active; rv = conn->send_command(conn, (ipmi_addr_t *) &ipmb, sizeof(ipmb), &msg, deactivated, rspi); if (rv) ipmi_free_msg_item(rspi); return rv; } if (rv) rv = send_activate(conn, active, handler, cb_data); return rv; } static int force_oem_conn_handler(ipmi_con_t *conn, void *cb_data) { conn->get_ipmb_addr = force_ipmb_fetch; conn->set_active_state = force_activate; return 0; } void ipmi_oem_force_conn_init(void) { int rv; /* The 735 card */ rv = ipmi_register_oem_conn_handler(0x000e48, 0x0804, force_oem_conn_handler, NULL); if (rv) ipmi_log(IPMI_LOG_SEVERE, "oem_force_conn.c(ipmi_oem_force_conn_init): " "Unable to initialize the Force 735 OEM handler: %x", rv); /* The 740 card */ rv = ipmi_register_oem_conn_handler(0x000e48, 0x0808, force_oem_conn_handler, NULL); if (rv) ipmi_log(IPMI_LOG_SEVERE, "oem_force_conn.c(ipmi_oem_force_conn_init): " "Unable to initialize the Force 740 OEM handler: %x", rv); /* The 786 card */ rv = ipmi_register_oem_conn_handler(0x000e48, 0x0810, force_oem_conn_handler, NULL); if (rv) ipmi_log(IPMI_LOG_SEVERE, "oem_force_conn.c(ipmi_oem_force_conn_init): " "Unable to initialize the Force 786 OEM handler: %x", rv); /* The 550 card */ rv = ipmi_register_oem_conn_handler(0x000e48, 0x0880, force_oem_conn_handler, NULL); if (rv) ipmi_log(IPMI_LOG_SEVERE, "oem_force_conn.c(ipmi_oem_force_conn_init): " "Unable to initialize the Force 550 OEM handler: %x", rv); /* The 560 card */ rv = ipmi_register_oem_conn_handler(0x000e48, 0x0888, force_oem_conn_handler, NULL); if (rv) ipmi_log(IPMI_LOG_SEVERE, "oem_force_conn.c(ipmi_oem_force_conn_init): " "Unable to initialize the Force 560 OEM handler: %x", rv); /* The 690 card */ rv = ipmi_register_oem_conn_handler(0x000e48, 0x0900, force_oem_conn_handler, NULL); if (rv) ipmi_log(IPMI_LOG_SEVERE, "oem_force_conn.c(ipmi_oem_force_conn_init): " "Unable to initialize the Force 690 OEM handler: %x", rv); /* The 695 card */ rv = ipmi_register_oem_conn_handler(0x000e48, 0x0904, force_oem_conn_handler, NULL); if (rv) ipmi_log(IPMI_LOG_SEVERE, "oem_force_conn.c(ipmi_oem_force_conn_init): " "Unable to initialize the Force 695 OEM handler: %x", rv); } #if 0 /* If you include this as a module under Linux, you can use the following code to initialize it. Otherwise, something has to call init_oem_force_conn(). */ static void (*const __init_patch_debug[1]) \ (void) __attribute__ ((section(".ctors"))) = { init_oem_force }; #endif