Mercurial > illumos > illumos-gate
changeset 13848:440c93ffaf29
370 would like an open ipmi baseboard driver
Reviewed by: Igor Kozhukhov <ikozhukhov@gmail.com>
Reviewed by: Albert Lee <trisk@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Alek Pinchuk <pinchuk.alek@gmail.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
Approved by: Dan McDonald <danmcd@nexenta.com>
line wrap: on
line diff
--- a/usr/src/cmd/devfsadm/i386/misc_link_i386.c Thu Sep 27 16:04:13 2012 -0400 +++ b/usr/src/cmd/devfsadm/i386/misc_link_i386.c Thu Apr 26 15:49:44 2012 +0000 @@ -21,6 +21,7 @@ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2012 Joyent, Inc. All rights reserved. */ #include <regex.h> @@ -41,7 +42,7 @@ static int diskette(di_minor_t minor, di_node_t node); static int vt00(di_minor_t minor, di_node_t node); static int kdmouse(di_minor_t minor, di_node_t node); -static int bmc(di_minor_t minor, di_node_t node); +static int ipmi(di_minor_t minor, di_node_t node); static int smbios(di_minor_t minor, di_node_t node); static int agp_process(di_minor_t minor, di_node_t node); static int drm_node(di_minor_t minor, di_node_t node); @@ -62,8 +63,8 @@ { "mouse", "ddi_mouse", "mouse8042", TYPE_EXACT | DRV_EXACT, ILEVEL_0, kdmouse }, - { "pseudo", "ddi_pseudo", "bmc", - TYPE_EXACT | DRV_EXACT, ILEVEL_0, bmc, + { "pseudo", "ddi_pseudo", "ipmi", + TYPE_EXACT | DRV_EXACT, ILEVEL_0, ipmi, }, { "pseudo", "ddi_pseudo", "smbios", TYPE_EXACT | DRV_EXACT, ILEVEL_1, smbios, @@ -350,9 +351,13 @@ } static int -bmc(di_minor_t minor, di_node_t node) +ipmi(di_minor_t minor, di_node_t node) { - (void) devfsadm_mklink("bmc", node, minor, 0); + /* + * Follow convention from other systems, and include an instance#, + * even though there will only be one. + */ + (void) devfsadm_mklink("ipmi0", node, minor, 0); return (DEVFSADM_CONTINUE); }
--- a/usr/src/cmd/fm/modules/common/fdd-msg/fdd_msg.c Thu Sep 27 16:04:13 2012 -0400 +++ b/usr/src/cmd/fm/modules/common/fdd-msg/fdd_msg.c Thu Apr 26 15:49:44 2012 +0000 @@ -188,7 +188,7 @@ if ((ipmi_hdl = ipmi_open(&error, &msg, IPMI_TRANSPORT_BMC, NULL)) == NULL) { /* - * If /dev/bmc doesn't exist on the system, then return + * If /dev/ipmi0 doesn't exist on the system, then return * without doing anything. */ if (error != EIPMI_BMC_OPEN_FAILED)
--- a/usr/src/cmd/fm/modules/common/sp-monitor/sp_monitor.c Thu Sep 27 16:04:13 2012 -0400 +++ b/usr/src/cmd/fm/modules/common/sp-monitor/sp_monitor.c Thu Apr 26 15:49:44 2012 +0000 @@ -22,13 +22,14 @@ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2012 Joyent, Inc. All rights reserved. */ /* - * /dev/bmc IPMI monitor + * /dev/ipmi IPMI monitor * * The purpose of this module is to monitor the connection between the system - * and the service processor attached via /dev/bmc. The module assumes the SP + * and the service processor attached via /dev/ipmi0. The module assumes the SP * supports the Sun OEM uptime IPMI command. If the BMC connection does not * exist, or the uptime function is not implemented, then the module unloads * without doing anything. @@ -148,7 +149,7 @@ if ((smp->sm_hdl = ipmi_open(&error, &msg, IPMI_TRANSPORT_BMC, NULL)) == NULL) { /* - * If /dev/bmc doesn't exist on the system, then unload the + * If /dev/ipmi0 doesn't exist on the system, then unload the * module without doing anything. */ if (error != EIPMI_BMC_OPEN_FAILED)
--- a/usr/src/lib/fm/topo/modules/common/fac_prov_ipmi/fac_prov_ipmi.c Thu Sep 27 16:04:13 2012 -0400 +++ b/usr/src/lib/fm/topo/modules/common/fac_prov_ipmi/fac_prov_ipmi.c Thu Apr 26 15:49:44 2012 +0000 @@ -271,7 +271,7 @@ /* * The spec states that any values between 0x20 and 0x29 are * legitimate for "system software". However, some versions of - * Sun's ILOM rejects messages over /dev/bmc with a generator + * Sun's ILOM rejects messages over /dev/ipmi0 with a generator * of 0x20, so we use 0x21 instead. */ pem.ipem_generator = 0x21;
--- a/usr/src/lib/libipmi/common/ipmi_bmc.c Thu Sep 27 16:04:13 2012 -0400 +++ b/usr/src/lib/libipmi/common/ipmi_bmc.c Thu Apr 26 15:49:44 2012 +0000 @@ -21,6 +21,7 @@ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2012 Joyent, Inc. All rights reserved. */ #include <errno.h> @@ -33,23 +34,23 @@ #include <stropts.h> #include <unistd.h> -#include <sys/bmc_intf.h> +#include <sys/ipmi.h> #include "ipmi_impl.h" /* - * IPMI transport for /dev/bmc + * IPMI transport for the local BMC at /dev/ipmi0. */ typedef struct ipmi_bmc { ipmi_handle_t *ib_ihp; /* ipmi handle */ - int ib_fd; /* /dev/bmc filedescriptor */ + int ib_fd; /* /dev/ipmi0 filedescriptor */ uint32_t ib_msgseq; /* message sequence number */ - bmc_msg_t *ib_msg; /* message buffer */ + uint8_t *ib_msg; /* message buffer */ size_t ib_msglen; /* size of message buffer */ } ipmi_bmc_t; -#define BMC_DEV "/dev/bmc" +#define BMC_DEV "/dev/ipmi0" static void ipmi_bmc_close(void *data) @@ -73,7 +74,7 @@ return (NULL); ibp->ib_ihp = ihp; - /* open /dev/bmc */ + /* open /dev/ipmi0 */ if ((ibp->ib_fd = open(BMC_DEV, O_RDWR)) < 0) { ipmi_free(ihp, ibp); (void) ipmi_set_error(ihp, EIPMI_BMC_OPEN_FAILED, "%s", @@ -81,7 +82,7 @@ return (NULL); } - if ((ibp->ib_msg = (bmc_msg_t *)ipmi_zalloc(ihp, BUFSIZ)) == NULL) { + if ((ibp->ib_msg = (uint8_t *)ipmi_zalloc(ihp, BUFSIZ)) == NULL) { ipmi_bmc_close(ibp); return (NULL); } @@ -95,84 +96,80 @@ int *completion) { ipmi_bmc_t *ibp = data; - struct strbuf sb; - int flags = 0; - size_t msgsz; - bmc_msg_t *msg; - bmc_req_t *bmcreq; - bmc_rsp_t *bmcrsp; + struct ipmi_req req; + struct ipmi_recv recv; + struct ipmi_addr addr; + fd_set rset; + struct ipmi_system_interface_addr bmc_addr; - /* - * The length of the message structure is equal to the size of the - * bmc_req_t structure, PLUS any additional data space in excess of - * the data space already reserved in the data member + <n> for - * the rest of the members in the bmc_msg_t structure. - */ - msgsz = offsetof(bmc_msg_t, msg) + sizeof (bmc_req_t) + - ((cmd->ic_dlen > SEND_MAX_PAYLOAD_SIZE) ? - (cmd->ic_dlen - SEND_MAX_PAYLOAD_SIZE) : 0); + bmc_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + bmc_addr.channel = IPMI_BMC_CHANNEL; + bmc_addr.lun = cmd->ic_lun; - /* construct and send the message */ - if ((msg = ipmi_zalloc(ibp->ib_ihp, msgsz)) == NULL) - return (-1); - bmcreq = (bmc_req_t *)&msg->msg[0]; + (void) memset(&req, 0, sizeof (struct ipmi_req)); + + req.addr = (unsigned char *) &bmc_addr; + req.addr_len = sizeof (bmc_addr); - msg->m_type = BMC_MSG_REQUEST; - msg->m_id = ibp->ib_msgseq++; - bmcreq->fn = cmd->ic_netfn; - bmcreq->lun = cmd->ic_lun; - bmcreq->cmd = cmd->ic_cmd; - bmcreq->datalength = cmd->ic_dlen; - (void) memcpy(bmcreq->data, cmd->ic_data, cmd->ic_dlen); - sb.len = msgsz; - sb.buf = (char *)msg; + req.msgid = ibp->ib_msgseq++; + req.msg.netfn = cmd->ic_netfn; + req.msg.cmd = cmd->ic_cmd; + req.msg.data = cmd->ic_data; + req.msg.data_len = cmd->ic_dlen; - if (putmsg(ibp->ib_fd, NULL, &sb, 0) < 0) { - ipmi_free(ibp->ib_ihp, msg); + if (ioctl(ibp->ib_fd, IPMICTL_SEND_COMMAND, &req) < 0) { (void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_PUTMSG, "%s", strerror(errno)); return (-1); } - ipmi_free(ibp->ib_ihp, msg); + /* get the response from the BMC */ + + FD_ZERO(&rset); + FD_SET(ibp->ib_fd, &rset); - /* get the response from the BMC */ - sb.buf = (char *)ibp->ib_msg; - sb.maxlen = ibp->ib_msglen; + if (select(ibp->ib_fd + 1, &rset, NULL, NULL, NULL) < 0) { + (void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_GETMSG, "%s", + strerror(errno)); + return (-1); + } + if (FD_ISSET(ibp->ib_fd, &rset) == 0) { + (void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_GETMSG, "%s", + "No data available"); + return (-1); + } - if (getmsg(ibp->ib_fd, NULL, &sb, &flags) < 0) { + recv.addr = (unsigned char *) &addr; + recv.addr_len = sizeof (addr); + recv.msg.data = (unsigned char *)ibp->ib_msg; + recv.msg.data_len = ibp->ib_msglen; + + /* get data */ + if (ioctl(ibp->ib_fd, IPMICTL_RECEIVE_MSG_TRUNC, &recv) < 0) { (void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_GETMSG, "%s", strerror(errno)); return (-1); } - switch (ibp->ib_msg->m_type) { - case BMC_MSG_RESPONSE: - bmcrsp = (bmc_rsp_t *)&ibp->ib_msg->msg[0]; + if (recv.recv_type != IPMI_RESPONSE_RECV_TYPE) { + (void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_RESPONSE, + "unknown BMC message type %d", recv.recv_type); + return (-1); + } - response->ic_netfn = bmcrsp->fn; - response->ic_lun = bmcrsp->lun; - response->ic_cmd = bmcrsp->cmd; - if (bmcrsp->ccode != 0) { - *completion = bmcrsp->ccode; - response->ic_dlen = 0; - response->ic_data = NULL; - } else { - *completion = 0; - response->ic_dlen = bmcrsp->datalength; - response->ic_data = bmcrsp->data; - } - break; - - case BMC_MSG_ERROR: - (void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_RESPONSE, "%s", - strerror(ibp->ib_msg->msg[0])); - return (-1); - - default: - (void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_RESPONSE, - "unknown BMC message type %d", ibp->ib_msg->m_type); - return (-1); + response->ic_netfn = recv.msg.netfn; + /* The lun is not returned in addr, return the lun passed in */ + response->ic_lun = cmd->ic_lun; + response->ic_cmd = recv.msg.cmd; + if (recv.msg.data[0] != 0) { + *completion = recv.msg.data[0]; + response->ic_dlen = 0; + response->ic_data = NULL; + } else { + *completion = 0; + response->ic_dlen = (recv.msg.data_len > 0) ? + recv.msg.data_len - 1 : 0; + response->ic_data = &(recv.msg.data[1]); } return (0);
--- a/usr/src/lib/libipmi/common/libipmi.c Thu Sep 27 16:04:13 2012 -0400 +++ b/usr/src/lib/libipmi/common/libipmi.c Thu Apr 26 15:49:44 2012 +0000 @@ -26,8 +26,6 @@ #include <libipmi.h> #include <string.h> -#include <sys/bmc_intf.h> - #include "ipmi_impl.h" ipmi_handle_t * @@ -119,7 +117,6 @@ { 0xD5, EIPMI_UNAVAILABLE }, { 0xD6, EIPMI_UNAVAILABLE }, { 0xFF, EIPMI_UNSPECIFIED }, - { BMC_IPMI_OEM_FAILURE_SENDBMC, EIPMI_SEND_FAILED }, }; #define IPMI_ERROR_COUNT \
--- a/usr/src/lib/libipmi/common/libipmi.h Thu Sep 27 16:04:13 2012 -0400 +++ b/usr/src/lib/libipmi/common/libipmi.h Thu Apr 26 15:49:44 2012 +0000 @@ -20,20 +20,20 @@ */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, Joyent, Inc. All rights reserved. */ #ifndef _LIBIPMI_H #define _LIBIPMI_H -#include <sys/bmc_intf.h> #include <sys/byteorder.h> #include <sys/nvpair.h> #include <sys/sysmacros.h> /* * Private interfaces for communicating with attached services over IPMI. This - * library is designed for system software communicating with Sun-supported - * service processors over /dev/bmc. It is not a generic IPMI library. + * library is designed for system software communicating with Illumos-supported + * service processors over /dev/ipmi0. It is not a generic IPMI library. * * Documentation references refer to "Intelligent Platform Management Interface * Specification Second Generation v2.0", document revision 1.0 with Februrary @@ -52,10 +52,12 @@ /* * Basic netfn definitions. See section 5.1. */ -#define IPMI_NETFN_CHASSIS BMC_NETFN_CHASSIS -#define IPMI_NETFN_APP BMC_NETFN_APP -#define IPMI_NETFN_STORAGE BMC_NETFN_STORAGE -#define IPMI_NETFN_SE BMC_NETFN_SE +#define IPMI_NETFN_CHASSIS 0x0 +#define IPMI_NETFN_BRIDGE 0x2 +#define IPMI_NETFN_SE 0x4 +#define IPMI_NETFN_APP 0x6 +#define IPMI_NETFN_FIRMWARE 0x8 +#define IPMI_NETFN_STORAGE 0xa #define IPMI_NETFN_TRANSPORT 0x0C #define IPMI_NETFN_OEM 0x2e @@ -66,10 +68,10 @@ typedef enum { EIPMI_NOMEM = EIPMI_BASE, /* memory allocation failure */ - EIPMI_BMC_OPEN_FAILED, /* failed to open /dev/bmc */ - EIPMI_BMC_PUTMSG, /* failed to send message to /dev/bmc */ - EIPMI_BMC_GETMSG, /* failed to read response from /dev/bmc */ - EIPMI_BMC_RESPONSE, /* response from /dev/bmc failed */ + EIPMI_BMC_OPEN_FAILED, /* failed to open /dev/ipmi0 */ + EIPMI_BMC_PUTMSG, /* failed to send message to /dev/ipmi0 */ + EIPMI_BMC_GETMSG, /* failed to read response from /dev/ipmi0 */ + EIPMI_BMC_RESPONSE, /* response from /dev/ipmi0 failed */ EIPMI_INVALID_COMMAND, /* invalid command */ EIPMI_COMMAND_TIMEOUT, /* command timeout */ EIPMI_DATA_LENGTH_EXCEEDED, /* maximum data length exceeded */
--- a/usr/src/man/man7d/Makefile Thu Sep 27 16:04:13 2012 -0400 +++ b/usr/src/man/man7d/Makefile Thu Apr 26 15:49:44 2012 +0000 @@ -209,6 +209,7 @@ ecpp.7d \ heci.7d \ i915.7d \ + ipmi.7d \ ipw.7d \ iwh.7d \ iwi.7d \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/man/man7d/ipmi.7d Thu Apr 26 15:49:44 2012 +0000 @@ -0,0 +1,180 @@ +'\" +.\" CDDL HEADER START +.\" +.\" The contents of this file are subject to the terms of the +.\" Common Development and Distribution License (the "License"). +.\" You may not use this file except in compliance with the License. +.\" +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +.\" or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions +.\" and limitations under the License. +.\" +.\" When distributing Covered Code, include this CDDL HEADER in each +.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. +.\" If applicable, add the following below this CDDL HEADER, with the +.\" fields enclosed by brackets "[]" replaced with your own identifying +.\" information: Portions Copyright [yyyy] [name of copyright owner] +.\" +.\" CDDL HEADER END +.\" +.\" Copyright (c) 2012, Joyent, Inc. All Rights Reserved +.\" +.TH IMPI 7D "Apr 21, 2012" +.SH NAME +ipmi \- OpenIPMI compatible IPMI interface driver +.SH SYNOPSIS +.LP +.nf +\fB/dev/ipmi0\fR +.fi + +.SH DESCRIPTION +.sp +.LP +The \fBipmi\fR device is a character special file that provides access to the +Intelligent Platform Management Interface for the system. For more +information on \fBIPMI\fR and to obtain a copy of the \fBIPMI\fR +specification and implementation guidelines, refer to +http://\fIhttp://www.intel.com/design/servers/ipmi/\fR. +The driver is adapted from the FreeBSD driver which is in turn adapted from +the Linux driver, however, not all features described in the standard are +supported. The current implementation depends on the \fBsmbios\fR(7d) to +discover the existence of an IPMI device. +.sp +.LP + +.SH IOCTLS +.sp +.LP +Sending and receiving messages through the IPMI drivers requires the use of +\fBioctl\fR(2). + +The ioctl command codes below are defined in \fBsys/ipmi.h\fR. +The third argument to ioctl should be a pointer to the type indicated. +Currently the following ioctls are supported: +.RS +4 +.TP +.ie t \(bu +.el o +IPMICTL_RECEIVE_MSG "struct ipmi_recv" +.br +Receive a message. +.br +Possible error values: +.RS +8 +EAGAIN No messages are in the process queue. +.br +EFAULT An address supplied was invalid. +.br +EMSGSIZE The address could not fit in the message buffer and +will remain in the buffer. +.RE +.RE + +.RS +4 +.TP +.ie t \(bu +.el o +IPMICTL_RECEIVE_MSG_TRUNC "struct ipmi_recv" +.br +Like IPMICTL_RECEIVE_MSG but if the message cannot fit into the buffer, it +will truncate the contents instead of leaving the data in the buffer. +.RE + +.RS +4 +.TP +.ie t \(bu +.el o +IPMICTL_SEND_COMMAND "struct ipmi_req" +.br +Send a message to the interface. +.br +Possible error values: +.RS +8 +EFAULT An address supplied was invalid +.br +ENOMEM Buffers could not be allowed for the command, out of memory. +.RE +.RE + +.RS +4 +.TP +.ie t \(bu +.el o +IPMICTL_SET_MY_ADDRESS_CMD "unsigned int" +.br +Set the slave address for source messages. +.RE + +.RS +4 +.TP +.ie t \(bu +.el o +IPMICTL_GET_MY_ADDRESS_CMD "unsigned int" +.br +Get the slave address for source messages. +.RE + +.RS +4 +.TP +.ie t \(bu +.el o +IPMICTL_SET_MY_LUN_CMD "unsigned int" +.br +Set the slave LUN for source messages. +.RE + +.RS +4 +.TP +.ie t \(bu +.el o +IPMICTL_GET_MY_LUN_CMD "unsigned int" +.br +Get the slave LUN for source messages. +.RE + +Stub Only Ioctl + +.RS +4 +.TP +.ie t \(bu +.el o +IPMICTL_SET_GETS_EVENTS_CMD int +.br +Set whether this interface receives events. +.RE + +Unimplemented Ioctls + +.RS +4 +.TP +.ie t \(bu +.el o +IPMICTL_REGISTER_FOR_CMD +.br +Register to receive a specific command +.RE + +.RS +4 +.TP +.ie t \(bu +.el o +IPMICTL_UNREGISTER_FOR_CMD +.br +Unregister to receive a specific command +.RE + +.SH SEE ALSO +.sp +.LP +\fBipmitool\fR(1M), \fBioctl\fR(2), \fBsmbios\fR(7d) +.sp +.LP +\fIIntelligent Platform Management Interface Specification Second +Generation\fR, v2.0 \(em +June 12, 2009 Markup +.SH NOTES +.sp +.LP +Not all systems include an \fBIPMI\fR.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkg/manifests/driver-ipmi.mf Thu Apr 26 15:49:44 2012 +0000 @@ -0,0 +1,45 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +<include global_zone_only_component> +set name=pkg.fmri value=pkg:/driver/ipmi@$(PKGVERS) +set name=pkg.summary \ + value="Intelligent Platform Management Interface baseboard driver" +set name=info.classification value=org.opensolaris.category.2008:Drivers/Ports +set name=variant.arch value=i386 +dir path=usr/include +dir path=usr/include/sys +dir path=usr/include/sys +dir path=usr/kernel group=sys +dir path=usr/kernel/drv group=sys +dir path=usr/kernel/drv/$(ARCH64) group=sys +dir path=usr/share +dir path=usr/share/man +dir path=usr/share/man/man7d +driver name=ipmi perms="* 0600 root sys" +file path=usr/include/sys/ipmi.h +file path=usr/kernel/drv/amd64/ipmi +file path=usr/kernel/drv/ipmi +file path=usr/kernel/drv/ipmi.conf +file path=usr/share/man/man7d/ipmi.7d +license lic_CDDL license=lic_CDDL +license usr/src/uts/intel/io/ipmi/THIRDPARTYLICENSE \ + license=usr/src/uts/intel/io/ipmi/THIRDPARTYLICENSE
--- a/usr/src/pkg/manifests/system-header.mf Thu Sep 27 16:04:13 2012 -0400 +++ b/usr/src/pkg/manifests/system-header.mf Thu Apr 26 15:49:44 2012 +0000 @@ -813,7 +813,6 @@ file path=usr/include/sys/bitset.h file path=usr/include/sys/bl.h file path=usr/include/sys/blkdev.h -file path=usr/include/sys/bmc_intf.h file path=usr/include/sys/bofi.h file path=usr/include/sys/bofi_impl.h file path=usr/include/sys/bootconf.h
--- a/usr/src/uts/common/sys/Makefile Thu Sep 27 16:04:13 2012 -0400 +++ b/usr/src/uts/common/sys/Makefile Thu Apr 26 15:49:44 2012 +0000 @@ -86,7 +86,6 @@ bitset.h \ bl.h \ blkdev.h \ - bmc_intf.h \ bofi.h \ bofi_impl.h \ bpp_io.h \ @@ -278,6 +277,7 @@ ipc.h \ ipc_impl.h \ ipc_rctl.h \ + ipmi.h \ isa_defs.h \ iscsi_authclient.h \ iscsi_authclientglue.h \
--- a/usr/src/uts/common/sys/bmc_intf.h Thu Sep 27 16:04:13 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,203 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ - -/* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _BMC_INTF_H -#define _BMC_INTF_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/types.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#define BMC_SUCCESS 0x0 -#define BMC_FAILURE 0x1 - -#define BMC_NETFN_CHASSIS 0x0 -#define BMC_NETFN_BRIDGE 0x2 -#define BMC_NETFN_SE 0x4 -#define BMC_NETFN_APP 0x6 -#define BMC_NETFN_FIRMWARE 0x8 -#define BMC_NETFN_STORAGE 0xa -#define BMC_NETFN_TRANSPORT 0xc - -#define SEND_MAX_PAYLOAD_SIZE 34 /* MAX payload */ -#define RECV_MAX_PAYLOAD_SIZE 33 /* MAX payload */ -#define BMC_MIN_RESPONSE_SIZE 3 -#define BMC_MIN_REQUEST_SIZE 2 -#define BMC_MAX_RESPONSE_SIZE (BMC_MIN_RESPONSE_SIZE + RECV_MAX_PAYLOAD_SIZE) -#define BMC_MAX_REQUEST_SIZE (BMC_MIN_REQUEST_SIZE + BMC_MAX_RESPONSE_SIZE) - -#define BUF_SIZE 256 -#define MAX_BUF_SIZE 256 - -/* - * Useful macros - */ -#define FORM_NETFNLUN(net, lun) ((((net) << 2) | ((lun) & 0x3))) -#define GET_NETFN(netfn) (((netfn) >> 2) & 0x3f) -#define GET_LUN(netfn) (netfn & 0x3) -#define RESP_NETFN(nflun) ((nflun) | 1) -#define ISREQUEST(nl) (((nl) & 1) == 0) /* test for request */ -#define ISRESPONSE(nl) (((nl) & 1) == 1) /* test for response */ - - -/* for checking BMC specific stuff */ -#define BMC_GET_DEVICE_ID 0x1 /* GET DEVICE ID COMMAND */ -#define BMC_IPMI_15_VER 0x51 /* IPMI 1.5 definion */ - -/* BMC Completion Code and OEM Completion Code */ -#define BMC_IPMI_UNSPECIFIC_ERROR 0xFF /* Unspecific Error */ -#define BMC_IPMI_INVALID_COMMAND 0xC1 /* Invalid Command */ -#define BMC_IPMI_COMMAND_TIMEOUT 0xC3 /* Command Timeout */ -#define BMC_IPMI_DATA_LENGTH_EXCEED 0xC8 /* DataLength exceeded limit */ -#define BMC_IPMI_OEM_FAILURE_SENDBMC 0x7E /* Cannot send BMC req */ - - -#define IOCTL_IPMI_KCS_ACTION 0x01 -#define IOCTL_IPMI_INTERFACE_METHOD 0x02 - -/* Interface methods returned from IOCTL_IPMI_INTERFACE_METHOD ioctl: */ - -#define BMC_IOCTL_METHOD 0 /* Not returned from ioctl, */ - /* but can be used by */ - /* applications that want to */ - /* compare against an */ - /* alternative method. */ -#define BMC_PUTMSG_METHOD 1 - -/* - * bmc_req_t is the data structure to send - * request packet from applications to the driver - * module. - * - * the request pkt is mainly for KCS-interface-BMC - * messages. Since the system interface is session-less - * connections, the packet won't have any session - * information. - * - * the data payload will be 2 bytes less than max - * BMC supported packet size. - * the address of the responder is always BMC and so - * rsSa field is not required. - */ -typedef struct bmc_req { - uint8_t fn; /* netFn for command */ - uint8_t lun; /* logical unit on responder */ - uint8_t cmd; /* command */ - uint8_t datalength; /* length of following data */ - uint8_t data[SEND_MAX_PAYLOAD_SIZE]; /* request data */ -} bmc_req_t; - -/* - * bmc_rsp_t is the data structure to send - * respond packet from applications to the driver - * module. - * - * the respond pkt is mainly for KCS-interface-BMC - * messages. Since the system interface is session-less - * connections, the packet won't have any session - * information. - * - * the data payload will be 2 bytes less than max - * BMC supported packet size. - */ -typedef struct bmc_rsp { - uint8_t fn; /* netFn for command */ - uint8_t lun; /* logical unit on responder */ - uint8_t cmd; /* command */ - uint8_t ccode; /* completion code */ - uint8_t datalength; /* Length */ - uint8_t data[RECV_MAX_PAYLOAD_SIZE]; /* response */ -} bmc_rsp_t; - -/* - * the data structure for synchronous operation via ioctl (DEPRECATED) - */ -typedef struct bmc_reqrsp { - bmc_req_t req; /* request half */ - bmc_rsp_t rsp; /* response half */ -} bmc_reqrsp_t; - - -/* - * The new way of communicating with the bmc driver is to use putmsg() to - * send a message of a particular type. Replies from the driver also have this - * form, and will require the user to process the type field before examining - * the rest of the reply. - * - * The only change that must be observed when using the request and response - * structures defined above is as follows: - * when sending messages to the bmc driver, the data portion is now variable - * (the caller must allocate enough space to store the all structure members, - * plus enough space to cover the amount of data in the request), e.g.: - * - * bmc_msg_t *msg = malloc(offsetof(bmc_msg_t, msg) + sizeof(bmc_req_t) + 10); - * - * The amount allocated for the message is (# of bytes before the msg field) + - * the size of a bmc_req_t (which includes SEND_MAX_PAYLOAD_SIZE - * bytes in the data field), plus an additional 10 bytes for the data - * field (so the data field would occupy (SEND_MAX_PAYLOAD_SIZE + 10) - * bytes). The datalength member must reflect the amount of data in the - * request's data field (as was required when using the ioctl interface). - */ -typedef struct bmc_msg { - uint8_t m_type; /* Message type (see below) */ - uint32_t m_id; /* Message ID */ - uint8_t reserved[32]; - uint8_t msg[1]; /* Variable length message data */ -} bmc_msg_t; - - -/* - * An error response passed back from the bmc driver will have its m_id - * field set to BMC_UNKNOWN_MSG_ID if a message is sent to it that is not - * at least as large as a bmc_msg_t. - */ -#define BMC_UNKNOWN_MSG_ID ~((uint32_t)0) - - -/* - * Possible values for the m_type field in bmc_msg_t: - */ -#define BMC_MSG_REQUEST 1 /* BMC request (as above, sent to the */ - /* driver by the user), bmc_msg.msg */ - /* begins with the bmc_req_t */ - /* structure. */ -#define BMC_MSG_RESPONSE 2 /* BMC response (sent by the driver) */ - /* bmc_msg.msg begins with the */ - /* bmc_rsp_t structure. */ -#define BMC_MSG_ERROR 3 /* Error while processing a user msg */ - /* msg[0] is the error code */ - /* (interpret as an errno value) */ - -#ifdef __cplusplus -} -#endif - -#endif /* _BMC_INTF_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/sys/ipmi.h Thu Apr 26 15:49:44 2012 +0000 @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2006 IronPort Systems Inc. <ambrisko@ironport.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + * $FreeBSD: src/sys/sys/ipmi.h,v 1.2 2006/09/22 22:11:29 jhb Exp $ + */ + +/* + * Copyright 2012 Joyent, Inc. All rights reserved. + */ + +#ifndef _SYS_IPMI_H_ +#define _SYS_IPMI_H_ + +#include <sys/types.h> +#include <sys/ioccom.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define IPMI_MAX_ADDR_SIZE 0x20 +#define IPMI_MAX_RX 1024 +#define IPMI_BMC_SLAVE_ADDR 0x20 /* Default slave address */ +#define IPMI_BMC_CHANNEL 0x0f /* BMC channel */ + +#define IPMI_BMC_SMS_LUN 0x02 + +#define IPMI_SYSTEM_INTERFACE_ADDR_TYPE 0x0c +#define IPMI_IPMB_ADDR_TYPE 0x01 +#define IPMI_IPMB_BROADCAST_ADDR_TYPE 0x41 + +#define IPMI_IOC_MAGIC 'i' +#define IPMICTL_RECEIVE_MSG_TRUNC \ + _IOWR(IPMI_IOC_MAGIC, 11, struct ipmi_recv) +#define IPMICTL_RECEIVE_MSG \ + _IOWR(IPMI_IOC_MAGIC, 12, struct ipmi_recv) +#define IPMICTL_SEND_COMMAND \ + _IOW(IPMI_IOC_MAGIC, 13, struct ipmi_req) +#define IPMICTL_REGISTER_FOR_CMD \ + _IOW(IPMI_IOC_MAGIC, 14, struct ipmi_cmdspec) +#define IPMICTL_UNREGISTER_FOR_CMD \ + _IOW(IPMI_IOC_MAGIC, 15, struct ipmi_cmdspec) +#define IPMICTL_SET_GETS_EVENTS_CMD _IOW(IPMI_IOC_MAGIC, 16, int) +#define IPMICTL_SET_MY_ADDRESS_CMD _IOW(IPMI_IOC_MAGIC, 17, unsigned int) +#define IPMICTL_GET_MY_ADDRESS_CMD _IOR(IPMI_IOC_MAGIC, 18, unsigned int) +#define IPMICTL_SET_MY_LUN_CMD _IOW(IPMI_IOC_MAGIC, 19, unsigned int) +#define IPMICTL_GET_MY_LUN_CMD _IOR(IPMI_IOC_MAGIC, 20, unsigned int) + +#define IPMI_RESPONSE_RECV_TYPE 1 +#define IPMI_ASYNC_EVENT_RECV_TYPE 2 +#define IPMI_CMD_RECV_TYPE 3 + +#define IPMI_APP_REQUEST 0x06 +#define IPMI_GET_DEVICE_ID 0x01 +#define IPMI_CLEAR_FLAGS 0x30 +#define IPMI_GET_MSG_FLAGS 0x31 +#define IPMI_MSG_AVAILABLE 0x01 +#define IPMI_MSG_BUFFER_FULL 0x02 +#define IPMI_WDT_PRE_TIMEOUT 0x08 +#define IPMI_GET_MSG 0x33 +#define IPMI_SEND_MSG 0x34 +#define IPMI_GET_CHANNEL_INFO 0x42 +#define IPMI_RESET_WDOG 0x22 +#define IPMI_SET_WDOG 0x24 +#define IPMI_GET_WDOG 0x25 + +#define IPMI_SET_WD_TIMER_SMS_OS 0x04 +#define IPMI_SET_WD_TIMER_DONT_STOP 0x40 +#define IPMI_SET_WD_ACTION_RESET 0x01 + +struct ipmi_msg { + unsigned char netfn; + unsigned char cmd; + unsigned short data_len; + unsigned char *data; +}; + +struct ipmi_req { + unsigned char *addr; + unsigned int addr_len; + long msgid; + struct ipmi_msg msg; +}; + +struct ipmi_recv { + int recv_type; + unsigned char *addr; + unsigned int addr_len; + long msgid; + struct ipmi_msg msg; +}; + +struct ipmi_cmdspec { + unsigned char netfn; + unsigned char cmd; +}; + +struct ipmi_addr { + int addr_type; + short channel; + unsigned char data[IPMI_MAX_ADDR_SIZE]; +}; + +struct ipmi_system_interface_addr { + int addr_type; + short channel; + unsigned char lun; +}; + +struct ipmi_ipmb_addr { + int addr_type; + short channel; + unsigned char slave_addr; + unsigned char lun; +}; + +#ifdef _KERNEL + +#define IPMICTL_RECEIVE_MSG_TRUNC_32 \ + _IOWR(IPMI_IOC_MAGIC, 11, struct ipmi_recv32) +#define IPMICTL_RECEIVE_MSG_32 \ + _IOWR(IPMI_IOC_MAGIC, 12, struct ipmi_recv32) +#define IPMICTL_SEND_COMMAND_32 \ + _IOW(IPMI_IOC_MAGIC, 13, struct ipmi_req32) + +struct ipmi_msg32 { + unsigned char netfn; + unsigned char cmd; + unsigned short data_len; + uint32_t data; +}; + +struct ipmi_req32 { + uint32_t addr; + unsigned int addr_len; + int32_t msgid; + struct ipmi_msg32 msg; +}; + +struct ipmi_recv32 { + int recv_type; + uint32_t addr; + unsigned int addr_len; + int32_t msgid; + struct ipmi_msg32 msg; +}; + +#endif /* _KERNEL */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_IPMI_H_ */
--- a/usr/src/uts/intel/Makefile.files Thu Sep 27 16:04:13 2012 -0400 +++ b/usr/src/uts/intel/Makefile.files Thu Apr 26 15:49:44 2012 +0000 @@ -21,6 +21,7 @@ # # Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, Joyent, Inc. All rights reserved. # # @@ -248,6 +249,10 @@ AMR_OBJS = amr.o # +# IPMI module +IPMI_OBJS += ipmi_main.o ipmi.o ipmi_kcs.o + +# # IOMMULIB module # IOMMULIB_OBJS = iommulib.o
--- a/usr/src/uts/intel/Makefile.intel.shared Thu Sep 27 16:04:13 2012 -0400 +++ b/usr/src/uts/intel/Makefile.intel.shared Thu Apr 26 15:49:44 2012 +0000 @@ -400,6 +400,7 @@ DRV_KMODS += sfe DRV_KMODS += amd8111s DRV_KMODS += igb +DRV_KMODS += ipmi DRV_KMODS += iprb DRV_KMODS += ixgbe DRV_KMODS += vr
--- a/usr/src/uts/intel/Makefile.rules Thu Sep 27 16:04:13 2012 -0400 +++ b/usr/src/uts/intel/Makefile.rules Thu Apr 26 15:49:44 2012 +0000 @@ -21,6 +21,7 @@ # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. +# Copyright 2012 Joyent, Inc. All rights reserved. # # @@ -168,6 +169,10 @@ $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) +$(OBJS_DIR)/%.o: $(UTSBASE)/intel/io/ipmi/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + $(OBJS_DIR)/%.o: $(UTSBASE)/intel/io/intel_nb5000/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) @@ -413,6 +418,9 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/intel/io/intel_nhm/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) +$(LINTS_DIR)/%.ln: $(UTSBASE)/intel/io/ipmi/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + $(LINTS_DIR)/%.ln: $(SRC)/common/mc/mc-amd/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/intel/io/ipmi/THIRDPARTYLICENSE Thu Apr 26 15:49:44 2012 +0000 @@ -0,0 +1,23 @@ +Copyright (c) 2006 IronPort Systems Inc. <ambrisko@ironport.com> +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/intel/io/ipmi/THIRDPARTYLICENSE.descrip Thu Apr 26 15:49:44 2012 +0000 @@ -0,0 +1,1 @@ +INTELLIGENT PLATFORM MANAGEMENT INTERFACE SUPPORT
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/intel/io/ipmi/ipmi.c Thu Apr 26 15:49:44 2012 +0000 @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2006 IronPort Systems Inc. <ambrisko@ironport.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + */ + +/* $FreeBSD: src/sys/dev/ipmi/ipmi.c,v 1.16 2011/11/07 15:43:11 ed Exp $ */ + +/* + * Copyright 2012, Joyent, Inc. All rights reserved. + */ + +#include <sys/devops.h> +#include <sys/conf.h> +#include <sys/modctl.h> +#include <sys/types.h> +#include <sys/file.h> +#include <sys/errno.h> +#include <sys/open.h> +#include <sys/cred.h> +#include <sys/uio.h> +#include <sys/stat.h> +#include <sys/cmn_err.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/smbios.h> +#include <sys/smbios_impl.h> +#include <sys/ipmi.h> +#include "ipmivars.h" + +static kmutex_t slpmutex; +static kcondvar_t slplock; + +/* + * Request management. + */ + +/* Allocate a new request with request and reply buffers. */ +struct ipmi_request * +ipmi_alloc_request(struct ipmi_device *dev, long msgid, uint8_t addr, + uint8_t command, size_t requestlen, size_t replylen) +{ + struct ipmi_request *req; + + req = kmem_zalloc(sizeof (struct ipmi_request) + requestlen + replylen, + KM_SLEEP); + req->ir_sz = sizeof (struct ipmi_request) + requestlen + replylen; + req->ir_owner = dev; + req->ir_msgid = msgid; + req->ir_addr = addr; + req->ir_command = command; + if (requestlen) { + req->ir_request = (uchar_t *)&req[1]; + req->ir_requestlen = requestlen; + } + if (replylen) { + req->ir_reply = (uchar_t *)&req[1] + requestlen; + req->ir_replybuflen = replylen; + } + return (req); +} + +/* Free a request no longer in use. */ +void +ipmi_free_request(struct ipmi_request *req) +{ + kmem_free(req, req->ir_sz); +} + +/* Store a processed request on the appropriate completion queue. */ +/*ARGSUSED*/ +void +ipmi_complete_request(struct ipmi_softc *sc, struct ipmi_request *req) +{ + struct ipmi_device *dev; + + IPMI_LOCK_ASSERT(sc); + + /* + * Anonymous requests (from inside the driver) always have a + * waiter that we awaken. + */ + if (req->ir_owner == NULL) { + mutex_enter(&slpmutex); + cv_signal(&slplock); + mutex_exit(&slpmutex); + } else { + dev = req->ir_owner; + TAILQ_INSERT_TAIL(&dev->ipmi_completed_requests, req, ir_link); + pollwakeup(dev->ipmi_pollhead, POLLIN | POLLRDNORM); + } +} + +/* + * Enqueue an internal driver request and wait until it is completed. + */ +static int +ipmi_submit_driver_request(struct ipmi_softc *sc, struct ipmi_request *req, + int timo) +{ + int error; + + IPMI_LOCK(sc); + error = sc->ipmi_enqueue_request(sc, req); + if (error == 0) { + /* Wait for result - see ipmi_complete_request */ + IPMI_UNLOCK(sc); + mutex_enter(&slpmutex); + if (timo == 0) + cv_wait(&slplock, &slpmutex); + else + error = cv_timedwait(&slplock, &slpmutex, + ddi_get_lbolt() + timo); + mutex_exit(&slpmutex); + IPMI_LOCK(sc); + if (error == -1) + error = EWOULDBLOCK; + else + error = req->ir_error; + } + IPMI_UNLOCK(sc); + + return (error); +} + +/* + * Helper routine for polled system interfaces that use + * ipmi_polled_enqueue_request() to queue requests. This request + * waits until there is a pending request and then returns the first + * request. If the driver is shutting down, it returns NULL. + */ +struct ipmi_request * +ipmi_dequeue_request(struct ipmi_softc *sc) +{ + struct ipmi_request *req; + + IPMI_LOCK_ASSERT(sc); + + while (!sc->ipmi_detaching && TAILQ_EMPTY(&sc->ipmi_pending_requests)) + cv_wait(&sc->ipmi_request_added, &sc->ipmi_lock); + if (sc->ipmi_detaching) + return (NULL); + + req = TAILQ_FIRST(&sc->ipmi_pending_requests); + TAILQ_REMOVE(&sc->ipmi_pending_requests, req, ir_link); + return (req); +} + +int +ipmi_polled_enqueue_request(struct ipmi_softc *sc, struct ipmi_request *req) +{ + + IPMI_LOCK_ASSERT(sc); + + TAILQ_INSERT_TAIL(&sc->ipmi_pending_requests, req, ir_link); + cv_signal(&sc->ipmi_request_added); + return (0); +} + +void +ipmi_startup(struct ipmi_softc *sc) +{ + struct ipmi_request *req; + int error, i; + + mutex_init(&slpmutex, NULL, MUTEX_DEFAULT, NULL); + cv_init(&slplock, NULL, CV_DEFAULT, NULL); + + /* Initialize interface-independent state. */ + mutex_init(&sc->ipmi_lock, NULL, MUTEX_DEFAULT, NULL); + cv_init(&sc->ipmi_request_added, NULL, CV_DEFAULT, NULL); + TAILQ_INIT(&sc->ipmi_pending_requests); + + /* Initialize interface-dependent state. */ + error = sc->ipmi_startup(sc); + if (error) { + cmn_err(CE_WARN, "Failed to initialize interface: %d", error); + return; + } + + /* Send a GET_DEVICE_ID request. */ + req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0), + IPMI_GET_DEVICE_ID, 0, 15); + + error = ipmi_submit_driver_request(sc, req, MAX_TIMEOUT); + if (error == EWOULDBLOCK) { + cmn_err(CE_WARN, "Timed out waiting for GET_DEVICE_ID"); + ipmi_free_request(req); + return; + } else if (error) { + cmn_err(CE_WARN, "Failed GET_DEVICE_ID: %d", error); + ipmi_free_request(req); + return; + } else if (req->ir_compcode != 0) { + cmn_err(CE_WARN, + "Bad completion code for GET_DEVICE_ID: %d", + req->ir_compcode); + ipmi_free_request(req); + return; + } else if (req->ir_replylen < 5) { + cmn_err(CE_WARN, "Short reply for GET_DEVICE_ID: %d", + req->ir_replylen); + ipmi_free_request(req); + return; + } + + cmn_err(CE_CONT, "!device rev. %d, firmware rev. %d.%d%d, " + "version %d.%d", + req->ir_reply[1] & 0x0f, req->ir_reply[2] & 0x7f, + req->ir_reply[3] >> 4, req->ir_reply[3] & 0x0f, + req->ir_reply[4] & 0x0f, req->ir_reply[4] >> 4); + + ipmi_free_request(req); + + req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0), + IPMI_CLEAR_FLAGS, 1, 0); + + if ((error = ipmi_submit_driver_request(sc, req, 0)) != 0) + cmn_err(CE_WARN, "Failed to clear IPMI flags: %d\n", error); + + /* Magic numbers */ + if (req->ir_compcode == 0xc0) { + cmn_err(CE_NOTE, "!Clear flags is busy"); + } + if (req->ir_compcode == 0xc1) { + cmn_err(CE_NOTE, "!Clear flags illegal"); + } + ipmi_free_request(req); + + for (i = 0; i < 8; i++) { + req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0), + IPMI_GET_CHANNEL_INFO, 1, 0); + req->ir_request[0] = (uchar_t)i; + + if (ipmi_submit_driver_request(sc, req, 0) != 0) { + ipmi_free_request(req); + break; + } + + if (req->ir_compcode != 0) { + ipmi_free_request(req); + break; + } + ipmi_free_request(req); + } + cmn_err(CE_CONT, "!number of channels %d", i); + + /* probe for watchdog */ + req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0), + IPMI_GET_WDOG, 0, 0); + + if ((error = ipmi_submit_driver_request(sc, req, 0)) != 0) { + cmn_err(CE_WARN, "Failed to check IPMI watchdog: %d\n", error); + ipmi_free_request(req); + return; + } + + if (req->ir_compcode == 0x00) { + cmn_err(CE_CONT, "!watchdog supported"); + + /* + * Here is where we could register a watchdog event handler. + * See ipmi_wd_event() in the FreeBSD code. + */ + } + ipmi_free_request(req); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/intel/io/ipmi/ipmi.conf Thu Apr 26 15:49:44 2012 +0000 @@ -0,0 +1,25 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2012, Joyent, Inc. All rights reserved. +# +name="ipmi" parent="pseudo" instance=0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/intel/io/ipmi/ipmi_kcs.c Thu Apr 26 15:49:44 2012 +0000 @@ -0,0 +1,508 @@ +/* + * Copyright (c) 2006 IronPort Systems Inc. <ambrisko@ironport.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + */ + +/* $FreeBSD: src/sys/dev/ipmi/ipmi_kcs.c,v 1.3 2008/08/28 02:11:04 jhb */ + +/* + * Copyright 2012, Joyent, Inc. All rights reserved. + */ + +#include <sys/param.h> +#include <sys/disp.h> +#include <sys/systm.h> +#include <sys/condvar.h> +#include <sys/cmn_err.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> + +#include <sys/ipmi.h> +#include "ipmivars.h" + +static void kcs_clear_obf(struct ipmi_softc *, int); +static void kcs_error(struct ipmi_softc *); +static int kcs_wait_for_ibf(struct ipmi_softc *, int); +static int kcs_wait_for_obf(struct ipmi_softc *, int); + +#define RETRY_USECS 100 +static clock_t timeout_usecs; + +static int +kcs_wait_for_ibf(struct ipmi_softc *sc, int state) +{ + int status; + clock_t i; + + status = INB(sc, KCS_CTL_STS); + if (state == 0) { + /* WAIT FOR IBF = 0 */ + for (i = 0; i < timeout_usecs && status & KCS_STATUS_IBF; + i += RETRY_USECS) { + drv_usecwait(RETRY_USECS); + status = INB(sc, KCS_CTL_STS); + } + } else { + /* WAIT FOR IBF = 1 */ + for (i = 0; i < timeout_usecs && !(status & KCS_STATUS_IBF); + i += RETRY_USECS) { + drv_usecwait(RETRY_USECS); + status = INB(sc, KCS_CTL_STS); + } + } + return (status); +} + +static int +kcs_wait_for_obf(struct ipmi_softc *sc, int state) +{ + int status; + clock_t i; + + status = INB(sc, KCS_CTL_STS); + if (state == 0) { + /* WAIT FOR OBF = 0 */ + for (i = 0; i < timeout_usecs && status & KCS_STATUS_OBF; + i += RETRY_USECS) { + drv_usecwait(RETRY_USECS); + status = INB(sc, KCS_CTL_STS); + } + } else { + /* WAIT FOR OBF = 1 */ + for (i = 0; i < timeout_usecs && !(status & KCS_STATUS_OBF); + i += RETRY_USECS) { + drv_usecwait(RETRY_USECS); + status = INB(sc, KCS_CTL_STS); + } + } + return (status); +} + +static void +kcs_clear_obf(struct ipmi_softc *sc, int status) +{ + /* Clear OBF */ + if (status & KCS_STATUS_OBF) { + (void) INB(sc, KCS_DATA); + } +} + +static void +kcs_error(struct ipmi_softc *sc) +{ + int retry, status; + uchar_t data; + + for (retry = 0; retry < 2; retry++) { + + /* Wait for IBF = 0 */ + status = kcs_wait_for_ibf(sc, 0); + + /* ABORT */ + OUTB(sc, KCS_CTL_STS, KCS_CONTROL_GET_STATUS_ABORT); + + /* Wait for IBF = 0 */ + status = kcs_wait_for_ibf(sc, 0); + + /* Clear OBF */ + kcs_clear_obf(sc, status); + + if (status & KCS_STATUS_OBF) { + data = INB(sc, KCS_DATA); + if (data != 0) + cmn_err(CE_WARN, + "KCS Error Data %02x", data); + } + + /* 0x00 to DATA_IN */ + OUTB(sc, KCS_DATA, 0x00); + + /* Wait for IBF = 0 */ + status = kcs_wait_for_ibf(sc, 0); + + if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_READ) { + + /* Wait for OBF = 1 */ + status = kcs_wait_for_obf(sc, 1); + + /* Read error status */ + data = INB(sc, KCS_DATA); + if (data != 0) + cmn_err(CE_WARN, "KCS error: %02x", data); + + /* Write READ into Data_in */ + OUTB(sc, KCS_DATA, KCS_DATA_IN_READ); + + /* Wait for IBF = 0 */ + status = kcs_wait_for_ibf(sc, 0); + } + + /* IDLE STATE */ + if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_IDLE) { + /* Wait for OBF = 1 */ + status = kcs_wait_for_obf(sc, 1); + + /* Clear OBF */ + kcs_clear_obf(sc, status); + return; + } + } + cmn_err(CE_WARN, "KCS: Error retry exhausted"); +} + +/* + * Start to write a request. Waits for IBF to clear and then sends the + * WR_START command. + */ +static int +kcs_start_write(struct ipmi_softc *sc) +{ + int retry, status; + + for (retry = 0; retry < 10; retry++) { + /* Wait for IBF = 0 */ + status = kcs_wait_for_ibf(sc, 0); + + /* Clear OBF */ + kcs_clear_obf(sc, status); + + /* Write start to command */ + OUTB(sc, KCS_CTL_STS, KCS_CONTROL_WRITE_START); + + /* Wait for IBF = 0 */ + status = kcs_wait_for_ibf(sc, 0); + if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_WRITE) + break; + delay(1000000); + } + + if (KCS_STATUS_STATE(status) != KCS_STATUS_STATE_WRITE) + /* error state */ + return (0); + + /* Clear OBF */ + kcs_clear_obf(sc, status); + + return (1); +} + +/* + * Write a byte of the request message, excluding the last byte of the + * message which requires special handling. + */ +static int +kcs_write_byte(struct ipmi_softc *sc, uchar_t data) +{ + int status; + + /* Data to Data */ + OUTB(sc, KCS_DATA, data); + + /* Wait for IBF = 0 */ + status = kcs_wait_for_ibf(sc, 0); + + if (KCS_STATUS_STATE(status) != KCS_STATUS_STATE_WRITE) + return (0); + + /* Clear OBF */ + kcs_clear_obf(sc, status); + return (1); +} + +/* + * Write the last byte of a request message. + */ +static int +kcs_write_last_byte(struct ipmi_softc *sc, uchar_t data) +{ + int status; + + /* Write end to command */ + OUTB(sc, KCS_CTL_STS, KCS_CONTROL_WRITE_END); + + /* Wait for IBF = 0 */ + status = kcs_wait_for_ibf(sc, 0); + + if (KCS_STATUS_STATE(status) != KCS_STATUS_STATE_WRITE) + /* error state */ + return (0); + + /* Clear OBF */ + kcs_clear_obf(sc, status); + + /* Send data byte to DATA. */ + OUTB(sc, KCS_DATA, data); + return (1); +} + +/* + * Read one byte of the reply message. + */ +static int +kcs_read_byte(struct ipmi_softc *sc, uchar_t *data) +{ + int status; + + /* Wait for IBF = 0 */ + status = kcs_wait_for_ibf(sc, 0); + + /* Read State */ + if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_READ) { + + /* Wait for OBF = 1 */ + status = kcs_wait_for_obf(sc, 1); + + /* Read Data_out */ + *data = INB(sc, KCS_DATA); + + /* Write READ into Data_in */ + OUTB(sc, KCS_DATA, KCS_DATA_IN_READ); + return (1); + } + + /* Idle State */ + if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_IDLE) { + + /* Wait for OBF = 1 */ + status = kcs_wait_for_obf(sc, 1); + + /* Read Dummy */ + (void) INB(sc, KCS_DATA); + return (2); + } + + /* Error State */ + return (0); +} + +/* + * Send a request message and collect the reply. Returns true if we + * succeed. + */ +static int +kcs_polled_request(struct ipmi_softc *sc, struct ipmi_request *req) +{ + uchar_t *cp, data; + int i, state; + + /* Send the request. */ + if (!kcs_start_write(sc)) { + cmn_err(CE_WARN, "KCS: Failed to start write"); + goto fail; + } +#ifdef KCS_DEBUG + cmn_err(CE_NOTE, "KCS: WRITE_START... ok"); +#endif + + if (!kcs_write_byte(sc, req->ir_addr)) { + cmn_err(CE_WARN, "KCS: Failed to write address"); + goto fail; + } +#ifdef KCS_DEBUG + cmn_err(CE_NOTE, "KCS: Wrote address: %02x", req->ir_addr); +#endif + + if (req->ir_requestlen == 0) { + if (!kcs_write_last_byte(sc, req->ir_command)) { + cmn_err(CE_WARN, + "KCS: Failed to write command"); + goto fail; + } +#ifdef KCS_DEBUG + cmn_err(CE_NOTE, "KCS: Wrote command: %02x", + req->ir_command); +#endif + } else { + if (!kcs_write_byte(sc, req->ir_command)) { + cmn_err(CE_WARN, + "KCS: Failed to write command"); + goto fail; + } +#ifdef KCS_DEBUG + cmn_err(CE_NOTE, "KCS: Wrote command: %02x", + req->ir_command); +#endif + + cp = req->ir_request; + for (i = 0; i < req->ir_requestlen - 1; i++) { + if (!kcs_write_byte(sc, *cp++)) { + cmn_err(CE_WARN, + "KCS: Failed to write data byte %d", + i + 1); + goto fail; + } +#ifdef KCS_DEBUG + cmn_err(CE_NOTE, "KCS: Wrote data: %02x", + cp[-1]); +#endif + } + + if (!kcs_write_last_byte(sc, *cp)) { + cmn_err(CE_WARN, + "KCS: Failed to write last dta byte"); + goto fail; + } +#ifdef KCS_DEBUG + cmn_err(CE_NOTE, "KCS: Wrote last data: %02x", + *cp); +#endif + } + + /* Read the reply. First, read the NetFn/LUN. */ + if (kcs_read_byte(sc, &data) != 1) { + cmn_err(CE_WARN, "KCS: Failed to read address"); + goto fail; + } +#ifdef KCS_DEBUG + cmn_err(CE_NOTE, "KCS: Read address: %02x", data); +#endif + if (data != IPMI_REPLY_ADDR(req->ir_addr)) { + cmn_err(CE_WARN, "KCS: Reply address mismatch"); + goto fail; + } + + /* Next we read the command. */ + if (kcs_read_byte(sc, &data) != 1) { + cmn_err(CE_WARN, "KCS: Failed to read command"); + goto fail; + } +#ifdef KCS_DEBUG + cmn_err(CE_NOTE, "KCS: Read command: %02x", data); +#endif + if (data != req->ir_command) { + cmn_err(CE_WARN, "KCS: Command mismatch"); + goto fail; + } + + /* Next we read the completion code. */ + if (kcs_read_byte(sc, &req->ir_compcode) != 1) { + cmn_err(CE_WARN, "KCS: Failed to read completion code"); + goto fail; + } +#ifdef KCS_DEBUG + cmn_err(CE_NOTE, "KCS: Read completion code: %02x", + req->ir_compcode); +#endif + + /* Finally, read the reply from the BMC. */ + i = 0; + for (;;) { + state = kcs_read_byte(sc, &data); + if (state == 0) { + cmn_err(CE_WARN, + "KCS: Read failed on byte %d", i + 1); + goto fail; + } + if (state == 2) + break; + if (i < req->ir_replybuflen) { + req->ir_reply[i] = data; +#ifdef KCS_DEBUG + cmn_err(CE_NOTE, "KCS: Read data %02x", + data); + } else { + cmn_err(CE_WARN, + "KCS: Read short %02x byte %d", data, i + 1); +#endif + } + i++; + } + req->ir_replylen = i; +#ifdef KCS_DEBUG + cmn_err(CE_NOTE, "KCS: READ finished (%d bytes)", i); + if (req->ir_replybuflen < i) +#else + if (req->ir_replybuflen < i && req->ir_replybuflen != 0) +#endif + cmn_err(CE_WARN, "KCS: Read short: %d buffer, %d actual", + (int)(req->ir_replybuflen), i); + return (1); +fail: + kcs_error(sc); + return (0); +} + +static void +kcs_loop(void *arg) +{ + struct ipmi_softc *sc = arg; + struct ipmi_request *req; + int i, ok; + + IPMI_LOCK(sc); + while ((req = ipmi_dequeue_request(sc)) != NULL) { + ok = 0; + for (i = 0; i < 3 && !ok; i++) + ok = kcs_polled_request(sc, req); + if (ok) + req->ir_error = 0; + else + req->ir_error = EIO; + ipmi_complete_request(sc, req); + } + IPMI_UNLOCK(sc); +} + +static int +kcs_startup(struct ipmi_softc *sc) +{ + sc->ipmi_kthread = taskq_create_proc("ipmi_kcs", 1, minclsyspri, 1, 1, + curzone->zone_zsched, TASKQ_PREPOPULATE); + + if (taskq_dispatch(sc->ipmi_kthread, kcs_loop, (void *) sc, + TQ_SLEEP) == NULL) { + taskq_destroy(sc->ipmi_kthread); + return (1); + } + + return (0); +} + +int +ipmi_kcs_attach(struct ipmi_softc *sc) +{ + int status; + + /* Setup function pointers. */ + sc->ipmi_startup = kcs_startup; + sc->ipmi_enqueue_request = ipmi_polled_enqueue_request; + + /* See if we can talk to the controller. */ + status = INB(sc, KCS_CTL_STS); + if (status == 0xff) { + cmn_err(CE_CONT, "!KCS couldn't find it"); + return (ENXIO); + } + + timeout_usecs = drv_hztousec(MAX_TIMEOUT); + +#ifdef KCS_DEBUG + cmn_err(CE_NOTE, "KCS: initial state: %02x", status); +#endif + if (status & KCS_STATUS_OBF || + KCS_STATUS_STATE(status) != KCS_STATUS_STATE_IDLE) + kcs_error(sc); + + return (0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/intel/io/ipmi/ipmi_main.c Thu Apr 26 15:49:44 2012 +0000 @@ -0,0 +1,611 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2012, Joyent, Inc. All rights reserved. + */ + +/* + * The ipmi driver is an openipmi compatible IPMI driver based on the FreeBSD + * driver. + * + * The current implementation has several limitations: + * 1) It only does discovery through the SMBIOS. The FreeBSD driver has + * several additional ways to discover the IPMI device (acpi, bus checking, + * etc.). This support could be ported if necessary. + * 2) The driver currently only supports the IPMI KCS_MODE mode (reported + * through the SMBIOS as SMBIOS SMB_IPMI_T_KCS). Support for the other modes + * (BT_MODE, SMIC_MODE, SSIF_MODE) could be ported if necessary. + * 3) The driver does not currently set up an IPMI watchdog. This also could + * be ported if necessary. + */ + +#include <sys/devops.h> +#include <sys/conf.h> +#include <sys/modctl.h> +#include <sys/types.h> +#include <sys/file.h> +#include <sys/errno.h> +#include <sys/open.h> +#include <sys/cred.h> +#include <sys/uio.h> +#include <sys/stat.h> +#include <sys/cmn_err.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/smbios.h> +#include <sys/smbios_impl.h> +#include <sys/policy.h> +#include <sys/ipmi.h> +#include "ipmivars.h" + +static dev_info_t *ipmi_dip; +static boolean_t ipmi_attached = B_FALSE; +static boolean_t ipmi_found = B_FALSE; +static struct ipmi_softc softc; +static struct ipmi_softc *sc = &softc; +static list_t dev_list; +static id_space_t *minor_ids; + +#define PTRIN(p) ((void *)(uintptr_t)(p)) +#define PTROUT(p) ((uintptr_t)(p)) + +/* + * Use the SMBIOS info to determine if the system has an IPMI. + */ +static int +get_smbios_ipmi_info(void) +{ + smbios_ipmi_t ipmi; + + if (ksmbios == NULL || smbios_info_ipmi(ksmbios, &ipmi) == SMB_ERR) + return (DDI_FAILURE); + + cmn_err(CE_CONT, "!SMBIOS type 0x%x, addr 0x%llx", ipmi.smbip_type, + (long long unsigned int)(ipmi.smbip_addr)); + + /* + * Some systems have a bios that will report an IPMI device even when + * it is not installed. In this case we see 0x0 as the base address. + * If we see this address, assume the device is not really present. + */ + if (ipmi.smbip_addr == NULL) { + cmn_err(CE_WARN, "!SMBIOS: Invalid base address"); + return (DDI_FAILURE); + } + + sc->ipmi_io_type = ipmi.smbip_type; + switch (ipmi.smbip_type) { + case SMB_IPMI_T_KCS: + case SMB_IPMI_T_SMIC: + sc->ipmi_io_address = ipmi.smbip_addr; + sc->ipmi_io_mode = (ipmi.smbip_flags & SMB_IPMI_F_IOADDR) ? + 1 : 0; + sc->ipmi_io_spacing = ipmi.smbip_regspacing; + break; + case SMB_IPMI_T_SSIF: + if ((ipmi.smbip_addr & 0xffffffffffffff00) != 0) { + cmn_err(CE_WARN, "!SMBIOS: Invalid SSIF SMBus address, " + "using BMC I2C slave address instead"); + sc->ipmi_io_address = ipmi.smbip_i2c; + } else { + sc->ipmi_io_address = ipmi.smbip_addr; + } + break; + default: + return (DDI_FAILURE); + } + + if (ipmi.smbip_intr > 15) { + cmn_err(CE_WARN, "!SMBIOS: Non-ISA IRQ %d for IPMI", + ipmi.smbip_intr); + return (DDI_FAILURE); + } + + sc->ipmi_io_irq = ipmi.smbip_intr; + return (DDI_SUCCESS); +} + +static ipmi_device_t * +lookup_ipmidev_by_dev(dev_t dev) +{ + ipmi_device_t *p; + + for (p = list_head(&dev_list); p; p = list_next(&dev_list, p)) { + if (dev == p->ipmi_dev) + return (p); + } + return (NULL); +} + +/* + * Each open returns a new pseudo device. + */ +/*ARGSUSED*/ +static int +ipmi_open(dev_t *devp, int flag, int otyp, cred_t *cred) +{ + minor_t minor; + ipmi_device_t *dev; + + if (ipmi_attached == B_FALSE) + return (ENXIO); + + if (ipmi_found == B_FALSE) + return (ENODEV); + + /* exclusive opens are not supported */ + if (flag & FEXCL) + return (ENOTSUP); + + if ((minor = (minor_t)id_alloc_nosleep(minor_ids)) == 0) + return (ENODEV); + + /* Initialize the per file descriptor data. */ + dev = kmem_zalloc(sizeof (ipmi_device_t), KM_SLEEP); + + dev->ipmi_pollhead = kmem_zalloc(sizeof (pollhead_t), KM_SLEEP); + + TAILQ_INIT(&dev->ipmi_completed_requests); + dev->ipmi_address = IPMI_BMC_SLAVE_ADDR; + dev->ipmi_lun = IPMI_BMC_SMS_LUN; + *devp = makedevice(getmajor(*devp), minor); + dev->ipmi_dev = *devp; + + list_insert_head(&dev_list, dev); + + return (0); +} + +/*ARGSUSED*/ +static int +ipmi_close(dev_t dev, int flag, int otyp, cred_t *cred) +{ + ipmi_device_t *dp; + struct ipmi_request *req, *next; + + if ((dp = lookup_ipmidev_by_dev(dev)) == NULL) + return (ENODEV); + + IPMI_LOCK(sc); + /* remove any pending requests */ + req = TAILQ_FIRST(&sc->ipmi_pending_requests); + while (req != NULL) { + next = TAILQ_NEXT(req, ir_link); + + if (req->ir_owner == dp) { + TAILQ_REMOVE(&sc->ipmi_pending_requests, req, ir_link); + ipmi_free_request(req); + } + req = next; + } + IPMI_UNLOCK(sc); + + /* remove any requests in queue of stuff completed */ + while ((req = TAILQ_FIRST(&dp->ipmi_completed_requests)) != NULL) { + TAILQ_REMOVE(&dp->ipmi_completed_requests, req, ir_link); + ipmi_free_request(req); + } + + list_remove(&dev_list, dp); + id_free(minor_ids, getminor(dev)); + kmem_free(dp->ipmi_pollhead, sizeof (pollhead_t)); + kmem_free(dp, sizeof (ipmi_device_t)); + + return (0); +} + +/*ARGSUSED*/ +static int +ipmi_ioctl(dev_t dv, int cmd, intptr_t data, int flags, cred_t *cr, int *rvalp) +{ + struct ipmi_device *dev; + struct ipmi_request *kreq; + struct ipmi_req req; + struct ipmi_recv recv; + struct ipmi_recv32 recv32; + struct ipmi_addr addr; + int error, len; + model_t model; + int orig_cmd = 0; + uchar_t t_lun; + + if (secpolicy_sys_config(cr, B_FALSE) != 0) + return (EPERM); + + if ((dev = lookup_ipmidev_by_dev(dv)) == NULL) + return (ENODEV); + + model = get_udatamodel(); + if (model == DATAMODEL_NATIVE) { + switch (cmd) { + case IPMICTL_SEND_COMMAND: + if (copyin((void *)data, &req, sizeof (req))) + return (EFAULT); + break; + case IPMICTL_RECEIVE_MSG_TRUNC: + case IPMICTL_RECEIVE_MSG: + if (copyin((void *)data, &recv, sizeof (recv))) + return (EFAULT); + break; + } + } else { + /* Convert 32-bit structures to native. */ + struct ipmi_req32 req32; + + switch (cmd) { + case IPMICTL_SEND_COMMAND_32: + if (copyin((void *)data, &req32, sizeof (req32))) + return (EFAULT); + + req.addr = PTRIN(req32.addr); + req.addr_len = req32.addr_len; + req.msgid = req32.msgid; + req.msg.netfn = req32.msg.netfn; + req.msg.cmd = req32.msg.cmd; + req.msg.data_len = req32.msg.data_len; + req.msg.data = PTRIN(req32.msg.data); + + cmd = IPMICTL_SEND_COMMAND; + break; + + case IPMICTL_RECEIVE_MSG_TRUNC_32: + case IPMICTL_RECEIVE_MSG_32: + if (copyin((void *)data, &recv32, sizeof (recv32))) + return (EFAULT); + + recv.addr = PTRIN(recv32.addr); + recv.addr_len = recv32.addr_len; + recv.msg.data_len = recv32.msg.data_len; + recv.msg.data = PTRIN(recv32.msg.data); + + orig_cmd = cmd; + cmd = (cmd == IPMICTL_RECEIVE_MSG_TRUNC_32) ? + IPMICTL_RECEIVE_MSG_TRUNC : IPMICTL_RECEIVE_MSG; + break; + } + } + + switch (cmd) { + case IPMICTL_SEND_COMMAND: + IPMI_LOCK(sc); + /* clear out old stuff in queue of stuff done */ + while ((kreq = TAILQ_FIRST(&dev->ipmi_completed_requests)) + != NULL) { + TAILQ_REMOVE(&dev->ipmi_completed_requests, kreq, + ir_link); + dev->ipmi_requests--; + ipmi_free_request(kreq); + } + IPMI_UNLOCK(sc); + + /* Check that we didn't get a ridiculous length */ + if (req.msg.data_len > IPMI_MAX_RX) + return (EINVAL); + + kreq = ipmi_alloc_request(dev, req.msgid, + IPMI_ADDR(req.msg.netfn, 0), req.msg.cmd, + req.msg.data_len, IPMI_MAX_RX); + /* This struct is the same for 32/64 */ + if (req.msg.data_len > 0 && + copyin(req.msg.data, kreq->ir_request, req.msg.data_len)) { + ipmi_free_request(kreq); + return (EFAULT); + } + IPMI_LOCK(sc); + dev->ipmi_requests++; + error = sc->ipmi_enqueue_request(sc, kreq); + IPMI_UNLOCK(sc); + if (error) + return (error); + break; + + case IPMICTL_RECEIVE_MSG_TRUNC: + case IPMICTL_RECEIVE_MSG: + /* This struct is the same for 32/64 */ + if (copyin(recv.addr, &addr, sizeof (addr))) + return (EFAULT); + + IPMI_LOCK(sc); + kreq = TAILQ_FIRST(&dev->ipmi_completed_requests); + if (kreq == NULL) { + IPMI_UNLOCK(sc); + return (EAGAIN); + } + addr.channel = IPMI_BMC_CHANNEL; + recv.recv_type = IPMI_RESPONSE_RECV_TYPE; + recv.msgid = kreq->ir_msgid; + recv.msg.netfn = IPMI_REPLY_ADDR(kreq->ir_addr) >> 2; + recv.msg.cmd = kreq->ir_command; + error = kreq->ir_error; + if (error) { + TAILQ_REMOVE(&dev->ipmi_completed_requests, kreq, + ir_link); + dev->ipmi_requests--; + IPMI_UNLOCK(sc); + ipmi_free_request(kreq); + return (error); + } + len = kreq->ir_replylen + 1; + if (recv.msg.data_len < len && cmd == IPMICTL_RECEIVE_MSG) { + IPMI_UNLOCK(sc); + ipmi_free_request(kreq); + return (EMSGSIZE); + } + TAILQ_REMOVE(&dev->ipmi_completed_requests, kreq, ir_link); + dev->ipmi_requests--; + IPMI_UNLOCK(sc); + len = min(recv.msg.data_len, len); + recv.msg.data_len = (unsigned short)len; + + if (orig_cmd == IPMICTL_RECEIVE_MSG_TRUNC_32 || + orig_cmd == IPMICTL_RECEIVE_MSG_32) { + /* Update changed fields in 32-bit structure. */ + recv32.recv_type = recv.recv_type; + recv32.msgid = (int32_t)recv.msgid; + recv32.msg.netfn = recv.msg.netfn; + recv32.msg.cmd = recv.msg.cmd; + recv32.msg.data_len = recv.msg.data_len; + + error = copyout(&recv32, (void *)data, sizeof (recv32)); + } else { + error = copyout(&recv, (void *)data, sizeof (recv)); + } + + /* This struct is the same for 32/64 */ + if (error == 0) + error = copyout(&addr, recv.addr, sizeof (addr)); + if (error == 0) + error = copyout(&kreq->ir_compcode, recv.msg.data, 1); + if (error == 0) + error = copyout(kreq->ir_reply, recv.msg.data + 1, + len - 1); + ipmi_free_request(kreq); + + if (error) + return (EFAULT); + + break; + + case IPMICTL_SET_MY_ADDRESS_CMD: + IPMI_LOCK(sc); + if (copyin((void *)data, &dev->ipmi_address, + sizeof (dev->ipmi_address))) { + IPMI_UNLOCK(sc); + return (EFAULT); + } + IPMI_UNLOCK(sc); + break; + + case IPMICTL_GET_MY_ADDRESS_CMD: + IPMI_LOCK(sc); + if (copyout(&dev->ipmi_address, (void *)data, + sizeof (dev->ipmi_address))) { + IPMI_UNLOCK(sc); + return (EFAULT); + } + IPMI_UNLOCK(sc); + break; + + case IPMICTL_SET_MY_LUN_CMD: + IPMI_LOCK(sc); + if (copyin((void *)data, &t_lun, sizeof (t_lun))) { + IPMI_UNLOCK(sc); + return (EFAULT); + } + dev->ipmi_lun = t_lun & 0x3; + IPMI_UNLOCK(sc); + break; + + case IPMICTL_GET_MY_LUN_CMD: + IPMI_LOCK(sc); + if (copyout(&dev->ipmi_lun, (void *)data, + sizeof (dev->ipmi_lun))) { + IPMI_UNLOCK(sc); + return (EFAULT); + } + IPMI_UNLOCK(sc); + break; + + case IPMICTL_SET_GETS_EVENTS_CMD: + break; + + case IPMICTL_REGISTER_FOR_CMD: + case IPMICTL_UNREGISTER_FOR_CMD: + return (EINVAL); + + default: + return (EINVAL); + } + + return (0); +} + +static int +ipmi_poll(dev_t dv, short events, int anyyet, short *reventsp, + pollhead_t **phpp) +{ + struct ipmi_device *dev; + short revent = 0; + + if ((dev = lookup_ipmidev_by_dev(dv)) == NULL) + return (ENODEV); + + if (events & (POLLIN | POLLRDNORM)) { + if (!TAILQ_EMPTY(&dev->ipmi_completed_requests)) + revent |= events & (POLLIN | POLLRDNORM); + if (dev->ipmi_requests == 0) + revent |= POLLERR; + } + + if (revent == 0) { + /* nothing has occurred */ + if (!anyyet) + *phpp = dev->ipmi_pollhead; + } + + *reventsp = revent; + return (0); +} + +/*ARGSUSED*/ +static int +ipmi_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) +{ + switch (cmd) { + case DDI_INFO_DEVT2DEVINFO: + *resultp = ipmi_dip; + return (DDI_SUCCESS); + case DDI_INFO_DEVT2INSTANCE: + *resultp = NULL; + return (DDI_SUCCESS); + } + return (DDI_FAILURE); +} + +static int +ipmi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) +{ + if (cmd != DDI_ATTACH) + return (DDI_FAILURE); + + if (get_smbios_ipmi_info() == DDI_FAILURE) + return (DDI_FAILURE); + + /* + * Support for the other types (SMIC, SSIF) should be added here. + */ + switch (sc->ipmi_io_type) { + case SMB_IPMI_T_KCS: + if (ipmi_kcs_attach(sc) != 0) + return (DDI_FAILURE); + break; + default: + return (DDI_FAILURE); + } + ipmi_found = B_TRUE; + + if (ddi_create_minor_node(dip, "ipmi", S_IFCHR, 0, DDI_PSEUDO, + 0) == DDI_FAILURE) { + cmn_err(CE_WARN, "!attach could not create minor node"); + ddi_remove_minor_node(dip, NULL); + return (DDI_FAILURE); + } + + ipmi_dip = dip; + + list_create(&dev_list, sizeof (ipmi_device_t), + offsetof(ipmi_device_t, ipmi_node)); + + /* Create ID space for open devs. ID 0 is reserved. */ + minor_ids = id_space_create("ipmi_id_space", 1, 128); + + ipmi_startup(sc); + ipmi_attached = B_TRUE; + + return (DDI_SUCCESS); +} + +static int +ipmi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) +{ + if (cmd != DDI_DETACH) + return (DDI_FAILURE); + + if (ipmi_found == B_FALSE) + return (DDI_SUCCESS); + + if (!list_is_empty(&dev_list)) + return (DDI_FAILURE); + + /* poke the taskq so that it can terminate */ + sc->ipmi_detaching = 1; + cv_signal(&sc->ipmi_request_added); + + ddi_remove_minor_node(dip, NULL); + ipmi_dip = NULL; + + taskq_destroy(sc->ipmi_kthread); + list_destroy(&dev_list); + id_space_destroy(minor_ids); + + ipmi_attached = B_FALSE; + return (DDI_SUCCESS); +} + +static struct cb_ops ipmi_cb_ops = { + ipmi_open, + ipmi_close, + nodev, /* strategy */ + nodev, /* print */ + nodev, /* dump */ + nodev, /* read */ + nodev, /* write */ + ipmi_ioctl, + nodev, /* devmap */ + nodev, /* mmap */ + nodev, /* segmap */ + ipmi_poll, + ddi_prop_op, + NULL, /* streamtab */ + D_NEW | D_MP /* flags */ +}; + +static struct dev_ops ipmi_ops = { + DEVO_REV, + 0, /* reference count */ + ipmi_info, + nulldev, /* identify */ + nulldev, /* probe */ + ipmi_attach, + ipmi_detach, + nodev, /* reset */ + &ipmi_cb_ops, + NULL, /* bus ops */ + NULL, /* power */ + ddi_quiesce_not_needed, +}; + +static struct modldrv md = { + &mod_driverops, "ipmi driver", &ipmi_ops +}; + +static struct modlinkage ml = { + MODREV_1, &md, NULL +}; + +int +_init(void) +{ + return (mod_install(&ml)); +} + +int +_fini(void) +{ + return (mod_remove(&ml)); +} + +int +_info(struct modinfo *mip) +{ + return (mod_info(&ml, mip)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/intel/io/ipmi/ipmivars.h Thu Apr 26 15:49:44 2012 +0000 @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2006 IronPort Systems Inc. <ambrisko@ironport.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + * $FreeBSD: src/sys/dev/ipmi/ipmivars.h,v 1.3 2008/08/28 02:13:53 jhb Exp $ + */ + +/* + * Copyright 2012, Joyent, Inc. All rights reserved. + */ + +#ifndef _IPMIVARS_H_ +#define _IPMIVARS_H_ + +#include <sys/types.h> +#include <sys/queue.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct ipmi_device; +struct ipmi_request; + +struct ipmi_request { + TAILQ_ENTRY(ipmi_request) ir_link; + struct ipmi_device *ir_owner; /* Driver uses NULL. */ + uchar_t *ir_request; /* Request is data to send to BMC. */ + size_t ir_requestlen; + uchar_t *ir_reply; /* Reply is data read from BMC. */ + size_t ir_replybuflen; /* Length of ir_reply[] buffer. */ + int ir_replylen; /* Length of reply from BMC. */ + int ir_error; + long ir_msgid; + uint8_t ir_addr; + uint8_t ir_command; + uint8_t ir_compcode; + int ir_sz; /* size of request */ +}; + +#define MAX_RES 3 +#define KCS_DATA 0 +#define KCS_CTL_STS 1 +#define SMIC_DATA 0 +#define SMIC_CTL_STS 1 +#define SMIC_FLAGS 2 + +/* Per file descriptor data. */ +typedef struct ipmi_device { + TAILQ_HEAD(, ipmi_request) ipmi_completed_requests; + pollhead_t *ipmi_pollhead; + int ipmi_requests; + uchar_t ipmi_address; /* IPMB address. */ + uchar_t ipmi_lun; + dev_t ipmi_dev; + list_node_t ipmi_node; /* list link for open devs */ +} ipmi_device_t; + +struct ipmi_softc { + int ipmi_io_rid; + int ipmi_io_type; + uint64_t ipmi_io_address; + int ipmi_io_mode; + int ipmi_io_spacing; + int ipmi_io_irq; + void *ipmi_irq; + int ipmi_detaching; + TAILQ_HEAD(, ipmi_request) ipmi_pending_requests; + kmutex_t ipmi_lock; + kcondvar_t ipmi_request_added; + taskq_t *ipmi_kthread; + int (*ipmi_startup)(struct ipmi_softc *); + int (*ipmi_enqueue_request)(struct ipmi_softc *, + struct ipmi_request *); +}; + +#define KCS_MODE 0x01 +#define SMIC_MODE 0x02 +#define BT_MODE 0x03 +#define SSIF_MODE 0x04 + +/* KCS status flags */ +#define KCS_STATUS_OBF 0x01 /* Data Out ready from BMC */ +#define KCS_STATUS_IBF 0x02 /* Data In from System */ +#define KCS_STATUS_SMS_ATN 0x04 /* Ready in RX queue */ +#define KCS_STATUS_C_D 0x08 /* Command/Data register write */ +#define KCS_STATUS_OEM1 0x10 +#define KCS_STATUS_OEM2 0x20 +#define KCS_STATUS_S0 0x40 +#define KCS_STATUS_S1 0x80 +#define KCS_STATUS_STATE(x) ((x)>>6) +#define KCS_STATUS_STATE_IDLE 0x0 +#define KCS_STATUS_STATE_READ 0x1 +#define KCS_STATUS_STATE_WRITE 0x2 +#define KCS_STATUS_STATE_ERROR 0x3 +#define KCS_IFACE_STATUS_OK 0x00 +#define KCS_IFACE_STATUS_ABORT 0x01 +#define KCS_IFACE_STATUS_ILLEGAL 0x02 +#define KCS_IFACE_STATUS_LENGTH_ERR 0x06 +#define KCS_IFACE_STATUS_UNKNOWN_ERR 0xff + +/* KCS control codes */ +#define KCS_CONTROL_GET_STATUS_ABORT 0x60 +#define KCS_CONTROL_WRITE_START 0x61 +#define KCS_CONTROL_WRITE_END 0x62 +#define KCS_DATA_IN_READ 0x68 + +/* SMIC status flags */ +#define SMIC_STATUS_BUSY 0x01 /* System set and BMC clears it */ +#define SMIC_STATUS_SMS_ATN 0x04 /* BMC has a message */ +#define SMIC_STATUS_EVT_ATN 0x08 /* Event has been RX */ +#define SMIC_STATUS_SMI 0x10 /* asserted SMI */ +#define SMIC_STATUS_TX_RDY 0x40 /* Ready to accept WRITE */ +#define SMIC_STATUS_RX_RDY 0x80 /* Ready to read */ +#define SMIC_STATUS_RESERVED 0x22 + +/* SMIC control codes */ +#define SMIC_CC_SMS_GET_STATUS 0x40 +#define SMIC_CC_SMS_WR_START 0x41 +#define SMIC_CC_SMS_WR_NEXT 0x42 +#define SMIC_CC_SMS_WR_END 0x43 +#define SMIC_CC_SMS_RD_START 0x44 +#define SMIC_CC_SMS_RD_NEXT 0x45 +#define SMIC_CC_SMS_RD_END 0x46 + +/* SMIC status codes */ +#define SMIC_SC_SMS_RDY 0xc0 +#define SMIC_SC_SMS_WR_START 0xc1 +#define SMIC_SC_SMS_WR_NEXT 0xc2 +#define SMIC_SC_SMS_WR_END 0xc3 +#define SMIC_SC_SMS_RD_START 0xc4 +#define SMIC_SC_SMS_RD_NEXT 0xc5 +#define SMIC_SC_SMS_RD_END 0xc6 + +#define IPMI_ADDR(netfn, lun) ((netfn) << 2 | (lun)) +#define IPMI_REPLY_ADDR(addr) ((addr) + 0x4) + +#define IPMI_LOCK(sc) mutex_enter(&(sc)->ipmi_lock) +#define IPMI_UNLOCK(sc) mutex_exit(&(sc)->ipmi_lock) +#define IPMI_LOCK_ASSERT(sc) ASSERT(MUTEX_HELD(&(sc)->ipmi_lock)) + +#define ipmi_alloc_driver_request(addr, cmd, reqlen, replylen) \ + ipmi_alloc_request(NULL, 0, (addr), (cmd), (reqlen), (replylen)) + +#define INB(sc, x) \ + inb((sc)->ipmi_io_address + ((sc)->ipmi_io_spacing * (x))) +#define OUTB(sc, x, value) \ + outb((sc)->ipmi_io_address + ((sc)->ipmi_io_spacing * (x)), value) + +#define MAX_TIMEOUT (3 * hz) + +/* Manage requests. */ +void ipmi_complete_request(struct ipmi_softc *, struct ipmi_request *); +struct ipmi_request *ipmi_dequeue_request(struct ipmi_softc *); +int ipmi_polled_enqueue_request(struct ipmi_softc *, struct ipmi_request *); +struct ipmi_request *ipmi_alloc_request(struct ipmi_device *, long msgid, + uint8_t, uint8_t, size_t, size_t); +void ipmi_free_request(struct ipmi_request *); + +/* Interface attach routines. */ +void ipmi_startup(struct ipmi_softc *sc); +int ipmi_kcs_attach(struct ipmi_softc *); + +#ifdef __cplusplus +} +#endif + +#endif /* _IPMIVARS_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/intel/ipmi/Makefile Thu Apr 26 15:49:44 2012 +0000 @@ -0,0 +1,83 @@ +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright (c) 2012, Joyent, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# IPMI interface +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = ipmi +OBJECTS = $(IPMI_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(IPMI_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(USR_DRV_DIR)/$(MODULE) +CONF_SRCDIR = $(UTSBASE)/intel/io/ipmi + +# +# Include common rules. +# +include $(UTSBASE)/intel/Makefile.intel + +# +# Define targets +# +ALL_TARGET = $(BINARY) $(SRC_CONFFILE) +LINT_TARGET = $(LINT_MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) + +# +# Kernel Module Dependencies +# +LDFLAGS += -dy + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +# +# Include common targets. +# +include $(UTSBASE)/intel/Makefile.targ