sgfru.c revision 193974072f41a843678abf5f61979c748687e66b
/*
* 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
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/ddi_impldefs.h>
#include <sys/sysmacros.h>
#include <sys/autoconf.h>
#include <sys/sgsbbc_mailbox.h>
#include <sys/sgfrutree.h>
#include <sys/sgfru_priv.h>
#include <sys/sgfru_mbox.h>
/*
* This driver implements the ioctls for the serengeti frutree picl plugin
* and the serengeti fruaccess library. These are all private,
* platform-dependent interfaces.
*/
/* Global Variables */
#ifdef DEBUG
uint_t sgfru_debug = 0;
#endif /* DEBUG */
/* Opaque state structure pointer */
static void *sgfru_statep; /* sgfru soft state hook */
/*
* the maximum amount of time this driver is prepared to wait for the mailbox
* to reply before it decides to timeout.
*/
/* Module Variables */
/*
* Driver entry points. These are located in sgfru.c so as to
* not cause a warning for the sgfru adb macro.
*/
static struct cb_ops sgfru_cb_ops = {
sgfru_open, /* open */
sgfru_close, /* close */
nulldev, /* strategy */
nulldev, /* print */
nulldev, /* dump */
nulldev, /* read */
nulldev, /* write */
sgfru_ioctl, /* ioctl */
nulldev, /* devmap */
nulldev, /* mmap */
nulldev, /* segmap */
nochpoll, /* poll */
ddi_prop_op, /* cb_prop_op */
NULL, /* streamtab */
};
DEVO_REV, /* devo_rev, */
0, /* refcnt */
ddi_getinfo_1to1, /* info */
nulldev, /* identify */
nulldev, /* probe */
sgfru_attach, /* attach */
sgfru_detach, /* detach */
nodev, /* reset */
&sgfru_cb_ops, /* driver operations */
(struct bus_ops *)0, /* bus operations */
nulldev, /* power */
ddi_quiesce_not_needed, /* quiesce */
};
/*
* Loadable module support. This is located in sgfru.c so as to
* pick up the 1.8 version of sgfru.c.
*/
extern struct mod_ops mod_driverops;
&mod_driverops, /* Type of module. This one is a pseudo driver */
"FRU Driver",
&sgfru_ops, /* driver ops */
};
static struct modlinkage modlinkage = {
(void *)&modldrv,
};
int
_init(void)
{
int error = 0;
/* Allocate the soft state info and add the module. */
sizeof (sgfru_soft_state_t), 1)) == 0 &&
}
return (error);
}
int
_fini(void)
{
int error = 0;
/* Remove the module and free the soft state info. */
}
return (error);
}
int
{
}
static int
{
int instance;
int error;
static fn_t f = "sgfru_attach";
switch (cmd) {
case DDI_ATTACH:
if (error != DDI_SUCCESS) {
"for inst %d.", f, instance);
return (DDI_FAILURE);
}
"structure for inst %d.", f, instance);
return (DDI_FAILURE);
}
if (error == DDI_FAILURE) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
case DDI_RESUME:
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
}
static int
{
int instance;
static fn_t f = "sgfru_detach";
"structure for inst %d.", f, instance);
return (DDI_FAILURE);
}
switch (cmd) {
case DDI_DETACH:
return (DDI_SUCCESS);
case DDI_SUSPEND:
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
}
/*ARGSUSED*/
static int
{
int error = 0;
static fn_t f = "sgfru_open";
f, instance);
return (error);
}
instance);
f, instance);
return (ENXIO);
}
return (error);
}
/*ARGSUSED*/
static int
{
return (ENXIO);
return (DDI_SUCCESS);
}
/*
* This function disperses the ioctls from the serengeti libpiclfruhier plugin
* and the serengeti libpiclfruaccess library to the appropriate sub-functions.
*/
/*ARGSUSED*/
static int
int *rval_p)
{
static fn_t f = "sgfru_ioctl";
return (ENXIO);
}
PR_STATE("sgfru:%s: dev %lx cmd %d, instance %d\n",
switch (cmd) {
case SGFRU_GETSECTIONS:
break;
case SGFRU_GETSEGMENTS:
break;
case SGFRU_ADDSEGMENT:
break;
case SGFRU_READRAWSEGMENT:
break;
case SGFRU_WRITERAWSEGMENT:
break;
case SGFRU_GETPACKETS:
break;
case SGFRU_APPENDPACKET:
break;
case SGFRU_GETPAYLOAD:
break;
case SGFRU_UPDATEPAYLOAD:
break;
case SGFRU_GETNUMSECTIONS:
case SGFRU_GETNUMSEGMENTS:
case SGFRU_GETNUMPACKETS:
break;
case SGFRU_DELETESEGMENT:
case SGFRU_DELETEPACKET:
break;
case SGFRU_GETCHILDLIST:
break;
case SGFRU_GETCHILDHANDLES:
break;
case SGFRU_GETNODEINFO:
break;
default:
break;
}
return (ret);
}
/*
* Used for private SGFRU_GETCHILDLIST ioctl.
*/
static int
{
static fn_t f = "sgfru_getchildlist";
/* copyin child_info_t aka frup_info_t */
return (EFAULT);
}
/* check on kmem_alloc space requirements */
return (EINVAL);
}
/* allocate buffer for unpadded fru_info_t + node_t's */
PR_NODE("sgfru:%s: FRU_INFO_SIZE %lu NODE_SIZE %lu size %lu\n",
PR_NODE("sgfru:%s: handle %lx cnt %d buffer 0x%p\n", f,
/* call mailbox */
!= 0) {
return (ret);
}
/* allocate buffer for padded node_t's */
/* translate unpadded to padded fru_info_t + node_t's */
!= 0) {
return (ret);
}
/* free node_t buffer */
/* copy out fru_info_t */
return (EFAULT);
}
/* copyout node_t's */
return (EFAULT);
}
/* free node_t buffer */
return (ret);
}
/*
* Used for private SGFRU_GETCHILDHANDLES ioctl.
*/
static int
{
static fn_t f = "sgfru_getchildhandles";
/* copyin handles_t aka frup_info_t */
return (EFAULT);
}
/* check on kmem_alloc space requirements */
return (EINVAL);
}
/* allocate buffer for child fru_hdl_t's */
/* call mailbox */
if (ret != 0) {
return (ret);
}
/* translate unpadded to fru_info_t */
/* copyout actual fru_cnt */
return (EFAULT);
}
/* copyout fru_hdl_t's */
return (EFAULT);
}
/* free datap buffer */
return (ret);
}
/*
* Used for private SGFRU_GETNODEINFO ioctl.
*/
static int
{
static fn_t f = "sgfru_getnodeinfo";
/* copyin node_info_t aka frup_info_t */
return (EFAULT);
}
/* allocate unpadded buffer for node_t */
/* call mailbox */
if (ret != 0) {
return (ret);
}
/* translate unpadded to padded node_t */
!= 0) {
return (ret);
}
/* free node_t buffer */
/* copyout node_t */
return (EFAULT);
}
PR_NODE("sgfru:%s: handle %lx nodename %s has_children %d class %d\n",
return (ret);
}
/*
* Used for fru_get_sections().
*/
static int
{
/* copyin sections_t aka frup_info_t */
return (EFAULT);
}
/* check on kmem_alloc space requirements */
return (EINVAL);
}
/* allocate buffer for unpadded fru_info_t + section_t's */
/* call mailbox */
!= 0) {
return (ret);
}
/* allocate buffer for padded section_t's */
/* translate unpadded to padded fru_info_t + section_t's */
!= 0) {
return (ret);
}
/* free section_t buffer */
/* copy out fru_info_t */
return (EFAULT);
}
/* copyout section_t's */
return (EFAULT);
}
/* free section_t buffer */
return (ret);
}
/*
* Used for fru_get_segments().
*/
static int
{
/* copyin frup_info_t */
return (EFAULT);
}
/* check on kmem_alloc space requirements */
return (EINVAL);
}
/* allocate unpadded buffer for fru_info_t + segment_t's */
/* call mailbox */
return (ret);
}
/* allocate buffer for padded segment_t's */
/* translate unpadded to padded fru_info_t + segment_t's */
!= 0) {
return (ret);
}
/* free segment_t buffer */
/* copy out fru_info_t */
return (EFAULT);
}
/* copyout segment_t's */
return (EFAULT);
}
/* free segment_t buffer */
return (ret);
}
static int
{
static fn_t f = "sgfru_addsegment";
/* copyin frup_info_t */
return (EFAULT);
}
/* copyin segment_t */
return (EFAULT);
}
PR_SEGMENT("sgfru:%s: handle %lx, max cnt %d\n",
PR_SEGMENT("sgfru:%s: handle %lx, name %s, descriptor 0x%x, "
/* allocate buffer for unpadded section_hdl_t + segment_t */
/* translate padded to unpadded section_hdl_t + segment_t */
/* call mailbox */
if (ret != 0) {
return (ret);
}
/* copyout updated section_hdl_t */
return (EFAULT);
}
/* copyout new segment_hdl_t */
return (EFAULT);
}
/* free segment_t buffer */
return (ret);
}
/*
* Used for fru_read_segment().
*/
static int
{
static fn_t f = "sgfru_readsegment";
/* copyin one segments_t aka frup_info_t */
return (EFAULT);
}
/* check on kmem_alloc space requirements */
return (EINVAL);
}
PR_SEGMENT("sgfru:%s: handle %lx, max cnt %d\n",
/* allocate unpadded buffer for raw data */
/* call mailbox */
return (ret);
}
/* translate unpadded to padded fru_info_t */
PR_SEGMENT("sgfru:%s: handle %lx, actual cnt %d\n",
/* copyout actual fru_cnt */
return (EFAULT);
}
/* copyout raw segment data */
return (EFAULT);
}
/* free buffer */
return (ret);
}
/*
* Used for fru_write_segment().
*/
static int
{
static fn_t f = "sgfru_writesegment";
/* copyin frup_info_t */
return (EFAULT);
}
/* check on kmem_alloc space requirements */
return (EINVAL);
}
PR_SEGMENT("sgfru:%s: handle %lx, max cnt %d\n",
/* allocate unpadded buffer for fru_info_t + raw data */
/* translate padded to unpadded fru_info_t */
/* copyin raw segment data */
return (EFAULT);
}
/* call mailbox */
return (ret);
}
/* free buffer */
PR_SEGMENT("sgfru:%s: handle %lx, actual cnt %d\n",
/* copyout updated segment handle and actual fru_cnt */
return (EFAULT);
}
return (ret);
}
/*
* Used for fru_get_packets().
*/
static int
{
/* copyin packets_t aka frup_info_t */
return (EFAULT);
}
/* check on kmem_alloc space requirements */
return (EINVAL);
}
/* allocate buffer for unpadded fru_info_t + packet_t's */
/* call mailbox */
!= 0) {
return (ret);
}
/* allocate buffer for padded packet_t's */
/* translate unpadded to padded fru_info_t + packet_t's */
!= 0) {
return (ret);
}
/* free packet_t buffer */
/* copy out fru_info_t */
return (EFAULT);
}
/* copyout packet_t's */
return (EFAULT);
}
/* free packet_t buffer */
return (ret);
}
/*
* Used for fru_append_packet().
*/
static int
{
/* copyin append_info_t */
return (EFAULT);
}
/* check on kmem_alloc space requirements */
return (EINVAL);
}
/* allocate buffer for unpadded fru_info_t + packet_t + payload */
/* translate padded to unpadded fru_info_t plus packet_t */
datap);
/* copyin payload to the end of the unpadded buffer */
tdatap) != 0) {
return (EFAULT);
}
/* call mailbox */
return (ret);
}
/* copyout new packet_hdl_t */
return (EFAULT);
}
/* copyout updated segment_hdl_t */
return (EFAULT);
}
/* free buffer */
return (ret);
}
/*
* Used for fru_get_payload().
*/
static int
{
static fn_t f = "sgfru_getpayload";
/* copyin payload_t aka frup_info_t */
return (EFAULT);
}
PR_PAYLOAD("sgfru:%s: handle %lx, max cnt %d\n",
/* check on kmem_alloc space requirements */
return (EINVAL);
}
/* allocate buffer for fru_info_t + payload */
/* call mailbox */
!= 0) {
return (ret);
}
/* translate unpadded to padded fru_info_t */
PR_PAYLOAD("sgfru:%s: handle %lx, max cnt %d\n",
/* copyout actual fru_cnt */
return (EFAULT);
}
/* copyout raw packet data, aka the payload */
return (EFAULT);
}
/* free buffer */
return (ret);
}
/*
* Used for fru_update_payload().
*/
static int
{
static fn_t f = "sgfru_updatepayload";
/* copyin frup_info_t */
return (EFAULT);
}
/* check on kmem_alloc space requirements */
return (EINVAL);
}
/* allocate buffer for fru_info_t + payload */
/* translate padded to unpadded fru_info_t */
/* copyin payload */
return (EFAULT);
}
PR_PAYLOAD("sgfru_updatepayload: handle %lx, actual cnt %d\n",
/* call mailbox */
!= 0) {
return (ret);
}
/* free buffer */
/* copyout new packet_hdl_t and actual count */
return (EFAULT);
}
PR_PAYLOAD("sgfru:%s: new handle %lx, cnt %d\n",
return (ret);
}
/*
* Used for fru_get_num_[sections|segments|packets]().
*/
static int
{
/* copyin fru_info_t */
return (EFAULT);
}
return (ret);
}
/* copyout fru_info_t */
return (EFAULT);
}
return (ret);
}
/*
* Used for fru_delete_[segment|packet].
*/
static int
{
static fn_t f = "sgfru_delete";
/* copyin fru_info_t */
return (EFAULT);
}
return (ret);
}
/* copyout fru_info_t */
return (EFAULT);
}
return (ret);
}
/*
* Calls the sgsbbc mailbox with data, returns data and status info.
*/
static int
{
int rv = 0;
static fn_t f = "sgfru_mbox";
switch (cmd) {
case SGFRU_GETCHILDLIST:
break;
case SGFRU_GETCHILDHANDLES:
break;
case SGFRU_GETNODEINFO:
break;
case SGFRU_GETNUMSECTIONS:
break;
case SGFRU_GETNUMSEGMENTS:
break;
case SGFRU_GETNUMPACKETS:
break;
case SGFRU_GETSECTIONS:
break;
case SGFRU_GETSEGMENTS:
break;
case SGFRU_GETPACKETS:
break;
case SGFRU_ADDSEGMENT:
break;
case SGFRU_APPENDPACKET:
break;
case SGFRU_DELETESEGMENT:
break;
case SGFRU_READRAWSEGMENT:
break;
case SGFRU_WRITERAWSEGMENT:
break;
case SGFRU_DELETEPACKET:
break;
case SGFRU_GETPAYLOAD:
break;
case SGFRU_UPDATEPAYLOAD:
break;
default:
return (EINVAL);
}
/* errors from sgsbbc */
if (resp->msg_status > 0) {
return (resp->msg_status);
}
/* errors from SCAPP */
switch (resp->msg_status) {
/* internal SCAPP error */
return (EINTR);
return (EIO);
/* illegal ioctl parameter */
return (EINVAL);
/* board access denied */
return (EACCES);
/* stale contents */
return (ESTALE);
/* stale handle */
return (ENOENT);
/* seprom lacks space */
return (ENOSPC);
case SG_MBOX_STATUS_NO_MEMORY:
/* user prog. lacks space */
return (ENOMEM);
/* unsupported operation */
return (ENOTSUP);
default:
return (EIO);
}
}
switch (cmd) {
/*
* These two calls get back two handles, a new handle for the
* added segment or packet, and an updated parent handle.
*/
case SGFRU_ADDSEGMENT:
case SGFRU_APPENDPACKET:
break;
/* These two calls get an updated parent handle. */
case SGFRU_DELETESEGMENT:
case SGFRU_DELETEPACKET:
break;
default:
break;
}
return (0);
}
/*
* Used to copy in one frup_info_t from user.
*/
static int
{
static fn_t f = "sgfru_copyin_frup";
#ifdef _MULTI_DATAMODEL
"frup32_t struct", f);
return (EFAULT);
}
PR_STATE("sgfru:%s: frus %p %x hdl %lx cnt %d\n",
} else
#endif /* _MULTI_DATAMODEL */
"sgfru:%s: failed to copyin frup_info_t struct", f);
return (EFAULT);
}
return (0);
}
/*
* Used to copy in one fru_info_t from user.
*/
static int
{
static fn_t f = "sgfru_copyin_fru";
"sgfru:%s: failed to copyin fru_info_t struct", f);
return (EFAULT);
}
return (0);
}
/*
* Used to copy in segment_t from user.
*/
static int
{
static fn_t f = "sgfru_copyin_segment";
"sgfru:%s: failed to copyin segment_t struct", f);
return (EFAULT);
}
return (0);
}
/*
* Used to copy in segment handle, packet and payload data from user.
*/
static int
{
static fn_t f = "sgfru_copyin_append";
#ifdef _MULTI_DATAMODEL
"append32_info_t struct", f);
return (EFAULT);
}
PR_PAYLOAD("sgfru:%s:: data %p hdl %lx cnt %d\n",
} else
#endif /* _MULTI_DATAMODEL */
"sgfru:%s: failed to copyin append_info_t struct", f);
return (EFAULT);
}
PR_PAYLOAD("sgfru:%s: hdl %lx, cnt %d pkt hdl %lx "
return (0);
}
/*
* Used to copy in raw segment and payload data from user.
*/
static int
{
static fn_t f = "sgfru_copyin_buffer";
!= DDI_SUCCESS) {
return (EFAULT);
}
return (0);
}
/*
* Used to copy out one fru_info_t to user.
*/
static int
{
static fn_t f = "sgfru_copyout_fru";
return (EFAULT);
}
return (0);
}
/*
* Used to copy out one fru_hdl_t to user.
*/
static int
{
static fn_t f = "sgfru_copyout_handle";
return (EFAULT);
}
return (0);
}
/*
* Used to copy out an array of fru_hdl_t's to user.
*/
static int
{
static fn_t f = "sgfru_copyout_handles";
/* copyout fru_hdl_t's */
!= DDI_SUCCESS) {
return (EFAULT);
}
return (0);
}
/*
* Used to copy out one or more node_t's to user.
*/
static int
{
static fn_t f = "sgfru_copyout_nodes";
/* copyout node_t's */
!= DDI_SUCCESS) {
return (EFAULT);
}
return (0);
}
/*
* Used to copy out section_t's to user.
*/
static int
{
static fn_t f = "sgfru_copyout_sections";
/* copyout section_t's */
!= DDI_SUCCESS) {
return (EFAULT);
}
return (0);
}
/*
* Used to copy out segment_t's to user.
*/
static int
{
static fn_t f = "sgfru_copyout_segments";
/* copyout segment_t's */
!= DDI_SUCCESS) {
return (EFAULT);
}
return (0);
}
/*
* Used to copy out packet_t's to user.
*/
static int
{
static fn_t f = "sgfru_copyout_packets";
/* copyout packet_t's */
!= DDI_SUCCESS) {
return (EFAULT);
}
return (0);
}
/*
* Used to copy out raw segment and payload data to user.
*/
static int
const char *buffer)
{
static fn_t f = "sgfru_copyout_buffer";
/* copyout packet_t */
!= DDI_SUCCESS) {
return (EFAULT);
}
return (0);
}
/*
* Used to pad a Java (SCAPP) fru_info_t, in preparation for sending it to
* C (Solaris). Assumes one fru_info_t.
*/
static caddr_t
{
tdatap += FRU_HDL_SIZE;
tdatap += FRU_CNT_SIZE;
return (tdatap);
}
/*
* Used to pad a Java (SCAPP) node_t, in preparation for sending it to
* C (Solaris). Assumes a fru_info_t and one or more node_t's.
*/
static int
{
int i, cnt = 1;
return (ENOMEM);
} else {
}
}
tdatap += FRU_HDL_SIZE;
tdatap += NODENAME_SIZE;
tdatap += CLASS_SIZE;
tdatap += LABEL_SIZE;
}
}
return (0);
}
/*
* Used to pad a Java (SCAPP) section, in preparation for sending it to
* C (Solaris). Assumes a fru_info_t and multiple section_t's.
*/
static int
{
int i;
return (ENOMEM);
tdatap += FRU_HDL_SIZE;
tdatap += OFFSET_SIZE;
tdatap += LENGTH_SIZE;
tdatap += PROTECTED_SIZE;
tdatap += VERSION_SIZE;
}
return (0);
}
/*
* Used to pad a Java (SCAPP) segment, in preparation for sending it to
* C (Solaris). Assumes a fru_info_t and multiple segment_t's.
*/
static int
{
int i;
return (ENOMEM);
tdatap += FRU_HDL_SIZE;
tdatap += OFFSET_SIZE;
tdatap += LENGTH_SIZE;
}
return (0);
}
/*
* Used to pad a Java (SCAPP) packet, in preparation for sending it to
* C (Solaris). Assumes a fru_info_t and multiple packet_t's.
*/
static int
{
int i;
return (ENOMEM);
tdatap += FRU_HDL_SIZE;
}
return (0);
}
/*
* Used to unpad a C (Solaris) fru_info_t, in preparation for sending it to
* Java (SCAPP). Assumes a fru_info_t.
*/
static caddr_t
{
tdatap += FRU_HDL_SIZE;
tdatap += FRU_CNT_SIZE;
return (tdatap);
}
/*
* Used to unpad a C (Solaris) segment, in preparation for sending it to
* Java (SCAPP). Assumes a section_hdl_t and one segment_t.
*/
static void
{
tdatap += FRU_HDL_SIZE;
tdatap += FRU_HDL_SIZE;
tdatap += OFFSET_SIZE;
}
/*
* Used to unpad a C (Solaris) packet, in preparation for sending it to
* Java (SCAPP). Assumes a fru_info_t and one packet_t.
*/
static caddr_t
{
tdatap += FRU_HDL_SIZE;
tdatap += FRU_CNT_SIZE;
tdatap += FRU_HDL_SIZE;
return (tdatap);
}