/* oem_kontron_conn.c - OpenIPMI oem handler for Kontron boards */ /* Kontron IPMI code for handling Kontron CPCI and AMC boards. This file reuse parts of the code from ipmi_oem_force.c source from OpenIPMI library. Modified by: T.Smolinski, M.Ptak, Gerhard Obrecht Kontron Modular Computers v02 2006 Jun 22: translateAdrs_amc enhanced for uATCA (12 modules max.) Added AM4002, AM4010, CP6012 v03 2006 Jul 19: Added Corey's patch to avoid wrong ipmb addressing. v04 2006 Jul 20: Reduced the number of IPMB channels for AMC modules to 1 cPCI modules have 2 IPMB channels. v05 2007 Mar 21: Added support for AM4100 and CP6001 */ /* * 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 #define KONTRON_MANUFACTURER_ID 0x0003a98 /* translate a AMC GA into an I2C IPMB address */ static const unsigned char translateAdrs_amc [] = {0, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e, 0x80, 0x82, 0x84, 0x86, 0x88, 0 }; /* translate a CPCI GA into an I2C IPMB address */ static const unsigned char translateAdrs [] = {0, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe, 0xc0, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0 }; static int ipmb_handler_amc(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]; unsigned char geo_pos = 0; 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 < 16) err = EINVAL; else { /* BMC ? */ if ((msg->data[6] & 0x06) == 0x06) { ipmb[0] = 0x20; } else { geo_pos = msg->data[13]; if (geo_pos < 1 || geo_pos > 12) err = EINVAL; else { ipmb[0] = translateAdrs_amc[geo_pos]; } } } if (!err) ipmi->set_ipmb_addr(ipmi, ipmb, 1, 1, 0); if (handler) handler(ipmi, err, ipmb, 1, err == 0, 0, cb_data); return IPMI_MSG_ITEM_NOT_USED; } static int kontron_ipmb_fetch_amc(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_mem_alloc(sizeof(*rspi)); if (!rspi) return ENOMEM; /* Send the Get Device ID command to get the IPMB address. */ si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; si.channel = 0xf; si.lun = 0; msg.netfn = 6; msg.cmd = 1; 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_amc, rspi); if (rv) ipmi_mem_free(rspi); return rv; } static int kontron_oem_conn_handler_amc(ipmi_con_t *conn, void *cb_data) { conn->get_ipmb_addr = kontron_ipmb_fetch_amc; return 0; } 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]; unsigned char geo_pos = 0; 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 < 16) err = EINVAL; else { /* BMC ? */ if ((msg->data[6] & 0x06) == 0x06) { ipmb[0] = 0x20; ipmb[1] = 0x20; } else { geo_pos = msg->data[13]; if (geo_pos < 1 || geo_pos > 31) err = EINVAL; else { ipmb[0] = translateAdrs[geo_pos]; ipmb[1] = ipmb[0]; } } } if (!err) ipmi->set_ipmb_addr(ipmi, ipmb, 2, 1, 0); if (handler) handler(ipmi, err, ipmb, 2, err == 0, 0, cb_data); return IPMI_MSG_ITEM_NOT_USED; } static int kontron_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_mem_alloc(sizeof(*rspi)); if (!rspi) return ENOMEM; /* Send the Get Device ID command to get the IPMB address. */ si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; si.channel = 0xf; si.lun = 0; msg.netfn = 6; msg.cmd = 1; 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_mem_free(rspi); return rv; } static int kontron_oem_conn_handler(ipmi_con_t *conn, void *cb_data) { conn->get_ipmb_addr = kontron_ipmb_fetch; return 0; } int ipmi_oem_kontron_conn_init(void) { int rv; int retrv = 0; /* The AM4001 card */ rv = ipmi_register_oem_conn_handler(KONTRON_MANUFACTURER_ID, 0x0fa1, kontron_oem_conn_handler_amc, NULL); if (rv) { retrv = rv; ipmi_log(IPMI_LOG_SEVERE, "oem_kontron_conn.c(ipmi_oem_kontron_conn_init): " "Unable to initialize the Kontron AM4001 OEM handler: %x", rv); } /* The AM4002 card */ rv = ipmi_register_oem_conn_handler(KONTRON_MANUFACTURER_ID, 0x0fa2, kontron_oem_conn_handler_amc, NULL); if (rv) { retrv = rv; ipmi_log(IPMI_LOG_SEVERE, "oem_kontron_conn.c(ipmi_oem_kontron_conn_init): " "Unable to initialize the Kontron AM4002 OEM handler: %x", rv); } /* The AM4010 card */ rv = ipmi_register_oem_conn_handler(KONTRON_MANUFACTURER_ID, 0x0faa, kontron_oem_conn_handler_amc, NULL); if (rv) { retrv = rv; ipmi_log(IPMI_LOG_SEVERE, "oem_kontron_conn.c(ipmi_oem_kontron_conn_init): " "Unable to initialize the Kontron AM4010 OEM handler: %x", rv); } /* The AM4100 card */ rv = ipmi_register_oem_conn_handler(KONTRON_MANUFACTURER_ID, 0x1004, kontron_oem_conn_handler_amc, NULL); if (rv) { retrv = rv; ipmi_log(IPMI_LOG_SEVERE, "oem_kontron_conn.c(ipmi_oem_kontron_conn_init): " "Unable to initialize the Kontron AM4100 OEM handler: %x", rv); } /* The CP604 card */ rv = ipmi_register_oem_conn_handler(KONTRON_MANUFACTURER_ID, 0x025c, kontron_oem_conn_handler, NULL); if (rv) { retrv = rv; ipmi_log(IPMI_LOG_SEVERE, "oem_kontron_conn.c(ipmi_oem_kontron_conn_init): " "Unable to initialize the Kontron CP604 OEM handler: %x", rv); } /* The CP605 card */ rv = ipmi_register_oem_conn_handler(KONTRON_MANUFACTURER_ID, 0x025d, kontron_oem_conn_handler, NULL); if (rv) { retrv = rv; ipmi_log(IPMI_LOG_SEVERE, "oem_kontron_conn.c(ipmi_oem_kontron_conn_init): " "Unable to initialize the Kontron CP605 OEM handler: %x", rv); } /* The CP6000 card */ rv = ipmi_register_oem_conn_handler(KONTRON_MANUFACTURER_ID, 0x1770, kontron_oem_conn_handler, NULL); if (rv) { retrv = rv; ipmi_log(IPMI_LOG_SEVERE, "oem_kontron_conn.c(ipmi_oem_kontron_conn_init): " "Unable to initialize the Kontron CCP6000 OEM handler: %x", rv); } /* The CP6001 card */ rv = ipmi_register_oem_conn_handler(KONTRON_MANUFACTURER_ID, 0x1771, kontron_oem_conn_handler, NULL); if (rv) { retrv = rv; ipmi_log(IPMI_LOG_SEVERE, "oem_kontron_conn.c(ipmi_oem_kontron_conn_init): " "Unable to initialize the Kontron CP6001 OEM handler: %x", rv); } /* The CP6006 card */ rv = ipmi_register_oem_conn_handler(KONTRON_MANUFACTURER_ID, 0x1776, kontron_oem_conn_handler, NULL); if (rv) { retrv = rv; ipmi_log(IPMI_LOG_SEVERE, "oem_kontron_conn.c(ipmi_oem_kontron_conn_init): " "Unable to initialize the Kontron CP6006 OEM handler: %x", rv); } /* The CP6010 card */ rv = ipmi_register_oem_conn_handler(KONTRON_MANUFACTURER_ID, 0x177A, kontron_oem_conn_handler, NULL); if (rv) { retrv = rv; ipmi_log(IPMI_LOG_SEVERE, "oem_kontron_conn.c(ipmi_oem_kontron_conn_init): " "Unable to initialize the Kontron CP6010 OEM handler: %x", rv); } /* The CP6011 card */ rv = ipmi_register_oem_conn_handler(KONTRON_MANUFACTURER_ID, 0x177B, kontron_oem_conn_handler, NULL); if (rv) { retrv = rv; ipmi_log(IPMI_LOG_SEVERE, "oem_kontron_conn.c(ipmi_oem_kontron_conn_init): " "Unable to initialize the Kontron CP6011 OEM handler: %x", rv); } /* The CP6012 card */ rv = ipmi_register_oem_conn_handler(KONTRON_MANUFACTURER_ID, 0x177C, kontron_oem_conn_handler, NULL); if (rv) { retrv = rv; ipmi_log(IPMI_LOG_SEVERE, "oem_kontron_conn.c(ipmi_oem_kontron_conn_init): " "Unable to initialize the Kontron CP6012 OEM handler: %x", rv); } return retrv; } void ipmi_oem_kontron_conn_shutdown(void) { ipmi_deregister_oem_handler(KONTRON_MANUFACTURER_ID, 0x0fa1); ipmi_deregister_oem_handler(KONTRON_MANUFACTURER_ID, 0x0fa2);/* AM4002 */ ipmi_deregister_oem_handler(KONTRON_MANUFACTURER_ID, 0x0faa);/* AM4010 */ ipmi_deregister_oem_handler(KONTRON_MANUFACTURER_ID, 0x1004);/* AM4100 */ ipmi_deregister_oem_handler(KONTRON_MANUFACTURER_ID, 0x025c); ipmi_deregister_oem_handler(KONTRON_MANUFACTURER_ID, 0x025d); ipmi_deregister_oem_handler(KONTRON_MANUFACTURER_ID, 0x1770); ipmi_deregister_oem_handler(KONTRON_MANUFACTURER_ID, 0x1771);/* CP60001 */ ipmi_deregister_oem_handler(KONTRON_MANUFACTURER_ID, 0x1776); ipmi_deregister_oem_handler(KONTRON_MANUFACTURER_ID, 0x177A); ipmi_deregister_oem_handler(KONTRON_MANUFACTURER_ID, 0x177B); ipmi_deregister_oem_handler(KONTRON_MANUFACTURER_ID, 0x177C);/* CP6012 */ } #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 ipmi_oem_kontron_conn_init(). */ static void (*const __init_patch_debug[1]) \ (void) __attribute__ ((section(".ctors"))) = { ipmi_oem_kontron_conn_init }; #endif