Mercurial > illumos > fmac
changeset 6451:ab21c2538653 onnv_88
6683029 Install -G and i86hvm don't mix well
6683772 yacc yacks when confronted with libumem
line wrap: on
line diff
--- a/usr/src/cmd/sgs/yacc/common/y2.c Mon Apr 14 22:16:59 2008 -0700 +++ b/usr/src/cmd/sgs/yacc/common/y2.c Mon Apr 14 22:44:34 2008 -0700 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -195,8 +195,8 @@ prdptr = (int **)malloc(sizeof (int *) * (nprodsz+2)); levprd = (int *)malloc(sizeof (int) * (nprodsz+2)); had_act = (wchar_t *)calloc((nprodsz + 2), sizeof (wchar_t)); - lhstext = (wchar_t *)malloc(sizeof (wchar_t) * LHS_TEXT_LEN); - rhstext = (wchar_t *)malloc(sizeof (wchar_t) * RHS_TEXT_LEN); + lhstext = (wchar_t *)calloc(1, sizeof (wchar_t) * LHS_TEXT_LEN); + rhstext = (wchar_t *)calloc(1, sizeof (wchar_t) * RHS_TEXT_LEN); aryfil(toklev, ntoksz, 0); aryfil(levprd, nprodsz, 0); for (ii = 0; ii < ntoksz; ++ii)
--- a/usr/src/uts/common/xen/io/hvm_bootstrap.c Mon Apr 14 22:16:59 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +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 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/modctl.h> -#include <sys/sunddi.h> -#include <sys/sunndi.h> - -/* - * The hvm_bootstrap misc module is installed in the i86hvm platform - * directly so it will only be loaded in HVM emulated environment. - */ - - -/* - * hvmboot_rootconf() exists to force attach all xdf disk driver nodes - * before the pv cmdk disk driver comes along and tries to access any of - * these nodes (which usually happens when mounting the root disk device - * in an hvm environment). See the block comments at the top of pv_cmdk.c - * for more information about why this is necessary. - */ -int -hvmboot_rootconf() -{ - dev_info_t *xpvd_dip; - major_t xdf_major; - - xdf_major = ddi_name_to_major("xdf"); - if (xdf_major == (major_t)-1) - cmn_err(CE_PANIC, "unable to load xdf disk driver"); - - if (resolve_pathname("/xpvd", &xpvd_dip, NULL, NULL) != 0) - cmn_err(CE_PANIC, "unable to configure /xpvd nexus"); - - (void) ndi_devi_config_driver(xpvd_dip, 0, xdf_major); - - ndi_rele_devi(xpvd_dip); - return (0); -} - -static struct modlmisc modlmisc = { - &mod_miscops, "hvm_bootstrap misc module" -}; - -static struct modlinkage modlinkage = { - MODREV_1, (void *)&modlmisc, NULL -}; - -int -_info(struct modinfo *modinfop) -{ - return (mod_info(&modlinkage, modinfop)); -} - -int -_init() -{ - return (mod_install(&modlinkage)); -} - -int -_fini() -{ - return (EBUSY); -}
--- a/usr/src/uts/i86pc/Makefile Mon Apr 14 22:16:59 2008 -0700 +++ b/usr/src/uts/i86pc/Makefile Mon Apr 14 22:44:34 2008 -0700 @@ -75,13 +75,14 @@ cpu/scripts def all clean clobber clean.lint: setup genassym unix .WAIT \ - $(KMODS) $(CLOSED_KMODS) $(XMODS) $(CLOSED_XMODS) + $(KMODS) $(CLOSED_KMODS) $(XMODS) $(CLOSED_XMODS) $(IMPLEMENTATIONS) install: install_platforms setup genassym unix .WAIT \ - $(KMODS) $(CLOSED_KMODS) $(XMODS) $(CLOSED_XMODS) + $(KMODS) $(CLOSED_KMODS) $(XMODS) $(CLOSED_XMODS) $(IMPLEMENTATIONS) # list the modules under i86pc. -modlist: unix $(KMODS) $(CLOSED_KMODS) $(XMODS) $(CLOSED_XMODS) +modlist: unix $(KMODS) $(CLOSED_KMODS) $(XMODS) $(CLOSED_XMODS) \ + $(IMPLEMENTATIONS) # list the modules for Install -k i86pc. modlist.karch: modlist modlist.intel @@ -99,6 +100,9 @@ setup: FRC @cd cpu/scripts; pwd; $(MAKE) $(TARGET) +$(IMPLEMENTATIONS): FRC + @cd $@; pwd; THISIMPL=$@ $(MAKE) $(NO_STATE) $(TARGET) + $(XMODS): FRC @if [ -f $@/Makefile ]; then \ cd $@; pwd; $(MAKE) $(NO_STATE) $(TARGET); \ @@ -117,7 +121,7 @@ true; \ fi -install_h check: FRC +install_h check: $(IMPLEMENTATIONS) FRC @cd sys; pwd; $(MAKE) $(TARGET) # @@ -148,7 +152,8 @@ @-$(ECHO) "\nFULL KERNEL: global crosschecks:" @-$(LINT) $(LINTFLAGS) $(LINT_LIBS) 2>&1 | $(LGREP.2) -lint: lintlib .WAIT modlintlib .WAIT $(INTEL_LINTS) $(LINT_DEPS) +lint: lintlib .WAIT modlintlib .WAIT $(INTEL_LINTS) $(LINT_DEPS) \ + $(IMPLEMENTATIONS) $(INTEL_LINTS): FRC @cd $(UTSBASE)/intel/$@; pwd; $(MAKE) modlintlib
--- a/usr/src/uts/i86pc/Makefile.files Mon Apr 14 22:16:59 2008 -0700 +++ b/usr/src/uts/i86pc/Makefile.files Mon Apr 14 22:44:34 2008 -0700 @@ -186,15 +186,6 @@ TZMON_OBJS += tzmon.o UPPC_OBJS += uppc.o psm_common.o XSVC_OBJS += xsvc.o -PV_CMDK_OBJS += pv_cmdk.o -PV_RTLS_OBJS += pv_rtls.o -HVM_BOOTSTRAP_OBJS += hvm_bootstrap.o -XDF_OBJS += xdf.o -XNF_OBJS += xnf.o -XPV_OBJS += xpv_support.o xvdi.o gnttab.o evtchn.o \ - xenbus_comms.o xenbus_client.o xenbus_probe.o xenbus_xs.o \ - hypercall.o hypersubr.o -XPVD_OBJS += xpvd.o # # Build up defines and paths.
--- a/usr/src/uts/i86pc/Makefile.hvm Mon Apr 14 22:16:59 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +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 -# -# -# uts/i86pc/Makefile.hvm -# -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" -# -# This makefile provides support for building PV drivers that run -# in an HVM environment. -# - -ROOT_HVM_DIR = $(ROOT)/platform/i86hvm -ROOT_HVM_MOD_DIR = $(ROOT_HVM_DIR)/kernel -ROOT_HVM_DRV_DIR_32 = $(ROOT_HVM_MOD_DIR)/drv -ROOT_HVM_DRV_DIR_64 = $(ROOT_HVM_MOD_DIR)/drv/$(MACH64) -ROOT_HVM_DRV_DIR = $(ROOT_HVM_DRV_DIR_$(CLASS)) -ROOT_HVM_MISC_DIR_32 = $(ROOT_HVM_MOD_DIR)/misc -ROOT_HVM_MISC_DIR_64 = $(ROOT_HVM_MOD_DIR)/misc/$(MACH64) -ROOT_HVM_MISC_DIR = $(ROOT_HVM_MISC_DIR_$(CLASS)) -USR_HVM_DIR = $(ROOT)/usr/platform/i86hvm - -# -# Indicate that we are building for the i86hvm semi-platform -# -CPPFLAGS += -DXPV_HVM_DRIVER -ASFLAGS += -DXPV_HVM_DRIVER - -# -# Installation targets and rules: -# -$(ROOT_HVM_DIR): - -$(INS.dir.root.sys) - -$(ROOT_HVM_MOD_DIR): $(ROOT_HVM_DIR) - -$(INS.dir.root.sys) - -$(ROOT_HVM_DRV_DIR): $(ROOT_MOD_DIR) - -$(INS.dir.root.sys) - -$(ROOT_HVM_MISC_DIR): $(ROOT_MOD_DIR) - -$(INS.dir.root.sys) - -$(ROOT_HVM_MOD_DIR)/%: $(OBJS_DIR)/% $(ROOT_HVM_MOD_DIR) FRC - $(INS.file) - -$(ROOT_HVM_DRV_DIR)/%: $(OBJS_DIR)/% $(ROOT_HVM_DRV_DIR) FRC - $(INS.file) - -$(ROOT_HVM_MISC_DIR)/%: $(OBJS_DIR)/% $(ROOT_HVM_MISC_DIR) FRC - $(INS.file) - -$(USR_HVM_DIR): - -$(INS.dir.root.sys) - -INSTALL_DEPS += $(ROOT_HVM_DIR) $(USR_HVM_DIR)
--- a/usr/src/uts/i86pc/Makefile.i86pc.shared Mon Apr 14 22:16:59 2008 -0700 +++ b/usr/src/uts/i86pc/Makefile.i86pc.shared Mon Apr 14 22:44:34 2008 -0700 @@ -42,6 +42,17 @@ UNAME_M = $(PLATFORM) # +# Definitions for the platform-specific /platform directories. +# +# IMPLEMENTATIONS is used to designate i86pc machines which have +# platform specific modules. All code specific to a given implementation +# resides in the appropriately named subdirectory. This requires +# these platforms to have their own Makefiles to define ROOT_PLAT_DIRS, +# USR_PLAT_DIRS, etc. +# +IMPLEMENTATIONS = i86hvm + +# # Everybody needs to know how to build modstubs.o and to locate unix.o # UNIX_DIR = $(UTSBASE)/$(PLATFORM)/unix @@ -246,12 +257,6 @@ DRV_KMODS += mc-amd DRV_KMODS += tzmon DRV_KMODS += battery -DRV_KMODS += pv_cmdk -DRV_KMODS += pv_rtls -DRV_KMODS += xdf -DRV_KMODS += xnf -DRV_KMODS += xpv -DRV_KMODS += xpvd DRV_KMODS += cpudrv @@ -299,7 +304,7 @@ # # 'Misc' Modules (/kernel/misc): # -MISC_KMODS += gfx_private pcie hvm_bootstrap +MISC_KMODS += gfx_private pcie # # 'Dacf' modules (/kernel/dacf)
--- a/usr/src/uts/i86pc/Makefile.rules Mon Apr 14 22:16:59 2008 -0700 +++ b/usr/src/uts/i86pc/Makefile.rules Mon Apr 14 22:44:34 2008 -0700 @@ -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" @@ -32,8 +32,8 @@ # # The following two-level ordering must be maintained in this file. # Lines are sorted first in order of decreasing specificity based on -# the first directory component. That is, sun4u rules come before -# sparc rules come before common rules. +# the first directory component. That is, i86pc rules come before +# intel rules come before common rules. # # Lines whose initial directory components are equal are sorted # alphabetically by the remaining components. @@ -110,13 +110,6 @@ $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) -$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/io/xpv/%.c - $(COMPILE.c) -o $@ $< - $(CTFCONVERT_O) - -$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/io/xpv/%.s - $(COMPILE.s) -o $@ $< - $(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/ml/%.s $(COMPILE.s) -o $@ $< @@ -152,14 +145,6 @@ $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) -$(OBJS_DIR)/%.o: $(UTSBASE)/common/xen/io/%.c - $(COMPILE.c) -o $@ $< - $(CTFCONVERT_O) - -$(OBJS_DIR)/%.o: $(UTSBASE)/common/xen/os/%.c - $(COMPILE.c) -o $@ $< - $(CTFCONVERT_O) - $(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/io/xsvc/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) @@ -304,12 +289,6 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/tzmon/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) -$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/xpv/%.c - @($(LHEAD) $(LINT.c) $< $(LTAIL)) - -$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/xpv/%.s - @($(LHEAD) $(LINT.s) $< $(LTAIL)) - $(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/ml/%.s @($(LHEAD) $(LINT.s) $< $(LTAIL)) @@ -340,12 +319,6 @@ $(LINTS_DIR)/%.ln: $(SRC)/common/mc/mc-amd/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) -$(LINTS_DIR)/%.ln: $(UTSBASE)/common/xen/io/%.c - @($(LHEAD) $(LINT.c) $< $(LTAIL)) - -$(LINTS_DIR)/%.ln: $(UTSBASE)/common/xen/os/%.c - @($(LHEAD) $(LINT.c) $< $(LTAIL)) - $(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/gfx_private/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL))
--- a/usr/src/uts/i86pc/hvm_bootstrap/Makefile Mon Apr 14 22:16:59 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +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 -# - -# -# uts/i86pc/hvm_bootstrap/Makefile -# -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "%Z%%M% %I% %E% SMI" -# -# i86pc architecture dependent -# -# Path to the base of the uts directory tree (usually /usr/src/uts). -# -UTSBASE = ../.. - -# -# Define the module and object file sets. -# -MODULE = hvm_bootstrap -OBJECTS = $(HVM_BOOTSTRAP_OBJS:%=$(OBJS_DIR)/%) -LINTS = $(HVM_BOOTSTRAP_OBJS:%.o=$(LINTS_DIR)/%.ln) -ROOTMODULE = $(ROOT_HVM_MISC_DIR)/$(MODULE) - -# -# Include common rules. -# -include $(UTSBASE)/i86pc/Makefile.i86pc -include $(UTSBASE)/i86pc/Makefile.hvm - -# -# Define targets -# -ALL_TARGET = $(BINARY) -LINT_TARGET = $(MODULE).lint -INSTALL_TARGET = $(BINARY) $(ROOTMODULE) - -# Overrides -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)/i86pc/Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/i86pc/i86hvm/Makefile Mon Apr 14 22:44:34 2008 -0700 @@ -0,0 +1,108 @@ +# +# 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 +# +# +# uts/i86pc/i86hvm/Makefile +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# +# This makefile drives the production of the i86hvm platform modules. +# +# i86pc implementation architecture dependent +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Include common rules. +# +include $(UTSBASE)/i86pc/i86hvm/Makefile.i86hvm + +def := TARGET= def +all := TARGET= all +install := TARGET= install +install_h := TARGET= install_h +clean := TARGET= clean +clobber := TARGET= clobber +lint := TARGET= lint +lintlib := TARGET= lintlib +modlintlib := TARGET= modlintlib +modlist := TARGET= modlist +modlist := NO_STATE= -K $$MODSTATE$$$$ +clean.lint := TARGET= clean.lint +check := TARGET= check + +# +# Default build targets. +# +.KEEP_STATE: + +.PARALLEL: $(HVM_KMODS) + +def all clean clobber clean.lint modlist modlintlib: $(HVM_KMODS) + +install: install_implementations .WAIT \ + $(HVM_KMODS) + +install_implementations: \ + $(ROOT_HVM_DIR) \ + $(ROOT_HVM_DRV_DIR) \ + $(ROOT_HVM_MISC_DIR) \ + $(USR_HVM_DIR) + +$(HVM_KMODS): FRC + @cd $@; pwd; $(MAKE) $(NO_STATE) $(TARGET) + +install_h check: FRC + +lintlib lint: modlintlib .WAIT $(LINT_DEPS) + +# +# The 'lint.platmod' target lints the i86hvm platform modules against the i86pc +# kernel. This ends up doing all the kernel cross-checks. +# +LINT_TARGET = lint.platmod +INTEL_LIB_DIR = $(UTSBASE)/intel/lint-libs/$(OBJS_DIR) +INTEL_LINTS = genunix +LINT_LIBS = $(LINT_LIB) \ + -L$(HVM_LINT_LIB_DIR) \ + -L$(LINT_LIB_DIR) \ + $(GENUNIX_KMODS:%=-l%) \ + $(PARALLEL_KMODS:%=-l%) \ + $(CLOSED_KMODS:%=-l%) \ + -L$(INTEL_LIB_DIR) \ + $(INTEL_LINTS:%=-l%) + +# workaround for multiply defined errors +lint.platmod := LINTFLAGS += -erroff=E_NAME_MULTIPLY_DEF2 + +lint.platmod: modlintlib + @-$(ECHO) "\ni86hvm platform-dependent module: global crosschecks:" + @-$(LINT) $(LINTFLAGS) $(LINT_LIBS) 2>&1 | $(LGREP.2) + +# +# Include common targets. +# +include $(UTSBASE)/$(PLATFORM)/i86hvm/Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/i86pc/i86hvm/Makefile.files Mon Apr 14 22:44:34 2008 -0700 @@ -0,0 +1,49 @@ +# +# 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" +# +# This Makefile defines file modules in the directory uts/i86pc/i86hvm +# and its children. These are the source files which are i86pc/i86hvm +# "implementation architecture" dependent. +# + +# +# Define objects +# +PV_CMDK_OBJS += pv_cmdk.o +PV_RTLS_OBJS += pv_rtls.o +HVM_BOOTSTRAP_OBJS += hvm_bootstrap.o +XDF_OBJS += xdf.o +XNF_OBJS += xnf.o +XPV_OBJS += xpv_support.o xvdi.o gnttab.o evtchn.o \ + xenbus_comms.o xenbus_client.o xenbus_probe.o \ + xenbus_xs.o hypercall.o hypersubr.o +XPVD_OBJS += xpvd.o + +# +# Include i86hvm header files +# -I$(UTSBASE)/../common +INC_PATH += -I$(UTSBASE)/common/xen -I$(UTSBASE)/i86pc/i86hvm
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/i86pc/i86hvm/Makefile.i86hvm Mon Apr 14 22:44:34 2008 -0700 @@ -0,0 +1,66 @@ +# +# 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 +# +# +# uts/i86pc/Makefile.hvm +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# +# This makefile provides support for building PV drivers that run +# in an HVM environment. +# + +ROOT_HVM_DIR = $(ROOT_PLAT_DIR)/i86hvm +ROOT_HVM_MOD_DIR = $(ROOT_HVM_DIR)/kernel +ROOT_HVM_DRV_DIR_32 = $(ROOT_HVM_MOD_DIR)/drv +ROOT_HVM_DRV_DIR_64 = $(ROOT_HVM_MOD_DIR)/drv/$(MACH64) +ROOT_HVM_DRV_DIR = $(ROOT_HVM_DRV_DIR_$(CLASS)) +ROOT_HVM_MISC_DIR_32 = $(ROOT_HVM_MOD_DIR)/misc +ROOT_HVM_MISC_DIR_64 = $(ROOT_HVM_MOD_DIR)/misc/$(MACH64) +ROOT_HVM_MISC_DIR = $(ROOT_HVM_MISC_DIR_$(CLASS)) +USR_HVM_DIR = $(USR_PLAT_DIR)/i86hvm + +HVM_LINT_LIB_DIR= $(UTSBASE)/$(PLATFORM)/i86hvm/lint-libs/$(OBJS_DIR) + +# +# Define modules. +# +HVM_DRV_KMODS = pv_cmdk pv_rtls xdf xnf xpv xpvd +HVM_MISC_KMODS = hvm_bootstrap +HVM_KMODS = $(HVM_DRV_KMODS) $(HVM_MISC_KMODS) + +include $(UTSBASE)/i86pc/i86hvm/Makefile.files +# +# Include common rules. +# +include $(UTSBASE)/i86pc/Makefile.i86pc + +LINTS_DIR = $(OBJS_DIR) +LINT_LIB_DIR = $(UTSBASE)/$(PLATFORM)/lint-libs/$(OBJS_DIR) + +# +# Indicate that we are building for the i86hvm semi-platform. +# Also use Solaris specific code in xen public header files. +# +CPPFLAGS += -DXPV_HVM_DRIVER -D_SOLARIS +ASFLAGS += -DXPV_HVM_DRIVER
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/i86pc/i86hvm/Makefile.rules Mon Apr 14 22:44:34 2008 -0700 @@ -0,0 +1,73 @@ +# +# 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" +# + +# +# This Makefile defines the build rules for the directory +# uts/i86pc/i86hvm. +# +# The following two-level ordering must be maintained in this file. +# Lines are sorted first in order of decreasing specificity based on +# the first directory component. That is, i86pc rules come before +# intel rules come before common rules. +# +# Lines whose initial directory components are equal are sorted +# alphabetically by the remaining components. + +# +# Section 1a: C object build rules +# + +$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/i86hvm/io/xpv/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + +$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/i86hvm/io/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + +$(OBJS_DIR)/%.o: $(UTSBASE)/common/xen/io/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + +$(OBJS_DIR)/%.o: $(UTSBASE)/common/xen/os/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + +# +# Section 1b: Lint `object' build rules +# + +$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/i86hvm/io/xpv/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + +$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/i86hvm/io/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + +$(LINTS_DIR)/%.ln: $(UTSBASE)/common/xen/io/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + +$(LINTS_DIR)/%.ln: $(UTSBASE)/common/xen/os/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/i86pc/i86hvm/Makefile.targ Mon Apr 14 22:44:34 2008 -0700 @@ -0,0 +1,63 @@ +# +# 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 +# +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# Common targets for i86hvm platform-implementation specific modules. +# + +.KEEP_STATE: + +# +# Rules for implementation subdirectories. +# +$(ROOT_HVM_DIR): + -$(INS.dir.root.sys) + +$(ROOT_HVM_MOD_DIR): $(ROOT_HVM_DIR) + -$(INS.dir.root.sys) + +$(ROOT_HVM_DRV_DIR): $(ROOT_MOD_DIR) + -$(INS.dir.root.sys) + +$(ROOT_HVM_MISC_DIR): $(ROOT_MOD_DIR) + -$(INS.dir.root.sys) + +$(ROOT_HVM_MOD_DIR)/%: $(OBJS_DIR)/% $(ROOT_HVM_MOD_DIR) FRC + $(INS.file) + +$(ROOT_HVM_DRV_DIR)/%: $(OBJS_DIR)/% $(ROOT_HVM_DRV_DIR) FRC + $(INS.file) + +$(ROOT_HVM_MISC_DIR)/%: $(OBJS_DIR)/% $(ROOT_HVM_MISC_DIR) FRC + $(INS.file) + +$(USR_HVM_DIR): + -$(INS.dir.root.sys) + +# +# Include common targets. +# +include $(UTSBASE)/$(PLATFORM)/i86hvm/Makefile.rules +include $(UTSBASE)/$(PLATFORM)/Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/i86pc/i86hvm/hvm_bootstrap/Makefile Mon Apr 14 22:44:34 2008 -0700 @@ -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 +# + +# +# uts/i86pc/hvm_bootstrap/Makefile +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# i86pc architecture dependent +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../../.. + +# +# Define the module and object file sets. +# +MODULE = hvm_bootstrap +OBJECTS = $(HVM_BOOTSTRAP_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(HVM_BOOTSTRAP_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_HVM_MISC_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/i86pc/i86hvm/Makefile.i86hvm + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +# Overrides +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)/i86pc/i86hvm/Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/i86pc/i86hvm/io/hvm_bootstrap.c Mon Apr 14 22:44:34 2008 -0700 @@ -0,0 +1,89 @@ +/* + * 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" + +#include <sys/modctl.h> +#include <sys/sunddi.h> +#include <sys/sunndi.h> + +/* + * The hvm_bootstrap misc module is installed in the i86hvm platform + * directly so it will only be loaded in HVM emulated environment. + */ + + +/* + * hvmboot_rootconf() exists to force attach all xdf disk driver nodes + * before the pv cmdk disk driver comes along and tries to access any of + * these nodes (which usually happens when mounting the root disk device + * in an hvm environment). See the block comments at the top of pv_cmdk.c + * for more information about why this is necessary. + */ +int +hvmboot_rootconf() +{ + dev_info_t *xpvd_dip; + major_t xdf_major; + + xdf_major = ddi_name_to_major("xdf"); + if (xdf_major == (major_t)-1) + cmn_err(CE_PANIC, "unable to load xdf disk driver"); + + if (resolve_pathname("/xpvd", &xpvd_dip, NULL, NULL) != 0) + cmn_err(CE_PANIC, "unable to configure /xpvd nexus"); + + (void) ndi_devi_config_driver(xpvd_dip, 0, xdf_major); + + ndi_rele_devi(xpvd_dip); + return (0); +} + +static struct modlmisc modlmisc = { + &mod_miscops, "hvm_bootstrap misc module" +}; + +static struct modlinkage modlinkage = { + MODREV_1, (void *)&modlmisc, NULL +}; + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + +int +_init() +{ + return (mod_install(&modlinkage)); +} + +int +_fini() +{ + return (EBUSY); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/i86pc/i86hvm/io/pv_cmdk.c Mon Apr 14 22:44:34 2008 -0700 @@ -0,0 +1,1541 @@ +/* + * 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" + +#include <sys/scsi/scsi_types.h> +#include <sys/modctl.h> +#include <sys/cmlb.h> +#include <sys/types.h> +#include <sys/xpv_support.h> +#include <sys/xendev.h> +#include <sys/gnttab.h> +#include <public/xen.h> +#include <public/grant_table.h> +#include <io/xdf.h> +#include <sys/vtoc.h> +#include <sys/dkio.h> +#include <sys/dktp/dadev.h> +#include <sys/dktp/dadkio.h> +#include <sys/dktp/tgdk.h> +#include <sys/dktp/bbh.h> +#include <sys/dktp/cmdk.h> +#include <sys/dktp/altsctr.h> + +/* + * General Notes + * + * We don't support disks with bad block mappins. We have this + * limitation because the underlying xdf driver doesn't support + * bad block remapping. If there is a need to support this feature + * it should be added directly to the xdf driver and we should just + * pass requests strait on through and let it handle the remapping. + * Also, it's probably worth pointing out that most modern disks do bad + * block remapping internally in the hardware so there's actually less + * of a chance of us ever discovering bad blocks. Also, in most cases + * this driver (and the xdf driver) will only be used with virtualized + * devices, so one might wonder why a virtual device would ever actually + * experience bad blocks. To wrap this up, you might be wondering how + * these bad block mappings get created and how they are managed. Well, + * there are two tools for managing bad block mappings, format(1M) and + * addbadsec(1M). Format(1M) can be used to do a surface scan of a disk + * to attempt to find bad block and create mappings for them. Format(1M) + * and addbadsec(1M) can also be used to edit existing mappings that may + * be saved on the disk. + * + * The underlying PV driver that this driver passes on requests to is the + * xdf driver. Since in most cases the xdf driver doesn't deal with + * physical disks it has it's own algorithm for assigning a physical + * geometry to a virtual disk (ie, cylinder count, head count, etc.) + * The default values chosen by the xdf driver may not match those + * assigned to a disk by a hardware disk emulator in an HVM environment. + * This is a problem since these physical geometry attributes affect + * things like the partition table, backup label location, etc. So + * to emulate disk devices correctly we need to know the physical geometry + * that was assigned to a disk at the time of it's initalization. + * Normally in an HVM environment this information will passed to + * the BIOS and operating system from the hardware emulator that is + * emulating the disk devices. In the case of a solaris dom0+xvm + * this would be qemu. So to work around this issue, this driver will + * query the emulated hardware to get the assigned physical geometry + * and then pass this geometry onto the xdf driver so that it can use it. + * But really, this information is essentially metadata about the disk + * that should be kept with the disk image itself. (Assuming or course + * that a disk image is the actual backingstore for this emulated device.) + * This metadata should also be made available to PV drivers via a common + * mechamisn, probably the xenstore. The fact that this metadata isn't + * available outside of HVM domains means that it's difficult to move + * disks between HVM and PV domains, since a fully PV domain will have no + * way of knowing what the correct geometry of the target device is. + * (Short of reading the disk, looking for things like partition tables + * and labels, and taking a best guess at what the geometry was when + * the disk was initialized. Unsuprisingly, qemu actually does this.) + * + * This driver has to map cmdk device instances into their corresponding + * xdf device instances. We have to do this to ensure that when a user + * accesses a emulated cmdk device we map those accesses to the proper + * paravirtualized device. Basically what we need to know is how multiple + * 'disk' entries in a domU configuration file get mapped to emulated + * cmdk devices and to xdf devices. The 'disk' entry to xdf instance + * mappings we know because those are done within the Solaris xvdi code + * and the xpvd nexus driver. But the config to emulated devices mappings + * are handled entirely within the xen management tool chain and the + * hardware emulator. Since all the tools that establish these mappings + * live in dom0, dom0 should really supply us with this information, + * probably via the xenstore. Unfortunatly it doesn't so, since there's + * no good way to determine this mapping dynamically, this driver uses + * a hard coded set of static mappings. These mappings are hardware + * emulator specific because each different hardware emulator could have + * a different device tree with different cmdk device paths. This + * means that if we want to continue to use this static mapping approach + * to allow Solaris to run on different hardware emulators we'll have + * to analyze each of those emulators to determine what paths they + * use and hard code those paths into this driver. yech. This metadata + * really needs to be supplied to us by dom0. + * + * This driver access underlying xdf nodes. Unfortunatly, devices + * must create minor nodes during attach, and for disk devices to create + * minor nodes, they have to look at the label on the disk, so this means + * that disk drivers must be able to access a disk contents during + * attach. That means that this disk driver must be able to access + * underlying xdf nodes during attach. Unfortunatly, due to device tree + * locking restrictions, we cannot have an attach operation occuring on + * this device and then attempt to access another device which may + * cause another attach to occur in a different device tree branch + * since this could result in deadlock. Hence, this driver can only + * access xdf device nodes that we know are attached, and it can't use + * any ddi interfaces to access those nodes if those interfaces could + * trigger an attach of the xdf device. So this driver works around + * these restrictions by talking directly to xdf devices via + * xdf_hvm_hold(). This interface takes a pathname to an xdf device, + * and if that device is already attached then it returns the a held dip + * pointer for that device node. This prevents us from getting into + * deadlock situations, but now we need a mechanism to ensure that all + * the xdf device nodes this driver might access are attached before + * this driver tries to access them. This is accomplished via the + * hvmboot_rootconf() callback which is invoked just before root is + * mounted. hvmboot_rootconf() will attach xpvd and tell it to configure + * all xdf device visible to the system. All these xdf device nodes + * will also be marked with the "ddi-no-autodetach" property so that + * once they are configured, the will not be automatically unconfigured. + * The only way that they could be unconfigured is if the administrator + * explicitly attempts to unload required modules via rem_drv(1M) + * or modunload(1M). + */ + +/* + * 16 paritions + fdisk (see xdf.h) + */ +#define XDF_DEV2UNIT(dev) XDF_INST((getminor((dev)))) +#define XDF_DEV2PART(dev) XDF_PART((getminor((dev)))) + +#define OTYP_VALID(otyp) ((otyp == OTYP_BLK) || \ + (otyp == OTYP_CHR) || \ + (otyp == OTYP_LYR)) + +#define PV_CMDK_NODES 4 + +typedef struct hvm_to_pv { + char *h2p_hvm_path; + char *h2p_pv_path; +} hvm_to_pv_t; + +/* + */ +static hvm_to_pv_t pv_cmdk_h2p_xen_qemu[] = { + /* + * The paths mapping here are very specific to xen and qemu. When a + * domU is booted under xen in HVM mode, qemu is normally used to + * emulate up to four ide disks. These disks always have the four + * path listed below. To configure an emulated ide device, the + * xen domain configuration file normally has an entry that looks + * like this: + * disk = [ 'file:/foo.img,hda,w' ] + * + * The part we're interested in is the 'hda', which we'll call the + * xen disk device name here. The xen management tools (which parse + * the xen domain configuration file and launch qemu) makes the + * following assumptions about this value: + * hda == emulated ide disk 0 (ide bus 0, master) + * hdb == emulated ide disk 1 (ide bus 0, slave) + * hdc == emulated ide disk 2 (ide bus 1, master) + * hdd == emulated ide disk 3 (ide bus 1, slave) + * + * (Uncoincidentally, these xen disk device names actually map to + * the /dev filesystem names of ide disk devices in Linux. So in + * Linux /dev/hda is the first ide disk.) So for the first part of + * our mapping we've just hardcoded the cmdk paths that we know + * qemu will use. + * + * To understand the second half of the mapping (ie, the xdf device + * that each emulated cmdk device should be mapped two) we need to + * know the solaris device node address that will be assigned to + * each xdf device. (The device node address is the hex number that + * comes after the "xdf@" in the device path.) + * + * Normally when a domU is run in non-HVM mode, the xen disk device + * names in the xen domain configuration file are specified with + * integers instead of Linux device names. (for example, '0' would + * be used instead of 'hda'.) So in the non-HVM case we simply + * convert the xen disk device name (which is an interger) into a + * hex number and use it as the Solaris xdf device node address. + * But when we're running in HVM mode then we have a string for the + * xen disk device name, so we can't simply use that as a solaris + * device node address. Instead we fall back to using the xenstore + * device id for the xen disk device as the xdf device node address. + * The xdf device node address assignment happens in xvdi_init_dev(). + * + * So the question becomes, how do we know what the xenstore device + * id for emulated disk will be? Well, it turns out that since the + * xen management tools expect the disk device names to be Linux + * device names, those same management tools assign each disk a + * device id that matches the dev_t of the corresponding device + * under Linux. (Big shocker.) This xen device name-to-id mapping + * is currently all hard coded here: + * xen.hg/tools/python/xen/util/blkif.py`blkdev_name_to_number() + * + * So looking at the code above we can see the following xen disk + * device name to xenstore device id mappings: + * 'hda' --> 0x300 == 0t768 == ((3 * 256) + (0 * 64)) + * 'hdb' --> 0x340 == 0t832 == ((3 * 256) + (1 * 64)) + * 'hdc' --> 0x1600 == 0t5632 == ((22 * 256) + (0 * 64)) + * 'hdd' --> 0x1640 == 0t5696 == ((22 * 256) + (1 * 64)) + */ + { "/pci@0,0/pci-ide@1,1/ide@0/cmdk@0,0", "/xpvd/xdf@300" }, + { "/pci@0,0/pci-ide@1,1/ide@0/cmdk@1,0", "/xpvd/xdf@340" }, + { "/pci@0,0/pci-ide@1,1/ide@1/cmdk@0,0", "/xpvd/xdf@1600" }, + { "/pci@0,0/pci-ide@1,1/ide@1/cmdk@1,0", "/xpvd/xdf@1640" }, + { NULL, 0 } +}; + +typedef struct pv_cmdk { + dev_info_t *dk_dip; + cmlb_handle_t dk_cmlbhandle; + ddi_devid_t dk_devid; + kmutex_t dk_mutex; + dev_info_t *dk_xdf_dip; + dev_t dk_xdf_dev; + int dk_xdf_otyp_count[OTYPCNT][XDF_PEXT]; + ldi_handle_t dk_xdf_lh[XDF_PEXT]; +} pv_cmdk_t; + +/* + * Globals + */ +static void *pv_cmdk_state; +static major_t pv_cmdk_major; +static hvm_to_pv_t *pv_cmdk_h2p; + +/* + * Function prototypes for xdf callback functions + */ +extern int xdf_lb_getinfo(dev_info_t *, int, void *, void *); +extern int xdf_lb_rdwr(dev_info_t *, uchar_t, void *, diskaddr_t, size_t, + void *); + +static boolean_t +pv_cmdk_isopen_part(struct pv_cmdk *dkp, int part) +{ + int otyp; + + ASSERT(MUTEX_HELD(&dkp->dk_mutex)); + + for (otyp = 0; (otyp < OTYPCNT); otyp++) { + if (dkp->dk_xdf_otyp_count[otyp][part] != 0) + return (B_TRUE); + } + return (B_FALSE); +} + +/* + * Cmlb ops vectors, allows the cmlb module to directly access the entire + * pv_cmdk disk device without going through any partitioning layers. + */ +/*ARGSUSED*/ +static int +pv_cmdk_lb_rdwr(dev_info_t *dip, uchar_t cmd, void *bufaddr, + diskaddr_t start, size_t count, void *tg_cookie) +{ + int instance = ddi_get_instance(dip); + struct pv_cmdk *dkp = ddi_get_soft_state(pv_cmdk_state, instance); + + if (dkp == NULL) + return (ENXIO); + + return (xdf_lb_rdwr(dkp->dk_xdf_dip, cmd, bufaddr, start, count, + tg_cookie)); +} + +/*ARGSUSED*/ +static int +pv_cmdk_lb_getinfo(dev_info_t *dip, int cmd, void *arg, void *tg_cookie) +{ + int instance = ddi_get_instance(dip); + struct pv_cmdk *dkp = ddi_get_soft_state(pv_cmdk_state, instance); + int err; + + if (dkp == NULL) + return (ENXIO); + + if (cmd == TG_GETVIRTGEOM) { + cmlb_geom_t pgeom, *vgeomp; + diskaddr_t capacity; + + /* + * The native xdf driver doesn't support this ioctl. + * Intead of passing it on, emulate it here so that the + * results look the same as what we get for a real cmdk + * device. + * + * Get the real size of the device + */ + if ((err = xdf_lb_getinfo(dkp->dk_xdf_dip, + TG_GETPHYGEOM, &pgeom, tg_cookie)) != 0) + return (err); + capacity = pgeom.g_capacity; + + /* + * If the controller returned us something that doesn't + * really fit into an Int 13/function 8 geometry + * result, just fail the ioctl. See PSARC 1998/313. + */ + if (capacity >= (63 * 254 * 1024)) + return (EINVAL); + + vgeomp = (cmlb_geom_t *)arg; + vgeomp->g_capacity = capacity; + vgeomp->g_nsect = 63; + vgeomp->g_nhead = 254; + vgeomp->g_ncyl = capacity / (63 * 254); + vgeomp->g_acyl = 0; + vgeomp->g_secsize = 512; + vgeomp->g_intrlv = 1; + vgeomp->g_rpm = 3600; + return (0); + } + + return (xdf_lb_getinfo(dkp->dk_xdf_dip, cmd, arg, tg_cookie)); +} + +static cmlb_tg_ops_t pv_cmdk_lb_ops = { + TG_DK_OPS_VERSION_1, + pv_cmdk_lb_rdwr, + pv_cmdk_lb_getinfo +}; + +/* + * devid management functions + */ + +/* + * pv_cmdk_get_modser() is basically a local copy of + * cmdk_get_modser() modified to work without the dadk layer. + * (which the non-pv version of the cmdk driver uses.) + */ +static int +pv_cmdk_get_modser(struct pv_cmdk *dkp, int ioccmd, char *buf, int len) +{ + struct scsi_device *scsi_device; + opaque_t ctlobjp; + dadk_ioc_string_t strarg; + char *s; + char ch; + boolean_t ret; + int i; + int tb; + + strarg.is_buf = buf; + strarg.is_size = len; + scsi_device = ddi_get_driver_private(dkp->dk_dip); + ctlobjp = scsi_device->sd_address.a_hba_tran; + if (CTL_IOCTL(ctlobjp, + ioccmd, (uintptr_t)&strarg, FNATIVE | FKIOCTL) != 0) + return (0); + + /* + * valid model/serial string must contain a non-zero non-space + * trim trailing spaces/NULL + */ + ret = B_FALSE; + s = buf; + for (i = 0; i < strarg.is_size; i++) { + ch = *s++; + if (ch != ' ' && ch != '\0') + tb = i + 1; + if (ch != ' ' && ch != '\0' && ch != '0') + ret = B_TRUE; + } + + if (ret == B_FALSE) + return (0); + + return (tb); +} + +/* + * pv_cmdk_devid_modser() is basically a copy of cmdk_devid_modser() + * that has been modified to use local pv cmdk driver functions. + * + * Build a devid from the model and serial number + * Return DDI_SUCCESS or DDI_FAILURE. + */ +static int +pv_cmdk_devid_modser(struct pv_cmdk *dkp) +{ + int rc = DDI_FAILURE; + char *hwid; + int modlen; + int serlen; + + /* + * device ID is a concatenation of model number, '=', serial number. + */ + hwid = kmem_alloc(CMDK_HWIDLEN, KM_SLEEP); + modlen = pv_cmdk_get_modser(dkp, DIOCTL_GETMODEL, hwid, CMDK_HWIDLEN); + if (modlen == 0) + goto err; + + hwid[modlen++] = '='; + serlen = pv_cmdk_get_modser(dkp, DIOCTL_GETSERIAL, + hwid + modlen, CMDK_HWIDLEN - modlen); + if (serlen == 0) + goto err; + + hwid[modlen + serlen] = 0; + + /* Initialize the device ID, trailing NULL not included */ + rc = ddi_devid_init(dkp->dk_dip, DEVID_ATA_SERIAL, modlen + serlen, + hwid, (ddi_devid_t *)&dkp->dk_devid); + if (rc != DDI_SUCCESS) + goto err; + + kmem_free(hwid, CMDK_HWIDLEN); + return (DDI_SUCCESS); + +err: + kmem_free(hwid, CMDK_HWIDLEN); + return (DDI_FAILURE); +} + +/* + * pv_cmdk_devid_read() is basically a local copy of + * cmdk_devid_read() modified to work without the dadk layer. + * (which the non-pv version of the cmdk driver uses.) + * + * Read a devid from on the first block of the last track of + * the last cylinder. Make sure what we read is a valid devid. + * Return DDI_SUCCESS or DDI_FAILURE. + */ +static int +pv_cmdk_devid_read(struct pv_cmdk *dkp) +{ + diskaddr_t blk; + struct dk_devid *dkdevidp; + uint_t *ip, chksum; + int i; + + if (cmlb_get_devid_block(dkp->dk_cmlbhandle, &blk, 0) != 0) + return (DDI_FAILURE); + + dkdevidp = kmem_zalloc(NBPSCTR, KM_SLEEP); + if (pv_cmdk_lb_rdwr(dkp->dk_dip, + TG_READ, dkdevidp, blk, NBPSCTR, NULL) != 0) + goto err; + + /* Validate the revision */ + if ((dkdevidp->dkd_rev_hi != DK_DEVID_REV_MSB) || + (dkdevidp->dkd_rev_lo != DK_DEVID_REV_LSB)) + goto err; + + /* Calculate the checksum */ + chksum = 0; + ip = (uint_t *)dkdevidp; + for (i = 0; i < ((NBPSCTR - sizeof (int))/sizeof (int)); i++) + chksum ^= ip[i]; + if (DKD_GETCHKSUM(dkdevidp) != chksum) + goto err; + + /* Validate the device id */ + if (ddi_devid_valid((ddi_devid_t)dkdevidp->dkd_devid) != DDI_SUCCESS) + goto err; + + /* keep a copy of the device id */ + i = ddi_devid_sizeof((ddi_devid_t)dkdevidp->dkd_devid); + dkp->dk_devid = kmem_alloc(i, KM_SLEEP); + bcopy(dkdevidp->dkd_devid, dkp->dk_devid, i); + kmem_free(dkdevidp, NBPSCTR); + return (DDI_SUCCESS); + +err: + kmem_free(dkdevidp, NBPSCTR); + return (DDI_FAILURE); +} + +/* + * pv_cmdk_devid_fabricate() is basically a local copy of + * cmdk_devid_fabricate() modified to work without the dadk layer. + * (which the non-pv version of the cmdk driver uses.) + * + * Create a devid and write it on the first block of the last track of + * the last cylinder. + * Return DDI_SUCCESS or DDI_FAILURE. + */ +static int +pv_cmdk_devid_fabricate(struct pv_cmdk *dkp) +{ + ddi_devid_t devid = NULL; /* devid made by ddi_devid_init */ + struct dk_devid *dkdevidp = NULL; /* devid struct stored on disk */ + diskaddr_t blk; + uint_t *ip, chksum; + int i; + + if (cmlb_get_devid_block(dkp->dk_cmlbhandle, &blk, 0) != 0) + return (DDI_FAILURE); + + if (ddi_devid_init(dkp->dk_dip, DEVID_FAB, 0, NULL, &devid) != + DDI_SUCCESS) + return (DDI_FAILURE); + + /* allocate a buffer */ + dkdevidp = (struct dk_devid *)kmem_zalloc(NBPSCTR, KM_SLEEP); + + /* Fill in the revision */ + dkdevidp->dkd_rev_hi = DK_DEVID_REV_MSB; + dkdevidp->dkd_rev_lo = DK_DEVID_REV_LSB; + + /* Copy in the device id */ + i = ddi_devid_sizeof(devid); + if (i > DK_DEVID_SIZE) + goto err; + bcopy(devid, dkdevidp->dkd_devid, i); + + /* Calculate the chksum */ + chksum = 0; + ip = (uint_t *)dkdevidp; + for (i = 0; i < ((NBPSCTR - sizeof (int))/sizeof (int)); i++) + chksum ^= ip[i]; + + /* Fill in the checksum */ + DKD_FORMCHKSUM(chksum, dkdevidp); + + if (pv_cmdk_lb_rdwr(dkp->dk_dip, + TG_WRITE, dkdevidp, blk, NBPSCTR, NULL) != 0) + goto err; + + kmem_free(dkdevidp, NBPSCTR); + + dkp->dk_devid = devid; + return (DDI_SUCCESS); + +err: + if (dkdevidp != NULL) + kmem_free(dkdevidp, NBPSCTR); + if (devid != NULL) + ddi_devid_free(devid); + return (DDI_FAILURE); +} + +/* + * pv_cmdk_devid_setup() is basically a local copy ofcmdk_devid_setup() + * that has been modified to use local pv cmdk driver functions. + * + * Create and register the devid. + * There are 4 different ways we can get a device id: + * 1. Already have one - nothing to do + * 2. Build one from the drive's model and serial numbers + * 3. Read one from the disk (first sector of last track) + * 4. Fabricate one and write it on the disk. + * If any of these succeeds, register the deviceid + */ +static void +pv_cmdk_devid_setup(struct pv_cmdk *dkp) +{ + int rc; + + /* Try options until one succeeds, or all have failed */ + + /* 1. All done if already registered */ + + if (dkp->dk_devid != NULL) + return; + + /* 2. Build a devid from the model and serial number */ + rc = pv_cmdk_devid_modser(dkp); + if (rc != DDI_SUCCESS) { + /* 3. Read devid from the disk, if present */ + rc = pv_cmdk_devid_read(dkp); + + /* 4. otherwise make one up and write it on the disk */ + if (rc != DDI_SUCCESS) + rc = pv_cmdk_devid_fabricate(dkp); + } + + /* If we managed to get a devid any of the above ways, register it */ + if (rc == DDI_SUCCESS) + (void) ddi_devid_register(dkp->dk_dip, dkp->dk_devid); +} + +/* + * Local Functions + */ +static int +pv_cmdk_iodone(struct buf *bp) +{ + struct buf *bp_orig = bp->b_chain; + + /* Propegate back the io results */ + bp_orig->b_resid = bp->b_resid; + bioerror(bp_orig, geterror(bp)); + biodone(bp_orig); + + freerbuf(bp); + return (0); +} + +static int +pv_cmdkstrategy(struct buf *bp) +{ + dev_t dev = bp->b_edev; + int instance = XDF_DEV2UNIT(dev); + int part = XDF_DEV2PART(dev); + struct pv_cmdk *dkp = ddi_get_soft_state(pv_cmdk_state, instance); + dev_t xdf_devt; + struct buf *bp_clone; + + /* + * Sanity checks that the dev_t associated with the buf we were + * passed actually corresponds us and that the partition we're + * trying to access is actually open. On debug kernels we'll + * panic and on non-debug kernels we'll return failure. + */ + ASSERT(getmajor(dev) == pv_cmdk_major); + if (getmajor(dev) != pv_cmdk_major) + goto err; + + mutex_enter(&dkp->dk_mutex); + ASSERT(pv_cmdk_isopen_part(dkp, part)); + if (!pv_cmdk_isopen_part(dkp, part)) { + mutex_exit(&dkp->dk_mutex); + goto err; + } + mutex_exit(&dkp->dk_mutex); + + /* clone this buffer */ + xdf_devt = dkp->dk_xdf_dev | part; + bp_clone = bioclone(bp, 0, bp->b_bcount, xdf_devt, bp->b_blkno, + pv_cmdk_iodone, NULL, KM_SLEEP); + bp_clone->b_chain = bp; + + /* + * If we're being invoked on behalf of the physio() call in + * pv_cmdk_dioctl_rwcmd() then b_private will be set to + * XB_SLICE_NONE and we need to propegate this flag into the + * cloned buffer so that the xdf driver will see it. + */ + if (bp->b_private == (void *)XB_SLICE_NONE) + bp_clone->b_private = (void *)XB_SLICE_NONE; + + /* + * Pass on the cloned buffer. Note that we don't bother to check + * for failure because the xdf strategy routine will have to + * invoke biodone() if it wants to return an error, which means + * that the pv_cmdk_iodone() callback will get invoked and it + * will propegate the error back up the stack and free the cloned + * buffer. + */ + ASSERT(dkp->dk_xdf_lh[part] != NULL); + return (ldi_strategy(dkp->dk_xdf_lh[part], bp_clone)); + +err: + bioerror(bp, ENXIO); + bp->b_resid = bp->b_bcount; + biodone(bp); + return (0); +} + +/*ARGSUSED*/ +static int +pv_cmdkread(dev_t dev, struct uio *uio, cred_t *credp) +{ + int instance = XDF_DEV2UNIT(dev); + int part = XDF_DEV2PART(dev); + struct pv_cmdk *dkp = ddi_get_soft_state(pv_cmdk_state, instance); + + return (ldi_read(dkp->dk_xdf_lh[part], uio, credp)); +} + +/*ARGSUSED*/ +static int +pv_cmdkwrite(dev_t dev, struct uio *uio, cred_t *credp) +{ + int instance = XDF_DEV2UNIT(dev); + int part = XDF_DEV2PART(dev); + struct pv_cmdk *dkp = ddi_get_soft_state(pv_cmdk_state, instance); + + return (ldi_write(dkp->dk_xdf_lh[part], uio, credp)); +} + +/*ARGSUSED*/ +static int +pv_cmdkaread(dev_t dev, struct aio_req *aio, cred_t *credp) +{ + int instance = XDF_DEV2UNIT(dev); + int part = XDF_DEV2PART(dev); + struct pv_cmdk *dkp = ddi_get_soft_state(pv_cmdk_state, instance); + return (ldi_aread(dkp->dk_xdf_lh[part], aio, credp)); +} + +/*ARGSUSED*/ +static int +pv_cmdkawrite(dev_t dev, struct aio_req *aio, cred_t *credp) +{ + int instance = XDF_DEV2UNIT(dev); + int part = XDF_DEV2PART(dev); + struct pv_cmdk *dkp = ddi_get_soft_state(pv_cmdk_state, instance); + return (ldi_awrite(dkp->dk_xdf_lh[part], aio, credp)); +} + +static int +pv_cmdkdump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk) +{ + int instance = XDF_DEV2UNIT(dev); + int part = XDF_DEV2PART(dev); + struct pv_cmdk *dkp = ddi_get_soft_state(pv_cmdk_state, instance); + + return (ldi_dump(dkp->dk_xdf_lh[part], addr, blkno, nblk)); +} + +/* + * pv_rwcmd_copyin() is a duplicate of rwcmd_copyin(). + */ +static int +pv_rwcmd_copyin(struct dadkio_rwcmd *rwcmdp, caddr_t inaddr, int flag) +{ + switch (ddi_model_convert_from(flag)) { + case DDI_MODEL_ILP32: { + struct dadkio_rwcmd32 cmd32; + + if (ddi_copyin(inaddr, &cmd32, + sizeof (struct dadkio_rwcmd32), flag)) { + return (EFAULT); + } + + rwcmdp->cmd = cmd32.cmd; + rwcmdp->flags = cmd32.flags; + rwcmdp->blkaddr = (daddr_t)cmd32.blkaddr; + rwcmdp->buflen = cmd32.buflen; + rwcmdp->bufaddr = (caddr_t)(intptr_t)cmd32.bufaddr; + /* + * Note: we do not convert the 'status' field, + * as it should not contain valid data at this + * point. + */ + bzero(&rwcmdp->status, sizeof (rwcmdp->status)); + break; + } + case DDI_MODEL_NONE: { + if (ddi_copyin(inaddr, rwcmdp, + sizeof (struct dadkio_rwcmd), flag)) { + return (EFAULT); + } + } + } + return (0); +} + +/* + * pv_rwcmd_copyout() is a duplicate of rwcmd_copyout(). + */ +static int +pv_rwcmd_copyout(struct dadkio_rwcmd *rwcmdp, caddr_t outaddr, int flag) +{ + switch (ddi_model_convert_from(flag)) { + case DDI_MODEL_ILP32: { + struct dadkio_rwcmd32 cmd32; + + cmd32.cmd = rwcmdp->cmd; + cmd32.flags = rwcmdp->flags; + cmd32.blkaddr = rwcmdp->blkaddr; + cmd32.buflen = rwcmdp->buflen; + ASSERT64(((uintptr_t)rwcmdp->bufaddr >> 32) == 0); + cmd32.bufaddr = (caddr32_t)(uintptr_t)rwcmdp->bufaddr; + + cmd32.status.status = rwcmdp->status.status; + cmd32.status.resid = rwcmdp->status.resid; + cmd32.status.failed_blk_is_valid = + rwcmdp->status.failed_blk_is_valid; + cmd32.status.failed_blk = rwcmdp->status.failed_blk; + cmd32.status.fru_code_is_valid = + rwcmdp->status.fru_code_is_valid; + cmd32.status.fru_code = rwcmdp->status.fru_code; + + bcopy(rwcmdp->status.add_error_info, + cmd32.status.add_error_info, DADKIO_ERROR_INFO_LEN); + + if (ddi_copyout(&cmd32, outaddr, + sizeof (struct dadkio_rwcmd32), flag)) + return (EFAULT); + break; + } + case DDI_MODEL_NONE: { + if (ddi_copyout(rwcmdp, outaddr, + sizeof (struct dadkio_rwcmd), flag)) + return (EFAULT); + } + } + return (0); +} + +static void +pv_cmdkmin(struct buf *bp) +{ + if (bp->b_bcount > DK_MAXRECSIZE) + bp->b_bcount = DK_MAXRECSIZE; +} + +static int +pv_cmdk_dioctl_rwcmd(dev_t dev, intptr_t arg, int flag) +{ + struct dadkio_rwcmd *rwcmdp; + struct iovec aiov; + struct uio auio; + struct buf *bp; + int rw, status; + + rwcmdp = kmem_alloc(sizeof (struct dadkio_rwcmd), KM_SLEEP); + status = pv_rwcmd_copyin(rwcmdp, (caddr_t)arg, flag); + + if (status != 0) + goto out; + + switch (rwcmdp->cmd) { + case DADKIO_RWCMD_READ: + case DADKIO_RWCMD_WRITE: + break; + default: + status = EINVAL; + goto out; + } + + bzero((caddr_t)&aiov, sizeof (struct iovec)); + aiov.iov_base = rwcmdp->bufaddr; + aiov.iov_len = rwcmdp->buflen; + + bzero((caddr_t)&auio, sizeof (struct uio)); + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_loffset = (offset_t)rwcmdp->blkaddr * (offset_t)XB_BSIZE; + auio.uio_resid = rwcmdp->buflen; + auio.uio_segflg = (flag & FKIOCTL) ? UIO_SYSSPACE : UIO_USERSPACE; + + /* + * Tell the xdf driver that this I/O request is using an absolute + * offset. + */ + bp = getrbuf(KM_SLEEP); + bp->b_private = (void *)XB_SLICE_NONE; + + rw = ((rwcmdp->cmd == DADKIO_RWCMD_WRITE) ? B_WRITE : B_READ); + status = physio(pv_cmdkstrategy, bp, dev, rw, pv_cmdkmin, &auio); + + biofini(bp); + kmem_free(bp, sizeof (buf_t)); + + if (status == 0) + status = pv_rwcmd_copyout(rwcmdp, (caddr_t)arg, flag); + +out: + kmem_free(rwcmdp, sizeof (struct dadkio_rwcmd)); + return (status); +} + +static int +pv_cmdkioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp, + int *rvalp) +{ + int instance = XDF_DEV2UNIT(dev); + int part = XDF_DEV2PART(dev); + struct pv_cmdk *dkp = ddi_get_soft_state(pv_cmdk_state, instance); + int err; + + switch (cmd) { + default: + return (ldi_ioctl(dkp->dk_xdf_lh[part], + cmd, arg, flag, credp, rvalp)); + case DKIOCGETWCE: + case DKIOCSETWCE: + return (EIO); + case DKIOCADDBAD: { + /* + * This is for ata/ide bad block handling. It is supposed + * to cause the driver to re-read the bad block list and + * alternate map after it has been updated. Our driver + * will refuse to attach to any disk which has a bad blocks + * list defined, so there really isn't much to do here. + */ + return (0); + } + case DKIOCGETDEF: { + /* + * I can't actually find any code that utilizes this ioctl, + * hence we're leaving it explicitly unimplemented. + */ + ASSERT("ioctl cmd unsupported by pv_cmdk: DKIOCGETDEF"); + return (EIO); + } + case DIOCTL_RWCMD: { + /* + * This just seems to just be an alternate interface for + * reading and writing the disk. Great, another way to + * do the same thing... + */ + return (pv_cmdk_dioctl_rwcmd(dev, arg, flag)); + } + case DKIOCINFO: { + dev_info_t *dip = dkp->dk_dip; + struct dk_cinfo info; + + /* Pass on the ioctl request, save the response */ + if ((err = ldi_ioctl(dkp->dk_xdf_lh[part], + cmd, (intptr_t)&info, FKIOCTL, credp, rvalp)) != 0) + return (err); + + /* Update controller info */ + info.dki_cnum = ddi_get_instance(ddi_get_parent(dip)); + (void) strlcpy(info.dki_cname, + ddi_get_name(ddi_get_parent(dip)), sizeof (info.dki_cname)); + + /* Update unit info. */ + if (info.dki_ctype == DKC_VBD) + info.dki_ctype = DKC_DIRECT; + info.dki_unit = instance; + (void) strlcpy(info.dki_dname, + ddi_driver_name(dip), sizeof (info.dki_dname)); + info.dki_addr = 1; + + if (ddi_copyout(&info, (void *)arg, sizeof (info), flag)) + return (EFAULT); + return (0); + } + } /* switch (cmd) */ + /*NOTREACHED*/ +} + +/*ARGSUSED*/ +static int +pv_cmdkopen(dev_t *dev_p, int flag, int otyp, cred_t *credp) +{ + ldi_ident_t li; + dev_t dev = *dev_p; + int instance = XDF_DEV2UNIT(dev); + int part = XDF_DEV2PART(dev); + struct pv_cmdk *dkp = ddi_get_soft_state(pv_cmdk_state, instance); + dev_t xdf_devt = dkp->dk_xdf_dev | part; + int err = 0; + + if ((otyp < 0) || (otyp >= OTYPCNT)) + return (EINVAL); + + /* allocate an ldi handle */ + VERIFY(ldi_ident_from_dev(*dev_p, &li) == 0); + + mutex_enter(&dkp->dk_mutex); + + /* + * We translate all device opens (chr, blk, and lyr) into + * block device opens. Why? Because for all the opens that + * come through this driver, we only keep around one LDI handle. + * So that handle can only be of one open type. The reason + * that we choose the block interface for this is that to use + * the block interfaces for a device the system needs to allocatex + * buf_ts, which are associated with system memory which can act + * as a cache for device data. So normally when a block device + * is closed the system will ensure that all these pages get + * flushed out of memory. But if we were to open the device + * as a character device, then when we went to close the underlying + * device (even if we had invoked the block interfaces) any data + * remaining in memory wouldn't necessairly be flushed out + * before the device was closed. + */ + if (dkp->dk_xdf_lh[part] == NULL) { + ASSERT(!pv_cmdk_isopen_part(dkp, part)); + + err = ldi_open_by_dev(&xdf_devt, OTYP_BLK, flag, credp, + &dkp->dk_xdf_lh[part], li); + + if (err != 0) { + mutex_exit(&dkp->dk_mutex); + ldi_ident_release(li); + return (err); + } + + /* Disk devices really shouldn't clone */ + ASSERT(xdf_devt == (dkp->dk_xdf_dev | part)); + } else { + ldi_handle_t lh_tmp; + + ASSERT(pv_cmdk_isopen_part(dkp, part)); + + /* do ldi open/close to get flags and cred check */ + err = ldi_open_by_dev(&xdf_devt, OTYP_BLK, flag, credp, + &lh_tmp, li); + if (err != 0) { + mutex_exit(&dkp->dk_mutex); + ldi_ident_release(li); + return (err); + } + + /* Disk devices really shouldn't clone */ + ASSERT(xdf_devt == (dkp->dk_xdf_dev | part)); + (void) ldi_close(lh_tmp, flag, credp); + } + ldi_ident_release(li); + + dkp->dk_xdf_otyp_count[otyp][part]++; + + mutex_exit(&dkp->dk_mutex); + return (0); +} + +/*ARGSUSED*/ +static int +pv_cmdkclose(dev_t dev, int flag, int otyp, cred_t *credp) +{ + int instance = XDF_DEV2UNIT(dev); + int part = XDF_DEV2PART(dev); + struct pv_cmdk *dkp = ddi_get_soft_state(pv_cmdk_state, instance); + int err = 0; + + ASSERT((otyp >= 0) && otyp < OTYPCNT); + + /* + * Sanity check that that the dev_t specified corresponds to this + * driver and that the device is actually open. On debug kernels we'll + * panic and on non-debug kernels we'll return failure. + */ + ASSERT(getmajor(dev) == pv_cmdk_major); + if (getmajor(dev) != pv_cmdk_major) + return (ENXIO); + + mutex_enter(&dkp->dk_mutex); + ASSERT(pv_cmdk_isopen_part(dkp, part)); + if (!pv_cmdk_isopen_part(dkp, part)) { + mutex_exit(&dkp->dk_mutex); + return (ENXIO); + } + + ASSERT(dkp->dk_xdf_lh[part] != NULL); + ASSERT(dkp->dk_xdf_otyp_count[otyp][part] > 0); + if (otyp == OTYP_LYR) { + dkp->dk_xdf_otyp_count[otyp][part]--; + } else { + dkp->dk_xdf_otyp_count[otyp][part] = 0; + } + + if (!pv_cmdk_isopen_part(dkp, part)) { + err = ldi_close(dkp->dk_xdf_lh[part], flag, credp); + dkp->dk_xdf_lh[part] = NULL; + } + + mutex_exit(&dkp->dk_mutex); + + return (err); +} + +static int +pv_cmdk_getpgeom(dev_info_t *dip, cmlb_geom_t *pgeom) +{ + struct scsi_device *scsi_device; + struct tgdk_geom tgdk_geom; + opaque_t ctlobjp; + int err; + + scsi_device = ddi_get_driver_private(dip); + ctlobjp = scsi_device->sd_address.a_hba_tran; + if ((err = CTL_IOCTL(ctlobjp, + DIOCTL_GETPHYGEOM, (uintptr_t)&tgdk_geom, FKIOCTL)) != 0) + return (err); + + /* This driver won't work if this isn't true */ + ASSERT(tgdk_geom.g_secsiz == XB_BSIZE); + + pgeom->g_ncyl = tgdk_geom.g_cyl; + pgeom->g_acyl = tgdk_geom.g_acyl; + pgeom->g_nhead = tgdk_geom.g_head; + pgeom->g_nsect = tgdk_geom.g_sec; + pgeom->g_secsize = tgdk_geom.g_secsiz; + pgeom->g_capacity = tgdk_geom.g_cap; + pgeom->g_intrlv = 1; + pgeom->g_rpm = 3600; + return (0); +} + +/* + * pv_cmdk_bb_check() checks for the existance of bad blocks mappings in + * the alternate partition/slice. Returns B_FALSE is there are no bad + * block mappins found, and B_TRUE is there are bad block mappins found. + */ +static boolean_t +pv_cmdk_bb_check(struct pv_cmdk *dkp) +{ + struct alts_parttbl *ap; + diskaddr_t nblocks, blk; + uint32_t altused, altbase, altlast; + uint16_t vtoctag; + int alts; + + /* find slice with V_ALTSCTR tag */ + for (alts = 0; alts < NDKMAP; alts++) { + + if (cmlb_partinfo(dkp->dk_cmlbhandle, alts, + &nblocks, &blk, NULL, &vtoctag, 0) != 0) { + /* no partition table exists */ + return (B_FALSE); + } + + if ((vtoctag == V_ALTSCTR) && (nblocks > 1)) + break; + } + if (alts >= NDKMAP) + return (B_FALSE); /* no V_ALTSCTR slice defined */ + + /* read in ALTS label block */ + ap = (struct alts_parttbl *)kmem_zalloc(NBPSCTR, KM_SLEEP); + if (pv_cmdk_lb_rdwr(dkp->dk_dip, + TG_READ, ap, blk, NBPSCTR, NULL) != 0) + goto err; + + altused = ap->alts_ent_used; /* number of BB entries */ + altbase = ap->alts_ent_base; /* blk offset from begin slice */ + altlast = ap->alts_ent_end; /* blk offset to last block */ + + if ((altused == 0) || (altbase < 1) || + (altbase > altlast) || (altlast >= nblocks)) + goto err; + + /* we found bad block mappins */ + kmem_free(ap, NBPSCTR); + return (B_TRUE); + +err: + kmem_free(ap, NBPSCTR); + return (B_FALSE); +} + +/* + * Autoconfiguration Routines + */ +static int +pv_cmdkattach(dev_info_t *dip, ddi_attach_cmd_t cmd) +{ + int instance = ddi_get_instance(dip); + dev_info_t *xdf_dip = NULL; + struct pv_cmdk *dkp; + cmlb_geom_t pgeom; + char *path; + int i; + + if (cmd != DDI_ATTACH) + return (DDI_FAILURE); + + /* + * This cmdk device layers on top of an xdf device. So the first + * thing we need to do is determine which xdf device instance this + * cmdk instance should be layered on top of. + */ + path = kmem_alloc(MAXPATHLEN, KM_SLEEP); + (void) ddi_pathname(dip, path); + for (i = 0; pv_cmdk_h2p[i].h2p_hvm_path != NULL; i++) { + if (strcmp(pv_cmdk_h2p[i].h2p_hvm_path, path) == 0) + break; + } + kmem_free(path, MAXPATHLEN); + + if (pv_cmdk_h2p[i].h2p_hvm_path == NULL) { + /* + * UhOh. We don't know what xdf instance this cmdk device + * should be mapped to. + */ + return (DDI_FAILURE); + } + + /* Check if this device exists */ + xdf_dip = xdf_hvm_hold(pv_cmdk_h2p[i].h2p_pv_path); + if (xdf_dip == NULL) + return (DDI_FAILURE); + + /* allocate and initialize our state structure */ + (void) ddi_soft_state_zalloc(pv_cmdk_state, instance); + dkp = ddi_get_soft_state(pv_cmdk_state, instance); + mutex_init(&dkp->dk_mutex, NULL, MUTEX_DRIVER, NULL); + dkp->dk_dip = dip; + dkp->dk_xdf_dip = xdf_dip; + dkp->dk_xdf_dev = makedevice(ddi_driver_major(xdf_dip), + XDF_MINOR(ddi_get_instance(xdf_dip), 0)); + + ASSERT((dkp->dk_xdf_dev & XDF_PMASK) == 0); + + /* + * GROSS HACK ALERT! GROSS HACK ALERT! + * + * Before we can initialize the cmlb layer, we have to tell the + * underlying xdf device what it's physical geometry should be. + * See the block comments at the top of this file for more info. + */ + if ((pv_cmdk_getpgeom(dip, &pgeom) != 0) || + (xdf_hvm_setpgeom(dkp->dk_xdf_dip, &pgeom) != 0)) { + ddi_release_devi(dkp->dk_xdf_dip); + mutex_destroy(&dkp->dk_mutex); + ddi_soft_state_free(pv_cmdk_state, instance); + return (DDI_FAILURE); + } + + /* create kstat for iostat(1M) */ + if (xdf_kstat_create(dkp->dk_xdf_dip, "cmdk", instance) != 0) { + ddi_release_devi(dkp->dk_xdf_dip); + mutex_destroy(&dkp->dk_mutex); + ddi_soft_state_free(pv_cmdk_state, instance); + return (DDI_FAILURE); + } + + /* + * Force the xdf front end driver to connect to the backend. From + * the solaris device tree perspective, the xdf driver devinfo node + * is already in the ATTACHED state. (Otherwise xdf_hvm_hold() + * would not have returned a dip.) But this doesn't mean that the + * xdf device has actually established a connection to it's back + * end driver. For us to be able to access the xdf device it needs + * to be connected. There are two ways to force the xdf driver to + * connect to the backend device. + */ + if (xdf_hvm_connect(dkp->dk_xdf_dip) != 0) { + cmn_err(CE_WARN, + "pv driver failed to connect: %s", + pv_cmdk_h2p[i].h2p_pv_path); + xdf_kstat_delete(dkp->dk_xdf_dip); + ddi_release_devi(dkp->dk_xdf_dip); + mutex_destroy(&dkp->dk_mutex); + ddi_soft_state_free(pv_cmdk_state, instance); + return (DDI_FAILURE); + } + + /* + * Initalize cmlb. Note that for partition information cmlb + * will access the underly xdf disk device directly via + * pv_cmdk_lb_rdwr() and pv_cmdk_lb_getinfo(). There are no + * layered driver handles associated with this access because + * it is a direct disk access that doesn't go through + * any of the device nodes exported by the xdf device (since + * all exported device nodes only reflect the portion of + * the device visible via the partition/slice that the node + * is associated with.) So while not observable via the LDI, + * this direct disk access is ok since we're actually holding + * the target device. + */ + cmlb_alloc_handle((cmlb_handle_t *)&dkp->dk_cmlbhandle); + if (cmlb_attach(dkp->dk_dip, &pv_cmdk_lb_ops, + DTYPE_DIRECT, /* device_type */ + 0, /* not removable */ + 0, /* not hot pluggable */ + DDI_NT_BLOCK, + CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT, /* mimic cmdk */ + dkp->dk_cmlbhandle, 0) != 0) { + cmlb_free_handle(&dkp->dk_cmlbhandle); + xdf_kstat_delete(dkp->dk_xdf_dip); + ddi_release_devi(dkp->dk_xdf_dip); + mutex_destroy(&dkp->dk_mutex); + ddi_soft_state_free(pv_cmdk_state, instance); + return (DDI_FAILURE); + } + + if (pv_cmdk_bb_check(dkp)) { + cmn_err(CE_WARN, + "pv cmdk disks with bad blocks are unsupported: %s", + pv_cmdk_h2p[i].h2p_hvm_path); + + cmlb_detach(dkp->dk_cmlbhandle, 0); + cmlb_free_handle(&dkp->dk_cmlbhandle); + xdf_kstat_delete(dkp->dk_xdf_dip); + ddi_release_devi(dkp->dk_xdf_dip); + mutex_destroy(&dkp->dk_mutex); + ddi_soft_state_free(pv_cmdk_state, instance); + return (DDI_FAILURE); + } + + /* setup devid string */ + pv_cmdk_devid_setup(dkp); + + /* Calling validate will create minor nodes according to disk label */ + (void) cmlb_validate(dkp->dk_cmlbhandle, 0, 0); + + /* + * Add a zero-length attribute to tell the world we support + * kernel ioctls (for layered drivers). + */ + (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, + DDI_KERNEL_IOCTL, NULL, 0); + + /* Have the system report any newly created device nodes */ + ddi_report_dev(dip); + + return (DDI_SUCCESS); +} + +static int +pv_cmdkdetach(dev_info_t *dip, ddi_detach_cmd_t cmd) +{ + int instance = ddi_get_instance(dip); + struct pv_cmdk *dkp = ddi_get_soft_state(pv_cmdk_state, instance); + + if (cmd != DDI_DETACH) + return (DDI_FAILURE); + + ASSERT(MUTEX_NOT_HELD(&dkp->dk_mutex)); + + ddi_devid_unregister(dip); + if (dkp->dk_devid) + ddi_devid_free(dkp->dk_devid); + cmlb_detach(dkp->dk_cmlbhandle, 0); + cmlb_free_handle(&dkp->dk_cmlbhandle); + mutex_destroy(&dkp->dk_mutex); + xdf_kstat_delete(dkp->dk_xdf_dip); + ddi_release_devi(dkp->dk_xdf_dip); + ddi_soft_state_free(pv_cmdk_state, instance); + ddi_prop_remove_all(dip); + + return (DDI_SUCCESS); +} + +/*ARGSUSED*/ +static int +pv_cmdk_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, + void **result) +{ + dev_t dev = (dev_t)arg; + int instance = XDF_DEV2UNIT(dev); + struct pv_cmdk *dkp = ddi_get_soft_state(pv_cmdk_state, instance); + + switch (infocmd) { + case DDI_INFO_DEVT2DEVINFO: + if (dkp == NULL) + return (DDI_FAILURE); + *result = (void *)dkp->dk_dip; + break; + case DDI_INFO_DEVT2INSTANCE: + *result = (void *)(intptr_t)instance; + break; + default: + return (DDI_FAILURE); + } + return (DDI_SUCCESS); +} + +static int +pv_cmdk_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, + int flags, char *name, caddr_t valuep, int *lengthp) +{ + int instance = ddi_get_instance(dip); + struct pv_cmdk *dkp = ddi_get_soft_state(pv_cmdk_state, instance); + dev_info_t *xdf_dip; + dev_t xdf_devt; + int err; + + /* + * Sanity check that if a dev_t or dip were specified that they + * correspond to this device driver. On debug kernels we'll + * panic and on non-debug kernels we'll return failure. + */ + ASSERT(ddi_driver_major(dip) == pv_cmdk_major); + ASSERT((dev == DDI_DEV_T_ANY) || (getmajor(dev) == pv_cmdk_major)); + if ((ddi_driver_major(dip) != pv_cmdk_major) || + ((dev != DDI_DEV_T_ANY) && (getmajor(dev) != pv_cmdk_major))) + return (DDI_PROP_NOT_FOUND); + + /* + * This property lookup might be associated with a device node + * that is not yet attached, if so pass it onto ddi_prop_op(). + */ + if (dkp == NULL) + return (ddi_prop_op(dev, dip, prop_op, flags, + name, valuep, lengthp)); + + /* + * Make sure we only lookup static properties. + * + * If there are static properties of the underlying xdf driver + * that we want to mirror, then we'll have to explicity look them + * up and define them during attach. There are a few reasons + * for this. Most importantly, most static properties are typed + * and all dynamic properties are untyped, ie, for dynamic + * properties the caller must know the type of the property and + * how to interpret the value of the property. the prop_op drivedr + * entry point is only designed for returning dynamic/untyped + * properties, so if we were to attempt to lookup and pass back + * static properties of the underlying device here then we would + * be losing the type information for those properties. Another + * reason we don't want to pass on static property requests is that + * static properties are enumerable in the device tree, where as + * dynamic ones are not. + */ + flags |= DDI_PROP_DYNAMIC; + + /* + * We can't use the ldi here to access the underlying device because + * the ldi actually opens the device, and that open might fail if the + * device has already been opened with the FEXCL flag. If we used + * the ldi here, it would also be possible for some other caller + * to try open the device with the FEXCL flag and get a failure + * back because we have it open to do a property query. + * + * Instad we'll grab a hold on the target dip and query the + * property directly. + */ + mutex_enter(&dkp->dk_mutex); + + if ((xdf_dip = dkp->dk_xdf_dip) == NULL) { + mutex_exit(&dkp->dk_mutex); + return (DDI_PROP_NOT_FOUND); + } + e_ddi_hold_devi(xdf_dip); + + /* figure out the dev_t we're going to pass on down */ + if (dev == DDI_DEV_T_ANY) { + xdf_devt = DDI_DEV_T_ANY; + } else { + xdf_devt = dkp->dk_xdf_dev | XDF_DEV2PART(dev); + } + + mutex_exit(&dkp->dk_mutex); + + /* + * Cdev_prop_op() is not a public interface, and normally the caller + * is required to make sure that the target driver actually implements + * this interface before trying to invoke it. In this case we know + * that we're always accessing the xdf driver and it does have this + * interface defined, so we can skip the check. + */ + err = cdev_prop_op(xdf_devt, xdf_dip, + prop_op, flags, name, valuep, lengthp); + ddi_release_devi(xdf_dip); + return (err); +} + +/* + * Device driver ops vector + */ +static struct cb_ops pv_cmdk_cb_ops = { + pv_cmdkopen, /* open */ + pv_cmdkclose, /* close */ + pv_cmdkstrategy, /* strategy */ + nodev, /* print */ + pv_cmdkdump, /* dump */ + pv_cmdkread, /* read */ + pv_cmdkwrite, /* write */ + pv_cmdkioctl, /* ioctl */ + nodev, /* devmap */ + nodev, /* mmap */ + nodev, /* segmap */ + nochpoll, /* poll */ + pv_cmdk_prop_op, /* cb_prop_op */ + 0, /* streamtab */ + D_64BIT | D_MP | D_NEW, /* Driver comaptibility flag */ + CB_REV, /* cb_rev */ + pv_cmdkaread, /* async read */ + pv_cmdkawrite /* async write */ +}; + +struct dev_ops pv_cmdk_ops = { + DEVO_REV, /* devo_rev, */ + 0, /* refcnt */ + pv_cmdk_getinfo, /* info */ + nulldev, /* identify */ + nulldev, /* probe */ + pv_cmdkattach, /* attach */ + pv_cmdkdetach, /* detach */ + nodev, /* reset */ + &pv_cmdk_cb_ops, /* driver operations */ + (struct bus_ops *)0 /* bus operations */ +}; + +/* + * Module linkage information for the kernel. + */ +static struct modldrv modldrv = { + &mod_driverops, /* Type of module. This one is a driver */ + "PV Common Direct Access Disk", + &pv_cmdk_ops, /* driver ops */ +}; + +static struct modlinkage modlinkage = { + MODREV_1, (void *)&modldrv, NULL +}; + +int +_init(void) +{ + int rval; + + if ((pv_cmdk_major = ddi_name_to_major("cmdk")) == (major_t)-1) + return (EINVAL); + + /* + * In general ide usually supports 4 disk devices, this same + * limitation also applies to software emulating ide devices. + * so by default we pre-allocate 4 cmdk soft state structures. + */ + if ((rval = ddi_soft_state_init(&pv_cmdk_state, + sizeof (struct pv_cmdk), PV_CMDK_NODES)) != 0) + return (rval); + + /* + * Currently we only support qemu as the backing hardware emulator + * for cmdk devices. + */ + pv_cmdk_h2p = pv_cmdk_h2p_xen_qemu; + + /* Install our module */ + if ((rval = mod_install(&modlinkage)) != 0) { + ddi_soft_state_fini(&pv_cmdk_state); + return (rval); + } + + return (0); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + +int +_fini(void) +{ + int rval; + if ((rval = mod_remove(&modlinkage)) != 0) + return (rval); + ddi_soft_state_fini(&pv_cmdk_state); + return (0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/i86pc/i86hvm/io/pv_rtls.c Mon Apr 14 22:44:34 2008 -0700 @@ -0,0 +1,79 @@ +/* + * 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" + +/* + * Fake rtls module. Prevents the real rtls driver from loading in + * a xen HVM domain so that xnf may operate instead. + */ + +#include <sys/sunddi.h> +#include <sys/errno.h> +#include <sys/modctl.h> + +struct dev_ops pv_rtls_ops = { + DEVO_REV, + 0, + NULL, + nulldev, + nulldev, + NULL, + NULL, + nodev, + NULL, + NULL +}; + +/* + * Module linkage information for the kernel. + */ +static struct modldrv modldrv = { + &mod_driverops, + "xVM rtls stub %I%", + &pv_rtls_ops +}; + +static struct modlinkage modlinkage = { + MODREV_1, (void *)&modldrv, NULL +}; + +int +_init(void) +{ + return (mod_install(&modlinkage)); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + +int +_fini(void) +{ + return (EBUSY); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/i86pc/i86hvm/io/xpv/evtchn.c Mon Apr 14 22:44:34 2008 -0700 @@ -0,0 +1,389 @@ +/* + * 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" + +#include <sys/types.h> +#include <sys/xpv_support.h> +#include <sys/hypervisor.h> +#include <sys/machsystm.h> +#include <sys/mutex.h> +#include <sys/cmn_err.h> +#include <sys/dditypes.h> +#include <sys/atomic.h> +#include <sys/sysmacros.h> +#include <sys/cpu.h> +#include <sys/psw.h> +#include <sys/psm.h> +#include <sys/sdt.h> + +extern dev_info_t *xpv_dip; +static ddi_intr_handle_t *evtchn_ihp = NULL; +static ddi_softint_handle_t evtchn_to_handle[NR_EVENT_CHANNELS]; +kmutex_t ec_lock; + +static int evtchn_callback_irq = -1; + +static volatile ulong_t *pending_events; +static volatile ulong_t *masked_events; + +/* log2(NBBY * sizeof (ulong)) */ +#ifdef __amd64 +#define EVTCHN_SHIFT 6 +#else /* __i386 */ +#define EVTCHN_SHIFT 5 +#endif + +/* Atomically get and clear a ulong from memory. */ +#define GET_AND_CLEAR(src, targ) { \ + membar_enter(); \ + do { \ + targ = *src; \ + } while (atomic_cas_ulong(src, targ, 0) != targ); \ +} + +/* Get the first and last bits set in a bitmap */ +#define GET_BOUNDS(bitmap, low, high) { \ + int _i; \ + low = high = -1; \ + for (_i = 0; _i <= sizeof (ulong_t); _i++) \ + if (bitmap & (1UL << _i)) { \ + if (low == -1) \ + low = _i; \ + high = _i; \ + } \ +} + +void +ec_bind_evtchn_to_handler(int evtchn, pri_t pri, ec_handler_fcn_t handler, + void *arg1) +{ + ddi_softint_handle_t hdl; + + if (evtchn < 0 || evtchn > NR_EVENT_CHANNELS) { + cmn_err(CE_WARN, "Binding invalid event channel: %d", evtchn); + return; + } + + (void) ddi_intr_add_softint(xpv_dip, &hdl, pri, handler, (caddr_t)arg1); + mutex_enter(&ec_lock); + ASSERT(evtchn_to_handle[evtchn] == NULL); + evtchn_to_handle[evtchn] = hdl; + mutex_exit(&ec_lock); + + /* Let the hypervisor know we're prepared to handle this event */ + hypervisor_unmask_event(evtchn); +} + +void +ec_unbind_evtchn(int evtchn) +{ + evtchn_close_t close; + ddi_softint_handle_t hdl; + + if (evtchn < 0 || evtchn > NR_EVENT_CHANNELS) { + cmn_err(CE_WARN, "Unbinding invalid event channel: %d", evtchn); + return; + } + + /* + * Let the hypervisor know we're no longer prepared to handle this + * event + */ + hypervisor_mask_event(evtchn); + + /* Cleanup the event handler metadata */ + mutex_enter(&ec_lock); + hdl = evtchn_to_handle[evtchn]; + evtchn_to_handle[evtchn] = NULL; + mutex_exit(&ec_lock); + + close.port = evtchn; + (void) HYPERVISOR_event_channel_op(EVTCHNOP_close, &close); + (void) ddi_intr_remove_softint(hdl); +} + +void +ec_notify_via_evtchn(unsigned int port) +{ + evtchn_send_t send; + + if ((int)port == -1) + return; + send.port = port; + (void) HYPERVISOR_event_channel_op(EVTCHNOP_send, &send); +} + +void +hypervisor_unmask_event(unsigned int ev) +{ + int index = ev >> EVTCHN_SHIFT; + ulong_t bit = 1UL << (ev & ((1UL << EVTCHN_SHIFT) - 1)); + volatile ulong_t *maskp; + evtchn_unmask_t unmask; + + /* + * index,bit contain the event number as an index into the + * masked-events bitmask. Set it to 0. + */ + maskp = &masked_events[index]; + atomic_and_ulong(maskp, ~bit); + + /* Let the hypervisor know the event has been unmasked */ + unmask.port = ev; + if (HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask) != 0) + panic("xen_evtchn_unmask() failed"); +} + +/* Set a bit in an evtchan mask word */ +void +hypervisor_mask_event(uint_t ev) +{ + int index = ev >> EVTCHN_SHIFT; + ulong_t bit = 1UL << (ev & ((1UL << EVTCHN_SHIFT) - 1)); + volatile ulong_t *maskp; + + maskp = &masked_events[index]; + atomic_or_ulong(maskp, bit); +} + +void +hypervisor_clear_event(uint_t ev) +{ + int index = ev >> EVTCHN_SHIFT; + ulong_t bit = 1UL << (ev & ((1UL << EVTCHN_SHIFT) - 1)); + volatile ulong_t *maskp; + + maskp = &pending_events[index]; + atomic_and_ulong(maskp, ~bit); +} + +int +xen_alloc_unbound_evtchn(int domid, int *evtchnp) +{ + evtchn_alloc_unbound_t alloc; + int err; + + alloc.dom = DOMID_SELF; + alloc.remote_dom = (domid_t)domid; + + if ((err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, + &alloc)) == 0) { + *evtchnp = alloc.port; + /* ensure evtchn is masked till we're ready to use it */ + (void) hypervisor_mask_event(*evtchnp); + } else { + err = xen_xlate_errcode(err); + } + + return (err); +} + +int +xen_bind_interdomain(int domid, int remote_port, int *port) +{ + evtchn_bind_interdomain_t bind; + int err; + + bind.remote_dom = (domid_t)domid; + bind.remote_port = remote_port; + if ((err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain, + &bind)) == 0) + *port = bind.local_port; + else + err = xen_xlate_errcode(err); + return (err); +} + +/*ARGSUSED*/ +uint_t +evtchn_callback_fcn(caddr_t arg0, caddr_t arg1) +{ + ulong_t pending_word; + int i, j, port; + volatile struct vcpu_info *vci; + uint_t rv = DDI_INTR_UNCLAIMED; + ddi_softint_handle_t hdl; + int low, high; + ulong_t sels; + + vci = &HYPERVISOR_shared_info->vcpu_info[CPU->cpu_id]; + +again: + DTRACE_PROBE2(evtchn__scan__start, int, vci->evtchn_upcall_pending, + ulong_t, vci->evtchn_pending_sel); + + atomic_and_8(&vci->evtchn_upcall_pending, 0); + + /* + * Find the upper and lower bounds in which we need to search for + * pending events. + */ + GET_AND_CLEAR(&vci->evtchn_pending_sel, sels); + + /* sels == 1 is by far the most common case. Make it fast */ + if (sels == 1) + low = high = 0; + else if (sels == 0) + return (rv); + else + GET_BOUNDS(sels, low, high); + + /* Scan the port list, looking for words with bits set */ + for (i = low; i <= high; i++) { + ulong_t tmp; + + GET_AND_CLEAR(&pending_events[i], tmp); + pending_word = tmp & ~(masked_events[i]); + + /* Scan the bits in the word, looking for pending events */ + while (pending_word != 0) { + j = lowbit(pending_word) - 1; + port = (i << EVTCHN_SHIFT) + j; + pending_word = pending_word & ~(1 << j); + + /* + * If there is a handler registered for this event, + * schedule a softint of the appropriate priority + * to execute it. + */ + if ((hdl = evtchn_to_handle[port]) != NULL) { + (void) ddi_intr_trigger_softint(hdl, NULL); + rv = DDI_INTR_CLAIMED; + } + } + } + DTRACE_PROBE2(evtchn__scan__end, int, vci->evtchn_upcall_pending, + ulong_t, vci->evtchn_pending_sel); + + if ((volatile uint8_t)vci->evtchn_upcall_pending || + ((volatile ulong_t)vci->evtchn_pending_sel)) + goto again; + + return (rv); +} + +static int +set_hvm_callback(int irq) +{ + struct xen_hvm_param xhp; + + xhp.domid = DOMID_SELF; + xhp.index = HVM_PARAM_CALLBACK_IRQ; + xhp.value = irq; + return (HYPERVISOR_hvm_op(HVMOP_set_param, &xhp)); +} + +void +ec_fini() +{ + int i; + + for (i = 0; i < NR_EVENT_CHANNELS; i++) + ec_unbind_evtchn(i); + + evtchn_callback_irq = -1; + if (evtchn_ihp != NULL) { + (void) ddi_intr_disable(*evtchn_ihp); + (void) ddi_intr_remove_handler(*evtchn_ihp); + (void) ddi_intr_free(*evtchn_ihp); + kmem_free(evtchn_ihp, sizeof (ddi_intr_handle_t)); + evtchn_ihp = NULL; + } +} + +int +ec_init(dev_info_t *dip) +{ + int i; + int rv, actual; + ddi_intr_handle_t *ihp; + + /* + * Translate the variable-sized pending and masked event bitmasks + * into constant-sized arrays of uint32_t's. + */ + pending_events = &HYPERVISOR_shared_info->evtchn_pending[0]; + masked_events = &HYPERVISOR_shared_info->evtchn_mask[0]; + + /* + * Clear our event handler structures and prevent the hypervisor + * from triggering any events. + */ + mutex_init(&ec_lock, NULL, MUTEX_SPIN, (void *)ipltospl(SPL7)); + for (i = 0; i < NR_EVENT_CHANNELS; i++) { + evtchn_to_handle[i] = NULL; + (void) hypervisor_mask_event(i); + } + + /* + * Allocate and initialize an interrupt handler to process the + * hypervisor's "hey you have events pending!" interrupt. + */ + ihp = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP); + rv = ddi_intr_alloc(dip, ihp, DDI_INTR_TYPE_FIXED, 0, 1, &actual, + DDI_INTR_ALLOC_NORMAL); + if (rv < 0 || actual != 1) { + cmn_err(CE_WARN, "Could not allocate evtchn interrupt: %d", + rv); + return (-1); + } + + rv = ddi_intr_add_handler(*ihp, evtchn_callback_fcn, NULL, NULL); + if (rv < 0) { + (void) ddi_intr_free(*ihp); + cmn_err(CE_WARN, "Could not attach evtchn handler"); + return (-1); + } + evtchn_ihp = ihp; + + if (ddi_intr_enable(*ihp) != DDI_SUCCESS) { + cmn_err(CE_WARN, "Could not enable evtchn interrupts\n"); + return (-1); + } + + /* Tell the hypervisor which interrupt we're waiting on. */ + evtchn_callback_irq = ((ddi_intr_handle_impl_t *)*ihp)->ih_vector; + + if (set_hvm_callback(evtchn_callback_irq) != 0) { + cmn_err(CE_WARN, "Couldn't register evtchn callback"); + return (-1); + } + return (0); +} + +void +ec_resume(void) +{ + int i; + + /* New event-channel space is not 'live' yet. */ + for (i = 0; i < NR_EVENT_CHANNELS; i++) + (void) hypervisor_mask_event(i); + if (set_hvm_callback(evtchn_callback_irq) != 0) + cmn_err(CE_WARN, "Couldn't register evtchn callback"); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/i86pc/i86hvm/io/xpv/xpv.conf Mon Apr 14 22:44:34 2008 -0700 @@ -0,0 +1,28 @@ +# +# 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. +# + +# ident "%Z%%M% %I% %E% SMI" + +interrupt-priorities=9;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/i86pc/i86hvm/io/xpv/xpv_support.c Mon Apr 14 22:44:34 2008 -0700 @@ -0,0 +1,956 @@ +/* + * 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" + +#include <sys/modctl.h> +#include <sys/types.h> +#include <sys/archsystm.h> +#include <sys/machsystm.h> +#include <sys/sunndi.h> +#include <sys/sunddi.h> +#include <sys/ddi_subrdefs.h> +#include <sys/xpv_support.h> +#include <sys/xen_errno.h> +#include <sys/hypervisor.h> +#include <sys/gnttab.h> +#include <sys/xenbus_comms.h> +#include <sys/xenbus_impl.h> +#include <xen/sys/xendev.h> +#include <sys/sysmacros.h> +#include <sys/x86_archext.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/conf.h> +#include <sys/devops.h> +#include <sys/pc_mmu.h> +#include <sys/cmn_err.h> +#include <sys/cpr.h> +#include <sys/ddi.h> +#include <vm/seg_kmem.h> +#include <vm/as.h> +#include <vm/hat_pte.h> +#include <vm/hat_i86.h> + +#define XPV_MINOR 0 +#define XPV_BUFSIZE 128 + +/* + * This structure is ordinarily constructed by Xen. In the HVM world, we + * manually fill in the few fields the PV drivers need. + */ +start_info_t *xen_info = NULL; + +/* Xen version number. */ +int xen_major, xen_minor; + +/* Metadata page shared between domain and Xen */ +shared_info_t *HYPERVISOR_shared_info = NULL; + +/* Page containing code to issue hypercalls. */ +extern caddr_t hypercall_page; + +/* Is the hypervisor 64-bit? */ +int xen_is_64bit = -1; + +/* virtual addr for the store_mfn page */ +caddr_t xb_addr; + +dev_info_t *xpv_dip; +static dev_info_t *xpvd_dip; + +/* saved pfn of the shared info page */ +static pfn_t shared_info_frame; + +#ifdef DEBUG +int xen_suspend_debug; + +#define SUSPEND_DEBUG if (xen_suspend_debug) xen_printf +#else +#define SUSPEND_DEBUG(...) +#endif + +/* + * Forward declarations + */ +static int xpv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); +static int xpv_attach(dev_info_t *, ddi_attach_cmd_t); +static int xpv_detach(dev_info_t *, ddi_detach_cmd_t); +static int xpv_open(dev_t *, int, int, cred_t *); +static int xpv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); + +static struct cb_ops xpv_cb_ops = { + xpv_open, + nulldev, /* close */ + nodev, /* strategy */ + nodev, /* print */ + nodev, /* dump */ + nodev, /* read */ + nodev, /* write */ + xpv_ioctl, /* ioctl */ + nodev, /* devmap */ + nodev, /* mmap */ + nodev, /* segmap */ + nochpoll, /* poll */ + ddi_prop_op, + NULL, + D_MP, + CB_REV, + NULL, + NULL +}; + +static struct dev_ops xpv_dv_ops = { + DEVO_REV, + 0, + xpv_getinfo, + nulldev, /* identify */ + nulldev, /* probe */ + xpv_attach, + xpv_detach, + nodev, /* reset */ + &xpv_cb_ops, + NULL, /* struct bus_ops */ + NULL /* power */ +}; + +static struct modldrv modldrv = { + &mod_driverops, + "xpv driver %I%", + &xpv_dv_ops +}; + +static struct modlinkage modl = { + MODREV_1, + { + (void *)&modldrv, + NULL /* null termination */ + } +}; + +static ddi_dma_attr_t xpv_dma_attr = { + DMA_ATTR_V0, /* version of this structure */ + 0, /* lowest usable address */ + 0xffffffffffffffffULL, /* highest usable address */ + 0x7fffffff, /* maximum DMAable byte count */ + MMU_PAGESIZE, /* alignment in bytes */ + 0x7ff, /* bitmap of burst sizes */ + 1, /* minimum transfer */ + 0xffffffffU, /* maximum transfer */ + 0x7fffffffULL, /* maximum segment length */ + 1, /* maximum number of segments */ + 1, /* granularity */ + 0, /* flags (reserved) */ +}; + +static ddi_device_acc_attr_t xpv_accattr = { + DDI_DEVICE_ATTR_V0, + DDI_NEVERSWAP_ACC, + DDI_STRICTORDER_ACC +}; + +#define MAX_ALLOCATIONS 10 +static ddi_dma_handle_t xpv_dma_handle[MAX_ALLOCATIONS]; +static ddi_acc_handle_t xpv_dma_acchandle[MAX_ALLOCATIONS]; +static int xen_alloc_cnt = 0; + +void * +xen_alloc_pages(pgcnt_t cnt) +{ + size_t len; + int a = xen_alloc_cnt++; + caddr_t addr; + + ASSERT(xen_alloc_cnt < MAX_ALLOCATIONS); + if (ddi_dma_alloc_handle(xpv_dip, &xpv_dma_attr, DDI_DMA_SLEEP, 0, + &xpv_dma_handle[a]) != DDI_SUCCESS) + return (NULL); + + if (ddi_dma_mem_alloc(xpv_dma_handle[a], MMU_PAGESIZE * cnt, + &xpv_accattr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0, + &addr, &len, &xpv_dma_acchandle[a]) != DDI_SUCCESS) { + ddi_dma_free_handle(&xpv_dma_handle[a]); + cmn_err(CE_WARN, "Couldn't allocate memory for xpv devices"); + return (NULL); + } + return (addr); +} + +/* + * This function is invoked twice, first time with reprogram=0 to set up + * the xpvd portion of the device tree. The second time it is ignored. + */ +static void +xpv_enumerate(int reprogram) +{ + dev_info_t *dip; + + if (reprogram != 0) + return; + + ndi_devi_alloc_sleep(ddi_root_node(), "xpvd", + (pnode_t)DEVI_SID_NODEID, &dip); + + (void) ndi_devi_bind_driver(dip, 0); + + /* + * Too early to enumerate split device drivers in domU + * since we need to create taskq thread during enumeration. + * So, we only enumerate softdevs and console here. + */ + xendev_enum_all(dip, B_TRUE); +} + +/* + * Translate a hypervisor errcode to a Solaris error code. + */ +int +xen_xlate_errcode(int error) +{ +#define CASE(num) case X_##num: error = num; break + + switch (-error) { + CASE(EPERM); CASE(ENOENT); CASE(ESRCH); + CASE(EINTR); CASE(EIO); CASE(ENXIO); + CASE(E2BIG); CASE(ENOMEM); CASE(EACCES); + CASE(EFAULT); CASE(EBUSY); CASE(EEXIST); + CASE(ENODEV); CASE(EISDIR); CASE(EINVAL); + CASE(ENOSPC); CASE(ESPIPE); CASE(EROFS); + CASE(ENOSYS); CASE(ENOTEMPTY); CASE(EISCONN); + CASE(ENODATA); + default: + panic("xen_xlate_errcode: unknown error %d", error); + } + return (error); +#undef CASE +} + +/*PRINTFLIKE1*/ +void +xen_printf(const char *fmt, ...) +{ + va_list adx; + + va_start(adx, fmt); + printf(fmt, adx); + va_end(adx); +} + +/* + * Stub functions to get the FE drivers to build, and to catch drivers that + * misbehave in HVM domains. + */ +/*ARGSUSED*/ +void +xen_release_pfn(pfn_t pfn, caddr_t va) +{ + panic("xen_release_pfn() is not supported in HVM domains"); +} + +/*ARGSUSED*/ +void +reassign_pfn(pfn_t pfn, mfn_t mfn) +{ + panic("reassign_pfn() is not supported in HVM domains"); +} + +/*ARGSUSED*/ +long +balloon_free_pages(uint_t page_cnt, mfn_t *mfns, caddr_t kva, pfn_t *pfns) +{ + panic("balloon_free_pages() is not supported in HVM domains"); + return (0); +} + +/*ARGSUSED*/ +void +balloon_drv_added(int64_t delta) +{ + panic("balloon_drv_added() is not supported in HVM domains"); +} + +/* + * Add a mapping for the machine page at the given virtual address. + */ +void +kbm_map_ma(maddr_t ma, uintptr_t va, uint_t level) +{ + ASSERT(level == 0); + + hat_devload(kas.a_hat, (caddr_t)va, MMU_PAGESIZE, + mmu_btop(ma), PROT_READ | PROT_WRITE, HAT_LOAD); +} + +static uint64_t +hvm_get_param(int param_id) +{ + struct xen_hvm_param xhp; + + xhp.domid = DOMID_SELF; + xhp.index = param_id; + if ((HYPERVISOR_hvm_op(HVMOP_get_param, &xhp) < 0)) + return (-1); + return (xhp.value); +} + +static struct xenbus_watch shutdown_watch; +taskq_t *xen_shutdown_tq; + +#define SHUTDOWN_INVALID -1 +#define SHUTDOWN_POWEROFF 0 +#define SHUTDOWN_REBOOT 1 +#define SHUTDOWN_SUSPEND 2 +#define SHUTDOWN_HALT 3 +#define SHUTDOWN_MAX 4 + +#define SHUTDOWN_TIMEOUT_SECS (60 * 5) + +static const char *cmd_strings[SHUTDOWN_MAX] = { + "poweroff", + "reboot", + "suspend", + "halt" +}; + +int +xen_suspend_devices(dev_info_t *dip) +{ + int error; + char buf[XPV_BUFSIZE]; + + SUSPEND_DEBUG("xen_suspend_devices\n"); + + for (; dip != NULL; dip = ddi_get_next_sibling(dip)) { + if (xen_suspend_devices(ddi_get_child(dip))) + return (ENXIO); + if (ddi_get_driver(dip) == NULL) + continue; + SUSPEND_DEBUG("Suspending device %s\n", ddi_deviname(dip, buf)); + ASSERT((DEVI(dip)->devi_cpr_flags & DCF_CPR_SUSPENDED) == 0); + + + if (!i_ddi_devi_attached(dip)) { + error = DDI_FAILURE; + } else { + error = devi_detach(dip, DDI_SUSPEND); + } + + if (error == DDI_SUCCESS) { + DEVI(dip)->devi_cpr_flags |= DCF_CPR_SUSPENDED; + } else { + SUSPEND_DEBUG("WARNING: Unable to suspend device %s\n", + ddi_deviname(dip, buf)); + cmn_err(CE_WARN, "Unable to suspend device %s.", + ddi_deviname(dip, buf)); + cmn_err(CE_WARN, "Device is busy or does not " + "support suspend/resume."); + return (ENXIO); + } + } + return (0); +} + +int +xen_resume_devices(dev_info_t *start, int resume_failed) +{ + dev_info_t *dip, *next, *last = NULL; + int did_suspend; + int error = resume_failed; + char buf[XPV_BUFSIZE]; + + SUSPEND_DEBUG("xen_resume_devices\n"); + + while (last != start) { + dip = start; + next = ddi_get_next_sibling(dip); + while (next != last) { + dip = next; + next = ddi_get_next_sibling(dip); + } + + /* + * cpr is the only one that uses this field and the device + * itself hasn't resumed yet, there is no need to use a + * lock, even though kernel threads are active by now. + */ + did_suspend = DEVI(dip)->devi_cpr_flags & DCF_CPR_SUSPENDED; + if (did_suspend) + DEVI(dip)->devi_cpr_flags &= ~DCF_CPR_SUSPENDED; + + /* + * There may be background attaches happening on devices + * that were not originally suspended by cpr, so resume + * only devices that were suspended by cpr. Also, stop + * resuming after the first resume failure, but traverse + * the entire tree to clear the suspend flag. + */ + if (did_suspend && !error) { + SUSPEND_DEBUG("Resuming device %s\n", + ddi_deviname(dip, buf)); + /* + * If a device suspended by cpr gets detached during + * the resume process (for example, due to hotplugging) + * before cpr gets around to issuing it a DDI_RESUME, + * we'll have problems. + */ + if (!i_ddi_devi_attached(dip)) { + cmn_err(CE_WARN, "Skipping %s, device " + "not ready for resume", + ddi_deviname(dip, buf)); + } else { + if (devi_attach(dip, DDI_RESUME) != + DDI_SUCCESS) { + error = ENXIO; + } + } + } + + if (error == ENXIO) { + cmn_err(CE_WARN, "Unable to resume device %s", + ddi_deviname(dip, buf)); + } + + error = xen_resume_devices(ddi_get_child(dip), error); + last = dip; + } + + return (error); +} + +/*ARGSUSED*/ +static int +check_xpvd(dev_info_t *dip, void *arg) +{ + char *name; + + name = ddi_node_name(dip); + if (name == NULL || strcmp(name, "xpvd")) { + return (DDI_WALK_CONTINUE); + } else { + xpvd_dip = dip; + return (DDI_WALK_TERMINATE); + } +} + +/* + * Top level routine to direct suspend/resume of a domain. + */ +void +xen_suspend_domain(void) +{ + extern void rtcsync(void); + extern void ec_resume(void); + extern kmutex_t ec_lock; + struct xen_add_to_physmap xatp; + ulong_t flags; + int err; + + cmn_err(CE_NOTE, "Domain suspending for save/migrate"); + + SUSPEND_DEBUG("xen_suspend_domain\n"); + + /* + * We only want to suspend the PV devices, since the emulated devices + * are suspended by saving the emulated device state. The PV devices + * are all children of the xpvd nexus device. So we search the + * device tree for the xpvd node to use as the root of the tree to + * be suspended. + */ + if (xpvd_dip == NULL) + ddi_walk_devs(ddi_root_node(), check_xpvd, NULL); + + /* + * suspend interrupts and devices + */ + if (xpvd_dip != NULL) + (void) xen_suspend_devices(ddi_get_child(xpvd_dip)); + else + cmn_err(CE_WARN, "No PV devices found to suspend"); + SUSPEND_DEBUG("xenbus_suspend\n"); + xenbus_suspend(); + + mutex_enter(&cpu_lock); + + /* + * Suspend on vcpu 0 + */ + thread_affinity_set(curthread, 0); + kpreempt_disable(); + + if (ncpus > 1) + pause_cpus(NULL); + /* + * We can grab the ec_lock as it's a spinlock with a high SPL. Hence + * any holder would have dropped it to get through pause_cpus(). + */ + mutex_enter(&ec_lock); + + /* + * From here on in, we can't take locks. + */ + + flags = intr_clear(); + + SUSPEND_DEBUG("HYPERVISOR_suspend\n"); + /* + * At this point we suspend and sometime later resume. + * Note that this call may return with an indication of a cancelled + * for now no matter ehat the return we do a full resume of all + * suspended drivers, etc. + */ + (void) HYPERVISOR_shutdown(SHUTDOWN_suspend); + + /* + * Point HYPERVISOR_shared_info to the proper place. + */ + xatp.domid = DOMID_SELF; + xatp.idx = 0; + xatp.space = XENMAPSPACE_shared_info; + xatp.gpfn = shared_info_frame; + if ((err = HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp)) != 0) + panic("Could not set shared_info page. error: %d", err); + + SUSPEND_DEBUG("gnttab_resume\n"); + gnttab_resume(); + + SUSPEND_DEBUG("ec_resume\n"); + ec_resume(); + + intr_restore(flags); + + if (ncpus > 1) + start_cpus(); + + mutex_exit(&ec_lock); + mutex_exit(&cpu_lock); + + /* + * Now we can take locks again. + */ + + rtcsync(); + + SUSPEND_DEBUG("xenbus_resume\n"); + xenbus_resume(); + SUSPEND_DEBUG("xen_resume_devices\n"); + if (xpvd_dip != NULL) + (void) xen_resume_devices(ddi_get_child(xpvd_dip), 0); + + thread_affinity_clear(curthread); + kpreempt_enable(); + + SUSPEND_DEBUG("finished xen_suspend_domain\n"); + + cmn_err(CE_NOTE, "domain restore/migrate completed"); +} + +static void +xen_dirty_shutdown(void *arg) +{ + int cmd = (uintptr_t)arg; + + cmn_err(CE_WARN, "Externally requested shutdown failed or " + "timed out.\nShutting down.\n"); + + switch (cmd) { + case SHUTDOWN_HALT: + case SHUTDOWN_POWEROFF: + (void) kadmin(A_SHUTDOWN, AD_POWEROFF, NULL, kcred); + break; + case SHUTDOWN_REBOOT: + (void) kadmin(A_REBOOT, AD_BOOT, NULL, kcred); + break; + } +} + +static void +xen_shutdown(void *arg) +{ + nvlist_t *attr_list = NULL; + sysevent_t *event = NULL; + sysevent_id_t eid; + int cmd = (uintptr_t)arg; + int err; + + ASSERT(cmd > SHUTDOWN_INVALID && cmd < SHUTDOWN_MAX); + + if (cmd == SHUTDOWN_SUSPEND) { + xen_suspend_domain(); + return; + } + + err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME, KM_SLEEP); + if (err != DDI_SUCCESS) + goto failure; + + err = nvlist_add_string(attr_list, "shutdown", cmd_strings[cmd]); + if (err != DDI_SUCCESS) + goto failure; + + if ((event = sysevent_alloc("EC_xpvsys", "control", "SUNW:kern:xpv", + SE_SLEEP)) == NULL) + goto failure; + (void) sysevent_attach_attributes(event, + (sysevent_attr_list_t *)attr_list); + + err = log_sysevent(event, SE_SLEEP, &eid); + + sysevent_detach_attributes(event); + sysevent_free(event); + + if (err != 0) + goto failure; + + (void) timeout(xen_dirty_shutdown, arg, + SHUTDOWN_TIMEOUT_SECS * drv_usectohz(MICROSEC)); + + nvlist_free(attr_list); + return; + +failure: + if (attr_list != NULL) + nvlist_free(attr_list); + xen_dirty_shutdown(arg); +} + +/*ARGSUSED*/ +static void +xen_shutdown_handler(struct xenbus_watch *watch, const char **vec, + unsigned int len) +{ + char *str; + xenbus_transaction_t xbt; + int err, shutdown_code = SHUTDOWN_INVALID; + unsigned int slen; + +again: + err = xenbus_transaction_start(&xbt); + if (err) + return; + if (xenbus_read(xbt, "control", "shutdown", (void *)&str, &slen)) { + (void) xenbus_transaction_end(xbt, 1); + return; + } + + SUSPEND_DEBUG("%d: xen_shutdown_handler: \"%s\"\n", CPU->cpu_id, str); + + /* + * If this is a watch fired from our write below, check out early to + * avoid an infinite loop. + */ + if (strcmp(str, "") == 0) { + (void) xenbus_transaction_end(xbt, 0); + kmem_free(str, slen); + return; + } else if (strcmp(str, "poweroff") == 0) { + shutdown_code = SHUTDOWN_POWEROFF; + } else if (strcmp(str, "reboot") == 0) { + shutdown_code = SHUTDOWN_REBOOT; + } else if (strcmp(str, "suspend") == 0) { + shutdown_code = SHUTDOWN_SUSPEND; + } else if (strcmp(str, "halt") == 0) { + shutdown_code = SHUTDOWN_HALT; + } else { + printf("Ignoring shutdown request: %s\n", str); + } + + (void) xenbus_write(xbt, "control", "shutdown", ""); + err = xenbus_transaction_end(xbt, 0); + if (err == EAGAIN) { + SUSPEND_DEBUG("%d: trying again\n", CPU->cpu_id); + kmem_free(str, slen); + goto again; + } + + kmem_free(str, slen); + if (shutdown_code != SHUTDOWN_INVALID) { + (void) taskq_dispatch(xen_shutdown_tq, xen_shutdown, + (void *)(intptr_t)shutdown_code, 0); + } +} + +static int +xen_pv_init(dev_info_t *xpv_dip) +{ + struct cpuid_regs cp; + uint32_t xen_signature[4]; + char *xen_str; + struct xen_add_to_physmap xatp; + xen_capabilities_info_t caps; + pfn_t pfn; + uint64_t msrval; + int err; + + /* + * Xen's pseudo-cpuid function 0x40000000 returns a string + * representing the Xen signature in %ebx, %ecx, and %edx. + * %eax contains the maximum supported cpuid function. + */ + cp.cp_eax = 0x40000000; + (void) __cpuid_insn(&cp); + xen_signature[0] = cp.cp_ebx; + xen_signature[1] = cp.cp_ecx; + xen_signature[2] = cp.cp_edx; + xen_signature[3] = 0; + xen_str = (char *)xen_signature; + if (strcmp("XenVMMXenVMM", xen_str) != 0 || + cp.cp_eax < 0x40000002) { + cmn_err(CE_WARN, + "Attempting to load Xen drivers on non-Xen system"); + return (-1); + } + + /* + * cpuid function 0x40000001 returns the Xen version in %eax. The + * top 16 bits are the major version, the bottom 16 are the minor + * version. + */ + cp.cp_eax = 0x40000001; + (void) __cpuid_insn(&cp); + xen_major = cp.cp_eax >> 16; + xen_minor = cp.cp_eax & 0xffff; + + /* + * The xpv driver is incompatible with xen versions older than 3.1. This + * is due to the changes in the vcpu_info and shared_info structs used + * to communicate with the hypervisor (the event channels in particular) + * that were introduced with 3.1. + */ + if (xen_major < 3 || (xen_major == 3 && xen_minor < 1)) { + cmn_err(CE_WARN, "Xen version %d.%d is not supported", + xen_major, xen_minor); + return (-1); + } + + /* + * cpuid function 0x40000002 returns information about the + * hypercall page. %eax nominally contains the number of pages + * with hypercall code, but according to the Xen guys, "I'll + * guarantee that remains one forever more, so you can just + * allocate a single page and get quite upset if you ever see CPUID + * return more than one page." %ebx contains an MSR we use to ask + * Xen to remap each page at a specific pfn. + */ + cp.cp_eax = 0x40000002; + (void) __cpuid_insn(&cp); + + /* + * Let Xen know where we want the hypercall page mapped. We + * already have a page allocated in the .text section to simplify + * the wrapper code. + */ + pfn = hat_getpfnum(kas.a_hat, (caddr_t)&hypercall_page); + msrval = mmu_ptob(pfn); + wrmsr(cp.cp_ebx, msrval); + + /* Fill in the xen_info data */ + xen_info = kmem_zalloc(sizeof (start_info_t), KM_SLEEP); + (void) sprintf(xen_info->magic, "xen-%d.%d", xen_major, xen_minor); + xen_info->store_mfn = (mfn_t)hvm_get_param(HVM_PARAM_STORE_PFN); + xen_info->store_evtchn = (int)hvm_get_param(HVM_PARAM_STORE_EVTCHN); + + /* Figure out whether the hypervisor is 32-bit or 64-bit. */ + if ((HYPERVISOR_xen_version(XENVER_capabilities, &caps) == 0)) { + ((char *)(caps))[sizeof (caps) - 1] = '\0'; + if (strstr(caps, "x86_64") != NULL) + xen_is_64bit = 1; + else if (strstr(caps, "x86_32") != NULL) + xen_is_64bit = 0; + } + if (xen_is_64bit < 0) { + cmn_err(CE_WARN, "Couldn't get capability info from Xen."); + return (-1); + } +#ifdef __amd64 + ASSERT(xen_is_64bit == 1); +#endif + + /* + * Allocate space for the shared_info page and tell Xen where it + * is. + */ + HYPERVISOR_shared_info = xen_alloc_pages(1); + shared_info_frame = hat_getpfnum(kas.a_hat, + (caddr_t)HYPERVISOR_shared_info); + xatp.domid = DOMID_SELF; + xatp.idx = 0; + xatp.space = XENMAPSPACE_shared_info; + xatp.gpfn = shared_info_frame; + if ((err = HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp)) != 0) { + cmn_err(CE_WARN, "Could not get shared_info page from Xen." + " error: %d", err); + return (-1); + } + + /* Set up the grant tables. */ + gnttab_init(); + + /* Set up event channel support */ + if (ec_init(xpv_dip) != 0) + return (-1); + + /* Set up xenbus */ + xb_addr = vmem_alloc(heap_arena, MMU_PAGESIZE, VM_SLEEP); + xs_early_init(); + xs_domu_init(); + + /* Set up for suspend/resume/migrate */ + xen_shutdown_tq = taskq_create("shutdown_taskq", 1, + maxclsyspri - 1, 1, 1, TASKQ_PREPOPULATE); + shutdown_watch.node = "control/shutdown"; + shutdown_watch.callback = xen_shutdown_handler; + if (register_xenbus_watch(&shutdown_watch)) + cmn_err(CE_WARN, "Failed to set shutdown watcher"); + + return (0); +} + +static void +xen_pv_fini() +{ + if (xen_info != NULL) + kmem_free(xen_info, sizeof (start_info_t)); + ec_fini(); +} + +/*ARGSUSED*/ +static int +xpv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) +{ + if (getminor((dev_t)arg) != XPV_MINOR) + return (DDI_FAILURE); + + switch (cmd) { + case DDI_INFO_DEVT2DEVINFO: + *result = xpv_dip; + break; + case DDI_INFO_DEVT2INSTANCE: + *result = 0; + break; + default: + return (DDI_FAILURE); + } + + return (DDI_SUCCESS); +} + +static int +xpv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) +{ + if (cmd != DDI_ATTACH) + return (DDI_FAILURE); + + if (ddi_create_minor_node(dip, ddi_get_name(dip), S_IFCHR, + ddi_get_instance(dip), DDI_PSEUDO, 0) != DDI_SUCCESS) + return (DDI_FAILURE); + + xpv_dip = dip; + + if (xen_pv_init(dip) != 0) + return (DDI_FAILURE); + + ddi_report_dev(dip); + + /* + * If the memscrubber attempts to scrub the pages we hand to Xen, + * the domain will panic. + */ + memscrub_disable(); + + /* + * Report our version to dom0. + */ + if (xenbus_printf(XBT_NULL, "hvmpv/xpv", "version", "%d", + HVMPV_XPV_VERS)) + cmn_err(CE_WARN, "xpv: couldn't write version\n"); + + return (DDI_SUCCESS); +} + +/* + * Attempts to reload the PV driver plumbing hang on Intel platforms, so + * we don't want to unload the framework by accident. + */ +int xpv_allow_detach = 0; + +static int +xpv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) +{ + if (cmd != DDI_DETACH || xpv_allow_detach == 0) + return (DDI_FAILURE); + + if (xpv_dip != NULL) { + xen_pv_fini(); + ddi_remove_minor_node(dip, NULL); + xpv_dip = NULL; + } + + return (DDI_SUCCESS); +} + +/*ARGSUSED1*/ +static int +xpv_open(dev_t *dev, int flag, int otyp, cred_t *cr) +{ + return (getminor(*dev) == XPV_MINOR ? 0 : ENXIO); +} + +/*ARGSUSED*/ +static int +xpv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, + int *rval_p) +{ + return (EINVAL); +} + +int +_init(void) +{ + int err; + + if ((err = mod_install(&modl)) != 0) + return (err); + + impl_bus_add_probe(xpv_enumerate); + return (0); +} + +int +_fini(void) +{ + int err; + + if ((err = mod_remove(&modl)) != 0) + return (err); + + impl_bus_delete_probe(xpv_enumerate); + return (0); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modl, modinfop)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/i86pc/i86hvm/pv_cmdk/Makefile Mon Apr 14 22:44:34 2008 -0700 @@ -0,0 +1,102 @@ +# +# 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 +# +# +# uts/i86pc/pv_cmdk/Makefile +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# +# This makefile drives the production of the xdc driver. +# +# i86pc implementation architecture dependent +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../../.. + +# +# Define the module and object file sets. +# +MODULE = cmdk +OBJECTS = $(PV_CMDK_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(PV_CMDK_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_HVM_DRV_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/i86pc/i86hvm/Makefile.i86hvm + +# +# When generating lint libraries, we want the name of the lint module +# that will be generated to by pv_cmdk and not cmdk, so override the +# default lint module name here. +# +LINT_MODULE = pv_cmdk + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(LINT_MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +LDFLAGS += -dy -Nmisc/strategy -Nmisc/cmlb +LDFLAGS += -Ndrv/xpvd -Ndrv/xdf + +# +# The Xen header files do not lint cleanly. Since the troublesome +# structures form part of the externally defined interface to the +# hypervisor, we're stuck with the noise. +# +LINTTAGS += -erroff=E_BAD_PTR_CAST_ALIGN +LINTTAGS += -erroff=E_SUPPRESSION_DIRECTIVE_UNUSED +LINTTAGS += -erroff=E_ASSIGN_NARROW_CONV + +# +# 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)/i86pc/i86hvm/Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/i86pc/i86hvm/pv_rtls/Makefile Mon Apr 14 22:44:34 2008 -0700 @@ -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 +# +# +# uts/i86pc/pv_rtls/Makefile +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# +# This makefile drives the production of the null rtls module for xvm. +# +# i86pc implementation architecture dependent +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../../.. + +# +# Define the module and object file sets. +# +MODULE = rtls +OBJECTS = $(PV_RTLS_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(PV_RTLS_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_HVM_DRV_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/i86pc/i86hvm/Makefile.i86hvm + +# +# When generating lint libraries, we want the name of the lint module +# that will be generated to be pv_rtls and not rtls, so override the +# default lint module name here. +# +LINT_MODULE = pv_rtls + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(LINT_MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +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)/i86pc/i86hvm/Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/i86pc/i86hvm/sys/xpv_support.h Mon Apr 14 22:44:34 2008 -0700 @@ -0,0 +1,91 @@ +/* + * 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 _SYS_XPV_SUPPORT_H +#define _SYS_XPV_SUPPORT_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#define __XEN_INTERFACE_VERSION__ __XEN_LATEST_INTERFACE_VERSION__ + +#if !defined(_ASM) + +#include <sys/types.h> +#include <sys/inttypes.h> +#include <sys/dditypes.h> + +typedef ulong_t mfn_t; +typedef uint64_t maddr_t; +#define mfn_to_ma(mfn) ((maddr_t)(mfn) << MMU_PAGESHIFT) +#define MFN_INVALID (-(mfn_t)1) + +#define IPL_DEBUG 15 /* domain debug interrupt */ +#define IPL_CONS 9 +#define IPL_VIF 6 +#define IPL_VBD 5 +#define IPL_EVTCHN 1 + +#define INVALID_EVTCHN 0 + +typedef uint_t (*ec_handler_fcn_t)(); + +extern int ec_init(dev_info_t *); +extern void ec_fini(); +extern void ec_bind_evtchn_to_handler(int, pri_t, ec_handler_fcn_t, void *); +extern void ec_unbind_evtchn(int); +extern void ec_notify_via_evtchn(uint_t); +extern void hypervisor_mask_event(uint_t); +extern void hypervisor_unmask_event(uint_t); + +extern int xen_bind_interdomain(int, int, int *); +extern int xen_alloc_unbound_evtchn(int, int *); +extern int xen_xlate_errcode(int error); +extern void *xen_alloc_pages(pgcnt_t cnt); +extern void kbm_map_ma(maddr_t ma, uintptr_t va, uint_t level); + +/* + * Stub functions to allow the FE drivers to build without littering them + * with #ifdefs + */ +extern void balloon_drv_added(int64_t); +extern long balloon_free_pages(uint_t, mfn_t *, caddr_t, pfn_t *); +extern void xen_release_pfn(pfn_t, caddr_t); +extern void reassign_pfn(pfn_t, mfn_t); + +extern int xen_is_64bit; + +#define IN_XPV_PANIC() (__lintzero) + +#ifdef __cplusplus +} +#endif + +#endif /* __ASM */ +#endif /* _SYS_XPV_SUPPORT_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/i86pc/i86hvm/xdf/Makefile Mon Apr 14 22:44:34 2008 -0700 @@ -0,0 +1,89 @@ +# +# 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 +# + +# +# uts/i86pc/xdf/Makefile +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# i86pc architecture dependent +# +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../../.. + +# +# Define the module and object file sets. +# +MODULE = xdf +OBJECTS = $(XDF_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(XDF_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_HVM_DRV_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/i86pc/i86hvm/Makefile.i86hvm + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +# Overrides +CPPFLAGS += -DHVMPV_XDF_VERS=1 +LDFLAGS += -dy -Nmisc/cmlb -Ndrv/xpvd -Ndrv/xpv + +LINTTAGS += -erroff=E_SUSPICIOUS_COMPARISON +LINTTAGS += -erroff=E_ASSIGN_NARROW_CONV +LINTTAGS += -erroff=E_BAD_PTR_CAST_ALIGN + +# +# 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)/i86pc/i86hvm/Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/i86pc/i86hvm/xnf/Makefile Mon Apr 14 22:44:34 2008 -0700 @@ -0,0 +1,95 @@ +# +# 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 +# + +# +# uts/i86pc/xnf/Makefile +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This makefile drives the production of the xve +# network driver kernel module. +# +# i86pc architecture dependent +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../../.. + +# +# Define the module and object file sets. +# +MODULE = xnf +OBJECTS = $(XNF_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(XNF_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_HVM_DRV_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/i86pc/i86hvm/Makefile.i86hvm + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +# +# Driver depends on MAC & IP +# +CPPFLAGS += -DHVMPV_XNF_VERS=1 +LDFLAGS += -dy -Nmisc/mac -Ndrv/ip -Ndrv/xpvd -Ndrv/xpv + +LINTTAGS += -erroff=E_ASSIGN_NARROW_CONV +LINTTAGS += -erroff=E_PTRDIFF_OVERFLOW +LINTTAGS += -erroff=E_BAD_PTR_CAST_ALIGN + +# +# 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)/i86pc/i86hvm/Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/i86pc/i86hvm/xpv/Makefile Mon Apr 14 22:44:34 2008 -0700 @@ -0,0 +1,98 @@ +# +# 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 +# +# +# uts/i86pc/xpv/Makefile +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# +# This makefile drives the production of the xpv +# driver, which provides the necessary infrastructure for +# paravirtualized front-end drivers in HVM systems. +# +# i86pc implementation architecture dependent +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../../.. + +# +# Define the module and object file sets. +# +MODULE = xpv +OBJECTS = $(XPV_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(XPV_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_HVM_DRV_DIR)/$(MODULE) +CONF_SRCDIR = $(UTSBASE)/i86pc/i86hvm/io/xpv + +# +# Include common rules. +# +include $(UTSBASE)/i86pc/i86hvm/Makefile.i86hvm + +# +# Define targets +# +ALL_TARGET = $(BINARY) $(CONFMOD) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) + +CPPFLAGS += -DHVMPV_XPV_VERS=1 +LDFLAGS += -dy -N mach/pcplusmp + +# +# The Xen header files do not lint cleanly. Since the troublesome +# structures form part of the externally defined interface to the +# hypervisor, we're stuck with the noise. +# +LINTTAGS += -erroff=E_BAD_PTR_CAST_ALIGN +LINTTAGS += -erroff=E_SUPPRESSION_DIRECTIVE_UNUSED +LINTTAGS += -erroff=E_ASSIGN_NARROW_CONV + +# +# 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)/i86pc/i86hvm/Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/i86pc/i86hvm/xpvd/Makefile Mon Apr 14 22:44:34 2008 -0700 @@ -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. +# +#ident "%Z%%M% %I% %E% SMI" +# +# This makefile drives the production of the xpvd nexus driver +# +# i86pc implementation architecture dependent +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../../.. + +# +# Define the module and object file sets. +# +MODULE = xpvd +OBJECTS = $(XPVD_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(XPVD_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_HVM_DRV_DIR)/$(MODULE) +CONF_SRCDIR = $(UTSBASE)/common/xen/io + +# +# Include common rules. +# +include $(UTSBASE)/i86pc/i86hvm/Makefile.i86hvm + +# +# Define targets +# +ALL_TARGET = $(BINARY) $(CONFMOD) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) + +CPPFLAGS += -DHVMPV_XPVD_VERS=1 +LDFLAGS += -dy -Ndrv/xpv + +LINTTAGS += -erroff=E_STATIC_UNUSED +LINTTAGS += -erroff=E_ASSIGN_NARROW_CONV +LINTTAGS += -erroff=E_BAD_PTR_CAST_ALIGN + +# +# 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)/i86pc/i86hvm/Makefile.targ
--- a/usr/src/uts/i86pc/io/pv_cmdk.c Mon Apr 14 22:16:59 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1541 +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 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/scsi/scsi_types.h> -#include <sys/modctl.h> -#include <sys/cmlb.h> -#include <sys/types.h> -#include <sys/xpv_support.h> -#include <sys/xendev.h> -#include <sys/gnttab.h> -#include <public/xen.h> -#include <public/grant_table.h> -#include <io/xdf.h> -#include <sys/vtoc.h> -#include <sys/dkio.h> -#include <sys/dktp/dadev.h> -#include <sys/dktp/dadkio.h> -#include <sys/dktp/tgdk.h> -#include <sys/dktp/bbh.h> -#include <sys/dktp/cmdk.h> -#include <sys/dktp/altsctr.h> - -/* - * General Notes - * - * We don't support disks with bad block mappins. We have this - * limitation because the underlying xdf driver doesn't support - * bad block remapping. If there is a need to support this feature - * it should be added directly to the xdf driver and we should just - * pass requests strait on through and let it handle the remapping. - * Also, it's probably worth pointing out that most modern disks do bad - * block remapping internally in the hardware so there's actually less - * of a chance of us ever discovering bad blocks. Also, in most cases - * this driver (and the xdf driver) will only be used with virtualized - * devices, so one might wonder why a virtual device would ever actually - * experience bad blocks. To wrap this up, you might be wondering how - * these bad block mappings get created and how they are managed. Well, - * there are two tools for managing bad block mappings, format(1M) and - * addbadsec(1M). Format(1M) can be used to do a surface scan of a disk - * to attempt to find bad block and create mappings for them. Format(1M) - * and addbadsec(1M) can also be used to edit existing mappings that may - * be saved on the disk. - * - * The underlying PV driver that this driver passes on requests to is the - * xdf driver. Since in most cases the xdf driver doesn't deal with - * physical disks it has it's own algorithm for assigning a physical - * geometry to a virtual disk (ie, cylinder count, head count, etc.) - * The default values chosen by the xdf driver may not match those - * assigned to a disk by a hardware disk emulator in an HVM environment. - * This is a problem since these physical geometry attributes affect - * things like the partition table, backup label location, etc. So - * to emulate disk devices correctly we need to know the physical geometry - * that was assigned to a disk at the time of it's initalization. - * Normally in an HVM environment this information will passed to - * the BIOS and operating system from the hardware emulator that is - * emulating the disk devices. In the case of a solaris dom0+xvm - * this would be qemu. So to work around this issue, this driver will - * query the emulated hardware to get the assigned physical geometry - * and then pass this geometry onto the xdf driver so that it can use it. - * But really, this information is essentially metadata about the disk - * that should be kept with the disk image itself. (Assuming or course - * that a disk image is the actual backingstore for this emulated device.) - * This metadata should also be made available to PV drivers via a common - * mechamisn, probably the xenstore. The fact that this metadata isn't - * available outside of HVM domains means that it's difficult to move - * disks between HVM and PV domains, since a fully PV domain will have no - * way of knowing what the correct geometry of the target device is. - * (Short of reading the disk, looking for things like partition tables - * and labels, and taking a best guess at what the geometry was when - * the disk was initialized. Unsuprisingly, qemu actually does this.) - * - * This driver has to map cmdk device instances into their corresponding - * xdf device instances. We have to do this to ensure that when a user - * accesses a emulated cmdk device we map those accesses to the proper - * paravirtualized device. Basically what we need to know is how multiple - * 'disk' entries in a domU configuration file get mapped to emulated - * cmdk devices and to xdf devices. The 'disk' entry to xdf instance - * mappings we know because those are done within the Solaris xvdi code - * and the xpvd nexus driver. But the config to emulated devices mappings - * are handled entirely within the xen management tool chain and the - * hardware emulator. Since all the tools that establish these mappings - * live in dom0, dom0 should really supply us with this information, - * probably via the xenstore. Unfortunatly it doesn't so, since there's - * no good way to determine this mapping dynamically, this driver uses - * a hard coded set of static mappings. These mappings are hardware - * emulator specific because each different hardware emulator could have - * a different device tree with different cmdk device paths. This - * means that if we want to continue to use this static mapping approach - * to allow Solaris to run on different hardware emulators we'll have - * to analyze each of those emulators to determine what paths they - * use and hard code those paths into this driver. yech. This metadata - * really needs to be supplied to us by dom0. - * - * This driver access underlying xdf nodes. Unfortunatly, devices - * must create minor nodes during attach, and for disk devices to create - * minor nodes, they have to look at the label on the disk, so this means - * that disk drivers must be able to access a disk contents during - * attach. That means that this disk driver must be able to access - * underlying xdf nodes during attach. Unfortunatly, due to device tree - * locking restrictions, we cannot have an attach operation occuring on - * this device and then attempt to access another device which may - * cause another attach to occur in a different device tree branch - * since this could result in deadlock. Hence, this driver can only - * access xdf device nodes that we know are attached, and it can't use - * any ddi interfaces to access those nodes if those interfaces could - * trigger an attach of the xdf device. So this driver works around - * these restrictions by talking directly to xdf devices via - * xdf_hvm_hold(). This interface takes a pathname to an xdf device, - * and if that device is already attached then it returns the a held dip - * pointer for that device node. This prevents us from getting into - * deadlock situations, but now we need a mechanism to ensure that all - * the xdf device nodes this driver might access are attached before - * this driver tries to access them. This is accomplished via the - * hvmboot_rootconf() callback which is invoked just before root is - * mounted. hvmboot_rootconf() will attach xpvd and tell it to configure - * all xdf device visible to the system. All these xdf device nodes - * will also be marked with the "ddi-no-autodetach" property so that - * once they are configured, the will not be automatically unconfigured. - * The only way that they could be unconfigured is if the administrator - * explicitly attempts to unload required modules via rem_drv(1M) - * or modunload(1M). - */ - -/* - * 16 paritions + fdisk (see xdf.h) - */ -#define XDF_DEV2UNIT(dev) XDF_INST((getminor((dev)))) -#define XDF_DEV2PART(dev) XDF_PART((getminor((dev)))) - -#define OTYP_VALID(otyp) ((otyp == OTYP_BLK) || \ - (otyp == OTYP_CHR) || \ - (otyp == OTYP_LYR)) - -#define PV_CMDK_NODES 4 - -typedef struct hvm_to_pv { - char *h2p_hvm_path; - char *h2p_pv_path; -} hvm_to_pv_t; - -/* - */ -static hvm_to_pv_t pv_cmdk_h2p_xen_qemu[] = { - /* - * The paths mapping here are very specific to xen and qemu. When a - * domU is booted under xen in HVM mode, qemu is normally used to - * emulate up to four ide disks. These disks always have the four - * path listed below. To configure an emulated ide device, the - * xen domain configuration file normally has an entry that looks - * like this: - * disk = [ 'file:/foo.img,hda,w' ] - * - * The part we're interested in is the 'hda', which we'll call the - * xen disk device name here. The xen management tools (which parse - * the xen domain configuration file and launch qemu) makes the - * following assumptions about this value: - * hda == emulated ide disk 0 (ide bus 0, master) - * hdb == emulated ide disk 1 (ide bus 0, slave) - * hdc == emulated ide disk 2 (ide bus 1, master) - * hdd == emulated ide disk 3 (ide bus 1, slave) - * - * (Uncoincidentally, these xen disk device names actually map to - * the /dev filesystem names of ide disk devices in Linux. So in - * Linux /dev/hda is the first ide disk.) So for the first part of - * our mapping we've just hardcoded the cmdk paths that we know - * qemu will use. - * - * To understand the second half of the mapping (ie, the xdf device - * that each emulated cmdk device should be mapped two) we need to - * know the solaris device node address that will be assigned to - * each xdf device. (The device node address is the hex number that - * comes after the "xdf@" in the device path.) - * - * Normally when a domU is run in non-HVM mode, the xen disk device - * names in the xen domain configuration file are specified with - * integers instead of Linux device names. (for example, '0' would - * be used instead of 'hda'.) So in the non-HVM case we simply - * convert the xen disk device name (which is an interger) into a - * hex number and use it as the Solaris xdf device node address. - * But when we're running in HVM mode then we have a string for the - * xen disk device name, so we can't simply use that as a solaris - * device node address. Instead we fall back to using the xenstore - * device id for the xen disk device as the xdf device node address. - * The xdf device node address assignment happens in xvdi_init_dev(). - * - * So the question becomes, how do we know what the xenstore device - * id for emulated disk will be? Well, it turns out that since the - * xen management tools expect the disk device names to be Linux - * device names, those same management tools assign each disk a - * device id that matches the dev_t of the corresponding device - * under Linux. (Big shocker.) This xen device name-to-id mapping - * is currently all hard coded here: - * xen.hg/tools/python/xen/util/blkif.py`blkdev_name_to_number() - * - * So looking at the code above we can see the following xen disk - * device name to xenstore device id mappings: - * 'hda' --> 0x300 == 0t768 == ((3 * 256) + (0 * 64)) - * 'hdb' --> 0x340 == 0t832 == ((3 * 256) + (1 * 64)) - * 'hdc' --> 0x1600 == 0t5632 == ((22 * 256) + (0 * 64)) - * 'hdd' --> 0x1640 == 0t5696 == ((22 * 256) + (1 * 64)) - */ - { "/pci@0,0/pci-ide@1,1/ide@0/cmdk@0,0", "/xpvd/xdf@300" }, - { "/pci@0,0/pci-ide@1,1/ide@0/cmdk@1,0", "/xpvd/xdf@340" }, - { "/pci@0,0/pci-ide@1,1/ide@1/cmdk@0,0", "/xpvd/xdf@1600" }, - { "/pci@0,0/pci-ide@1,1/ide@1/cmdk@1,0", "/xpvd/xdf@1640" }, - { NULL, 0 } -}; - -typedef struct pv_cmdk { - dev_info_t *dk_dip; - cmlb_handle_t dk_cmlbhandle; - ddi_devid_t dk_devid; - kmutex_t dk_mutex; - dev_info_t *dk_xdf_dip; - dev_t dk_xdf_dev; - int dk_xdf_otyp_count[OTYPCNT][XDF_PEXT]; - ldi_handle_t dk_xdf_lh[XDF_PEXT]; -} pv_cmdk_t; - -/* - * Globals - */ -static void *pv_cmdk_state; -static major_t pv_cmdk_major; -static hvm_to_pv_t *pv_cmdk_h2p; - -/* - * Function prototypes for xdf callback functions - */ -extern int xdf_lb_getinfo(dev_info_t *, int, void *, void *); -extern int xdf_lb_rdwr(dev_info_t *, uchar_t, void *, diskaddr_t, size_t, - void *); - -static boolean_t -pv_cmdk_isopen_part(struct pv_cmdk *dkp, int part) -{ - int otyp; - - ASSERT(MUTEX_HELD(&dkp->dk_mutex)); - - for (otyp = 0; (otyp < OTYPCNT); otyp++) { - if (dkp->dk_xdf_otyp_count[otyp][part] != 0) - return (B_TRUE); - } - return (B_FALSE); -} - -/* - * Cmlb ops vectors, allows the cmlb module to directly access the entire - * pv_cmdk disk device without going through any partitioning layers. - */ -/*ARGSUSED*/ -static int -pv_cmdk_lb_rdwr(dev_info_t *dip, uchar_t cmd, void *bufaddr, - diskaddr_t start, size_t count, void *tg_cookie) -{ - int instance = ddi_get_instance(dip); - struct pv_cmdk *dkp = ddi_get_soft_state(pv_cmdk_state, instance); - - if (dkp == NULL) - return (ENXIO); - - return (xdf_lb_rdwr(dkp->dk_xdf_dip, cmd, bufaddr, start, count, - tg_cookie)); -} - -/*ARGSUSED*/ -static int -pv_cmdk_lb_getinfo(dev_info_t *dip, int cmd, void *arg, void *tg_cookie) -{ - int instance = ddi_get_instance(dip); - struct pv_cmdk *dkp = ddi_get_soft_state(pv_cmdk_state, instance); - int err; - - if (dkp == NULL) - return (ENXIO); - - if (cmd == TG_GETVIRTGEOM) { - cmlb_geom_t pgeom, *vgeomp; - diskaddr_t capacity; - - /* - * The native xdf driver doesn't support this ioctl. - * Intead of passing it on, emulate it here so that the - * results look the same as what we get for a real cmdk - * device. - * - * Get the real size of the device - */ - if ((err = xdf_lb_getinfo(dkp->dk_xdf_dip, - TG_GETPHYGEOM, &pgeom, tg_cookie)) != 0) - return (err); - capacity = pgeom.g_capacity; - - /* - * If the controller returned us something that doesn't - * really fit into an Int 13/function 8 geometry - * result, just fail the ioctl. See PSARC 1998/313. - */ - if (capacity >= (63 * 254 * 1024)) - return (EINVAL); - - vgeomp = (cmlb_geom_t *)arg; - vgeomp->g_capacity = capacity; - vgeomp->g_nsect = 63; - vgeomp->g_nhead = 254; - vgeomp->g_ncyl = capacity / (63 * 254); - vgeomp->g_acyl = 0; - vgeomp->g_secsize = 512; - vgeomp->g_intrlv = 1; - vgeomp->g_rpm = 3600; - return (0); - } - - return (xdf_lb_getinfo(dkp->dk_xdf_dip, cmd, arg, tg_cookie)); -} - -static cmlb_tg_ops_t pv_cmdk_lb_ops = { - TG_DK_OPS_VERSION_1, - pv_cmdk_lb_rdwr, - pv_cmdk_lb_getinfo -}; - -/* - * devid management functions - */ - -/* - * pv_cmdk_get_modser() is basically a local copy of - * cmdk_get_modser() modified to work without the dadk layer. - * (which the non-pv version of the cmdk driver uses.) - */ -static int -pv_cmdk_get_modser(struct pv_cmdk *dkp, int ioccmd, char *buf, int len) -{ - struct scsi_device *scsi_device; - opaque_t ctlobjp; - dadk_ioc_string_t strarg; - char *s; - char ch; - boolean_t ret; - int i; - int tb; - - strarg.is_buf = buf; - strarg.is_size = len; - scsi_device = ddi_get_driver_private(dkp->dk_dip); - ctlobjp = scsi_device->sd_address.a_hba_tran; - if (CTL_IOCTL(ctlobjp, - ioccmd, (uintptr_t)&strarg, FNATIVE | FKIOCTL) != 0) - return (0); - - /* - * valid model/serial string must contain a non-zero non-space - * trim trailing spaces/NULL - */ - ret = B_FALSE; - s = buf; - for (i = 0; i < strarg.is_size; i++) { - ch = *s++; - if (ch != ' ' && ch != '\0') - tb = i + 1; - if (ch != ' ' && ch != '\0' && ch != '0') - ret = B_TRUE; - } - - if (ret == B_FALSE) - return (0); - - return (tb); -} - -/* - * pv_cmdk_devid_modser() is basically a copy of cmdk_devid_modser() - * that has been modified to use local pv cmdk driver functions. - * - * Build a devid from the model and serial number - * Return DDI_SUCCESS or DDI_FAILURE. - */ -static int -pv_cmdk_devid_modser(struct pv_cmdk *dkp) -{ - int rc = DDI_FAILURE; - char *hwid; - int modlen; - int serlen; - - /* - * device ID is a concatenation of model number, '=', serial number. - */ - hwid = kmem_alloc(CMDK_HWIDLEN, KM_SLEEP); - modlen = pv_cmdk_get_modser(dkp, DIOCTL_GETMODEL, hwid, CMDK_HWIDLEN); - if (modlen == 0) - goto err; - - hwid[modlen++] = '='; - serlen = pv_cmdk_get_modser(dkp, DIOCTL_GETSERIAL, - hwid + modlen, CMDK_HWIDLEN - modlen); - if (serlen == 0) - goto err; - - hwid[modlen + serlen] = 0; - - /* Initialize the device ID, trailing NULL not included */ - rc = ddi_devid_init(dkp->dk_dip, DEVID_ATA_SERIAL, modlen + serlen, - hwid, (ddi_devid_t *)&dkp->dk_devid); - if (rc != DDI_SUCCESS) - goto err; - - kmem_free(hwid, CMDK_HWIDLEN); - return (DDI_SUCCESS); - -err: - kmem_free(hwid, CMDK_HWIDLEN); - return (DDI_FAILURE); -} - -/* - * pv_cmdk_devid_read() is basically a local copy of - * cmdk_devid_read() modified to work without the dadk layer. - * (which the non-pv version of the cmdk driver uses.) - * - * Read a devid from on the first block of the last track of - * the last cylinder. Make sure what we read is a valid devid. - * Return DDI_SUCCESS or DDI_FAILURE. - */ -static int -pv_cmdk_devid_read(struct pv_cmdk *dkp) -{ - diskaddr_t blk; - struct dk_devid *dkdevidp; - uint_t *ip, chksum; - int i; - - if (cmlb_get_devid_block(dkp->dk_cmlbhandle, &blk, 0) != 0) - return (DDI_FAILURE); - - dkdevidp = kmem_zalloc(NBPSCTR, KM_SLEEP); - if (pv_cmdk_lb_rdwr(dkp->dk_dip, - TG_READ, dkdevidp, blk, NBPSCTR, NULL) != 0) - goto err; - - /* Validate the revision */ - if ((dkdevidp->dkd_rev_hi != DK_DEVID_REV_MSB) || - (dkdevidp->dkd_rev_lo != DK_DEVID_REV_LSB)) - goto err; - - /* Calculate the checksum */ - chksum = 0; - ip = (uint_t *)dkdevidp; - for (i = 0; i < ((NBPSCTR - sizeof (int))/sizeof (int)); i++) - chksum ^= ip[i]; - if (DKD_GETCHKSUM(dkdevidp) != chksum) - goto err; - - /* Validate the device id */ - if (ddi_devid_valid((ddi_devid_t)dkdevidp->dkd_devid) != DDI_SUCCESS) - goto err; - - /* keep a copy of the device id */ - i = ddi_devid_sizeof((ddi_devid_t)dkdevidp->dkd_devid); - dkp->dk_devid = kmem_alloc(i, KM_SLEEP); - bcopy(dkdevidp->dkd_devid, dkp->dk_devid, i); - kmem_free(dkdevidp, NBPSCTR); - return (DDI_SUCCESS); - -err: - kmem_free(dkdevidp, NBPSCTR); - return (DDI_FAILURE); -} - -/* - * pv_cmdk_devid_fabricate() is basically a local copy of - * cmdk_devid_fabricate() modified to work without the dadk layer. - * (which the non-pv version of the cmdk driver uses.) - * - * Create a devid and write it on the first block of the last track of - * the last cylinder. - * Return DDI_SUCCESS or DDI_FAILURE. - */ -static int -pv_cmdk_devid_fabricate(struct pv_cmdk *dkp) -{ - ddi_devid_t devid = NULL; /* devid made by ddi_devid_init */ - struct dk_devid *dkdevidp = NULL; /* devid struct stored on disk */ - diskaddr_t blk; - uint_t *ip, chksum; - int i; - - if (cmlb_get_devid_block(dkp->dk_cmlbhandle, &blk, 0) != 0) - return (DDI_FAILURE); - - if (ddi_devid_init(dkp->dk_dip, DEVID_FAB, 0, NULL, &devid) != - DDI_SUCCESS) - return (DDI_FAILURE); - - /* allocate a buffer */ - dkdevidp = (struct dk_devid *)kmem_zalloc(NBPSCTR, KM_SLEEP); - - /* Fill in the revision */ - dkdevidp->dkd_rev_hi = DK_DEVID_REV_MSB; - dkdevidp->dkd_rev_lo = DK_DEVID_REV_LSB; - - /* Copy in the device id */ - i = ddi_devid_sizeof(devid); - if (i > DK_DEVID_SIZE) - goto err; - bcopy(devid, dkdevidp->dkd_devid, i); - - /* Calculate the chksum */ - chksum = 0; - ip = (uint_t *)dkdevidp; - for (i = 0; i < ((NBPSCTR - sizeof (int))/sizeof (int)); i++) - chksum ^= ip[i]; - - /* Fill in the checksum */ - DKD_FORMCHKSUM(chksum, dkdevidp); - - if (pv_cmdk_lb_rdwr(dkp->dk_dip, - TG_WRITE, dkdevidp, blk, NBPSCTR, NULL) != 0) - goto err; - - kmem_free(dkdevidp, NBPSCTR); - - dkp->dk_devid = devid; - return (DDI_SUCCESS); - -err: - if (dkdevidp != NULL) - kmem_free(dkdevidp, NBPSCTR); - if (devid != NULL) - ddi_devid_free(devid); - return (DDI_FAILURE); -} - -/* - * pv_cmdk_devid_setup() is basically a local copy ofcmdk_devid_setup() - * that has been modified to use local pv cmdk driver functions. - * - * Create and register the devid. - * There are 4 different ways we can get a device id: - * 1. Already have one - nothing to do - * 2. Build one from the drive's model and serial numbers - * 3. Read one from the disk (first sector of last track) - * 4. Fabricate one and write it on the disk. - * If any of these succeeds, register the deviceid - */ -static void -pv_cmdk_devid_setup(struct pv_cmdk *dkp) -{ - int rc; - - /* Try options until one succeeds, or all have failed */ - - /* 1. All done if already registered */ - - if (dkp->dk_devid != NULL) - return; - - /* 2. Build a devid from the model and serial number */ - rc = pv_cmdk_devid_modser(dkp); - if (rc != DDI_SUCCESS) { - /* 3. Read devid from the disk, if present */ - rc = pv_cmdk_devid_read(dkp); - - /* 4. otherwise make one up and write it on the disk */ - if (rc != DDI_SUCCESS) - rc = pv_cmdk_devid_fabricate(dkp); - } - - /* If we managed to get a devid any of the above ways, register it */ - if (rc == DDI_SUCCESS) - (void) ddi_devid_register(dkp->dk_dip, dkp->dk_devid); -} - -/* - * Local Functions - */ -static int -pv_cmdk_iodone(struct buf *bp) -{ - struct buf *bp_orig = bp->b_chain; - - /* Propegate back the io results */ - bp_orig->b_resid = bp->b_resid; - bioerror(bp_orig, geterror(bp)); - biodone(bp_orig); - - freerbuf(bp); - return (0); -} - -static int -pv_cmdkstrategy(struct buf *bp) -{ - dev_t dev = bp->b_edev; - int instance = XDF_DEV2UNIT(dev); - int part = XDF_DEV2PART(dev); - struct pv_cmdk *dkp = ddi_get_soft_state(pv_cmdk_state, instance); - dev_t xdf_devt; - struct buf *bp_clone; - - /* - * Sanity checks that the dev_t associated with the buf we were - * passed actually corresponds us and that the partition we're - * trying to access is actually open. On debug kernels we'll - * panic and on non-debug kernels we'll return failure. - */ - ASSERT(getmajor(dev) == pv_cmdk_major); - if (getmajor(dev) != pv_cmdk_major) - goto err; - - mutex_enter(&dkp->dk_mutex); - ASSERT(pv_cmdk_isopen_part(dkp, part)); - if (!pv_cmdk_isopen_part(dkp, part)) { - mutex_exit(&dkp->dk_mutex); - goto err; - } - mutex_exit(&dkp->dk_mutex); - - /* clone this buffer */ - xdf_devt = dkp->dk_xdf_dev | part; - bp_clone = bioclone(bp, 0, bp->b_bcount, xdf_devt, bp->b_blkno, - pv_cmdk_iodone, NULL, KM_SLEEP); - bp_clone->b_chain = bp; - - /* - * If we're being invoked on behalf of the physio() call in - * pv_cmdk_dioctl_rwcmd() then b_private will be set to - * XB_SLICE_NONE and we need to propegate this flag into the - * cloned buffer so that the xdf driver will see it. - */ - if (bp->b_private == (void *)XB_SLICE_NONE) - bp_clone->b_private = (void *)XB_SLICE_NONE; - - /* - * Pass on the cloned buffer. Note that we don't bother to check - * for failure because the xdf strategy routine will have to - * invoke biodone() if it wants to return an error, which means - * that the pv_cmdk_iodone() callback will get invoked and it - * will propegate the error back up the stack and free the cloned - * buffer. - */ - ASSERT(dkp->dk_xdf_lh[part] != NULL); - return (ldi_strategy(dkp->dk_xdf_lh[part], bp_clone)); - -err: - bioerror(bp, ENXIO); - bp->b_resid = bp->b_bcount; - biodone(bp); - return (0); -} - -/*ARGSUSED*/ -static int -pv_cmdkread(dev_t dev, struct uio *uio, cred_t *credp) -{ - int instance = XDF_DEV2UNIT(dev); - int part = XDF_DEV2PART(dev); - struct pv_cmdk *dkp = ddi_get_soft_state(pv_cmdk_state, instance); - - return (ldi_read(dkp->dk_xdf_lh[part], uio, credp)); -} - -/*ARGSUSED*/ -static int -pv_cmdkwrite(dev_t dev, struct uio *uio, cred_t *credp) -{ - int instance = XDF_DEV2UNIT(dev); - int part = XDF_DEV2PART(dev); - struct pv_cmdk *dkp = ddi_get_soft_state(pv_cmdk_state, instance); - - return (ldi_write(dkp->dk_xdf_lh[part], uio, credp)); -} - -/*ARGSUSED*/ -static int -pv_cmdkaread(dev_t dev, struct aio_req *aio, cred_t *credp) -{ - int instance = XDF_DEV2UNIT(dev); - int part = XDF_DEV2PART(dev); - struct pv_cmdk *dkp = ddi_get_soft_state(pv_cmdk_state, instance); - return (ldi_aread(dkp->dk_xdf_lh[part], aio, credp)); -} - -/*ARGSUSED*/ -static int -pv_cmdkawrite(dev_t dev, struct aio_req *aio, cred_t *credp) -{ - int instance = XDF_DEV2UNIT(dev); - int part = XDF_DEV2PART(dev); - struct pv_cmdk *dkp = ddi_get_soft_state(pv_cmdk_state, instance); - return (ldi_awrite(dkp->dk_xdf_lh[part], aio, credp)); -} - -static int -pv_cmdkdump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk) -{ - int instance = XDF_DEV2UNIT(dev); - int part = XDF_DEV2PART(dev); - struct pv_cmdk *dkp = ddi_get_soft_state(pv_cmdk_state, instance); - - return (ldi_dump(dkp->dk_xdf_lh[part], addr, blkno, nblk)); -} - -/* - * pv_rwcmd_copyin() is a duplicate of rwcmd_copyin(). - */ -static int -pv_rwcmd_copyin(struct dadkio_rwcmd *rwcmdp, caddr_t inaddr, int flag) -{ - switch (ddi_model_convert_from(flag)) { - case DDI_MODEL_ILP32: { - struct dadkio_rwcmd32 cmd32; - - if (ddi_copyin(inaddr, &cmd32, - sizeof (struct dadkio_rwcmd32), flag)) { - return (EFAULT); - } - - rwcmdp->cmd = cmd32.cmd; - rwcmdp->flags = cmd32.flags; - rwcmdp->blkaddr = (daddr_t)cmd32.blkaddr; - rwcmdp->buflen = cmd32.buflen; - rwcmdp->bufaddr = (caddr_t)(intptr_t)cmd32.bufaddr; - /* - * Note: we do not convert the 'status' field, - * as it should not contain valid data at this - * point. - */ - bzero(&rwcmdp->status, sizeof (rwcmdp->status)); - break; - } - case DDI_MODEL_NONE: { - if (ddi_copyin(inaddr, rwcmdp, - sizeof (struct dadkio_rwcmd), flag)) { - return (EFAULT); - } - } - } - return (0); -} - -/* - * pv_rwcmd_copyout() is a duplicate of rwcmd_copyout(). - */ -static int -pv_rwcmd_copyout(struct dadkio_rwcmd *rwcmdp, caddr_t outaddr, int flag) -{ - switch (ddi_model_convert_from(flag)) { - case DDI_MODEL_ILP32: { - struct dadkio_rwcmd32 cmd32; - - cmd32.cmd = rwcmdp->cmd; - cmd32.flags = rwcmdp->flags; - cmd32.blkaddr = rwcmdp->blkaddr; - cmd32.buflen = rwcmdp->buflen; - ASSERT64(((uintptr_t)rwcmdp->bufaddr >> 32) == 0); - cmd32.bufaddr = (caddr32_t)(uintptr_t)rwcmdp->bufaddr; - - cmd32.status.status = rwcmdp->status.status; - cmd32.status.resid = rwcmdp->status.resid; - cmd32.status.failed_blk_is_valid = - rwcmdp->status.failed_blk_is_valid; - cmd32.status.failed_blk = rwcmdp->status.failed_blk; - cmd32.status.fru_code_is_valid = - rwcmdp->status.fru_code_is_valid; - cmd32.status.fru_code = rwcmdp->status.fru_code; - - bcopy(rwcmdp->status.add_error_info, - cmd32.status.add_error_info, DADKIO_ERROR_INFO_LEN); - - if (ddi_copyout(&cmd32, outaddr, - sizeof (struct dadkio_rwcmd32), flag)) - return (EFAULT); - break; - } - case DDI_MODEL_NONE: { - if (ddi_copyout(rwcmdp, outaddr, - sizeof (struct dadkio_rwcmd), flag)) - return (EFAULT); - } - } - return (0); -} - -static void -pv_cmdkmin(struct buf *bp) -{ - if (bp->b_bcount > DK_MAXRECSIZE) - bp->b_bcount = DK_MAXRECSIZE; -} - -static int -pv_cmdk_dioctl_rwcmd(dev_t dev, intptr_t arg, int flag) -{ - struct dadkio_rwcmd *rwcmdp; - struct iovec aiov; - struct uio auio; - struct buf *bp; - int rw, status; - - rwcmdp = kmem_alloc(sizeof (struct dadkio_rwcmd), KM_SLEEP); - status = pv_rwcmd_copyin(rwcmdp, (caddr_t)arg, flag); - - if (status != 0) - goto out; - - switch (rwcmdp->cmd) { - case DADKIO_RWCMD_READ: - case DADKIO_RWCMD_WRITE: - break; - default: - status = EINVAL; - goto out; - } - - bzero((caddr_t)&aiov, sizeof (struct iovec)); - aiov.iov_base = rwcmdp->bufaddr; - aiov.iov_len = rwcmdp->buflen; - - bzero((caddr_t)&auio, sizeof (struct uio)); - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - auio.uio_loffset = (offset_t)rwcmdp->blkaddr * (offset_t)XB_BSIZE; - auio.uio_resid = rwcmdp->buflen; - auio.uio_segflg = (flag & FKIOCTL) ? UIO_SYSSPACE : UIO_USERSPACE; - - /* - * Tell the xdf driver that this I/O request is using an absolute - * offset. - */ - bp = getrbuf(KM_SLEEP); - bp->b_private = (void *)XB_SLICE_NONE; - - rw = ((rwcmdp->cmd == DADKIO_RWCMD_WRITE) ? B_WRITE : B_READ); - status = physio(pv_cmdkstrategy, bp, dev, rw, pv_cmdkmin, &auio); - - biofini(bp); - kmem_free(bp, sizeof (buf_t)); - - if (status == 0) - status = pv_rwcmd_copyout(rwcmdp, (caddr_t)arg, flag); - -out: - kmem_free(rwcmdp, sizeof (struct dadkio_rwcmd)); - return (status); -} - -static int -pv_cmdkioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp, - int *rvalp) -{ - int instance = XDF_DEV2UNIT(dev); - int part = XDF_DEV2PART(dev); - struct pv_cmdk *dkp = ddi_get_soft_state(pv_cmdk_state, instance); - int err; - - switch (cmd) { - default: - return (ldi_ioctl(dkp->dk_xdf_lh[part], - cmd, arg, flag, credp, rvalp)); - case DKIOCGETWCE: - case DKIOCSETWCE: - return (EIO); - case DKIOCADDBAD: { - /* - * This is for ata/ide bad block handling. It is supposed - * to cause the driver to re-read the bad block list and - * alternate map after it has been updated. Our driver - * will refuse to attach to any disk which has a bad blocks - * list defined, so there really isn't much to do here. - */ - return (0); - } - case DKIOCGETDEF: { - /* - * I can't actually find any code that utilizes this ioctl, - * hence we're leaving it explicitly unimplemented. - */ - ASSERT("ioctl cmd unsupported by pv_cmdk: DKIOCGETDEF"); - return (EIO); - } - case DIOCTL_RWCMD: { - /* - * This just seems to just be an alternate interface for - * reading and writing the disk. Great, another way to - * do the same thing... - */ - return (pv_cmdk_dioctl_rwcmd(dev, arg, flag)); - } - case DKIOCINFO: { - dev_info_t *dip = dkp->dk_dip; - struct dk_cinfo info; - - /* Pass on the ioctl request, save the response */ - if ((err = ldi_ioctl(dkp->dk_xdf_lh[part], - cmd, (intptr_t)&info, FKIOCTL, credp, rvalp)) != 0) - return (err); - - /* Update controller info */ - info.dki_cnum = ddi_get_instance(ddi_get_parent(dip)); - (void) strlcpy(info.dki_cname, - ddi_get_name(ddi_get_parent(dip)), sizeof (info.dki_cname)); - - /* Update unit info. */ - if (info.dki_ctype == DKC_VBD) - info.dki_ctype = DKC_DIRECT; - info.dki_unit = instance; - (void) strlcpy(info.dki_dname, - ddi_driver_name(dip), sizeof (info.dki_dname)); - info.dki_addr = 1; - - if (ddi_copyout(&info, (void *)arg, sizeof (info), flag)) - return (EFAULT); - return (0); - } - } /* switch (cmd) */ - /*NOTREACHED*/ -} - -/*ARGSUSED*/ -static int -pv_cmdkopen(dev_t *dev_p, int flag, int otyp, cred_t *credp) -{ - ldi_ident_t li; - dev_t dev = *dev_p; - int instance = XDF_DEV2UNIT(dev); - int part = XDF_DEV2PART(dev); - struct pv_cmdk *dkp = ddi_get_soft_state(pv_cmdk_state, instance); - dev_t xdf_devt = dkp->dk_xdf_dev | part; - int err = 0; - - if ((otyp < 0) || (otyp >= OTYPCNT)) - return (EINVAL); - - /* allocate an ldi handle */ - VERIFY(ldi_ident_from_dev(*dev_p, &li) == 0); - - mutex_enter(&dkp->dk_mutex); - - /* - * We translate all device opens (chr, blk, and lyr) into - * block device opens. Why? Because for all the opens that - * come through this driver, we only keep around one LDI handle. - * So that handle can only be of one open type. The reason - * that we choose the block interface for this is that to use - * the block interfaces for a device the system needs to allocatex - * buf_ts, which are associated with system memory which can act - * as a cache for device data. So normally when a block device - * is closed the system will ensure that all these pages get - * flushed out of memory. But if we were to open the device - * as a character device, then when we went to close the underlying - * device (even if we had invoked the block interfaces) any data - * remaining in memory wouldn't necessairly be flushed out - * before the device was closed. - */ - if (dkp->dk_xdf_lh[part] == NULL) { - ASSERT(!pv_cmdk_isopen_part(dkp, part)); - - err = ldi_open_by_dev(&xdf_devt, OTYP_BLK, flag, credp, - &dkp->dk_xdf_lh[part], li); - - if (err != 0) { - mutex_exit(&dkp->dk_mutex); - ldi_ident_release(li); - return (err); - } - - /* Disk devices really shouldn't clone */ - ASSERT(xdf_devt == (dkp->dk_xdf_dev | part)); - } else { - ldi_handle_t lh_tmp; - - ASSERT(pv_cmdk_isopen_part(dkp, part)); - - /* do ldi open/close to get flags and cred check */ - err = ldi_open_by_dev(&xdf_devt, OTYP_BLK, flag, credp, - &lh_tmp, li); - if (err != 0) { - mutex_exit(&dkp->dk_mutex); - ldi_ident_release(li); - return (err); - } - - /* Disk devices really shouldn't clone */ - ASSERT(xdf_devt == (dkp->dk_xdf_dev | part)); - (void) ldi_close(lh_tmp, flag, credp); - } - ldi_ident_release(li); - - dkp->dk_xdf_otyp_count[otyp][part]++; - - mutex_exit(&dkp->dk_mutex); - return (0); -} - -/*ARGSUSED*/ -static int -pv_cmdkclose(dev_t dev, int flag, int otyp, cred_t *credp) -{ - int instance = XDF_DEV2UNIT(dev); - int part = XDF_DEV2PART(dev); - struct pv_cmdk *dkp = ddi_get_soft_state(pv_cmdk_state, instance); - int err = 0; - - ASSERT((otyp >= 0) && otyp < OTYPCNT); - - /* - * Sanity check that that the dev_t specified corresponds to this - * driver and that the device is actually open. On debug kernels we'll - * panic and on non-debug kernels we'll return failure. - */ - ASSERT(getmajor(dev) == pv_cmdk_major); - if (getmajor(dev) != pv_cmdk_major) - return (ENXIO); - - mutex_enter(&dkp->dk_mutex); - ASSERT(pv_cmdk_isopen_part(dkp, part)); - if (!pv_cmdk_isopen_part(dkp, part)) { - mutex_exit(&dkp->dk_mutex); - return (ENXIO); - } - - ASSERT(dkp->dk_xdf_lh[part] != NULL); - ASSERT(dkp->dk_xdf_otyp_count[otyp][part] > 0); - if (otyp == OTYP_LYR) { - dkp->dk_xdf_otyp_count[otyp][part]--; - } else { - dkp->dk_xdf_otyp_count[otyp][part] = 0; - } - - if (!pv_cmdk_isopen_part(dkp, part)) { - err = ldi_close(dkp->dk_xdf_lh[part], flag, credp); - dkp->dk_xdf_lh[part] = NULL; - } - - mutex_exit(&dkp->dk_mutex); - - return (err); -} - -static int -pv_cmdk_getpgeom(dev_info_t *dip, cmlb_geom_t *pgeom) -{ - struct scsi_device *scsi_device; - struct tgdk_geom tgdk_geom; - opaque_t ctlobjp; - int err; - - scsi_device = ddi_get_driver_private(dip); - ctlobjp = scsi_device->sd_address.a_hba_tran; - if ((err = CTL_IOCTL(ctlobjp, - DIOCTL_GETPHYGEOM, (uintptr_t)&tgdk_geom, FKIOCTL)) != 0) - return (err); - - /* This driver won't work if this isn't true */ - ASSERT(tgdk_geom.g_secsiz == XB_BSIZE); - - pgeom->g_ncyl = tgdk_geom.g_cyl; - pgeom->g_acyl = tgdk_geom.g_acyl; - pgeom->g_nhead = tgdk_geom.g_head; - pgeom->g_nsect = tgdk_geom.g_sec; - pgeom->g_secsize = tgdk_geom.g_secsiz; - pgeom->g_capacity = tgdk_geom.g_cap; - pgeom->g_intrlv = 1; - pgeom->g_rpm = 3600; - return (0); -} - -/* - * pv_cmdk_bb_check() checks for the existance of bad blocks mappings in - * the alternate partition/slice. Returns B_FALSE is there are no bad - * block mappins found, and B_TRUE is there are bad block mappins found. - */ -static boolean_t -pv_cmdk_bb_check(struct pv_cmdk *dkp) -{ - struct alts_parttbl *ap; - diskaddr_t nblocks, blk; - uint32_t altused, altbase, altlast; - uint16_t vtoctag; - int alts; - - /* find slice with V_ALTSCTR tag */ - for (alts = 0; alts < NDKMAP; alts++) { - - if (cmlb_partinfo(dkp->dk_cmlbhandle, alts, - &nblocks, &blk, NULL, &vtoctag, 0) != 0) { - /* no partition table exists */ - return (B_FALSE); - } - - if ((vtoctag == V_ALTSCTR) && (nblocks > 1)) - break; - } - if (alts >= NDKMAP) - return (B_FALSE); /* no V_ALTSCTR slice defined */ - - /* read in ALTS label block */ - ap = (struct alts_parttbl *)kmem_zalloc(NBPSCTR, KM_SLEEP); - if (pv_cmdk_lb_rdwr(dkp->dk_dip, - TG_READ, ap, blk, NBPSCTR, NULL) != 0) - goto err; - - altused = ap->alts_ent_used; /* number of BB entries */ - altbase = ap->alts_ent_base; /* blk offset from begin slice */ - altlast = ap->alts_ent_end; /* blk offset to last block */ - - if ((altused == 0) || (altbase < 1) || - (altbase > altlast) || (altlast >= nblocks)) - goto err; - - /* we found bad block mappins */ - kmem_free(ap, NBPSCTR); - return (B_TRUE); - -err: - kmem_free(ap, NBPSCTR); - return (B_FALSE); -} - -/* - * Autoconfiguration Routines - */ -static int -pv_cmdkattach(dev_info_t *dip, ddi_attach_cmd_t cmd) -{ - int instance = ddi_get_instance(dip); - dev_info_t *xdf_dip = NULL; - struct pv_cmdk *dkp; - cmlb_geom_t pgeom; - char *path; - int i; - - if (cmd != DDI_ATTACH) - return (DDI_FAILURE); - - /* - * This cmdk device layers on top of an xdf device. So the first - * thing we need to do is determine which xdf device instance this - * cmdk instance should be layered on top of. - */ - path = kmem_alloc(MAXPATHLEN, KM_SLEEP); - (void) ddi_pathname(dip, path); - for (i = 0; pv_cmdk_h2p[i].h2p_hvm_path != NULL; i++) { - if (strcmp(pv_cmdk_h2p[i].h2p_hvm_path, path) == 0) - break; - } - kmem_free(path, MAXPATHLEN); - - if (pv_cmdk_h2p[i].h2p_hvm_path == NULL) { - /* - * UhOh. We don't know what xdf instance this cmdk device - * should be mapped to. - */ - return (DDI_FAILURE); - } - - /* Check if this device exists */ - xdf_dip = xdf_hvm_hold(pv_cmdk_h2p[i].h2p_pv_path); - if (xdf_dip == NULL) - return (DDI_FAILURE); - - /* allocate and initialize our state structure */ - (void) ddi_soft_state_zalloc(pv_cmdk_state, instance); - dkp = ddi_get_soft_state(pv_cmdk_state, instance); - mutex_init(&dkp->dk_mutex, NULL, MUTEX_DRIVER, NULL); - dkp->dk_dip = dip; - dkp->dk_xdf_dip = xdf_dip; - dkp->dk_xdf_dev = makedevice(ddi_driver_major(xdf_dip), - XDF_MINOR(ddi_get_instance(xdf_dip), 0)); - - ASSERT((dkp->dk_xdf_dev & XDF_PMASK) == 0); - - /* - * GROSS HACK ALERT! GROSS HACK ALERT! - * - * Before we can initialize the cmlb layer, we have to tell the - * underlying xdf device what it's physical geometry should be. - * See the block comments at the top of this file for more info. - */ - if ((pv_cmdk_getpgeom(dip, &pgeom) != 0) || - (xdf_hvm_setpgeom(dkp->dk_xdf_dip, &pgeom) != 0)) { - ddi_release_devi(dkp->dk_xdf_dip); - mutex_destroy(&dkp->dk_mutex); - ddi_soft_state_free(pv_cmdk_state, instance); - return (DDI_FAILURE); - } - - /* create kstat for iostat(1M) */ - if (xdf_kstat_create(dkp->dk_xdf_dip, "cmdk", instance) != 0) { - ddi_release_devi(dkp->dk_xdf_dip); - mutex_destroy(&dkp->dk_mutex); - ddi_soft_state_free(pv_cmdk_state, instance); - return (DDI_FAILURE); - } - - /* - * Force the xdf front end driver to connect to the backend. From - * the solaris device tree perspective, the xdf driver devinfo node - * is already in the ATTACHED state. (Otherwise xdf_hvm_hold() - * would not have returned a dip.) But this doesn't mean that the - * xdf device has actually established a connection to it's back - * end driver. For us to be able to access the xdf device it needs - * to be connected. There are two ways to force the xdf driver to - * connect to the backend device. - */ - if (xdf_hvm_connect(dkp->dk_xdf_dip) != 0) { - cmn_err(CE_WARN, - "pv driver failed to connect: %s", - pv_cmdk_h2p[i].h2p_pv_path); - xdf_kstat_delete(dkp->dk_xdf_dip); - ddi_release_devi(dkp->dk_xdf_dip); - mutex_destroy(&dkp->dk_mutex); - ddi_soft_state_free(pv_cmdk_state, instance); - return (DDI_FAILURE); - } - - /* - * Initalize cmlb. Note that for partition information cmlb - * will access the underly xdf disk device directly via - * pv_cmdk_lb_rdwr() and pv_cmdk_lb_getinfo(). There are no - * layered driver handles associated with this access because - * it is a direct disk access that doesn't go through - * any of the device nodes exported by the xdf device (since - * all exported device nodes only reflect the portion of - * the device visible via the partition/slice that the node - * is associated with.) So while not observable via the LDI, - * this direct disk access is ok since we're actually holding - * the target device. - */ - cmlb_alloc_handle((cmlb_handle_t *)&dkp->dk_cmlbhandle); - if (cmlb_attach(dkp->dk_dip, &pv_cmdk_lb_ops, - DTYPE_DIRECT, /* device_type */ - 0, /* not removable */ - 0, /* not hot pluggable */ - DDI_NT_BLOCK, - CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT, /* mimic cmdk */ - dkp->dk_cmlbhandle, 0) != 0) { - cmlb_free_handle(&dkp->dk_cmlbhandle); - xdf_kstat_delete(dkp->dk_xdf_dip); - ddi_release_devi(dkp->dk_xdf_dip); - mutex_destroy(&dkp->dk_mutex); - ddi_soft_state_free(pv_cmdk_state, instance); - return (DDI_FAILURE); - } - - if (pv_cmdk_bb_check(dkp)) { - cmn_err(CE_WARN, - "pv cmdk disks with bad blocks are unsupported: %s", - pv_cmdk_h2p[i].h2p_hvm_path); - - cmlb_detach(dkp->dk_cmlbhandle, 0); - cmlb_free_handle(&dkp->dk_cmlbhandle); - xdf_kstat_delete(dkp->dk_xdf_dip); - ddi_release_devi(dkp->dk_xdf_dip); - mutex_destroy(&dkp->dk_mutex); - ddi_soft_state_free(pv_cmdk_state, instance); - return (DDI_FAILURE); - } - - /* setup devid string */ - pv_cmdk_devid_setup(dkp); - - /* Calling validate will create minor nodes according to disk label */ - (void) cmlb_validate(dkp->dk_cmlbhandle, 0, 0); - - /* - * Add a zero-length attribute to tell the world we support - * kernel ioctls (for layered drivers). - */ - (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, - DDI_KERNEL_IOCTL, NULL, 0); - - /* Have the system report any newly created device nodes */ - ddi_report_dev(dip); - - return (DDI_SUCCESS); -} - -static int -pv_cmdkdetach(dev_info_t *dip, ddi_detach_cmd_t cmd) -{ - int instance = ddi_get_instance(dip); - struct pv_cmdk *dkp = ddi_get_soft_state(pv_cmdk_state, instance); - - if (cmd != DDI_DETACH) - return (DDI_FAILURE); - - ASSERT(MUTEX_NOT_HELD(&dkp->dk_mutex)); - - ddi_devid_unregister(dip); - if (dkp->dk_devid) - ddi_devid_free(dkp->dk_devid); - cmlb_detach(dkp->dk_cmlbhandle, 0); - cmlb_free_handle(&dkp->dk_cmlbhandle); - mutex_destroy(&dkp->dk_mutex); - xdf_kstat_delete(dkp->dk_xdf_dip); - ddi_release_devi(dkp->dk_xdf_dip); - ddi_soft_state_free(pv_cmdk_state, instance); - ddi_prop_remove_all(dip); - - return (DDI_SUCCESS); -} - -/*ARGSUSED*/ -static int -pv_cmdk_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, - void **result) -{ - dev_t dev = (dev_t)arg; - int instance = XDF_DEV2UNIT(dev); - struct pv_cmdk *dkp = ddi_get_soft_state(pv_cmdk_state, instance); - - switch (infocmd) { - case DDI_INFO_DEVT2DEVINFO: - if (dkp == NULL) - return (DDI_FAILURE); - *result = (void *)dkp->dk_dip; - break; - case DDI_INFO_DEVT2INSTANCE: - *result = (void *)(intptr_t)instance; - break; - default: - return (DDI_FAILURE); - } - return (DDI_SUCCESS); -} - -static int -pv_cmdk_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, - int flags, char *name, caddr_t valuep, int *lengthp) -{ - int instance = ddi_get_instance(dip); - struct pv_cmdk *dkp = ddi_get_soft_state(pv_cmdk_state, instance); - dev_info_t *xdf_dip; - dev_t xdf_devt; - int err; - - /* - * Sanity check that if a dev_t or dip were specified that they - * correspond to this device driver. On debug kernels we'll - * panic and on non-debug kernels we'll return failure. - */ - ASSERT(ddi_driver_major(dip) == pv_cmdk_major); - ASSERT((dev == DDI_DEV_T_ANY) || (getmajor(dev) == pv_cmdk_major)); - if ((ddi_driver_major(dip) != pv_cmdk_major) || - ((dev != DDI_DEV_T_ANY) && (getmajor(dev) != pv_cmdk_major))) - return (DDI_PROP_NOT_FOUND); - - /* - * This property lookup might be associated with a device node - * that is not yet attached, if so pass it onto ddi_prop_op(). - */ - if (dkp == NULL) - return (ddi_prop_op(dev, dip, prop_op, flags, - name, valuep, lengthp)); - - /* - * Make sure we only lookup static properties. - * - * If there are static properties of the underlying xdf driver - * that we want to mirror, then we'll have to explicity look them - * up and define them during attach. There are a few reasons - * for this. Most importantly, most static properties are typed - * and all dynamic properties are untyped, ie, for dynamic - * properties the caller must know the type of the property and - * how to interpret the value of the property. the prop_op drivedr - * entry point is only designed for returning dynamic/untyped - * properties, so if we were to attempt to lookup and pass back - * static properties of the underlying device here then we would - * be losing the type information for those properties. Another - * reason we don't want to pass on static property requests is that - * static properties are enumerable in the device tree, where as - * dynamic ones are not. - */ - flags |= DDI_PROP_DYNAMIC; - - /* - * We can't use the ldi here to access the underlying device because - * the ldi actually opens the device, and that open might fail if the - * device has already been opened with the FEXCL flag. If we used - * the ldi here, it would also be possible for some other caller - * to try open the device with the FEXCL flag and get a failure - * back because we have it open to do a property query. - * - * Instad we'll grab a hold on the target dip and query the - * property directly. - */ - mutex_enter(&dkp->dk_mutex); - - if ((xdf_dip = dkp->dk_xdf_dip) == NULL) { - mutex_exit(&dkp->dk_mutex); - return (DDI_PROP_NOT_FOUND); - } - e_ddi_hold_devi(xdf_dip); - - /* figure out the dev_t we're going to pass on down */ - if (dev == DDI_DEV_T_ANY) { - xdf_devt = DDI_DEV_T_ANY; - } else { - xdf_devt = dkp->dk_xdf_dev | XDF_DEV2PART(dev); - } - - mutex_exit(&dkp->dk_mutex); - - /* - * Cdev_prop_op() is not a public interface, and normally the caller - * is required to make sure that the target driver actually implements - * this interface before trying to invoke it. In this case we know - * that we're always accessing the xdf driver and it does have this - * interface defined, so we can skip the check. - */ - err = cdev_prop_op(xdf_devt, xdf_dip, - prop_op, flags, name, valuep, lengthp); - ddi_release_devi(xdf_dip); - return (err); -} - -/* - * Device driver ops vector - */ -static struct cb_ops pv_cmdk_cb_ops = { - pv_cmdkopen, /* open */ - pv_cmdkclose, /* close */ - pv_cmdkstrategy, /* strategy */ - nodev, /* print */ - pv_cmdkdump, /* dump */ - pv_cmdkread, /* read */ - pv_cmdkwrite, /* write */ - pv_cmdkioctl, /* ioctl */ - nodev, /* devmap */ - nodev, /* mmap */ - nodev, /* segmap */ - nochpoll, /* poll */ - pv_cmdk_prop_op, /* cb_prop_op */ - 0, /* streamtab */ - D_64BIT | D_MP | D_NEW, /* Driver comaptibility flag */ - CB_REV, /* cb_rev */ - pv_cmdkaread, /* async read */ - pv_cmdkawrite /* async write */ -}; - -struct dev_ops pv_cmdk_ops = { - DEVO_REV, /* devo_rev, */ - 0, /* refcnt */ - pv_cmdk_getinfo, /* info */ - nulldev, /* identify */ - nulldev, /* probe */ - pv_cmdkattach, /* attach */ - pv_cmdkdetach, /* detach */ - nodev, /* reset */ - &pv_cmdk_cb_ops, /* driver operations */ - (struct bus_ops *)0 /* bus operations */ -}; - -/* - * Module linkage information for the kernel. - */ -static struct modldrv modldrv = { - &mod_driverops, /* Type of module. This one is a driver */ - "PV Common Direct Access Disk", - &pv_cmdk_ops, /* driver ops */ -}; - -static struct modlinkage modlinkage = { - MODREV_1, (void *)&modldrv, NULL -}; - -int -_init(void) -{ - int rval; - - if ((pv_cmdk_major = ddi_name_to_major("cmdk")) == (major_t)-1) - return (EINVAL); - - /* - * In general ide usually supports 4 disk devices, this same - * limitation also applies to software emulating ide devices. - * so by default we pre-allocate 4 cmdk soft state structures. - */ - if ((rval = ddi_soft_state_init(&pv_cmdk_state, - sizeof (struct pv_cmdk), PV_CMDK_NODES)) != 0) - return (rval); - - /* - * Currently we only support qemu as the backing hardware emulator - * for cmdk devices. - */ - pv_cmdk_h2p = pv_cmdk_h2p_xen_qemu; - - /* Install our module */ - if ((rval = mod_install(&modlinkage)) != 0) { - ddi_soft_state_fini(&pv_cmdk_state); - return (rval); - } - - return (0); -} - -int -_info(struct modinfo *modinfop) -{ - return (mod_info(&modlinkage, modinfop)); -} - -int -_fini(void) -{ - int rval; - if ((rval = mod_remove(&modlinkage)) != 0) - return (rval); - ddi_soft_state_fini(&pv_cmdk_state); - return (0); -}
--- a/usr/src/uts/i86pc/io/pv_rtls.c Mon Apr 14 22:16:59 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +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 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Fake rtls module. Prevents the real rtls driver from loading in - * a xen HVM domain so that xnf may operate instead. - */ - -#include <sys/sunddi.h> -#include <sys/errno.h> -#include <sys/modctl.h> - -struct dev_ops pv_rtls_ops = { - DEVO_REV, - 0, - NULL, - nulldev, - nulldev, - NULL, - NULL, - nodev, - NULL, - NULL -}; - -/* - * Module linkage information for the kernel. - */ -static struct modldrv modldrv = { - &mod_driverops, - "xVM rtls stub %I%", - &pv_rtls_ops -}; - -static struct modlinkage modlinkage = { - MODREV_1, (void *)&modldrv, NULL -}; - -int -_init(void) -{ - return (mod_install(&modlinkage)); -} - -int -_info(struct modinfo *modinfop) -{ - return (mod_info(&modlinkage, modinfop)); -} - -int -_fini(void) -{ - return (EBUSY); -}
--- a/usr/src/uts/i86pc/io/xpv/evtchn.c Mon Apr 14 22:16:59 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,389 +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 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/types.h> -#include <sys/xpv_support.h> -#include <sys/hypervisor.h> -#include <sys/machsystm.h> -#include <sys/mutex.h> -#include <sys/cmn_err.h> -#include <sys/dditypes.h> -#include <sys/atomic.h> -#include <sys/sysmacros.h> -#include <sys/cpu.h> -#include <sys/psw.h> -#include <sys/psm.h> -#include <sys/sdt.h> - -extern dev_info_t *xpv_dip; -static ddi_intr_handle_t *evtchn_ihp = NULL; -static ddi_softint_handle_t evtchn_to_handle[NR_EVENT_CHANNELS]; -kmutex_t ec_lock; - -static int evtchn_callback_irq = -1; - -static volatile ulong_t *pending_events; -static volatile ulong_t *masked_events; - -/* log2(NBBY * sizeof (ulong)) */ -#ifdef __amd64 -#define EVTCHN_SHIFT 6 -#else /* __i386 */ -#define EVTCHN_SHIFT 5 -#endif - -/* Atomically get and clear a ulong from memory. */ -#define GET_AND_CLEAR(src, targ) { \ - membar_enter(); \ - do { \ - targ = *src; \ - } while (atomic_cas_ulong(src, targ, 0) != targ); \ -} - -/* Get the first and last bits set in a bitmap */ -#define GET_BOUNDS(bitmap, low, high) { \ - int _i; \ - low = high = -1; \ - for (_i = 0; _i <= sizeof (ulong_t); _i++) \ - if (bitmap & (1UL << _i)) { \ - if (low == -1) \ - low = _i; \ - high = _i; \ - } \ -} - -void -ec_bind_evtchn_to_handler(int evtchn, pri_t pri, ec_handler_fcn_t handler, - void *arg1) -{ - ddi_softint_handle_t hdl; - - if (evtchn < 0 || evtchn > NR_EVENT_CHANNELS) { - cmn_err(CE_WARN, "Binding invalid event channel: %d", evtchn); - return; - } - - (void) ddi_intr_add_softint(xpv_dip, &hdl, pri, handler, (caddr_t)arg1); - mutex_enter(&ec_lock); - ASSERT(evtchn_to_handle[evtchn] == NULL); - evtchn_to_handle[evtchn] = hdl; - mutex_exit(&ec_lock); - - /* Let the hypervisor know we're prepared to handle this event */ - hypervisor_unmask_event(evtchn); -} - -void -ec_unbind_evtchn(int evtchn) -{ - evtchn_close_t close; - ddi_softint_handle_t hdl; - - if (evtchn < 0 || evtchn > NR_EVENT_CHANNELS) { - cmn_err(CE_WARN, "Unbinding invalid event channel: %d", evtchn); - return; - } - - /* - * Let the hypervisor know we're no longer prepared to handle this - * event - */ - hypervisor_mask_event(evtchn); - - /* Cleanup the event handler metadata */ - mutex_enter(&ec_lock); - hdl = evtchn_to_handle[evtchn]; - evtchn_to_handle[evtchn] = NULL; - mutex_exit(&ec_lock); - - close.port = evtchn; - (void) HYPERVISOR_event_channel_op(EVTCHNOP_close, &close); - (void) ddi_intr_remove_softint(hdl); -} - -void -ec_notify_via_evtchn(unsigned int port) -{ - evtchn_send_t send; - - if ((int)port == -1) - return; - send.port = port; - (void) HYPERVISOR_event_channel_op(EVTCHNOP_send, &send); -} - -void -hypervisor_unmask_event(unsigned int ev) -{ - int index = ev >> EVTCHN_SHIFT; - ulong_t bit = 1UL << (ev & ((1UL << EVTCHN_SHIFT) - 1)); - volatile ulong_t *maskp; - evtchn_unmask_t unmask; - - /* - * index,bit contain the event number as an index into the - * masked-events bitmask. Set it to 0. - */ - maskp = &masked_events[index]; - atomic_and_ulong(maskp, ~bit); - - /* Let the hypervisor know the event has been unmasked */ - unmask.port = ev; - if (HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask) != 0) - panic("xen_evtchn_unmask() failed"); -} - -/* Set a bit in an evtchan mask word */ -void -hypervisor_mask_event(uint_t ev) -{ - int index = ev >> EVTCHN_SHIFT; - ulong_t bit = 1UL << (ev & ((1UL << EVTCHN_SHIFT) - 1)); - volatile ulong_t *maskp; - - maskp = &masked_events[index]; - atomic_or_ulong(maskp, bit); -} - -void -hypervisor_clear_event(uint_t ev) -{ - int index = ev >> EVTCHN_SHIFT; - ulong_t bit = 1UL << (ev & ((1UL << EVTCHN_SHIFT) - 1)); - volatile ulong_t *maskp; - - maskp = &pending_events[index]; - atomic_and_ulong(maskp, ~bit); -} - -int -xen_alloc_unbound_evtchn(int domid, int *evtchnp) -{ - evtchn_alloc_unbound_t alloc; - int err; - - alloc.dom = DOMID_SELF; - alloc.remote_dom = (domid_t)domid; - - if ((err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, - &alloc)) == 0) { - *evtchnp = alloc.port; - /* ensure evtchn is masked till we're ready to use it */ - (void) hypervisor_mask_event(*evtchnp); - } else { - err = xen_xlate_errcode(err); - } - - return (err); -} - -int -xen_bind_interdomain(int domid, int remote_port, int *port) -{ - evtchn_bind_interdomain_t bind; - int err; - - bind.remote_dom = (domid_t)domid; - bind.remote_port = remote_port; - if ((err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain, - &bind)) == 0) - *port = bind.local_port; - else - err = xen_xlate_errcode(err); - return (err); -} - -/*ARGSUSED*/ -uint_t -evtchn_callback_fcn(caddr_t arg0, caddr_t arg1) -{ - ulong_t pending_word; - int i, j, port; - volatile struct vcpu_info *vci; - uint_t rv = DDI_INTR_UNCLAIMED; - ddi_softint_handle_t hdl; - int low, high; - ulong_t sels; - - vci = &HYPERVISOR_shared_info->vcpu_info[CPU->cpu_id]; - -again: - DTRACE_PROBE2(evtchn__scan__start, int, vci->evtchn_upcall_pending, - ulong_t, vci->evtchn_pending_sel); - - atomic_and_8(&vci->evtchn_upcall_pending, 0); - - /* - * Find the upper and lower bounds in which we need to search for - * pending events. - */ - GET_AND_CLEAR(&vci->evtchn_pending_sel, sels); - - /* sels == 1 is by far the most common case. Make it fast */ - if (sels == 1) - low = high = 0; - else if (sels == 0) - return (rv); - else - GET_BOUNDS(sels, low, high); - - /* Scan the port list, looking for words with bits set */ - for (i = low; i <= high; i++) { - ulong_t tmp; - - GET_AND_CLEAR(&pending_events[i], tmp); - pending_word = tmp & ~(masked_events[i]); - - /* Scan the bits in the word, looking for pending events */ - while (pending_word != 0) { - j = lowbit(pending_word) - 1; - port = (i << EVTCHN_SHIFT) + j; - pending_word = pending_word & ~(1 << j); - - /* - * If there is a handler registered for this event, - * schedule a softint of the appropriate priority - * to execute it. - */ - if ((hdl = evtchn_to_handle[port]) != NULL) { - (void) ddi_intr_trigger_softint(hdl, NULL); - rv = DDI_INTR_CLAIMED; - } - } - } - DTRACE_PROBE2(evtchn__scan__end, int, vci->evtchn_upcall_pending, - ulong_t, vci->evtchn_pending_sel); - - if ((volatile uint8_t)vci->evtchn_upcall_pending || - ((volatile ulong_t)vci->evtchn_pending_sel)) - goto again; - - return (rv); -} - -static int -set_hvm_callback(int irq) -{ - struct xen_hvm_param xhp; - - xhp.domid = DOMID_SELF; - xhp.index = HVM_PARAM_CALLBACK_IRQ; - xhp.value = irq; - return (HYPERVISOR_hvm_op(HVMOP_set_param, &xhp)); -} - -void -ec_fini() -{ - int i; - - for (i = 0; i < NR_EVENT_CHANNELS; i++) - ec_unbind_evtchn(i); - - evtchn_callback_irq = -1; - if (evtchn_ihp != NULL) { - (void) ddi_intr_disable(*evtchn_ihp); - (void) ddi_intr_remove_handler(*evtchn_ihp); - (void) ddi_intr_free(*evtchn_ihp); - kmem_free(evtchn_ihp, sizeof (ddi_intr_handle_t)); - evtchn_ihp = NULL; - } -} - -int -ec_init(dev_info_t *dip) -{ - int i; - int rv, actual; - ddi_intr_handle_t *ihp; - - /* - * Translate the variable-sized pending and masked event bitmasks - * into constant-sized arrays of uint32_t's. - */ - pending_events = &HYPERVISOR_shared_info->evtchn_pending[0]; - masked_events = &HYPERVISOR_shared_info->evtchn_mask[0]; - - /* - * Clear our event handler structures and prevent the hypervisor - * from triggering any events. - */ - mutex_init(&ec_lock, NULL, MUTEX_SPIN, (void *)ipltospl(SPL7)); - for (i = 0; i < NR_EVENT_CHANNELS; i++) { - evtchn_to_handle[i] = NULL; - (void) hypervisor_mask_event(i); - } - - /* - * Allocate and initialize an interrupt handler to process the - * hypervisor's "hey you have events pending!" interrupt. - */ - ihp = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP); - rv = ddi_intr_alloc(dip, ihp, DDI_INTR_TYPE_FIXED, 0, 1, &actual, - DDI_INTR_ALLOC_NORMAL); - if (rv < 0 || actual != 1) { - cmn_err(CE_WARN, "Could not allocate evtchn interrupt: %d", - rv); - return (-1); - } - - rv = ddi_intr_add_handler(*ihp, evtchn_callback_fcn, NULL, NULL); - if (rv < 0) { - (void) ddi_intr_free(*ihp); - cmn_err(CE_WARN, "Could not attach evtchn handler"); - return (-1); - } - evtchn_ihp = ihp; - - if (ddi_intr_enable(*ihp) != DDI_SUCCESS) { - cmn_err(CE_WARN, "Could not enable evtchn interrupts\n"); - return (-1); - } - - /* Tell the hypervisor which interrupt we're waiting on. */ - evtchn_callback_irq = ((ddi_intr_handle_impl_t *)*ihp)->ih_vector; - - if (set_hvm_callback(evtchn_callback_irq) != 0) { - cmn_err(CE_WARN, "Couldn't register evtchn callback"); - return (-1); - } - return (0); -} - -void -ec_resume(void) -{ - int i; - - /* New event-channel space is not 'live' yet. */ - for (i = 0; i < NR_EVENT_CHANNELS; i++) - (void) hypervisor_mask_event(i); - if (set_hvm_callback(evtchn_callback_irq) != 0) - cmn_err(CE_WARN, "Couldn't register evtchn callback"); - -}
--- a/usr/src/uts/i86pc/io/xpv/xpv.conf Mon Apr 14 22:16:59 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +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. -# - -# ident "%Z%%M% %I% %E% SMI" - -interrupt-priorities=9;
--- a/usr/src/uts/i86pc/io/xpv/xpv_support.c Mon Apr 14 22:16:59 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,956 +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 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/modctl.h> -#include <sys/types.h> -#include <sys/archsystm.h> -#include <sys/machsystm.h> -#include <sys/sunndi.h> -#include <sys/sunddi.h> -#include <sys/ddi_subrdefs.h> -#include <sys/xpv_support.h> -#include <sys/xen_errno.h> -#include <sys/hypervisor.h> -#include <sys/gnttab.h> -#include <sys/xenbus_comms.h> -#include <sys/xenbus_impl.h> -#include <xen/sys/xendev.h> -#include <sys/sysmacros.h> -#include <sys/x86_archext.h> -#include <sys/mman.h> -#include <sys/stat.h> -#include <sys/conf.h> -#include <sys/devops.h> -#include <sys/pc_mmu.h> -#include <sys/cmn_err.h> -#include <sys/cpr.h> -#include <sys/ddi.h> -#include <vm/seg_kmem.h> -#include <vm/as.h> -#include <vm/hat_pte.h> -#include <vm/hat_i86.h> - -#define XPV_MINOR 0 -#define XPV_BUFSIZE 128 - -/* - * This structure is ordinarily constructed by Xen. In the HVM world, we - * manually fill in the few fields the PV drivers need. - */ -start_info_t *xen_info = NULL; - -/* Xen version number. */ -int xen_major, xen_minor; - -/* Metadata page shared between domain and Xen */ -shared_info_t *HYPERVISOR_shared_info = NULL; - -/* Page containing code to issue hypercalls. */ -extern caddr_t hypercall_page; - -/* Is the hypervisor 64-bit? */ -int xen_is_64bit = -1; - -/* virtual addr for the store_mfn page */ -caddr_t xb_addr; - -dev_info_t *xpv_dip; -static dev_info_t *xpvd_dip; - -/* saved pfn of the shared info page */ -static pfn_t shared_info_frame; - -#ifdef DEBUG -int xen_suspend_debug; - -#define SUSPEND_DEBUG if (xen_suspend_debug) xen_printf -#else -#define SUSPEND_DEBUG(...) -#endif - -/* - * Forward declarations - */ -static int xpv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); -static int xpv_attach(dev_info_t *, ddi_attach_cmd_t); -static int xpv_detach(dev_info_t *, ddi_detach_cmd_t); -static int xpv_open(dev_t *, int, int, cred_t *); -static int xpv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); - -static struct cb_ops xpv_cb_ops = { - xpv_open, - nulldev, /* close */ - nodev, /* strategy */ - nodev, /* print */ - nodev, /* dump */ - nodev, /* read */ - nodev, /* write */ - xpv_ioctl, /* ioctl */ - nodev, /* devmap */ - nodev, /* mmap */ - nodev, /* segmap */ - nochpoll, /* poll */ - ddi_prop_op, - NULL, - D_MP, - CB_REV, - NULL, - NULL -}; - -static struct dev_ops xpv_dv_ops = { - DEVO_REV, - 0, - xpv_getinfo, - nulldev, /* identify */ - nulldev, /* probe */ - xpv_attach, - xpv_detach, - nodev, /* reset */ - &xpv_cb_ops, - NULL, /* struct bus_ops */ - NULL /* power */ -}; - -static struct modldrv modldrv = { - &mod_driverops, - "xpv driver %I%", - &xpv_dv_ops -}; - -static struct modlinkage modl = { - MODREV_1, - { - (void *)&modldrv, - NULL /* null termination */ - } -}; - -static ddi_dma_attr_t xpv_dma_attr = { - DMA_ATTR_V0, /* version of this structure */ - 0, /* lowest usable address */ - 0xffffffffffffffffULL, /* highest usable address */ - 0x7fffffff, /* maximum DMAable byte count */ - MMU_PAGESIZE, /* alignment in bytes */ - 0x7ff, /* bitmap of burst sizes */ - 1, /* minimum transfer */ - 0xffffffffU, /* maximum transfer */ - 0x7fffffffULL, /* maximum segment length */ - 1, /* maximum number of segments */ - 1, /* granularity */ - 0, /* flags (reserved) */ -}; - -static ddi_device_acc_attr_t xpv_accattr = { - DDI_DEVICE_ATTR_V0, - DDI_NEVERSWAP_ACC, - DDI_STRICTORDER_ACC -}; - -#define MAX_ALLOCATIONS 10 -static ddi_dma_handle_t xpv_dma_handle[MAX_ALLOCATIONS]; -static ddi_acc_handle_t xpv_dma_acchandle[MAX_ALLOCATIONS]; -static int xen_alloc_cnt = 0; - -void * -xen_alloc_pages(pgcnt_t cnt) -{ - size_t len; - int a = xen_alloc_cnt++; - caddr_t addr; - - ASSERT(xen_alloc_cnt < MAX_ALLOCATIONS); - if (ddi_dma_alloc_handle(xpv_dip, &xpv_dma_attr, DDI_DMA_SLEEP, 0, - &xpv_dma_handle[a]) != DDI_SUCCESS) - return (NULL); - - if (ddi_dma_mem_alloc(xpv_dma_handle[a], MMU_PAGESIZE * cnt, - &xpv_accattr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0, - &addr, &len, &xpv_dma_acchandle[a]) != DDI_SUCCESS) { - ddi_dma_free_handle(&xpv_dma_handle[a]); - cmn_err(CE_WARN, "Couldn't allocate memory for xpv devices"); - return (NULL); - } - return (addr); -} - -/* - * This function is invoked twice, first time with reprogram=0 to set up - * the xpvd portion of the device tree. The second time it is ignored. - */ -static void -xpv_enumerate(int reprogram) -{ - dev_info_t *dip; - - if (reprogram != 0) - return; - - ndi_devi_alloc_sleep(ddi_root_node(), "xpvd", - (pnode_t)DEVI_SID_NODEID, &dip); - - (void) ndi_devi_bind_driver(dip, 0); - - /* - * Too early to enumerate split device drivers in domU - * since we need to create taskq thread during enumeration. - * So, we only enumerate softdevs and console here. - */ - xendev_enum_all(dip, B_TRUE); -} - -/* - * Translate a hypervisor errcode to a Solaris error code. - */ -int -xen_xlate_errcode(int error) -{ -#define CASE(num) case X_##num: error = num; break - - switch (-error) { - CASE(EPERM); CASE(ENOENT); CASE(ESRCH); - CASE(EINTR); CASE(EIO); CASE(ENXIO); - CASE(E2BIG); CASE(ENOMEM); CASE(EACCES); - CASE(EFAULT); CASE(EBUSY); CASE(EEXIST); - CASE(ENODEV); CASE(EISDIR); CASE(EINVAL); - CASE(ENOSPC); CASE(ESPIPE); CASE(EROFS); - CASE(ENOSYS); CASE(ENOTEMPTY); CASE(EISCONN); - CASE(ENODATA); - default: - panic("xen_xlate_errcode: unknown error %d", error); - } - return (error); -#undef CASE -} - -/*PRINTFLIKE1*/ -void -xen_printf(const char *fmt, ...) -{ - va_list adx; - - va_start(adx, fmt); - printf(fmt, adx); - va_end(adx); -} - -/* - * Stub functions to get the FE drivers to build, and to catch drivers that - * misbehave in HVM domains. - */ -/*ARGSUSED*/ -void -xen_release_pfn(pfn_t pfn, caddr_t va) -{ - panic("xen_release_pfn() is not supported in HVM domains"); -} - -/*ARGSUSED*/ -void -reassign_pfn(pfn_t pfn, mfn_t mfn) -{ - panic("reassign_pfn() is not supported in HVM domains"); -} - -/*ARGSUSED*/ -long -balloon_free_pages(uint_t page_cnt, mfn_t *mfns, caddr_t kva, pfn_t *pfns) -{ - panic("balloon_free_pages() is not supported in HVM domains"); - return (0); -} - -/*ARGSUSED*/ -void -balloon_drv_added(int64_t delta) -{ - panic("balloon_drv_added() is not supported in HVM domains"); -} - -/* - * Add a mapping for the machine page at the given virtual address. - */ -void -kbm_map_ma(maddr_t ma, uintptr_t va, uint_t level) -{ - ASSERT(level == 0); - - hat_devload(kas.a_hat, (caddr_t)va, MMU_PAGESIZE, - mmu_btop(ma), PROT_READ | PROT_WRITE, HAT_LOAD); -} - -static uint64_t -hvm_get_param(int param_id) -{ - struct xen_hvm_param xhp; - - xhp.domid = DOMID_SELF; - xhp.index = param_id; - if ((HYPERVISOR_hvm_op(HVMOP_get_param, &xhp) < 0)) - return (-1); - return (xhp.value); -} - -static struct xenbus_watch shutdown_watch; -taskq_t *xen_shutdown_tq; - -#define SHUTDOWN_INVALID -1 -#define SHUTDOWN_POWEROFF 0 -#define SHUTDOWN_REBOOT 1 -#define SHUTDOWN_SUSPEND 2 -#define SHUTDOWN_HALT 3 -#define SHUTDOWN_MAX 4 - -#define SHUTDOWN_TIMEOUT_SECS (60 * 5) - -static const char *cmd_strings[SHUTDOWN_MAX] = { - "poweroff", - "reboot", - "suspend", - "halt" -}; - -int -xen_suspend_devices(dev_info_t *dip) -{ - int error; - char buf[XPV_BUFSIZE]; - - SUSPEND_DEBUG("xen_suspend_devices\n"); - - for (; dip != NULL; dip = ddi_get_next_sibling(dip)) { - if (xen_suspend_devices(ddi_get_child(dip))) - return (ENXIO); - if (ddi_get_driver(dip) == NULL) - continue; - SUSPEND_DEBUG("Suspending device %s\n", ddi_deviname(dip, buf)); - ASSERT((DEVI(dip)->devi_cpr_flags & DCF_CPR_SUSPENDED) == 0); - - - if (!i_ddi_devi_attached(dip)) { - error = DDI_FAILURE; - } else { - error = devi_detach(dip, DDI_SUSPEND); - } - - if (error == DDI_SUCCESS) { - DEVI(dip)->devi_cpr_flags |= DCF_CPR_SUSPENDED; - } else { - SUSPEND_DEBUG("WARNING: Unable to suspend device %s\n", - ddi_deviname(dip, buf)); - cmn_err(CE_WARN, "Unable to suspend device %s.", - ddi_deviname(dip, buf)); - cmn_err(CE_WARN, "Device is busy or does not " - "support suspend/resume."); - return (ENXIO); - } - } - return (0); -} - -int -xen_resume_devices(dev_info_t *start, int resume_failed) -{ - dev_info_t *dip, *next, *last = NULL; - int did_suspend; - int error = resume_failed; - char buf[XPV_BUFSIZE]; - - SUSPEND_DEBUG("xen_resume_devices\n"); - - while (last != start) { - dip = start; - next = ddi_get_next_sibling(dip); - while (next != last) { - dip = next; - next = ddi_get_next_sibling(dip); - } - - /* - * cpr is the only one that uses this field and the device - * itself hasn't resumed yet, there is no need to use a - * lock, even though kernel threads are active by now. - */ - did_suspend = DEVI(dip)->devi_cpr_flags & DCF_CPR_SUSPENDED; - if (did_suspend) - DEVI(dip)->devi_cpr_flags &= ~DCF_CPR_SUSPENDED; - - /* - * There may be background attaches happening on devices - * that were not originally suspended by cpr, so resume - * only devices that were suspended by cpr. Also, stop - * resuming after the first resume failure, but traverse - * the entire tree to clear the suspend flag. - */ - if (did_suspend && !error) { - SUSPEND_DEBUG("Resuming device %s\n", - ddi_deviname(dip, buf)); - /* - * If a device suspended by cpr gets detached during - * the resume process (for example, due to hotplugging) - * before cpr gets around to issuing it a DDI_RESUME, - * we'll have problems. - */ - if (!i_ddi_devi_attached(dip)) { - cmn_err(CE_WARN, "Skipping %s, device " - "not ready for resume", - ddi_deviname(dip, buf)); - } else { - if (devi_attach(dip, DDI_RESUME) != - DDI_SUCCESS) { - error = ENXIO; - } - } - } - - if (error == ENXIO) { - cmn_err(CE_WARN, "Unable to resume device %s", - ddi_deviname(dip, buf)); - } - - error = xen_resume_devices(ddi_get_child(dip), error); - last = dip; - } - - return (error); -} - -/*ARGSUSED*/ -static int -check_xpvd(dev_info_t *dip, void *arg) -{ - char *name; - - name = ddi_node_name(dip); - if (name == NULL || strcmp(name, "xpvd")) { - return (DDI_WALK_CONTINUE); - } else { - xpvd_dip = dip; - return (DDI_WALK_TERMINATE); - } -} - -/* - * Top level routine to direct suspend/resume of a domain. - */ -void -xen_suspend_domain(void) -{ - extern void rtcsync(void); - extern void ec_resume(void); - extern kmutex_t ec_lock; - struct xen_add_to_physmap xatp; - ulong_t flags; - int err; - - cmn_err(CE_NOTE, "Domain suspending for save/migrate"); - - SUSPEND_DEBUG("xen_suspend_domain\n"); - - /* - * We only want to suspend the PV devices, since the emulated devices - * are suspended by saving the emulated device state. The PV devices - * are all children of the xpvd nexus device. So we search the - * device tree for the xpvd node to use as the root of the tree to - * be suspended. - */ - if (xpvd_dip == NULL) - ddi_walk_devs(ddi_root_node(), check_xpvd, NULL); - - /* - * suspend interrupts and devices - */ - if (xpvd_dip != NULL) - (void) xen_suspend_devices(ddi_get_child(xpvd_dip)); - else - cmn_err(CE_WARN, "No PV devices found to suspend"); - SUSPEND_DEBUG("xenbus_suspend\n"); - xenbus_suspend(); - - mutex_enter(&cpu_lock); - - /* - * Suspend on vcpu 0 - */ - thread_affinity_set(curthread, 0); - kpreempt_disable(); - - if (ncpus > 1) - pause_cpus(NULL); - /* - * We can grab the ec_lock as it's a spinlock with a high SPL. Hence - * any holder would have dropped it to get through pause_cpus(). - */ - mutex_enter(&ec_lock); - - /* - * From here on in, we can't take locks. - */ - - flags = intr_clear(); - - SUSPEND_DEBUG("HYPERVISOR_suspend\n"); - /* - * At this point we suspend and sometime later resume. - * Note that this call may return with an indication of a cancelled - * for now no matter ehat the return we do a full resume of all - * suspended drivers, etc. - */ - (void) HYPERVISOR_shutdown(SHUTDOWN_suspend); - - /* - * Point HYPERVISOR_shared_info to the proper place. - */ - xatp.domid = DOMID_SELF; - xatp.idx = 0; - xatp.space = XENMAPSPACE_shared_info; - xatp.gpfn = shared_info_frame; - if ((err = HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp)) != 0) - panic("Could not set shared_info page. error: %d", err); - - SUSPEND_DEBUG("gnttab_resume\n"); - gnttab_resume(); - - SUSPEND_DEBUG("ec_resume\n"); - ec_resume(); - - intr_restore(flags); - - if (ncpus > 1) - start_cpus(); - - mutex_exit(&ec_lock); - mutex_exit(&cpu_lock); - - /* - * Now we can take locks again. - */ - - rtcsync(); - - SUSPEND_DEBUG("xenbus_resume\n"); - xenbus_resume(); - SUSPEND_DEBUG("xen_resume_devices\n"); - if (xpvd_dip != NULL) - (void) xen_resume_devices(ddi_get_child(xpvd_dip), 0); - - thread_affinity_clear(curthread); - kpreempt_enable(); - - SUSPEND_DEBUG("finished xen_suspend_domain\n"); - - cmn_err(CE_NOTE, "domain restore/migrate completed"); -} - -static void -xen_dirty_shutdown(void *arg) -{ - int cmd = (uintptr_t)arg; - - cmn_err(CE_WARN, "Externally requested shutdown failed or " - "timed out.\nShutting down.\n"); - - switch (cmd) { - case SHUTDOWN_HALT: - case SHUTDOWN_POWEROFF: - (void) kadmin(A_SHUTDOWN, AD_POWEROFF, NULL, kcred); - break; - case SHUTDOWN_REBOOT: - (void) kadmin(A_REBOOT, AD_BOOT, NULL, kcred); - break; - } -} - -static void -xen_shutdown(void *arg) -{ - nvlist_t *attr_list = NULL; - sysevent_t *event = NULL; - sysevent_id_t eid; - int cmd = (uintptr_t)arg; - int err; - - ASSERT(cmd > SHUTDOWN_INVALID && cmd < SHUTDOWN_MAX); - - if (cmd == SHUTDOWN_SUSPEND) { - xen_suspend_domain(); - return; - } - - err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME, KM_SLEEP); - if (err != DDI_SUCCESS) - goto failure; - - err = nvlist_add_string(attr_list, "shutdown", cmd_strings[cmd]); - if (err != DDI_SUCCESS) - goto failure; - - if ((event = sysevent_alloc("EC_xpvsys", "control", "SUNW:kern:xpv", - SE_SLEEP)) == NULL) - goto failure; - (void) sysevent_attach_attributes(event, - (sysevent_attr_list_t *)attr_list); - - err = log_sysevent(event, SE_SLEEP, &eid); - - sysevent_detach_attributes(event); - sysevent_free(event); - - if (err != 0) - goto failure; - - (void) timeout(xen_dirty_shutdown, arg, - SHUTDOWN_TIMEOUT_SECS * drv_usectohz(MICROSEC)); - - nvlist_free(attr_list); - return; - -failure: - if (attr_list != NULL) - nvlist_free(attr_list); - xen_dirty_shutdown(arg); -} - -/*ARGSUSED*/ -static void -xen_shutdown_handler(struct xenbus_watch *watch, const char **vec, - unsigned int len) -{ - char *str; - xenbus_transaction_t xbt; - int err, shutdown_code = SHUTDOWN_INVALID; - unsigned int slen; - -again: - err = xenbus_transaction_start(&xbt); - if (err) - return; - if (xenbus_read(xbt, "control", "shutdown", (void *)&str, &slen)) { - (void) xenbus_transaction_end(xbt, 1); - return; - } - - SUSPEND_DEBUG("%d: xen_shutdown_handler: \"%s\"\n", CPU->cpu_id, str); - - /* - * If this is a watch fired from our write below, check out early to - * avoid an infinite loop. - */ - if (strcmp(str, "") == 0) { - (void) xenbus_transaction_end(xbt, 0); - kmem_free(str, slen); - return; - } else if (strcmp(str, "poweroff") == 0) { - shutdown_code = SHUTDOWN_POWEROFF; - } else if (strcmp(str, "reboot") == 0) { - shutdown_code = SHUTDOWN_REBOOT; - } else if (strcmp(str, "suspend") == 0) { - shutdown_code = SHUTDOWN_SUSPEND; - } else if (strcmp(str, "halt") == 0) { - shutdown_code = SHUTDOWN_HALT; - } else { - printf("Ignoring shutdown request: %s\n", str); - } - - (void) xenbus_write(xbt, "control", "shutdown", ""); - err = xenbus_transaction_end(xbt, 0); - if (err == EAGAIN) { - SUSPEND_DEBUG("%d: trying again\n", CPU->cpu_id); - kmem_free(str, slen); - goto again; - } - - kmem_free(str, slen); - if (shutdown_code != SHUTDOWN_INVALID) { - (void) taskq_dispatch(xen_shutdown_tq, xen_shutdown, - (void *)(intptr_t)shutdown_code, 0); - } -} - -static int -xen_pv_init(dev_info_t *xpv_dip) -{ - struct cpuid_regs cp; - uint32_t xen_signature[4]; - char *xen_str; - struct xen_add_to_physmap xatp; - xen_capabilities_info_t caps; - pfn_t pfn; - uint64_t msrval; - int err; - - /* - * Xen's pseudo-cpuid function 0x40000000 returns a string - * representing the Xen signature in %ebx, %ecx, and %edx. - * %eax contains the maximum supported cpuid function. - */ - cp.cp_eax = 0x40000000; - (void) __cpuid_insn(&cp); - xen_signature[0] = cp.cp_ebx; - xen_signature[1] = cp.cp_ecx; - xen_signature[2] = cp.cp_edx; - xen_signature[3] = 0; - xen_str = (char *)xen_signature; - if (strcmp("XenVMMXenVMM", xen_str) != 0 || - cp.cp_eax < 0x40000002) { - cmn_err(CE_WARN, - "Attempting to load Xen drivers on non-Xen system"); - return (-1); - } - - /* - * cpuid function 0x40000001 returns the Xen version in %eax. The - * top 16 bits are the major version, the bottom 16 are the minor - * version. - */ - cp.cp_eax = 0x40000001; - (void) __cpuid_insn(&cp); - xen_major = cp.cp_eax >> 16; - xen_minor = cp.cp_eax & 0xffff; - - /* - * The xpv driver is incompatible with xen versions older than 3.1. This - * is due to the changes in the vcpu_info and shared_info structs used - * to communicate with the hypervisor (the event channels in particular) - * that were introduced with 3.1. - */ - if (xen_major < 3 || (xen_major == 3 && xen_minor < 1)) { - cmn_err(CE_WARN, "Xen version %d.%d is not supported", - xen_major, xen_minor); - return (-1); - } - - /* - * cpuid function 0x40000002 returns information about the - * hypercall page. %eax nominally contains the number of pages - * with hypercall code, but according to the Xen guys, "I'll - * guarantee that remains one forever more, so you can just - * allocate a single page and get quite upset if you ever see CPUID - * return more than one page." %ebx contains an MSR we use to ask - * Xen to remap each page at a specific pfn. - */ - cp.cp_eax = 0x40000002; - (void) __cpuid_insn(&cp); - - /* - * Let Xen know where we want the hypercall page mapped. We - * already have a page allocated in the .text section to simplify - * the wrapper code. - */ - pfn = hat_getpfnum(kas.a_hat, (caddr_t)&hypercall_page); - msrval = mmu_ptob(pfn); - wrmsr(cp.cp_ebx, msrval); - - /* Fill in the xen_info data */ - xen_info = kmem_zalloc(sizeof (start_info_t), KM_SLEEP); - (void) sprintf(xen_info->magic, "xen-%d.%d", xen_major, xen_minor); - xen_info->store_mfn = (mfn_t)hvm_get_param(HVM_PARAM_STORE_PFN); - xen_info->store_evtchn = (int)hvm_get_param(HVM_PARAM_STORE_EVTCHN); - - /* Figure out whether the hypervisor is 32-bit or 64-bit. */ - if ((HYPERVISOR_xen_version(XENVER_capabilities, &caps) == 0)) { - ((char *)(caps))[sizeof (caps) - 1] = '\0'; - if (strstr(caps, "x86_64") != NULL) - xen_is_64bit = 1; - else if (strstr(caps, "x86_32") != NULL) - xen_is_64bit = 0; - } - if (xen_is_64bit < 0) { - cmn_err(CE_WARN, "Couldn't get capability info from Xen."); - return (-1); - } -#ifdef __amd64 - ASSERT(xen_is_64bit == 1); -#endif - - /* - * Allocate space for the shared_info page and tell Xen where it - * is. - */ - HYPERVISOR_shared_info = xen_alloc_pages(1); - shared_info_frame = hat_getpfnum(kas.a_hat, - (caddr_t)HYPERVISOR_shared_info); - xatp.domid = DOMID_SELF; - xatp.idx = 0; - xatp.space = XENMAPSPACE_shared_info; - xatp.gpfn = shared_info_frame; - if ((err = HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp)) != 0) { - cmn_err(CE_WARN, "Could not get shared_info page from Xen." - " error: %d", err); - return (-1); - } - - /* Set up the grant tables. */ - gnttab_init(); - - /* Set up event channel support */ - if (ec_init(xpv_dip) != 0) - return (-1); - - /* Set up xenbus */ - xb_addr = vmem_alloc(heap_arena, MMU_PAGESIZE, VM_SLEEP); - xs_early_init(); - xs_domu_init(); - - /* Set up for suspend/resume/migrate */ - xen_shutdown_tq = taskq_create("shutdown_taskq", 1, - maxclsyspri - 1, 1, 1, TASKQ_PREPOPULATE); - shutdown_watch.node = "control/shutdown"; - shutdown_watch.callback = xen_shutdown_handler; - if (register_xenbus_watch(&shutdown_watch)) - cmn_err(CE_WARN, "Failed to set shutdown watcher"); - - return (0); -} - -static void -xen_pv_fini() -{ - if (xen_info != NULL) - kmem_free(xen_info, sizeof (start_info_t)); - ec_fini(); -} - -/*ARGSUSED*/ -static int -xpv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) -{ - if (getminor((dev_t)arg) != XPV_MINOR) - return (DDI_FAILURE); - - switch (cmd) { - case DDI_INFO_DEVT2DEVINFO: - *result = xpv_dip; - break; - case DDI_INFO_DEVT2INSTANCE: - *result = 0; - break; - default: - return (DDI_FAILURE); - } - - return (DDI_SUCCESS); -} - -static int -xpv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) -{ - if (cmd != DDI_ATTACH) - return (DDI_FAILURE); - - if (ddi_create_minor_node(dip, ddi_get_name(dip), S_IFCHR, - ddi_get_instance(dip), DDI_PSEUDO, 0) != DDI_SUCCESS) - return (DDI_FAILURE); - - xpv_dip = dip; - - if (xen_pv_init(dip) != 0) - return (DDI_FAILURE); - - ddi_report_dev(dip); - - /* - * If the memscrubber attempts to scrub the pages we hand to Xen, - * the domain will panic. - */ - memscrub_disable(); - - /* - * Report our version to dom0. - */ - if (xenbus_printf(XBT_NULL, "hvmpv/xpv", "version", "%d", - HVMPV_XPV_VERS)) - cmn_err(CE_WARN, "xpv: couldn't write version\n"); - - return (DDI_SUCCESS); -} - -/* - * Attempts to reload the PV driver plumbing hang on Intel platforms, so - * we don't want to unload the framework by accident. - */ -int xpv_allow_detach = 0; - -static int -xpv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) -{ - if (cmd != DDI_DETACH || xpv_allow_detach == 0) - return (DDI_FAILURE); - - if (xpv_dip != NULL) { - xen_pv_fini(); - ddi_remove_minor_node(dip, NULL); - xpv_dip = NULL; - } - - return (DDI_SUCCESS); -} - -/*ARGSUSED1*/ -static int -xpv_open(dev_t *dev, int flag, int otyp, cred_t *cr) -{ - return (getminor(*dev) == XPV_MINOR ? 0 : ENXIO); -} - -/*ARGSUSED*/ -static int -xpv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, - int *rval_p) -{ - return (EINVAL); -} - -int -_init(void) -{ - int err; - - if ((err = mod_install(&modl)) != 0) - return (err); - - impl_bus_add_probe(xpv_enumerate); - return (0); -} - -int -_fini(void) -{ - int err; - - if ((err = mod_remove(&modl)) != 0) - return (err); - - impl_bus_delete_probe(xpv_enumerate); - return (0); -} - -int -_info(struct modinfo *modinfop) -{ - return (mod_info(&modl, modinfop)); -}
--- a/usr/src/uts/i86pc/pv_cmdk/Makefile Mon Apr 14 22:16:59 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,111 +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 -# -# -# uts/i86pc/pv_cmdk/Makefile -# -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" -# -# This makefile drives the production of the xdc driver. -# -# i86pc implementation architecture dependent -# - -# -# Path to the base of the uts directory tree (usually /usr/src/uts). -# -UTSBASE = ../.. - -# -# Define the module and object file sets. -# -MODULE = cmdk -OBJECTS = $(PV_CMDK_OBJS:%=$(OBJS_DIR)/%) -LINTS = $(PV_CMDK_OBJS:%.o=$(LINTS_DIR)/%.ln) -ROOTMODULE = $(ROOT_HVM_DRV_DIR)/$(MODULE) - -INC_PATH += -I$(UTSBASE)/common/xen -I$(UTSBASE)/../common - -# -# Include common rules. -# -include $(UTSBASE)/i86pc/Makefile.i86pc -include $(UTSBASE)/i86pc/Makefile.hvm - -# -# When generating lint libraries, we want the name of the lint module -# that will be generated to by pv_cmdk and not cmdk, so override the -# default lint module name here. -# -LINT_MODULE = pv_cmdk - -# -# Define targets -# -ALL_TARGET = $(BINARY) -LINT_TARGET = $(LINT_MODULE).lint -INSTALL_TARGET = $(BINARY) $(ROOTMODULE) - -# -# use Solaris specific code in xen public header files -# -CPPFLAGS += -D_SOLARIS -CPPFLAGS += -DXPV_HVM_DRIVER - -LDFLAGS += -dy -Nmisc/strategy -Nmisc/cmlb -LDFLAGS += -Ndrv/xpvd -Ndrv/xdf - -# -# The Xen header files do not lint cleanly. Since the troublesome -# structures form part of the externally defined interface to the -# hypervisor, we're stuck with the noise. -# -LINTTAGS += -erroff=E_BAD_PTR_CAST_ALIGN -LINTTAGS += -erroff=E_SUPPRESSION_DIRECTIVE_UNUSED -LINTTAGS += -erroff=E_ASSIGN_NARROW_CONV - -# -# 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)/i86pc/Makefile.targ
--- a/usr/src/uts/i86pc/pv_rtls/Makefile Mon Apr 14 22:16:59 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +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 -# -# -# uts/i86pc/pv_rtls/Makefile -# -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" -# -# This makefile drives the production of the null rtls module for xvm. -# -# i86pc implementation architecture dependent -# -# Path to the base of the uts directory tree (usually /usr/src/uts). -# -UTSBASE = ../.. - -# -# Define the module and object file sets. -# -MODULE = rtls -OBJECTS = $(PV_RTLS_OBJS:%=$(OBJS_DIR)/%) -LINTS = $(PV_RTLS_OBJS:%.o=$(LINTS_DIR)/%.ln) -ROOTMODULE = $(ROOT_HVM_DRV_DIR)/$(MODULE) - -# -# Include common rules. -# -include $(UTSBASE)/i86pc/Makefile.i86pc -include $(UTSBASE)/i86pc/Makefile.hvm - -# -# When generating lint libraries, we want the name of the lint module -# that will be generated to be pv_rtls and not rtls, so override the -# default lint module name here. -# -LINT_MODULE = pv_rtls - -# -# Define targets -# -ALL_TARGET = $(BINARY) -LINT_TARGET = $(LINT_MODULE).lint -INSTALL_TARGET = $(BINARY) $(ROOTMODULE) - -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)/i86pc/Makefile.targ
--- a/usr/src/uts/i86pc/sys/xpv_support.h Mon Apr 14 22:16:59 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +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 _SYS_XPV_SUPPORT_H -#define _SYS_XPV_SUPPORT_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef __cplusplus -extern "C" { -#endif - -#define __XEN_INTERFACE_VERSION__ __XEN_LATEST_INTERFACE_VERSION__ - -#if !defined(_ASM) - -#include <sys/types.h> -#include <sys/inttypes.h> -#include <sys/dditypes.h> - -typedef ulong_t mfn_t; -typedef uint64_t maddr_t; -#define mfn_to_ma(mfn) ((maddr_t)(mfn) << MMU_PAGESHIFT) -#define MFN_INVALID (-(mfn_t)1) - -#define IPL_DEBUG 15 /* domain debug interrupt */ -#define IPL_CONS 9 -#define IPL_VIF 6 -#define IPL_VBD 5 -#define IPL_EVTCHN 1 - -#define INVALID_EVTCHN 0 - -typedef uint_t (*ec_handler_fcn_t)(); - -extern int ec_init(dev_info_t *); -extern void ec_fini(); -extern void ec_bind_evtchn_to_handler(int, pri_t, ec_handler_fcn_t, void *); -extern void ec_unbind_evtchn(int); -extern void ec_notify_via_evtchn(uint_t); -extern void hypervisor_mask_event(uint_t); -extern void hypervisor_unmask_event(uint_t); - -extern int xen_bind_interdomain(int, int, int *); -extern int xen_alloc_unbound_evtchn(int, int *); -extern int xen_xlate_errcode(int error); -extern void *xen_alloc_pages(pgcnt_t cnt); -extern void kbm_map_ma(maddr_t ma, uintptr_t va, uint_t level); - -/* - * Stub functions to allow the FE drivers to build without littering them - * with #ifdefs - */ -extern void balloon_drv_added(int64_t); -extern long balloon_free_pages(uint_t, mfn_t *, caddr_t, pfn_t *); -extern void xen_release_pfn(pfn_t, caddr_t); -extern void reassign_pfn(pfn_t, mfn_t); - -extern int xen_is_64bit; - -#define IN_XPV_PANIC() (__lintzero) - -#ifdef __cplusplus -} -#endif - -#endif /* __ASM */ -#endif /* _SYS_XPV_SUPPORT_H */
--- a/usr/src/uts/i86pc/xdf/Makefile Mon Apr 14 22:16:59 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +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 -# - -# -# uts/i86pc/xdf/Makefile -# -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "%Z%%M% %I% %E% SMI" -# -# i86pc architecture dependent -# -# -# Path to the base of the uts directory tree (usually /usr/src/uts). -# -UTSBASE = ../.. -INC_PATH += -I$(UTSBASE)/common/xen - -# -# Define the module and object file sets. -# -MODULE = xdf -OBJECTS = $(XDF_OBJS:%=$(OBJS_DIR)/%) -LINTS = $(XDF_OBJS:%.o=$(LINTS_DIR)/%.ln) -ROOTMODULE = $(ROOT_HVM_DRV_DIR)/$(MODULE) - -# -# Include common rules. -# -include $(UTSBASE)/i86pc/Makefile.i86pc -include $(UTSBASE)/i86pc/Makefile.hvm - -# -# Define targets -# -ALL_TARGET = $(BINARY) -LINT_TARGET = $(MODULE).lint -INSTALL_TARGET = $(BINARY) $(ROOTMODULE) - -# Overrides -CPPFLAGS += -DXPV_HVM_DRIVER -DHVMPV_XDF_VERS=1 -LDFLAGS += -dy -Nmisc/cmlb -Ndrv/xpvd -Ndrv/xpv - -LINTTAGS += -erroff=E_SUSPICIOUS_COMPARISON -LINTTAGS += -erroff=E_ASSIGN_NARROW_CONV -LINTTAGS += -erroff=E_BAD_PTR_CAST_ALIGN - -# -# 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)/i86pc/Makefile.targ
--- a/usr/src/uts/i86pc/xnf/Makefile Mon Apr 14 22:16:59 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,98 +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 -# - -# -# uts/i86pc/xnf/Makefile -# -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "%Z%%M% %I% %E% SMI" -# -# This makefile drives the production of the xve -# network driver kernel module. -# -# i86pc architecture dependent -# - -# -# Path to the base of the uts directory tree (usually /usr/src/uts). -# -UTSBASE = ../.. - -# -# Define the module and object file sets. -# -MODULE = xnf -OBJECTS = $(XNF_OBJS:%=$(OBJS_DIR)/%) -LINTS = $(XNF_OBJS:%.o=$(LINTS_DIR)/%.ln) -ROOTMODULE = $(ROOT_HVM_DRV_DIR)/$(MODULE) - -INC_PATH += -I$(UTSBASE)/common/xen - -# -# Include common rules. -# -include $(UTSBASE)/i86pc/Makefile.i86pc -include $(UTSBASE)/i86pc/Makefile.hvm - -# -# Define targets -# -ALL_TARGET = $(BINARY) -LINT_TARGET = $(MODULE).lint -INSTALL_TARGET = $(BINARY) $(ROOTMODULE) - -# -# Driver depends on MAC & IP -# -LDFLAGS += -dy -Nmisc/mac -Ndrv/ip -Ndrv/xpvd -Ndrv/xpv - -CPPFLAGS += -D_SOLARIS -DHVMPV_XNF_VERS=1 -LINTTAGS += -erroff=E_ASSIGN_NARROW_CONV -LINTTAGS += -erroff=E_PTRDIFF_OVERFLOW -LINTTAGS += -erroff=E_BAD_PTR_CAST_ALIGN - -# -# 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)/i86pc/Makefile.targ
--- a/usr/src/uts/i86pc/xpv/Makefile Mon Apr 14 22:16:59 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,101 +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 -# -# -# uts/i86pc/xpv/Makefile -# -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" -# -# This makefile drives the production of the xpv -# driver, which provides the necessary infrastructure for -# paravirtualized front-end drivers in HVM systems. -# -# i86pc implementation architecture dependent -# - -# -# Path to the base of the uts directory tree (usually /usr/src/uts). -# -UTSBASE = ../.. - -# -# Define the module and object file sets. -# -MODULE = xpv -OBJECTS = $(XPV_OBJS:%=$(OBJS_DIR)/%) -LINTS = $(XPV_OBJS:%.o=$(LINTS_DIR)/%.ln) -ROOTMODULE = $(ROOT_HVM_DRV_DIR)/$(MODULE) -CONF_SRCDIR = $(UTSBASE)/i86pc/io/xpv - -INC_PATH += -I$(UTSBASE)/common/xen -I$(UTSBASE)/../common - -# -# Include common rules. -# -include $(UTSBASE)/i86pc/Makefile.i86pc -include $(UTSBASE)/i86pc/Makefile.hvm - -# -# Define targets -# -ALL_TARGET = $(BINARY) $(CONFMOD) -LINT_TARGET = $(MODULE).lint -INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) - -CPPFLAGS += -D_SOLARIS -DHVMPV_XPV_VERS=1 -LDFLAGS += -dy -N mach/pcplusmp - -# -# The Xen header files do not lint cleanly. Since the troublesome -# structures form part of the externally defined interface to the -# hypervisor, we're stuck with the noise. -# -LINTTAGS += -erroff=E_BAD_PTR_CAST_ALIGN -LINTTAGS += -erroff=E_SUPPRESSION_DIRECTIVE_UNUSED -LINTTAGS += -erroff=E_ASSIGN_NARROW_CONV - -# -# 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)/i86pc/Makefile.targ
--- a/usr/src/uts/i86pc/xpvd/Makefile Mon Apr 14 22:16:59 2008 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,93 +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 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" -# -# This makefile drives the production of the xpvd nexus driver -# -# i86pc implementation architecture dependent -# - -# -# Path to the base of the uts directory tree (usually /usr/src/uts). -# -UTSBASE = ../.. - -# -# Define the module and object file sets. -# -MODULE = xpvd -OBJECTS = $(XPVD_OBJS:%=$(OBJS_DIR)/%) -LINTS = $(XPVD_OBJS:%.o=$(LINTS_DIR)/%.ln) -ROOTMODULE = $(ROOT_HVM_DRV_DIR)/$(MODULE) -CONF_SRCDIR = $(UTSBASE)/common/xen/io - -# -# Include common rules. -# -include $(UTSBASE)/i86pc/Makefile.i86pc -include $(UTSBASE)/i86pc/Makefile.hvm - -# -# Define targets -# -ALL_TARGET = $(BINARY) $(CONFMOD) -LINT_TARGET = $(MODULE).lint -INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) - -INC_PATH += -I$(UTSBASE)/common/xen -I$(UTSBASE)/../common - -CPPFLAGS += -DHVMPV_XPVD_VERS=1 -LDFLAGS += -dy -Ndrv/xpv - -LINTTAGS += -erroff=E_STATIC_UNUSED -LINTTAGS += -erroff=E_ASSIGN_NARROW_CONV -LINTTAGS += -erroff=E_BAD_PTR_CAST_ALIGN - -# -# 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)/i86pc/Makefile.targ