diff options
author | jm22469 <none@none> | 2008-04-14 17:18:38 -0700 |
---|---|---|
committer | jm22469 <none@none> | 2008-04-14 17:18:38 -0700 |
commit | 8fea755a86ff6c596183a4366bfbd59f1bfdfe55 (patch) | |
tree | 049064eb07b4e9b2cdef308bb0d09dc028b2c23c /usr/src | |
parent | 142c9f13e148d687426ed2d4e8bd93717eeaebbc (diff) | |
download | illumos-joyent-8fea755a86ff6c596183a4366bfbd59f1bfdfe55.tar.gz |
6651197 Add support for LDoms Virtual I/O Dynamic Reconfiguration (VIO DR)
FWARC 2008/229 Virtual IO DR Domain Service
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/cmd/drd/drd.c | 14 | ||||
-rw-r--r-- | usr/src/cmd/drd/drd.h | 6 | ||||
-rw-r--r-- | usr/src/cmd/drd/drd_rcm.c | 216 | ||||
-rw-r--r-- | usr/src/pkgdefs/SUNWldomr.v/prototype_sparc | 3 | ||||
-rw-r--r-- | usr/src/uts/sun4v/Makefile.files | 1 | ||||
-rw-r--r-- | usr/src/uts/sun4v/Makefile.sun4v.shared | 1 | ||||
-rw-r--r-- | usr/src/uts/sun4v/dr_io/Makefile | 93 | ||||
-rw-r--r-- | usr/src/uts/sun4v/io/dr_io.c | 872 | ||||
-rw-r--r-- | usr/src/uts/sun4v/io/drctl.c | 50 | ||||
-rw-r--r-- | usr/src/uts/sun4v/os/mach_startup.c | 3 | ||||
-rw-r--r-- | usr/src/uts/sun4v/sys/dr_io.h | 90 | ||||
-rw-r--r-- | usr/src/uts/sun4v/sys/dr_util.h | 6 |
12 files changed, 1325 insertions, 30 deletions
diff --git a/usr/src/cmd/drd/drd.c b/usr/src/cmd/drd/drd.c index a0c61c988e..a6e33f9237 100644 --- a/usr/src/cmd/drd/drd.c +++ b/usr/src/cmd/drd/drd.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -392,11 +392,19 @@ drd_door_server(void *cookie, char *argp, size_t arg_sz, door_desc_t *dp, break; case DRCTL_IO_CONFIG_REQUEST: + (*drd_backend->io_config_request)(rsrcs, nrsrc); + break; + case DRCTL_IO_CONFIG_NOTIFY: + (*drd_backend->io_config_notify)(rsrcs, nrsrc); + break; + case DRCTL_IO_UNCONFIG_REQUEST: + (*drd_backend->io_unconfig_request)(rsrcs, nrsrc); + break; + case DRCTL_IO_UNCONFIG_NOTIFY: - drd_err("I/O DR operations not supported yet"); - DRD_DOOR_RETURN_ERR(); + (*drd_backend->io_unconfig_notify)(rsrcs, nrsrc); break; default: diff --git a/usr/src/cmd/drd/drd.h b/usr/src/cmd/drd/drd.h index 2743efd25b..bf8efe3b07 100644 --- a/usr/src/cmd/drd/drd.h +++ b/usr/src/cmd/drd/drd.h @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -61,6 +61,10 @@ typedef struct { int (*cpu_config_notify)(drctl_rsrc_t *rsrcs, int nrsrc); int (*cpu_unconfig_request)(drctl_rsrc_t *rsrcs, int nrsrc); int (*cpu_unconfig_notify)(drctl_rsrc_t *rsrcs, int nrsrc); + int (*io_config_request)(drctl_rsrc_t *rsrc, int nrsrc); + int (*io_config_notify)(drctl_rsrc_t *rsrc, int nrsrc); + int (*io_unconfig_request)(drctl_rsrc_t *rsrc, int nrsrc); + int (*io_unconfig_notify)(drctl_rsrc_t *rsrc, int nrsrc); } drd_backend_t; extern drd_backend_t drd_rcm_backend; diff --git a/usr/src/cmd/drd/drd_rcm.c b/usr/src/cmd/drd/drd_rcm.c index 5f16ef1c7b..cdee9840e7 100644 --- a/usr/src/cmd/drd/drd_rcm.c +++ b/usr/src/cmd/drd/drd_rcm.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -36,6 +36,7 @@ #include <kstat.h> #include <libnvpair.h> #include <librcm.h> +#include <locale.h> #include "drd.h" @@ -48,6 +49,10 @@ static int drd_rcm_cpu_config_request(drctl_rsrc_t *rsrcs, int nrsrc); static int drd_rcm_cpu_config_notify(drctl_rsrc_t *rsrcs, int nrsrc); static int drd_rcm_cpu_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc); static int drd_rcm_cpu_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc); +static int drd_rcm_io_config_request(drctl_rsrc_t *rsrc, int nrsrc); +static int drd_rcm_io_config_notify(drctl_rsrc_t *rsrc, int nrsrc); +static int drd_rcm_io_unconfig_request(drctl_rsrc_t *rsrc, int nrsrc); +static int drd_rcm_io_unconfig_notify(drctl_rsrc_t *rsrc, int nrsrc); drd_backend_t drd_rcm_backend = { drd_rcm_init, /* init */ @@ -55,7 +60,11 @@ drd_backend_t drd_rcm_backend = { drd_rcm_cpu_config_request, /* cpu_config_request */ drd_rcm_cpu_config_notify, /* cpu_config_notify */ drd_rcm_cpu_unconfig_request, /* cpu_unconfig_request */ - drd_rcm_cpu_unconfig_notify /* cpu_unconfig_notify */ + drd_rcm_cpu_unconfig_notify, /* cpu_unconfig_notify */ + drd_rcm_io_config_request, /* io_config_request */ + drd_rcm_io_config_notify, /* io_config_notify */ + drd_rcm_io_unconfig_request, /* io_unconfig_request */ + drd_rcm_io_unconfig_notify /* io_unconfig_notify */ }; #define RCM_CPU_ALL "SUNW_cpu" @@ -80,6 +89,7 @@ static void drd_rcm_cpu_rlist_fini(char **rlist); static drctl_rsrc_t *cpu_rsrcstr_to_rsrc(const char *, drctl_rsrc_t *, int); static int get_sys_cpuids(cpuid_t **cpuids, int *ncpuids); static boolean_t is_cpu_in_list(cpuid_t cpuid, cpuid_t *list, int len); +static char *rcm_info_table(rcm_info_t *rinfo); /* debugging utility functions */ static void dump_cpu_list(char *prefix, cpuid_t *cpuids, int ncpuids); @@ -123,7 +133,7 @@ drd_rcm_cpu_config_request(drctl_rsrc_t *rsrcs, int nrsrc) /* * There is no RCM operation to request the addition - * of resources. So, by definition, the operation for + * of resources. So, by definition, the operation for * all the CPUs is allowed. */ for (idx = 0; idx < nrsrc; idx++) @@ -988,3 +998,203 @@ dump_cpu_rlist(char **rlist) rlist[idx], state, rcm_state_str[state]); } } + +static int +drd_rcm_io_config_request(drctl_rsrc_t *rsrc, int nrsrc) +{ + drd_dbg("drd_rcm_io_config_request..."); + + if (nrsrc != 1) { + drd_dbg("drd_rcm_cpu_config_request: only 1 resource " + "allowed for I/O requests, passed %d resources\n", nrsrc); + rsrc->status = DRCTL_STATUS_DENY; + + return (-1); + } + + /* + * There is no RCM operation to request the addition + * of resources. So, by definition, the operation for + * the current resource is allowed. + */ + rsrc->status = DRCTL_STATUS_ALLOW; + + return (0); +} + +/*ARGSUSED*/ +static int +drd_rcm_io_config_notify(drctl_rsrc_t *rsrcs, int nrsrc) +{ + drd_dbg("drd_rcm_io_config_notify..."); + + if (nrsrc != 1) { + drd_dbg("drd_rcm_cpu_config_notify: only 1 resource " + "allowed for I/O requests, passed %d resources\n", nrsrc); + + return (-1); + } + + return (0); +} + + +static int +drd_rcm_io_unconfig_request(drctl_rsrc_t *rsrc, int nrsrc) +{ + int rv; + char *dev = rsrc->res_dev_path; + rcm_info_t *rinfo = NULL; + + if (nrsrc != 1) { + drd_dbg("drd_io_unconfig_request: only 1 resource " + "allowed for I/O requests, passed %d resources\n", nrsrc); + rsrc->status = DRCTL_STATUS_DENY; + + return (-1); + } + + if ((rv = rcm_request_offline(rcm_hdl, dev, 0, &rinfo)) == RCM_SUCCESS) + rsrc->status = DRCTL_STATUS_ALLOW; + else { + rcm_notify_online(rcm_hdl, dev, 0, NULL); + rsrc->status = DRCTL_STATUS_DENY; + rsrc->offset = (uintptr_t)rcm_info_table(rinfo); + + } + + rcm_free_info(rinfo); + drd_dbg("drd_rcm_io_unconfig_request(%s) = %d", dev, rv); + + return (rv); +} + +static int +drd_rcm_io_unconfig_notify(drctl_rsrc_t *rsrc, int nrsrc) +{ + drd_dbg("drd_rcm_io_unconfig_notify..."); + + if (nrsrc != 1) { + drd_dbg("drd_io_cpu_unconfig_notify: only 1 resource " + "allowed for I/O requests, passed %d resources\n", nrsrc); + + return (-1); + } + + return (rcm_notify_remove(rcm_hdl, rsrc->res_dev_path, 0, NULL)); +} + +#define MAX_FORMAT 80 + +/* + * Convert rcm_info_t data into a printable table. + */ +static char * +rcm_info_table(rcm_info_t *rinfo) +{ + int i; + size_t w; + size_t width = 0; + size_t w_rsrc = 0; + size_t w_info = 0; + size_t table_size = 0; + uint_t tuples = 0; + rcm_info_tuple_t *tuple = NULL; + char *rsrc; + char *info; + char *table; + static char format[MAX_FORMAT]; + const char *infostr; + + /* Protect against invalid arguments */ + if (rinfo == NULL) + return (NULL); + + /* Set localized table header strings */ + rsrc = dgettext(TEXT_DOMAIN, "Resource"); + info = dgettext(TEXT_DOMAIN, "Information"); + + /* A first pass, to size up the RCM information */ + while (tuple = rcm_info_next(rinfo, tuple)) { + if ((infostr = rcm_info_info(tuple)) != NULL) { + tuples++; + if ((w = strlen(rcm_info_rsrc(tuple))) > w_rsrc) + w_rsrc = w; + if ((w = strlen(infostr)) > w_info) + w_info = w; + } + } + + /* If nothing was sized up above, stop early */ + if (tuples == 0) + return (NULL); + + /* Adjust column widths for column headings */ + if ((w = strlen(rsrc)) > w_rsrc) + w_rsrc = w; + else if ((w_rsrc - w) % 2) + w_rsrc++; + if ((w = strlen(info)) > w_info) + w_info = w; + else if ((w_info - w) % 2) + w_info++; + + /* + * Compute the total line width of each line, + * accounting for intercolumn spacing. + */ + width = w_info + w_rsrc + 4; + + /* Allocate space for the table */ + table_size = (2 + tuples) * (width + 1) + 2; + + /* zero fill for the strcat() call below */ + table = calloc(table_size, sizeof (char)); + if (table == NULL) + return (NULL); + + /* Place a table header into the string */ + + /* The resource header */ + (void) strcat(table, "\n"); + w = strlen(rsrc); + for (i = 0; i < ((w_rsrc - w) / 2); i++) + (void) strcat(table, " "); + (void) strcat(table, rsrc); + for (i = 0; i < ((w_rsrc - w) / 2); i++) + (void) strcat(table, " "); + + /* The information header */ + (void) strcat(table, " "); + w = strlen(info); + for (i = 0; i < ((w_info - w) / 2); i++) + (void) strcat(table, " "); + (void) strcat(table, info); + for (i = 0; i < ((w_info - w) / 2); i++) + (void) strcat(table, " "); + /* Underline the headers */ + (void) strcat(table, "\n"); + for (i = 0; i < w_rsrc; i++) + (void) strcat(table, "-"); + (void) strcat(table, " "); + for (i = 0; i < w_info; i++) + (void) strcat(table, "-"); + + /* Construct the format string */ + (void) snprintf(format, MAX_FORMAT, "%%-%ds %%-%ds", + (int)w_rsrc, (int)w_info); + + /* Add the tuples to the table string */ + tuple = NULL; + while ((tuple = rcm_info_next(rinfo, tuple)) != NULL) { + if ((infostr = rcm_info_info(tuple)) != NULL) { + (void) strcat(table, "\n"); + (void) sprintf(&((table)[strlen(table)]), + format, rcm_info_rsrc(tuple), + infostr); + } + } + drd_dbg("rcm_info_table: %s\n", table); + + return (table); +} diff --git a/usr/src/pkgdefs/SUNWldomr.v/prototype_sparc b/usr/src/pkgdefs/SUNWldomr.v/prototype_sparc index 6e7aac0b63..825734cc4a 100644 --- a/usr/src/pkgdefs/SUNWldomr.v/prototype_sparc +++ b/usr/src/pkgdefs/SUNWldomr.v/prototype_sparc @@ -20,7 +20,7 @@ # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -74,6 +74,7 @@ f none platform/sun4v/kernel/drv/sparcv9/vsw 755 root sys d none platform/sun4v/kernel/misc 755 root sys d none platform/sun4v/kernel/misc/sparcv9 755 root sys f none platform/sun4v/kernel/misc/sparcv9/dr_cpu 755 root sys +f none platform/sun4v/kernel/misc/sparcv9/dr_io 755 root sys f none platform/sun4v/kernel/misc/sparcv9/ds 755 root sys f none platform/sun4v/kernel/misc/sparcv9/fault_iso 755 root sys f none platform/sun4v/kernel/misc/sparcv9/ldc 755 root sys diff --git a/usr/src/uts/sun4v/Makefile.files b/usr/src/uts/sun4v/Makefile.files index 2d6bbad4a3..135e3110c0 100644 --- a/usr/src/uts/sun4v/Makefile.files +++ b/usr/src/uts/sun4v/Makefile.files @@ -164,6 +164,7 @@ DS_SNMP_OBJS = ds_snmp.o # BOOTDEV_OBJS += bootdev.o DR_CPU_OBJS += dr_cpu.o +DR_IO_OBJS += dr_io.o DRCTL_OBJS = drctl.o drctl_impl.o dr_util.o DS_OBJS = ds.o FAULT_ISO_OBJS = fault_iso.o diff --git a/usr/src/uts/sun4v/Makefile.sun4v.shared b/usr/src/uts/sun4v/Makefile.sun4v.shared index 1df7f3ca83..b5b86bca12 100644 --- a/usr/src/uts/sun4v/Makefile.sun4v.shared +++ b/usr/src/uts/sun4v/Makefile.sun4v.shared @@ -390,6 +390,7 @@ SYS_KMODS += # MISC_KMODS += bootdev MISC_KMODS += dr_cpu +MISC_KMODS += dr_io MISC_KMODS += ds MISC_KMODS += fault_iso MISC_KMODS += ldc diff --git a/usr/src/uts/sun4v/dr_io/Makefile b/usr/src/uts/sun4v/dr_io/Makefile new file mode 100644 index 0000000000..37ecb9fc06 --- /dev/null +++ b/usr/src/uts/sun4v/dr_io/Makefile @@ -0,0 +1,93 @@ +# +# 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 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = dr_io +OBJECTS = $(DR_IO_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(DR_IO_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_PSM_MISC_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/sun4v/Makefile.sun4v + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +# +# lint pass one enforcement +# +CFLAGS += $(CCVERBOSE) + +# +# Turn on doubleword alignment for 64 bit registers +# +CFLAGS += -dalign + +# +# Module Dependencies +# +LDFLAGS += -dy -Nmisc/ds -Ndrv/drctl + +# +# 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)/$(PLATFORM)/Makefile.targ diff --git a/usr/src/uts/sun4v/io/dr_io.c b/usr/src/uts/sun4v/io/dr_io.c new file mode 100644 index 0000000000..64cd9a46b7 --- /dev/null +++ b/usr/src/uts/sun4v/io/dr_io.c @@ -0,0 +1,872 @@ +/* + * 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 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * sun4v VIO DR Module + */ + +#include <sys/modctl.h> +#include <sys/sunddi.h> +#include <sys/sunndi.h> +#include <sys/note.h> +#include <sys/sysevent/dr.h> +#include <sys/hypervisor_api.h> +#include <sys/mach_descrip.h> +#include <sys/mdesc.h> +#include <sys/mdesc_impl.h> +#include <sys/ds.h> +#include <sys/drctl.h> +#include <sys/dr_util.h> +#include <sys/dr_io.h> +#include <sys/promif.h> +#include <sys/machsystm.h> +#include <sys/ethernet.h> +#include <sys/hotplug/pci/pcicfg.h> + + +static struct modlmisc modlmisc = { + &mod_miscops, + "sun4v VIO DR %I%" +}; + +static struct modlinkage modlinkage = { + MODREV_1, + (void *)&modlmisc, + NULL +}; + + +/* + * VIO DS Interface + */ + +/* + * Global DS Handle + */ +static ds_svc_hdl_t ds_vio_handle; + +/* + * Supported DS Capability Versions + */ +static ds_ver_t dr_vio_vers[] = { { 1, 0 } }; +#define DR_VIO_NVERS (sizeof (dr_vio_vers) / sizeof (dr_vio_vers[0])) + +/* + * DS Capability Description + */ +static ds_capability_t dr_vio_cap = { + DR_VIO_DS_ID, /* svc_id */ + dr_vio_vers, /* vers */ + DR_VIO_NVERS /* nvers */ +}; + +/* + * DS Callbacks + */ +static void dr_vio_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t); +static void dr_vio_unreg_handler(ds_cb_arg_t arg); +static void dr_vio_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen); + +/* + * DS Client Ops Vector + */ +static ds_clnt_ops_t dr_vio_ops = { + dr_vio_reg_handler, /* ds_reg_cb */ + dr_vio_unreg_handler, /* ds_unreg_cb */ + dr_vio_data_handler, /* ds_data_cb */ + NULL /* cb_arg */ +}; + + +typedef struct { + char *name; + uint64_t devid; + dev_info_t *dip; +} dr_search_arg_t; + +static int +dr_io_check_node(dev_info_t *dip, void *arg) +{ + char *name; + uint64_t devid; + dr_search_arg_t *sarg = (dr_search_arg_t *)arg; + + name = ddi_node_name(dip); + + if (strcmp(name, sarg->name) != 0) + return (DDI_WALK_CONTINUE); + + devid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, + "reg", -1); + + DR_DBG_IO("%s: found devid=%ld, looking for %ld\n", + __func__, devid, sarg->devid); + + if (devid == sarg->devid) { + DR_DBG_IO("%s: matched", __func__); + + /* matching node must be returned held */ + if (!e_ddi_branch_held(dip)) + e_ddi_branch_hold(dip); + + sarg->dip = dip; + return (DDI_WALK_TERMINATE); + } + + return (DDI_WALK_CONTINUE); +} + +/* + * Walk the device tree to find the dip corresponding to the devid + * passed in. If present, the dip is returned held. The caller must + * release the hold on the dip once it is no longer required. If no + * matching node if found, NULL is returned. + */ +static dev_info_t * +dr_io_find_node(char *name, uint64_t devid) +{ + dr_search_arg_t arg; + + DR_DBG_IO("dr_io_find_node...\n"); + + arg.name = name; + arg.devid = devid; + arg.dip = NULL; + + ddi_walk_devs(ddi_root_node(), dr_io_check_node, &arg); + + ASSERT((arg.dip == NULL) || (e_ddi_branch_held(arg.dip))); + + return ((arg.dip) ? arg.dip : NULL); +} + +/* + * Look up a particular IO node in the MD. Returns the mde_cookie_t + * representing that IO node if present, and MDE_INVAL_ELEM_COOKIE otherwise. + * It is assumed the scratch array has already been allocated so that + * it can accommodate the worst case scenario, every node in the MD. + */ +static mde_cookie_t +dr_io_find_node_md(md_t *mdp, char *name, uint64_t id, mde_cookie_t *listp) +{ + int i; + int nnodes; + char *devnm; + uint64_t devid; + mde_cookie_t rootnode; + mde_cookie_t result = MDE_INVAL_ELEM_COOKIE; + + DR_DBG_IO("%s: %s@%ld\n", __func__, name, id); + + rootnode = md_root_node(mdp); + ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE); + + /* + * Scan the DAG for all candidate nodes. + */ + nnodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "virtual-device"), + md_find_name(mdp, "fwd"), listp); + + if (nnodes < 0) { + DR_DBG_IO("%s: scan for " + "'virtual-device' nodes failed\n", __func__); + return (result); + } + + DR_DBG_IO("%s: found %d nodes in the MD\n", __func__, nnodes); + + /* + * Find the node of interest + */ + for (i = 0; i < nnodes; i++) { + + if (md_get_prop_str(mdp, listp[i], "name", &devnm)) { + DR_DBG_IO("%s: missing 'name' property for" + " IO node %d\n", __func__, i); + return (DDI_WALK_ERROR); + } + + if (strcmp(devnm, name) != 0) + continue; + + if (md_get_prop_val(mdp, listp[i], "cfg-handle", &devid)) { + DR_DBG_IO("%s: missing 'cfg-handle' property for" + " IO node %d\n", __func__, i); + break; + } + + if (devid == id) { + /* found a match */ + DR_DBG_IO("%s: found IO node %s@%ld " + "in MD\n", __func__, name, id); + result = listp[i]; + break; + } + } + + if (result == MDE_INVAL_ELEM_COOKIE) + DR_DBG_IO("%s: IO node %ld not in MD\n", __func__, id); + + return (result); +} + +typedef struct { + md_t *mdp; + mde_cookie_t node; + dev_info_t *dip; +} cb_arg_t; + +#define STR_ARR_LEN 5 + +static int +new_dev_node(dev_info_t *new_node, void *arg, uint_t flags) +{ + _NOTE(ARGUNUSED(flags)) + + cb_arg_t *cba; + char *devnm, *devtype; + char *compat; + uint64_t devid; + int len = 0; + char *curr; + int i = 0; + char *str_arr[STR_ARR_LEN]; + + cba = (cb_arg_t *)arg; + + /* + * Add 'name' property + */ + if (md_get_prop_str(cba->mdp, cba->node, "name", &devnm)) { + DR_DBG_IO("%s: failed to read 'name' prop from MD\n", __func__); + return (DDI_WALK_ERROR); + } + DR_DBG_IO("%s: device name is %s\n", __func__, devnm); + + if (ndi_prop_update_string(DDI_DEV_T_NONE, new_node, + "name", devnm) != DDI_SUCCESS) { + DR_DBG_IO("%s: failed to create 'name' prop\n", __func__); + return (DDI_WALK_ERROR); + } + + /* + * Add 'compatible' property + */ + if (md_get_prop_data(cba->mdp, cba->node, "compatible", + (uint8_t **)&compat, &len)) { + DR_DBG_IO("%s: failed to read " + "'compatible' prop from MD\n", __func__); + return (DDI_WALK_ERROR); + } + + /* parse the MD string array */ + curr = compat; + while (curr < (compat + len)) { + + DR_DBG_IO("%s: adding '%s' to " + "'compatible' prop\n", __func__, curr); + + str_arr[i++] = curr; + curr += strlen(curr) + 1; + + if (i == STR_ARR_LEN) { + DR_DBG_CPU("exceeded str_arr len (%d)\n", STR_ARR_LEN); + break; + } + } + + + if (ndi_prop_update_string_array(DDI_DEV_T_NONE, new_node, + "compatible", str_arr, i) != DDI_SUCCESS) { + DR_DBG_IO("%s: cannot create 'compatible' prop\n", __func__); + return (DDI_WALK_ERROR); + } + + /* + * Add 'device_type' property + */ + if (md_get_prop_str(cba->mdp, cba->node, "device-type", &devtype)) { + DR_DBG_IO("%s: failed to read " + "'device-type' prop from MD\n", __func__); + return (DDI_WALK_ERROR); + } + if (ndi_prop_update_string(DDI_DEV_T_NONE, new_node, + "device_type", devtype) != DDI_SUCCESS) { + DR_DBG_IO("%s: failed to create " + "'device-type' prop\n", __func__); + return (DDI_WALK_ERROR); + } + + DR_DBG_IO("%s: device type is %s\n", __func__, devtype); + + /* + * Add 'reg' (cfg-handle) property + */ + if (md_get_prop_val(cba->mdp, cba->node, "cfg-handle", &devid)) { + DR_DBG_IO("%s: failed to read " + "'cfg-handle' prop from MD\n", __func__); + return (DDI_WALK_ERROR); + } + + DR_DBG_IO("%s: new device is %s@%ld\n", __func__, devnm, devid); + + if (ndi_prop_update_int(DDI_DEV_T_NONE, new_node, "reg", devid) + != DDI_SUCCESS) { + DR_DBG_IO("%s: failed to create 'reg' prop\n", __func__); + return (DDI_WALK_ERROR); + } + + /* if vnet/vswitch, probe and add mac-address and mtu properties */ + if (strcmp(devnm, "vsw") == 0 || strcmp(devnm, "network") == 0) { + + int i, j; + uint64_t mtu, macaddr; + uchar_t maddr_arr[ETHERADDRL]; + + if (md_get_prop_val(cba->mdp, cba->node, "local-mac-address", + &macaddr)) { + DR_DBG_IO("%s: failed to read " + "'local-mac-address' prop from MD\n", __func__); + return (DDI_WALK_ERROR); + } + + for (i = 0, j = (ETHERADDRL - 1); i < ETHERADDRL; i++, j--) + maddr_arr[j] = (macaddr >> (i * 8)) & 0xff; + + if (ndi_prop_update_byte_array(DDI_DEV_T_NONE, new_node, + "local-mac-address", maddr_arr, ETHERADDRL) + != DDI_SUCCESS) { + DR_DBG_IO("%s: failed to create " + "'local-mac-address' prop\n", __func__); + return (DDI_WALK_ERROR); + } + + if (md_get_prop_val(cba->mdp, cba->node, "mtu", &mtu)) { + DR_DBG_IO("%s: failed to read " + "'mtu' prop from MD\n", __func__); + return (DDI_WALK_ERROR); + } + + if (ndi_prop_update_int64(DDI_DEV_T_NONE, new_node, "mtu", + mtu) != DDI_SUCCESS) { + DR_DBG_IO("%s: failed to " + "create 'mtu' prop\n", __func__); + return (DDI_WALK_ERROR); + } + + DR_DBG_IO("%s: Added properties for %s@%ld, " + "mac=%ld, mtu=%ld\n", __func__, devnm, devid, macaddr, mtu); + } + + cba->dip = new_node; + + return (DDI_WALK_TERMINATE); +} + +/* + * Find the parent node of the argument virtual device node in + * the MD. For virtual devices, the parent is always + * "channel-devices", so scan the MD using the "back" arcs + * looking for a node with that name. + */ +static mde_cookie_t +dr_vio_find_parent_md(md_t *mdp, mde_cookie_t node) +{ + int max_nodes; + int num_nodes; + int listsz; + mde_cookie_t *listp; + mde_cookie_t pnode = MDE_INVAL_ELEM_COOKIE; + + max_nodes = md_node_count(mdp); + listsz = max_nodes * sizeof (mde_cookie_t); + listp = kmem_zalloc(listsz, KM_SLEEP); + + num_nodes = md_scan_dag(mdp, node, + md_find_name(mdp, "channel-devices"), + md_find_name(mdp, "back"), listp); + + ASSERT(num_nodes == 1); + + if (num_nodes == 1) + pnode = listp[0]; + + kmem_free(listp, listsz); + + return (pnode); +} + +static int +dr_io_configure(dr_vio_req_t *req, dr_vio_res_t *res) +{ + int rv = ENXIO; + int listsz; + int nnodes; + uint64_t devid = req->dev_id; + uint64_t pdevid; + char *name = req->name; + char *pname; + md_t *mdp = NULL; + mde_cookie_t *listp = NULL; + mde_cookie_t node; + mde_cookie_t pnode; + dev_info_t *pdip = NULL; + dev_info_t *dip; + devi_branch_t br; + cb_arg_t cba; + int drctl_cmd; + int drctl_flags = 0; + drctl_rsrc_t *drctl_req; + size_t drctl_req_len; + drctl_rsrc_t *drctl_res = NULL; + size_t drctl_res_len = 0; + drctl_cookie_t drctl_res_ck; + char *p; + size_t reason_len; + + res->result = DR_VIO_RES_FAILURE; + + if ((dip = dr_io_find_node(name, devid)) != NULL) { + DR_DBG_IO("%s: %s@%ld already configured\n", + __func__, name, devid); + + /* Return success if resources is already there. */ + res->result = DR_VIO_RES_OK; + res->status = DR_VIO_STAT_CONFIGURED; + e_ddi_branch_rele(dip); + return (0); + } + + /* Assume we fail to find the node to be added. */ + res->status = DR_VIO_STAT_NOT_PRESENT; + + if ((mdp = md_get_handle()) == NULL) { + DR_DBG_IO("%s: unable to initialize MD\n", __func__); + return (ENXIO); + } + + nnodes = md_node_count(mdp); + ASSERT(nnodes > 0); + + listsz = nnodes * sizeof (mde_cookie_t); + listp = kmem_zalloc(listsz, KM_SLEEP); + + /* + * Get the MD device node. + */ + node = dr_io_find_node_md(mdp, name, devid, listp); + + if (node == MDE_INVAL_ELEM_COOKIE) { + DR_DBG_IO("%s: scan for %s name node failed\n", __func__, name); + res->result = DR_VIO_RES_NOT_IN_MD; + goto done; + } + + /* + * Get the MD parent node. + */ + pnode = dr_vio_find_parent_md(mdp, node); + if (pnode == MDE_INVAL_ELEM_COOKIE) { + DR_DBG_IO("%s: failed to find MD parent of %lx\n", + __func__, pnode); + goto done; + } + + if (md_get_prop_str(mdp, pnode, "name", &pname)) { + DR_DBG_IO("%s: failed to read " + "'name' for pnode %lx from MD\n", __func__, pnode); + goto done; + } + + if (md_get_prop_val(mdp, pnode, "cfg-handle", &pdevid)) { + DR_DBG_IO("%s: failed to read 'cfg-handle' " + "for pnode '%s' from MD\n", __func__, pname); + goto done; + } + + DR_DBG_IO("%s: parent device %s@%lx\n", __func__, pname, pdevid); + + /* + * Get the devinfo parent node. + */ + if ((pdip = dr_io_find_node(pname, pdevid)) == NULL) { + DR_DBG_IO("%s: parent device %s@%ld not found\n", + __func__, pname, pdevid); + goto done; + } + + drctl_req_len = sizeof (drctl_rsrc_t) + MAXPATHLEN; + drctl_req = kmem_zalloc(drctl_req_len, KM_SLEEP); + drctl_req->status = DRCTL_STATUS_INIT; + + drctl_cmd = DRCTL_IO_CONFIG_REQUEST; + + /* + * Construct the path of the device as it will be if it + * is successfully added. + */ + p = drctl_req->res_dev_path; + (void) sprintf(p, "/devices"); + (void) ddi_pathname(pdip, p + strlen(p)); + (void) sprintf(p + strlen(p), "/%s@%ld", name, devid); + DR_DBG_IO("%s: devpath=%s\n", __func__, drctl_req->res_dev_path); + + if ((rv = drctl_config_init(drctl_cmd, drctl_flags, drctl_req, + 1, &drctl_res, &drctl_res_len, &drctl_res_ck)) != 0) { + + DR_DBG_IO("%s: drctl_config_init failed: %d\n", __func__, rv); + goto done; + + } else if (drctl_res->status == DRCTL_STATUS_DENY) { + res->result = DR_VIO_RES_BLOCKED; + + DR_DBG_IO("%s: drctl_config_init denied\n", __func__); + p = (char *)drctl_res + drctl_res->offset; + reason_len = strlen(p); + + if (reason_len >= DR_VIO_MAXREASONLEN) + reason_len = DR_VIO_MAXREASONLEN - 1; + + (void) strncpy(res->reason, p, reason_len); + res->reason[reason_len] = '\0'; + DR_DBG_IO("%s: %s\n", __func__, res->reason); + + drctl_req->status = DRCTL_STATUS_CONFIG_FAILURE; + + rv = EPERM; + } else { + cba.mdp = mdp; + cba.node = node; + + br.arg = (void *)&cba; + br.type = DEVI_BRANCH_SID; + br.create.sid_branch_create = new_dev_node; + br.devi_branch_callback = NULL; + + rv = e_ddi_branch_create(pdip, + &br, NULL, DEVI_BRANCH_CONFIGURE); + + drctl_req->status = (rv == 0) ? + DRCTL_STATUS_CONFIG_SUCCESS : DRCTL_STATUS_CONFIG_FAILURE; + + DR_DBG_IO("%s: %s@%ld = %d\n", __func__, name, devid, rv); + } + + if (drctl_config_fini(&drctl_res_ck, drctl_req, 1) != 0) + DR_DBG_IO("%s: drctl_config_fini returned: %d\n", __func__, rv); + +done: + if (listp) + kmem_free(listp, listsz); + + if (mdp) + (void) md_fini_handle(mdp); + + if (pdip) + e_ddi_branch_rele(pdip); + + kmem_free(drctl_req, drctl_req_len); + if (drctl_res) + kmem_free(drctl_res, drctl_res_len); + + if (rv == 0) { + res->result = DR_VIO_RES_OK; + res->status = DR_VIO_STAT_CONFIGURED; + + /* notify interested parties about the operation */ + dr_generate_event(DR_TYPE_VIO, SE_HINT_INSERT); + } else { + res->status = DR_VIO_STAT_UNCONFIGURED; + } + + return (rv); +} + +static int +dr_io_unconfigure(dr_vio_req_t *req, dr_vio_res_t *res) +{ + int rv; + char *name = req->name; + char *p; + uint64_t devid = req->dev_id; + dev_info_t *dip; + dev_info_t *fdip = NULL; + int drctl_cmd; + int drctl_flags = 0; + drctl_rsrc_t *drctl_req; + size_t drctl_req_len; + drctl_rsrc_t *drctl_res = NULL; + size_t drctl_res_len = 0; + drctl_cookie_t drctl_res_ck; + size_t reason_len; + + if ((dip = dr_io_find_node(name, devid)) == NULL) { + DR_DBG_IO("%s: %s@%ld already unconfigured\n", + __func__, name, devid); + res->result = DR_VIO_RES_OK; + res->status = DR_VIO_STAT_NOT_PRESENT; + return (0); + } + + res->result = DR_VIO_RES_FAILURE; + + ASSERT(e_ddi_branch_held(dip)); + + /* Assume we fail to unconfigure the resource. */ + res->status = DR_VIO_STAT_CONFIGURED; + + drctl_req_len = sizeof (drctl_rsrc_t) + MAXPATHLEN; + drctl_req = kmem_zalloc(drctl_req_len, KM_SLEEP); + drctl_req->status = DRCTL_STATUS_INIT; + + drctl_cmd = DRCTL_IO_UNCONFIG_REQUEST; + + if (req->msg_type == DR_VIO_FORCE_UNCONFIG) + drctl_flags = DRCTL_FLAG_FORCE; + + p = drctl_req->res_dev_path; + (void) sprintf(p, "/devices"); + (void) ddi_pathname(dip, p + strlen(p)); + DR_DBG_IO("%s: devpath=%s\n", __func__, drctl_req->res_dev_path); + + if ((rv = drctl_config_init(drctl_cmd, drctl_flags, drctl_req, + 1, &drctl_res, &drctl_res_len, &drctl_res_ck)) != 0) { + + DR_DBG_IO("%s: drctl_config_init failed: %d\n", __func__, rv); + goto done; + + } else if (drctl_res->status == DRCTL_STATUS_DENY) { + res->result = DR_VIO_RES_BLOCKED; + + DR_DBG_IO("%s: drctl_config_init denied\n", __func__); + p = (char *)drctl_res + drctl_res->offset; + reason_len = strlen(p); + + if (reason_len >= DR_VIO_MAXREASONLEN) + reason_len = DR_VIO_MAXREASONLEN - 1; + + (void) strncpy(res->reason, p, reason_len); + res->reason[reason_len] = '\0'; + DR_DBG_IO("%s: %s\n", __func__, res->reason); + + drctl_req->status = DRCTL_STATUS_CONFIG_FAILURE; + + rv = EPERM; + } else if (rv = e_ddi_branch_destroy(dip, &fdip, 0)) { + char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP); + + /* + * If non-NULL, fdip is held and must be released. + */ + if (fdip != NULL) { + (void) ddi_pathname(fdip, path); + ddi_release_devi(fdip); + } else { + (void) ddi_pathname(dip, path); + } + + DR_DBG_IO("%s: node removal failed: %s (%p)", + __func__, path, (fdip) ? (void *)fdip : (void *)dip); + + drctl_req->status = DRCTL_STATUS_CONFIG_FAILURE; + + kmem_free(path, MAXPATHLEN); + } else { + drctl_req->status = DRCTL_STATUS_CONFIG_SUCCESS; + } + + if (drctl_config_fini(&drctl_res_ck, drctl_req, 1) != 0) + DR_DBG_IO("%s: drctl_config_fini returned: %d\n", __func__, rv); + + DR_DBG_IO("%s: (%s@%ld) = %d\n", __func__, name, devid, rv); + + if (rv == 0) { + res->result = DR_VIO_RES_OK; + res->status = DR_VIO_STAT_UNCONFIGURED; + + /* Notify interested parties about the operation. */ + dr_generate_event(DR_TYPE_VIO, SE_HINT_REMOVE); + } +done: + kmem_free(drctl_req, drctl_req_len); + + if (drctl_res) + kmem_free(drctl_res, drctl_res_len); + + return (rv); +} + +static void +dr_vio_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen) +{ + _NOTE(ARGUNUSED(arg)) + + size_t res_len; + dr_vio_res_t *res; + dr_vio_req_t *req; + + /* + * Allocate a response buffer, because we always want to + * send back a response message. + */ + res_len = sizeof (dr_vio_res_t) + DR_VIO_MAXREASONLEN; + res = kmem_zalloc(res_len, KM_SLEEP); + res->result = DR_VIO_RES_FAILURE; + + /* + * Sanity check the message + */ + if (buf == NULL) { + DR_DBG_IO("empty message: expected at least %ld bytes\n", + sizeof (dr_vio_req_t)); + goto done; + } + if (buflen < sizeof (dr_vio_req_t)) { + DR_DBG_IO("incoming message short: expected at least %ld " + "bytes, received %ld\n", sizeof (dr_vio_req_t), buflen); + goto done; + } + + DR_DBG_TRANS("incoming request:\n"); + DR_DBG_DUMP_MSG(buf, buflen); + + req = buf; + switch (req->msg_type) { + case DR_VIO_CONFIGURE: + (void) dr_io_configure(req, res); + break; + case DR_VIO_FORCE_UNCONFIG: + case DR_VIO_UNCONFIGURE: + (void) dr_io_unconfigure(req, res); + break; + default: + cmn_err(CE_NOTE, "bad msg_type %d\n", req->msg_type); + break; + } +done: + res->req_num = (req) ? req->req_num : 0; + + DR_DBG_TRANS("outgoing response:\n"); + DR_DBG_DUMP_MSG(res, res_len); + + /* send back the response */ + if (ds_cap_send(ds_vio_handle, res, res_len) != 0) + DR_DBG_IO("ds_send failed\n"); + + if (res) + kmem_free(res, res_len); +} + +static void +dr_vio_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl) +{ + DR_DBG_IO("vio_reg_handler: arg=0x%p, ver=%d.%d, hdl=0x%lx\n", + arg, ver->major, ver->minor, hdl); + + ds_vio_handle = hdl; +} + +static void +dr_vio_unreg_handler(ds_cb_arg_t arg) +{ + DR_DBG_IO("vio_unreg_handler: arg=0x%p\n", arg); + + ds_vio_handle = DS_INVALID_HDL; +} + +static int +dr_io_init(void) +{ + int rv; + + if ((rv = ds_cap_init(&dr_vio_cap, &dr_vio_ops)) != 0) { + cmn_err(CE_NOTE, "ds_cap_init vio failed: %d", rv); + return (-1); + } + + return (0); +} + +static int +dr_io_fini(void) +{ + int rv; + + if ((rv = ds_cap_fini(&dr_vio_cap)) != 0) { + cmn_err(CE_NOTE, "ds_cap_fini vio failed: %d", rv); + return (-1); + } + + return (0); +} + +int +_init(void) +{ + int status; + + /* check that IO DR is enabled */ + if (dr_is_disabled(DR_TYPE_VIO)) { + cmn_err(CE_CONT, "!VIO DR is disabled\n"); + return (-1); + } + + if ((status = dr_io_init()) != 0) { + cmn_err(CE_NOTE, "VIO DR initialization failed"); + return (status); + } + + if ((status = mod_install(&modlinkage)) != 0) { + (void) dr_io_fini(); + } + + return (status); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + +int dr_io_allow_unload = 0; + +int +_fini(void) +{ + int status; + + if (dr_io_allow_unload == 0) + return (EBUSY); + + if ((status = mod_remove(&modlinkage)) == 0) { + (void) dr_io_fini(); + } + + return (status); +} diff --git a/usr/src/uts/sun4v/io/drctl.c b/usr/src/uts/sun4v/io/drctl.c index 1383c2d41f..1a49beba03 100644 --- a/usr/src/uts/sun4v/io/drctl.c +++ b/usr/src/uts/sun4v/io/drctl.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -314,16 +314,16 @@ drctl_config_common(int cmd, int flags, drctl_rsrc_t *res, case DRCTL_CPU_CONFIG_NOTIFY: case DRCTL_CPU_UNCONFIG_REQUEST: case DRCTL_CPU_UNCONFIG_NOTIFY: + case DRCTL_IO_UNCONFIG_REQUEST: + case DRCTL_IO_UNCONFIG_NOTIFY: + case DRCTL_IO_CONFIG_REQUEST: + case DRCTL_IO_CONFIG_NOTIFY: rv = 0; break; case DRCTL_MEM_CONFIG_REQUEST: case DRCTL_MEM_CONFIG_NOTIFY: case DRCTL_MEM_UNCONFIG_REQUEST: case DRCTL_MEM_UNCONFIG_NOTIFY: - case DRCTL_IO_CONFIG_REQUEST: - case DRCTL_IO_CONFIG_NOTIFY: - case DRCTL_IO_UNCONFIG_REQUEST: - case DRCTL_IO_UNCONFIG_NOTIFY: rv = ENOTSUP; break; } @@ -498,14 +498,18 @@ drctl_config_fini(drctl_cookie_t ck, drctl_rsrc_t *res, int count) notify_cmd = DRCTL_CPU_UNCONFIG_NOTIFY; break; + case DRCTL_IO_UNCONFIG_REQUEST: + notify_cmd = DRCTL_IO_UNCONFIG_NOTIFY; + break; + + case DRCTL_IO_CONFIG_REQUEST: + notify_cmd = DRCTL_IO_CONFIG_NOTIFY; + break; + case DRCTL_MEM_CONFIG_REQUEST: case DRCTL_MEM_CONFIG_NOTIFY: case DRCTL_MEM_UNCONFIG_REQUEST: case DRCTL_MEM_UNCONFIG_NOTIFY: - case DRCTL_IO_CONFIG_REQUEST: - case DRCTL_IO_CONFIG_NOTIFY: - case DRCTL_IO_UNCONFIG_REQUEST: - case DRCTL_IO_UNCONFIG_NOTIFY: default: /* none of the above should have been accepted in _init */ ASSERT(0); @@ -566,27 +570,37 @@ send_message(void *msg, size_t size, void **obufp, size_t *osize) static void * pack_message(int cmd, int flags, int count, void *data, size_t *osize) { - drd_msg_t *msgp; + drd_msg_t *msgp = NULL; size_t hdr_size = offsetof(drd_msg_t, data); + size_t data_size = 0; switch (cmd) { case DRCTL_CPU_CONFIG_REQUEST: case DRCTL_CPU_CONFIG_NOTIFY: case DRCTL_CPU_UNCONFIG_REQUEST: case DRCTL_CPU_UNCONFIG_NOTIFY: + data_size = count * sizeof (drctl_rsrc_t); + break; + case DRCTL_IO_CONFIG_REQUEST: + case DRCTL_IO_CONFIG_NOTIFY: + case DRCTL_IO_UNCONFIG_REQUEST: + case DRCTL_IO_UNCONFIG_NOTIFY: + data_size = sizeof (drctl_rsrc_t) + + strlen(((drctl_rsrc_t *)data)->res_dev_path); + break; + default: + cmn_err(CE_WARN, + "drctl: pack_message received invalid cmd %d", cmd); + break; + } - *osize = hdr_size + count * sizeof (drctl_rsrc_t); - + if (data_size) { + *osize = hdr_size + data_size; msgp = kmem_alloc(*osize, KM_SLEEP); msgp->cmd = cmd; msgp->count = count; msgp->flags = flags; - bcopy(data, msgp->data, count * sizeof (drctl_rsrc_t)); - break; - default: - cmn_err(CE_WARN, - "drctl: pack_message received invalid cmd %d", cmd); - msgp = NULL; + bcopy(data, msgp->data, data_size); } return (msgp); diff --git a/usr/src/uts/sun4v/os/mach_startup.c b/usr/src/uts/sun4v/os/mach_startup.c index 8159aa8967..6c521d5374 100644 --- a/usr/src/uts/sun4v/os/mach_startup.c +++ b/usr/src/uts/sun4v/os/mach_startup.c @@ -498,6 +498,9 @@ load_mach_drivers(void) if (domaining_enabled() && modload("misc", "dr_cpu") == -1) cmn_err(CE_NOTE, "!'dr_cpu' module failed to load"); + if (modload("misc", "dr_io") == -1) + cmn_err(CE_NOTE, "!'dr_io' module failed to load"); + /* * Attempt to attach any virtual device servers. These * drivers must be loaded at start of day so that they diff --git a/usr/src/uts/sun4v/sys/dr_io.h b/usr/src/uts/sun4v/sys/dr_io.h new file mode 100644 index 0000000000..a189aa0248 --- /dev/null +++ b/usr/src/uts/sun4v/sys/dr_io.h @@ -0,0 +1,90 @@ +/* + * 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 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _DR_IO_H +#define _DR_IO_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * VIO DR Control Protocol + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Values of 'msg_type' element of the request message + */ +#define DR_VIO_CONFIGURE 0x494f43 /* 'IOC' */ +#define DR_VIO_UNCONFIGURE 0x494f55 /* 'IOU' */ +#define DR_VIO_FORCE_UNCONFIG 0x494f46 /* 'IOF' */ +#define DR_VIO_STATUS 0x494f53 /* 'IOS' */ + +/* + * VIO DR Request + */ +typedef struct { + uint64_t req_num; + uint64_t dev_id; + uint32_t msg_type; + char name[1]; +} dr_vio_req_t; + +/* + * Values of 'result' element of the response message + */ +#define DR_VIO_RES_OK 0x0 +#define DR_VIO_RES_FAILURE 0x1 +#define DR_VIO_RES_BLOCKED 0x2 +#define DR_VIO_RES_NOT_IN_MD 0x3 + +/* + * Values of 'status' element of the response message + */ +#define DR_VIO_STAT_NOT_PRESENT 0x0 +#define DR_VIO_STAT_UNCONFIGURED 0x1 +#define DR_VIO_STAT_CONFIGURED 0x2 + +/* + * VIO DR Response + */ +typedef struct { + uint64_t req_num; + uint32_t result; + uint32_t status; + char reason[1]; +} dr_vio_res_t; + +#define DR_VIO_DS_ID "dr-vio" +#define DR_VIO_MAXREASONLEN 1024 + +#ifdef __cplusplus +} +#endif + +#endif /* _DR_IO_H */ diff --git a/usr/src/uts/sun4v/sys/dr_util.h b/usr/src/uts/sun4v/sys/dr_util.h index 944738ff29..7f99cf0461 100644 --- a/usr/src/uts/sun4v/sys/dr_util.h +++ b/usr/src/uts/sun4v/sys/dr_util.h @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -82,8 +82,7 @@ typedef enum { DR_TYPE_INVAL, DR_TYPE_CPU, DR_TYPE_MEM, - DR_TYPE_VIO, - DR_TYPE_DIO + DR_TYPE_VIO } dr_type_t; /* @@ -95,7 +94,6 @@ typedef enum { (t) == DR_TYPE_CPU ? OBP_CPU : \ (t) == DR_TYPE_MEM ? "memory" : \ (t) == DR_TYPE_VIO ? "vio" : \ - (t) == DR_TYPE_DIO ? "dio" : \ "unknown") extern boolean_t dr_is_disabled(dr_type_t type); |