diff options
author | eschrock <none@none> | 2008-03-28 17:41:18 -0700 |
---|---|---|
committer | eschrock <none@none> | 2008-03-28 17:41:18 -0700 |
commit | 275c9da86e89f8abf71135cf63d9fc23671b2e60 (patch) | |
tree | c00ea3adc6cc1d4140ca524271718bab19f96d6f | |
parent | a4e703601c0d75298c6e1fb6c2617c37ec86bf33 (diff) | |
download | illumos-joyent-275c9da86e89f8abf71135cf63d9fc23671b2e60.tar.gz |
PSARC 2008/146 sgen(7d) multiple opens
PSARC 2008/196 libscsi and libses
6667022 sgen should support multiple concurrent opens
6667023 ses mishandles uscsi requests
6667024 want a generic SCSI library
6667025 want a generic SES library
120 files changed, 16067 insertions, 122 deletions
diff --git a/usr/src/Makefile.lint b/usr/src/Makefile.lint index 6ed5c8ab98..702b14089d 100644 --- a/usr/src/Makefile.lint +++ b/usr/src/Makefile.lint @@ -403,6 +403,7 @@ COMMON_SUBDIRS = \ lib/pkcs11 \ lib/print \ lib/raidcfg_plugins \ + lib/scsi \ lib/smbsrv \ lib/fm \ lib/udapl \ diff --git a/usr/src/Targetdirs b/usr/src/Targetdirs index e038856497..102f1648cb 100644 --- a/usr/src/Targetdirs +++ b/usr/src/Targetdirs @@ -246,6 +246,7 @@ ROOT.BIN= \ /usr/include/libmilter \ /usr/include/libpolkit \ /usr/include/sasl \ + /usr/include/scsi \ /usr/include/tsol \ /usr/include/security \ /usr/lib \ @@ -288,6 +289,7 @@ ROOT.BIN= \ /usr/lib/sasl \ /usr/lib/secure \ /usr/lib/security \ + /usr/lib/scsi \ /usr/lib/smbsrv \ /usr/lib/term \ /usr/lib/vscan \ @@ -361,6 +363,7 @@ ROOT.BIN64= \ /usr/lib/sasl/$(MACH64) \ /usr/lib/secure/$(MACH64) \ /usr/lib/security/$(MACH64) \ + /usr/lib/scsi/$(MACH64) \ /usr/lib/smbsrv/$(MACH64) \ /usr/lib/abi/$(MACH64) \ /usr/sbin/$(MACH64) \ diff --git a/usr/src/cmd/Makefile b/usr/src/cmd/Makefile index 6402d952e2..2ba780c0d2 100644 --- a/usr/src/cmd/Makefile +++ b/usr/src/cmd/Makefile @@ -339,6 +339,7 @@ COMMON_SUBDIRS= \ saf \ savecore \ script \ + scsi \ sdiff \ sdpadm \ sendmail \ @@ -653,6 +654,7 @@ MSGSUBDIRS= \ rmvolmgr \ scadm \ script \ + scsi \ sdiff \ sdpadm \ sgs \ diff --git a/usr/src/cmd/scsi/Makefile b/usr/src/cmd/scsi/Makefile new file mode 100644 index 0000000000..1f48541baa --- /dev/null +++ b/usr/src/cmd/scsi/Makefile @@ -0,0 +1,32 @@ +# +# 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" + +SUBDIRS = \ + sestopo + +_msg: + +include ./Makefile.subdirs diff --git a/usr/src/cmd/scsi/Makefile.subdirs b/usr/src/cmd/scsi/Makefile.subdirs new file mode 100644 index 0000000000..12ac2c721d --- /dev/null +++ b/usr/src/cmd/scsi/Makefile.subdirs @@ -0,0 +1,43 @@ +# +# 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" + +.KEEP_STATE: + +all := TARGET += all +clean := TARGET += clean +clobber := TARGET += clobber +install := TARGET += install +install_h := TARGET += install_h +lint := TARGET += lint +_msg := TARGET += _msg +check := TARGET += check + +all clean clobber install install_h lint: $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; VERSION='$(VERSION)' $(MAKE) $(TARGET) + +FRC: diff --git a/usr/src/cmd/scsi/sestopo/Makefile b/usr/src/cmd/scsi/sestopo/Makefile new file mode 100644 index 0000000000..d53cbbfdbf --- /dev/null +++ b/usr/src/cmd/scsi/sestopo/Makefile @@ -0,0 +1,29 @@ +# +# 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" + +SUBDIRS = $(MACH) + +include ../Makefile.subdirs diff --git a/usr/src/cmd/scsi/sestopo/Makefile.com b/usr/src/cmd/scsi/sestopo/Makefile.com new file mode 100644 index 0000000000..8fdbbb6ab5 --- /dev/null +++ b/usr/src/cmd/scsi/sestopo/Makefile.com @@ -0,0 +1,69 @@ +# +# 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" + +.KEEP_STATE: +.SUFFIXES: + +PROG = sestopo +SRCS = $(PROG:%=../common/%.c) +OBJS = $(PROG:%=%.o) + +include ../../../Makefile.cmd + +ROOTLIBSCSI = $(ROOT)/usr/lib/scsi +ROOTPROG = $(ROOTLIBSCSI)/$(PROG) + +$(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG +CPPFLAGS += -I. -I../common +CFLAGS += $(CTF_FLAGS) $(CCVERBOSE) $(XSTRCONST) +LDLIBS += -L$(ROOT)/usr/lib/scsi -lses -lnvpair +LDFLAGS += -R/usr/lib/scsi + +all: $(PROG) + +$(PROG): $(OBJS) + $(LINK.c) $(OBJS) -o $@ $(LDLIBS) + $(CTFMERGE) -L VERSION -o $@ $(OBJS) + $(POST_PROCESS) + +%.o: ../common/%.c + $(COMPILE.c) $< + $(CTFCONVERT_O) + +clean: + $(RM) $(OBJS) + +lint: lint_SRCS + +$(ROOTLIBSCSI)/%: % + $(INS.file) + +install_h: + +install: all $(ROOTPROG) + +include ../../../Makefile.targ diff --git a/usr/src/cmd/scsi/sestopo/common/sestopo.c b/usr/src/cmd/scsi/sestopo/common/sestopo.c new file mode 100644 index 0000000000..e4c59e0365 --- /dev/null +++ b/usr/src/cmd/scsi/sestopo/common/sestopo.c @@ -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 + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <libnvpair.h> +#include <stdio.h> +#include <unistd.h> +#include <scsi/libses.h> + +static void fatal(int, const char *, ...) __NORETURN; + +static void +fatal(int err, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + (void) vfprintf(stderr, fmt, ap); + va_end(ap); + + (void) fprintf(stderr, "\n"); + (void) fflush(stderr); + + _exit(err); +} + +/*ARGSUSED*/ +static ses_walk_action_t +node(ses_node_t *np, void *arg) +{ + ses_node_type_t type; + uint64_t val; + nvlist_t *props; + char *t; + + type = ses_node_type(np); + (void) printf("Node Type: %d\n", type); + if ((props = ses_node_props(np)) == NULL) { + (void) printf("No properties\n"); + return (SES_WALK_ACTION_CONTINUE); + } + if (type == SES_NODE_ELEMENT || type == SES_NODE_AGGREGATE) { + (void) nvlist_lookup_uint64(props, SES_PROP_ELEMENT_TYPE, &val); + if (nvlist_lookup_string(props, LIBSES_PROP_ELEMENT_TYPE_NAME, + &t) != 0) + t = NULL; + (void) printf("Element Type: %s\n", t ? t : "<unknown>"); + } + nvlist_print(stdout, props); + + return (SES_WALK_ACTION_CONTINUE); +} + +int +main(int argc, char *argv[]) +{ + ses_target_t *tp; + ses_snap_t *sp; + + if (argc != 2) + fatal(1, "Usage: %s <device>", argv[0]); + + if ((tp = ses_open(LIBSES_VERSION, argv[1])) == NULL) + fatal(-1, "failed to open %s: %s", argv[1], ses_errmsg()); + + sp = ses_snap_hold(tp); + + (void) ses_walk(sp, node, NULL); + + ses_snap_rele(sp); + ses_close(tp); + + return (0); +} diff --git a/usr/src/cmd/scsi/sestopo/i386/Makefile b/usr/src/cmd/scsi/sestopo/i386/Makefile new file mode 100644 index 0000000000..16356f9dd8 --- /dev/null +++ b/usr/src/cmd/scsi/sestopo/i386/Makefile @@ -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 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" + +include ../../../Makefile.cmd +include ../Makefile.com diff --git a/usr/src/cmd/scsi/sestopo/sparc/Makefile b/usr/src/cmd/scsi/sestopo/sparc/Makefile new file mode 100644 index 0000000000..16356f9dd8 --- /dev/null +++ b/usr/src/cmd/scsi/sestopo/sparc/Makefile @@ -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 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" + +include ../../../Makefile.cmd +include ../Makefile.com diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile index f7acd48612..cd2dd14e2a 100644 --- a/usr/src/lib/Makefile +++ b/usr/src/lib/Makefile @@ -238,6 +238,7 @@ SUBDIRS += \ libexacct/demo \ libvscan \ smbsrv \ + scsi \ $($(MACH)_SUBDIRS) sparc_SUBDIRS= .WAIT \ @@ -432,6 +433,7 @@ HDRSUBDIRS= \ libidmap \ libvscan \ smbsrv \ + scsi \ $($(MACH)_HDRSUBDIRS) $(CLOSED_BUILD)HDRSUBDIRS += \ @@ -561,6 +563,7 @@ libtsalarm: libpcp smbsrv: libsocket libnsl libmd libxnet libpthread librt \ libshare libidmap pkcs11 libsqlite libvscan: libscf +scsi: libnvpair # # The reason this rule checks for the existence of the diff --git a/usr/src/lib/scsi/Makefile b/usr/src/lib/scsi/Makefile new file mode 100644 index 0000000000..18c7ae7c2c --- /dev/null +++ b/usr/src/lib/scsi/Makefile @@ -0,0 +1,41 @@ +# +# 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" + +SUBDIRS = \ + libscsi \ + libses \ + plugins + +.KEEP_STATE: + +.PARALLEL: + +libses: libscsi + +plugins: libscsi libses + +include Makefile.subdirs diff --git a/usr/src/lib/scsi/Makefile.defs b/usr/src/lib/scsi/Makefile.defs new file mode 100644 index 0000000000..5e6b48caf3 --- /dev/null +++ b/usr/src/lib/scsi/Makefile.defs @@ -0,0 +1,35 @@ +# +# 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" + +SCSILIBDIR = /usr/lib/scsi +ROOTSCSILIBDIR = $(ROOT)/usr/lib/scsi +SCSIHDRDIR = /usr/include/scsi +ROOTSCSIHDRDIR = $(ROOT)/usr/include/scsi + +PLUGINLIBDIR = $(SCSILIBDIR)/plugins +ROOTPLUGINLIBDIR = $(ROOTSCSILIBDIR)/plugins +PLUGINHDRDIR = $(SCSIHDRDIR)/plugins +ROOTPLUGINHDRDIR = $(ROOTSCSIHDRDIR)/plugins diff --git a/usr/src/lib/scsi/Makefile.rootdirs b/usr/src/lib/scsi/Makefile.rootdirs new file mode 100644 index 0000000000..c92390410c --- /dev/null +++ b/usr/src/lib/scsi/Makefile.rootdirs @@ -0,0 +1,69 @@ +# +# 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" + +# +# Define the transitive set of rules to create a common module's install dir +# within the proto area. +# + +$(ROOTPLUGINLIBDIR): + $(INS.dir) + +$(ROOTPLUGINLIBDIR)/scsi: $(ROOTPLUGINLIBDIR) + $(INS.dir) + +$(ROOTPLUGINLIBDIR)/scsi/engines: $(ROOTPLUGINLIBDIR)/scsi + $(INS.dir) + +$(ROOTPLUGINLIBDIR)/scsi/engines/$(MACH64): $(ROOTPLUGINLIBDIR)/scsi/engines + $(INS.dir) + +$(ROOTPLUGINLIBDIR)/ses: $(ROOTPLUGINLIBDIR) + $(INS.dir) + +$(ROOTPLUGINLIBDIR)/ses/framework: $(ROOTPLUGINLIBDIR)/ses + $(INS.dir) + +$(ROOTPLUGINLIBDIR)/ses/framework/$(MACH64): $(ROOTPLUGINLIBDIR)/ses/framework + $(INS.dir) + +$(ROOTPLUGINLIBDIR)/ses/vendor: $(ROOTPLUGINLIBDIR)/ses + $(INS.dir) + +$(ROOTPLUGINLIBDIR)/ses/vendor/$(MACH64): $(ROOTPLUGINLIBDIR)/ses/vendor + $(INS.dir) + +$(ROOTPLUGINHDRDIR): + $(INS.dir) + +$(ROOTPLUGINHDRDIR)/ses: $(ROOTPLUGINHDRDIR) + $(INS.dir) + +$(ROOTPLUGINHDRDIR)/ses/framework: $(ROOTPLUGINHDRDIR)/ses + $(INS.dir) + +$(ROOTPLUGINHDRDIR)/ses/vendor: $(ROOTPLUGINHDRDIR)/ses + $(INS.dir) diff --git a/usr/src/lib/scsi/Makefile.subdirs b/usr/src/lib/scsi/Makefile.subdirs new file mode 100644 index 0000000000..246da18969 --- /dev/null +++ b/usr/src/lib/scsi/Makefile.subdirs @@ -0,0 +1,44 @@ +# +# 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" + +.KEEP_STATE: + +all := TARGET += all +check := TARGET += check +clean := TARGET += clean +clobber := TARGET += clobber +install := TARGET += install +install_h := TARGET += install_h +lint := TARGET += lint +_msg := TARGET += _msg + +all check clean clobber install install_h lint: $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; VERSION='$(VERSION)' $(MAKE) $(TARGET) + +FRC: diff --git a/usr/src/lib/scsi/libscsi/Makefile b/usr/src/lib/scsi/libscsi/Makefile new file mode 100644 index 0000000000..c21f8e06fd --- /dev/null +++ b/usr/src/lib/scsi/libscsi/Makefile @@ -0,0 +1,61 @@ +# +# 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" + +include ../../Makefile.lib +include ../Makefile.defs + +HDRS = libscsi.h +ROOTHDRDIR = $(ROOTSCSIHDRDIR) +ROOTHDRS = $(HDRS:%=$(ROOTHDRDIR)/%) +CHECKDIRS = $(HDRS:%.h=%.check) +HDRDIR = common + +SUBDIRS = $(MACH) +$(BUILD64)SUBDIRS += $(MACH64) + +all := TARGET= all +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install +lint := TARGET= lint +install_h:= TARGET = install_h + +.KEEP_STATE: + +all install clean clobber lint: $(SUBDIRS) + +install_h: $(ROOTHDRS) + +check: $(CHECKHDRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + +include ../Makefile.rootdirs +include ../../Makefile.targ diff --git a/usr/src/lib/scsi/libscsi/Makefile.com b/usr/src/lib/scsi/libscsi/Makefile.com new file mode 100644 index 0000000000..88e3f7fa4c --- /dev/null +++ b/usr/src/lib/scsi/libscsi/Makefile.com @@ -0,0 +1,71 @@ +# +# 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" + +LIBRARY = libscsi.a +VERS = .1 + +OBJECTS = \ + scsi_engine.o \ + scsi_errno.o \ + scsi_status.o \ + scsi_subr.o + +include ../../../Makefile.lib +include ../../Makefile.defs + +SRCS = $(OBJECTS:%.o=../common/%.c) +C99MODE = $(C99_ENABLE) +CPPFLAGS += -I../common -I. -D_REENTRANT +$(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG +CFLAGS += $(CCVERBOSE) +LDLIBS += \ + -lumem \ + -lc +LIBS = $(DYNLIB) $(LINTLIB) +ROOTLIBDIR = $(ROOTSCSILIBDIR) +ROOTLIBDIR64 = $(ROOTSCSILIBDIR)/$(MACH64) + +CLEANFILES += \ + ../common/scsi_errno.c + +$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) + +.KEEP_STATE: + +all : $(LIBS) + +lint : lintcheck + +../common/scsi_errno.c: ../common/mkerrno.sh ../common/libscsi.h + sh ../common/mkerrno.sh < ../common/libscsi.h > $@ + +pics/%.o: ../common/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +include ../../../Makefile.targ +include ../../Makefile.rootdirs diff --git a/usr/src/lib/scsi/libscsi/amd64/Makefile b/usr/src/lib/scsi/libscsi/amd64/Makefile new file mode 100644 index 0000000000..e3fab7e838 --- /dev/null +++ b/usr/src/lib/scsi/libscsi/amd64/Makefile @@ -0,0 +1,31 @@ +# +# 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" + +include ../Makefile.com +include ../../../Makefile.lib.64 + +install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64) diff --git a/usr/src/lib/scsi/libscsi/common/libscsi.h b/usr/src/lib/scsi/libscsi/common/libscsi.h new file mode 100644 index 0000000000..748913ee1e --- /dev/null +++ b/usr/src/lib/scsi/libscsi/common/libscsi.h @@ -0,0 +1,182 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _LIBSCSI_H +#define _LIBSCSI_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> +#include <sys/sysmacros.h> +#include <sys/scsi/impl/spc3_types.h> +#include <stdarg.h> + +#define LIBSCSI_VERSION 1 +#define LIBSCSI_STATUS_INVALID ((sam4_status_t)-1) +#define LIBSCSI_DEFAULT_ENGINE_PATH "/usr/lib/scsi/plugins/scsi/engines" +#define LIBSCSI_DEFAULT_ENGINE "uscsi" + +/* + * Flags for action creation. Selected to avoid overlap with the uscsi + * flags with similar or identical meaning. + */ +#define LIBSCSI_AF_READ 0x80000000 +#define LIBSCSI_AF_WRITE 0x40000000 +#define LIBSCSI_AF_SILENT 0x20000000 +#define LIBSCSI_AF_DIAGNOSE 0x10000000 +#define LIBSCSI_AF_ISOLATE 0x08000000 +#define LIBSCSI_AF_RQSENSE 0x04000000 + +typedef enum libscsi_errno { + ESCSI_NONE, /* no error */ + ESCSI_NOMEM, /* no memory */ + ESCSI_ZERO_LENGTH, /* zero-length allocation requested */ + ESCSI_VERSION, /* library version mismatch */ + ESCSI_BADTARGET, /* invalid target specification */ + ESCSI_BADCMD, /* invalid SCSI command */ + ESCSI_BADENGINE, /* engine library corrupt */ + ESCSI_NOENGINE, /* engine library not found */ + ESCSI_ENGINE_INIT, /* engine initialization failed */ + ESCSI_ENGINE_VER, /* engine version mismatch */ + ESCSI_ENGINE_BADPATH, /* engine path contains no usable components */ + ESCSI_BADFLAGS, /* incorrect action flags */ + ESCSI_BOGUSFLAGS, /* unknown flag value */ + ESCSI_BADLENGTH, /* buffer length overflow */ + ESCSI_NEEDBUF, /* missing required buffer */ + ESCSI_IO, /* I/O operation failed */ + ESCSI_SYS, /* system call failed */ + ESCSI_PERM, /* insufficient permissions */ + ESCSI_RANGE, /* parameter outside valid range */ + ESCSI_NOTSUP, /* operation not supported */ + ESCSI_UNKNOWN, /* error of unknown type */ + ESCSI_INQUIRY_FAILED, /* initial inquiry command failed */ + ESCSI_MAX /* maximum libscsi errno value */ +} libscsi_errno_t; + +struct libscsi_hdl; +typedef struct libscsi_hdl libscsi_hdl_t; + +struct libscsi_target; +typedef struct libscsi_target libscsi_target_t; + +typedef struct libscsi_status { + uint64_t lss_status; /* SCSI status of this command */ + size_t lss_sense_len; /* Length in bytes of sense data */ + uint8_t *lss_sense_data; /* Pointer to sense data */ +} libscsi_status_t; + +struct libscsi_action; +typedef struct libscsi_action libscsi_action_t; + +struct libscsi_result; +typedef struct libscsi_result libscsi_result_t; + +typedef struct libscsi_engine_ops { + void *(*lseo_open)(libscsi_hdl_t *, const void *); + void (*lseo_close)(libscsi_hdl_t *, void *); + int (*lseo_exec)(libscsi_hdl_t *, void *, libscsi_action_t *); + void (*lseo_target_name)(libscsi_hdl_t *, void *, char *, size_t); +} libscsi_engine_ops_t; + +typedef struct libscsi_engine { + const char *lse_name; + uint_t lse_libversion; + const libscsi_engine_ops_t *lse_ops; +} libscsi_engine_t; + +extern libscsi_hdl_t *libscsi_init(uint_t, libscsi_errno_t *); +extern void libscsi_fini(libscsi_hdl_t *); + +extern libscsi_target_t *libscsi_open(libscsi_hdl_t *, const char *, + const void *); +extern void libscsi_close(libscsi_hdl_t *, libscsi_target_t *); +extern libscsi_hdl_t *libscsi_get_handle(libscsi_target_t *); + +extern const char *libscsi_vendor(libscsi_target_t *); +extern const char *libscsi_product(libscsi_target_t *); +extern const char *libscsi_revision(libscsi_target_t *); + +extern libscsi_errno_t libscsi_errno(libscsi_hdl_t *); +extern const char *libscsi_errmsg(libscsi_hdl_t *); +extern const char *libscsi_strerror(libscsi_errno_t); +extern const char *libscsi_errname(libscsi_errno_t); +extern libscsi_errno_t libscsi_errcode(const char *); + +extern libscsi_action_t *libscsi_action_alloc(libscsi_hdl_t *, spc3_cmd_t, + uint_t, void *, size_t); +extern sam4_status_t libscsi_action_get_status(const libscsi_action_t *); +extern void libscsi_action_set_timeout(libscsi_action_t *, uint32_t); +extern uint32_t libscsi_action_get_timeout(const libscsi_action_t *); +extern uint_t libscsi_action_get_flags(const libscsi_action_t *); +extern uint8_t *libscsi_action_get_cdb(const libscsi_action_t *); +extern int libscsi_action_get_buffer(const libscsi_action_t *, + uint8_t **, size_t *, size_t *); +extern int libscsi_action_get_sense(const libscsi_action_t *, + uint8_t **, size_t *, size_t *); +extern int libscsi_action_parse_sense(const libscsi_action_t *, uint64_t *, + uint64_t *, uint64_t *, diskaddr_t *); +extern void libscsi_action_set_status(libscsi_action_t *, sam4_status_t); +extern int libscsi_action_set_datalen(libscsi_action_t *, size_t); +extern int libscsi_action_set_senselen(libscsi_action_t *, size_t); +extern int libscsi_exec(libscsi_action_t *, libscsi_target_t *); +extern void libscsi_action_free(libscsi_action_t *); + +extern const char *libscsi_sense_key_name(uint64_t); +extern const char *libscsi_sense_code_name(uint64_t, uint64_t); + +/* + * Interfaces for engine providers + */ +extern void *libscsi_alloc(libscsi_hdl_t *, size_t); +extern void *libscsi_zalloc(libscsi_hdl_t *, size_t); +extern char *libscsi_strdup(libscsi_hdl_t *, const char *); +extern void libscsi_free(libscsi_hdl_t *, void *); +extern libscsi_status_t *libscsi_status_alloc(libscsi_hdl_t *, size_t); +extern int libscsi_status_fill(libscsi_hdl_t *, libscsi_status_t *, + uint16_t, size_t); +extern void libscsi_status_free(libscsi_hdl_t *, libscsi_status_t *); + +extern int libscsi_set_errno(libscsi_hdl_t *, libscsi_errno_t); +extern int libscsi_verror(libscsi_hdl_t *, libscsi_errno_t, const char *, + va_list); +extern int libscsi_error(libscsi_hdl_t *, libscsi_errno_t, const char *, ...); + +typedef const libscsi_engine_t *(*libscsi_engine_init_f)(libscsi_hdl_t *); + +/* + * Generic SCSI utility functions. + */ +extern size_t libscsi_cmd_cdblen(libscsi_hdl_t *, uint8_t); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBSCSI_H */ diff --git a/usr/src/lib/scsi/libscsi/common/libscsi_impl.h b/usr/src/lib/scsi/libscsi/common/libscsi_impl.h new file mode 100644 index 0000000000..c34879dab4 --- /dev/null +++ b/usr/src/lib/scsi/libscsi/common/libscsi_impl.h @@ -0,0 +1,100 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _LIBSCSI_IMPL_H +#define _LIBSCSI_IMPL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <libscsi.h> + +#define LIBSCSI_ENGINE_EXT ".so" + +#define LIBSCSI_ERRMSGLEN 512 + +typedef struct libscsi_engine_impl { + const libscsi_engine_t *lsei_engine; + void *lsei_dl_hdl; + struct libscsi_engine_impl *lsei_next; +} libscsi_engine_impl_t; + +typedef struct libscsi_action_impl { + libscsi_hdl_t *lsai_hdl; + uint_t lsai_flags; + uint32_t lsai_timeout; + uint8_t *lsai_cdb; + size_t lsai_cdb_len; + size_t lsai_data_len; + size_t lsai_data_alloc; + uint8_t *lsai_data; + sam4_status_t lsai_status; + size_t lsai_sense_len; + uint8_t *lsai_sense_data; + uint8_t lsai_buf[1]; +} libscsi_action_impl_t; + +struct libscsi_hdl { + uint_t lsh_version; + libscsi_errno_t lsh_errno; + char lsh_errmsg[LIBSCSI_ERRMSGLEN]; + libscsi_engine_impl_t *lsh_engines; + uint_t lsh_targets; +}; + +struct libscsi_target { + const libscsi_engine_t *lst_engine; + char *lst_vendor; + char *lst_product; + char *lst_revision; + void *lst_priv; + uint_t lst_mtbf_cdb; + uint_t lst_mtbf_read; + uint_t lst_mtbf_write; + struct libscsi_hdl *lst_hdl; +}; + +#define VERIFY(x) ((void)((x) || libscsi_assert(#x, __FILE__, __LINE__))) + +#ifdef DEBUG +#define ASSERT(x) VERIFY(x) +#else +#define ASSERT(x) +#endif + +#define LXOR(l, r) (((l) != 0) ^ ((r) != 0)) + +extern int libscsi_assert(const char *, const char *, int); +extern int libscsi_get_inquiry(struct libscsi_hdl *, struct libscsi_target *); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBSCSI_IMPL_H */ diff --git a/usr/src/lib/scsi/libscsi/common/mkerrno.sh b/usr/src/lib/scsi/libscsi/common/mkerrno.sh new file mode 100644 index 0000000000..604c63e643 --- /dev/null +++ b/usr/src/lib/scsi/libscsi/common/mkerrno.sh @@ -0,0 +1,88 @@ +#!/bin/sh +# +# 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" + +echo "\ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident\t\"%Z%%M%\t%I%\t%E%\tSMI\" + +#include <strings.h> +#include <scsi/libscsi.h> + +static const struct { +\tchar *name;\t\t/* error name */ +\tchar *msg;\t\t/* error message */ +} _libscsi_errstr[] = {" + +pattern='^ \(ESCSI_[A-Z0-9_]*\),*' +replace=' { "\1",' +open=' \/\* ' +openrepl='"' +close=' \*\/$' +closerepl='" },' + +( sed -n "s/$pattern/$replace/p" | sed -n "s/$open/$openrepl/p" | + sed -n "s/$close/$closerepl/p" ) || exit 1 + +echo "\ +};\n\ +\n\ +static int _libscsi_nerrno = sizeof (_libscsi_errstr) /\n\ + sizeof (_libscsi_errstr[0]);\n\ +\n\ +const char * +libscsi_strerror(libscsi_errno_t err) +{ + return (err < 0 || err >= _libscsi_nerrno ? \"unknown error\" : + _libscsi_errstr[err].msg); +} + +const char * +libscsi_errname(libscsi_errno_t err) +{ + return (err < 0 || err >= _libscsi_nerrno ? NULL : + _libscsi_errstr[err].name); +} + +libscsi_errno_t +libscsi_errcode(const char *name) +{ + libscsi_errno_t err; + + for (err = 0; err < _libscsi_nerrno; err++) { + if (strcmp(name, _libscsi_errstr[err].name) == 0) + return (err); + } + + return (ESCSI_UNKNOWN); +}" + +exit 0 diff --git a/usr/src/lib/scsi/libscsi/common/scsi_engine.c b/usr/src/lib/scsi/libscsi/common/scsi_engine.c new file mode 100644 index 0000000000..df221eea55 --- /dev/null +++ b/usr/src/lib/scsi/libscsi/common/scsi_engine.c @@ -0,0 +1,621 @@ +/* + * 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/isa_defs.h> +#include <sys/systeminfo.h> +#include <sys/scsi/generic/commands.h> +#include <sys/scsi/impl/commands.h> +#include <sys/scsi/impl/uscsi.h> + +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <string.h> +#include <dlfcn.h> +#include <limits.h> + +#include <scsi/libscsi.h> +#include "libscsi_impl.h" + +static const libscsi_engine_t * +get_engine(libscsi_hdl_t *hp, const char *name) +{ + libscsi_engine_impl_t *eip; + const libscsi_engine_t *ep; + const char *engine_path, *p, *q; + char engine_dir[MAXPATHLEN]; + char engine_lib[MAXPATHLEN]; + char init_name[MAXPATHLEN]; + void *dl_hdl; + libscsi_engine_init_f init; + boolean_t found_lib = B_FALSE, found_init = B_FALSE; + int dirs_tried = 0; + char isa[257]; + + for (eip = hp->lsh_engines; eip != NULL; eip = eip->lsei_next) { + if (strcmp(eip->lsei_engine->lse_name, name) == 0) + return (eip->lsei_engine); + } + + if ((engine_path = getenv("LIBSCSI_ENGINE_PATH")) == NULL) + engine_path = LIBSCSI_DEFAULT_ENGINE_PATH; + +#if defined(_LP64) + if (sysinfo(SI_ARCHITECTURE_64, isa, sizeof (isa)) < 0) + isa[0] = '\0'; +#else + isa[0] = '\0'; +#endif + + for (p = engine_path, q = strchr(p, ':'); p != NULL; p = q) { + if (q != NULL) { + ptrdiff_t len = q - p; + (void) strncpy(engine_dir, p, len); + engine_dir[len] = '\0'; + while (*q == ':') + ++q; + if (*q == '\0') + q = NULL; + if (len == 0) + continue; + } else { + (void) strcpy(engine_dir, p); + } + if (engine_dir[0] != '/') + continue; + + ++dirs_tried; + + (void) snprintf(engine_lib, MAXPATHLEN, "%s/%s/%s%s", + engine_dir, isa, name, LIBSCSI_ENGINE_EXT); + + dl_hdl = dlopen(engine_lib, + RTLD_LOCAL | RTLD_LAZY | RTLD_PARENT); + if (dl_hdl == NULL) { + if (!found_lib) + (void) libscsi_error(hp, ESCSI_NOENGINE, + "unable to dlopen %s: %s", engine_lib, + dlerror()); + continue; + } + found_lib = B_TRUE; + (void) snprintf(init_name, MAXPATHLEN, "libscsi_%s_init", name); + init = (libscsi_engine_init_f)dlsym(dl_hdl, init_name); + if (init == NULL) { + if (!found_init) + (void) libscsi_error(hp, ESCSI_NOENGINE, + "failed to find %s in %s: %s", init_name, + engine_lib, dlerror()); + (void) dlclose(dl_hdl); + continue; + } + if ((ep = init(hp)) == NULL) { + (void) dlclose(dl_hdl); + /* + * libscsi errno set by init. + */ + return (NULL); + } + if (ep->lse_libversion != hp->lsh_version) { + (void) dlclose(dl_hdl); + (void) libscsi_error(hp, ESCSI_ENGINE_VER, "engine " + "%s version %u does not match library version %u", + engine_lib, ep->lse_libversion, hp->lsh_version); + return (NULL); + } + + eip = libscsi_zalloc(hp, sizeof (libscsi_engine_impl_t)); + if (eip == NULL) { + (void) dlclose(dl_hdl); + return (NULL); + } + eip->lsei_engine = ep; + eip->lsei_dl_hdl = dl_hdl; + eip->lsei_next = hp->lsh_engines; + hp->lsh_engines = eip; + + return (ep); + } + + if (dirs_tried == 0) + (void) libscsi_error(hp, ESCSI_ENGINE_BADPATH, "no valid " + "directories found in engine path %s", engine_path); + + return (NULL); +} + +static void +scsi_parse_mtbf(const char *envvar, uint_t *intp) +{ + const char *strval; + int intval; + + if ((strval = getenv(envvar)) != NULL && + (intval = atoi(strval)) > 0) { + srand48(gethrtime()); + *intp = intval; + } +} + +libscsi_target_t * +libscsi_open(libscsi_hdl_t *hp, const char *engine, const void *target) +{ + const libscsi_engine_t *ep; + libscsi_target_t *tp; + void *private; + + if (engine == NULL) { + if ((engine = getenv("LIBSCSI_DEFAULT_ENGINE")) == NULL) + engine = LIBSCSI_DEFAULT_ENGINE; + } + + if ((ep = get_engine(hp, engine)) == NULL) + return (NULL); + + if ((tp = libscsi_zalloc(hp, sizeof (libscsi_target_t))) == NULL) + return (NULL); + + if ((private = ep->lse_ops->lseo_open(hp, target)) == NULL) { + libscsi_free(hp, tp); + return (NULL); + } + + scsi_parse_mtbf("LIBSCSI_MTBF_CDB", &tp->lst_mtbf_cdb); + scsi_parse_mtbf("LIBSCSI_MTBF_READ", &tp->lst_mtbf_read); + scsi_parse_mtbf("LIBSCSI_MTBF_WRITE", &tp->lst_mtbf_write); + + tp->lst_hdl = hp; + tp->lst_engine = ep; + tp->lst_priv = private; + + ++hp->lsh_targets; + + if (libscsi_get_inquiry(hp, tp) != 0) { + libscsi_close(hp, tp); + return (NULL); + } + + return (tp); +} + +libscsi_hdl_t * +libscsi_get_handle(libscsi_target_t *tp) +{ + return (tp->lst_hdl); +} + +void +libscsi_close(libscsi_hdl_t *hp, libscsi_target_t *tp) +{ + tp->lst_engine->lse_ops->lseo_close(hp, tp->lst_priv); + libscsi_free(hp, tp->lst_vendor); + libscsi_free(hp, tp->lst_product); + libscsi_free(hp, tp->lst_revision); + libscsi_free(hp, tp); + --hp->lsh_targets; +} + +sam4_status_t +libscsi_action_get_status(const libscsi_action_t *ap) +{ + const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap; + + return (aip->lsai_status); +} + +/* + * Set the timeout in seconds for this action. If no timeout is specified + * or if the timeout is set to 0, an implementation-specific timeout will be + * used (which may vary based on the target, command or other variables). + * Not all engines support all timeout values. Setting the timeout to a value + * not supported by the engine will cause engine-defined behavior when the + * action is executed. + */ +void +libscsi_action_set_timeout(libscsi_action_t *ap, uint32_t timeout) +{ + libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap; + + aip->lsai_timeout = timeout; +} + +/* + * Obtain the timeout setting for this action. + */ +uint32_t +libscsi_action_get_timeout(const libscsi_action_t *ap) +{ + const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap; + + return (aip->lsai_timeout); +} + +/* + * Returns the flags associated with this action. Never fails. + */ +uint_t +libscsi_action_get_flags(const libscsi_action_t *ap) +{ + const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap; + + return (aip->lsai_flags); +} + +/* + * Returns the address of the action's CDB. The CDB buffer is guaranteed to + * be large enough to hold the complete CDB for the command specified when the + * action was allocated. Therefore, changing the command/opcode portion of + * the CDB has undefined effects. The remainder of the CDB may be modified. + */ +uint8_t * +libscsi_action_get_cdb(const libscsi_action_t *ap) +{ + const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap; + + return (aip->lsai_cdb); +} + +/* + * Places the address of the action buffer in the location pointed to by bp, + * if bp is not NULL. If ap is not NULL, it will contain the allocated size + * of the buffer itself. If vp is not NULL, it will contain the number of + * bytes of valid data currently stored in the buffer. + * + * If the action has LIBSCSI_AF_WRITE set and it has not yet been executed + * successfully, the entire buffer is assumed to contain valid data. + * + * If the action has LIBSCSI_AF_READ set and it has not yet been executed + * successfully, the amount of valid data is 0. + * + * If both LIBSCSI_AF_READ and LIBSCSI_AF_WRITE are clear, this function + * fails with ESCSI_BADFLAGS to indicate that the action flags are + * incompatible with the action data buffer. + */ +int +libscsi_action_get_buffer(const libscsi_action_t *ap, uint8_t **bp, + size_t *sp, size_t *vp) +{ + const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap; + + if ((aip->lsai_flags & (LIBSCSI_AF_READ | LIBSCSI_AF_WRITE)) == 0) + return (libscsi_error(aip->lsai_hdl, ESCSI_BADFLAGS, + "data buffer not supported for actions with both " + "LIBSCSI_AF_READ and LIBSCSI_AF_WRITE clear")); + + if ((aip->lsai_flags & LIBSCSI_AF_WRITE) && + aip->lsai_status == LIBSCSI_STATUS_INVALID) { + if (bp != NULL) + *bp = aip->lsai_data; + if (sp != NULL) + *sp = aip->lsai_data_alloc; + if (vp != NULL) + *vp = aip->lsai_data_alloc; + + return (0); + } + + if ((aip->lsai_flags & LIBSCSI_AF_READ) && + aip->lsai_status != LIBSCSI_STATUS_INVALID) { + if (bp != NULL) + *bp = aip->lsai_data; + if (sp != NULL) + *sp = aip->lsai_data_alloc; + if (vp != NULL) + *vp = aip->lsai_data_len; + + return (0); + } + + if (aip->lsai_flags & LIBSCSI_AF_WRITE) { + if (bp != NULL) + *bp = NULL; + if (sp != NULL) + *sp = NULL; + if (vp != NULL) + *vp = 0; + } else { + if (bp != NULL) + *bp = aip->lsai_data; + if (sp != NULL) + *sp = aip->lsai_data_alloc; + if (vp != NULL) + *vp = 0; + } + + return (0); +} + +/* + * Obtain a pointer to the sense buffer for this action, if any, along with + * the size of the sense buffer and the amount of valid data it contains. + */ +int +libscsi_action_get_sense(const libscsi_action_t *ap, uint8_t **bp, + size_t *sp, size_t *vp) +{ + const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap; + + if (!(aip->lsai_flags & LIBSCSI_AF_RQSENSE)) + return (libscsi_error(aip->lsai_hdl, ESCSI_BADFLAGS, + "sense data unavailable: LIBSCSI_AF_RQSENSE is clear")); + + if (vp != NULL) { + if (aip->lsai_status == LIBSCSI_STATUS_INVALID) + *vp = 0; + else + *vp = aip->lsai_sense_len; + } + + if (bp != NULL) { + ASSERT(aip->lsai_sense_data != NULL); + *bp = aip->lsai_sense_data; + } + + if (sp != NULL) + *sp = UINT8_MAX; + + return (0); +} + +/* + * Set the SCSI status of the action. + * + * Engines only. + */ +void +libscsi_action_set_status(libscsi_action_t *ap, sam4_status_t status) +{ + libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap; + + ASSERT(aip->lsai_status == LIBSCSI_STATUS_INVALID); + + aip->lsai_status = status; +} + +/* + * Set the length of valid data returned by a READ action. If the action is + * not a READ action, or the length exceeds the size of the buffer, an error + * results. + * + * Engines only. + */ +int +libscsi_action_set_datalen(libscsi_action_t *ap, size_t len) +{ + libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap; + + if ((aip->lsai_flags & LIBSCSI_AF_READ) == 0) + return (libscsi_error(aip->lsai_hdl, ESCSI_BADFLAGS, + "data cannot be returned for actions with LIBSCSI_AF_READ " + "clear")); + if (len > aip->lsai_data_alloc) + return (libscsi_error(aip->lsai_hdl, ESCSI_BADLENGTH, + "data length %lu exceeds allocated buffer capacity %lu", + (ulong_t)len, (ulong_t)aip->lsai_data_alloc)); + + ASSERT(aip->lsai_data_len == 0); + aip->lsai_data_len = len; + + return (0); +} + +/* + * Set the length of the valid sense data returned following the command, if + * LIBSCSI_AF_RQSENSE is set for this action. Otherwise, fail. + * + * Engines only. + */ +int +libscsi_action_set_senselen(libscsi_action_t *ap, size_t len) +{ + libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap; + + if (!(aip->lsai_flags & LIBSCSI_AF_RQSENSE)) + return (libscsi_error(aip->lsai_hdl, ESCSI_BADFLAGS, + "sense data not supported: LIBSCSI_AF_RQSENSE is clear")); + + if (len > UINT8_MAX) + return (libscsi_error(aip->lsai_hdl, ESCSI_BADLENGTH, + "sense length %lu exceeds allocated buffer capacity %lu", + (ulong_t)len, (ulong_t)UINT8_MAX)); + + ASSERT(aip->lsai_sense_len == 0); + aip->lsai_sense_len = len; + + return (0); +} + +/* + * Allocate an action object. The object will contain a CDB area sufficiently + * large to hold a CDB for the given command, and the CDB's opcode will be + * filled in. A pointer to this CDB, the contents of which may be modified by + * the caller, may be obtained by a subsequent call to libscsi_action_cdb(). + * + * If flags includes LIBSCSI_AF_READ or LIBSCSI_AF_WRITE, buflen must be + * greater than zero. Otherwise, buflen must be 0 and buf must be NULL. + * If buflen is nonzero but buf is NULL, a suitably-sized buffer will be + * allocated; otherwise, the specified buffer will be used. In either case, + * a pointer to the buffer may be obtained via a subsequent call to + * libscsi_action_buffer(). + * + * If flags includes LIBSCSI_AF_RQSENSE, a REQUEST SENSE command will be + * issued immediately following the termination of the specified command. + * A buffer will be allocated to receive this sense data. Following successful + * execution of the action, a pointer to this buffer and the length of + * valid sense data may be obtained by a call to libscsi_action_sense(). + * If cmd is SPC3_CMD_REQUEST_SENSE, this flag must be clear. + */ +libscsi_action_t * +libscsi_action_alloc(libscsi_hdl_t *hp, spc3_cmd_t cmd, uint_t flags, + void *buf, size_t buflen) +{ + libscsi_action_impl_t *aip; + size_t cdbsz, sz; + ptrdiff_t off; + + /* + * If there's no buffer, it makes no sense to try to read or write + * data. Likewise, if we're neither reading nor writing data, we + * should not have a buffer. Both of these are programmer error. + */ + if (buflen == 0 && (flags & (LIBSCSI_AF_READ | LIBSCSI_AF_WRITE))) { + (void) libscsi_error(hp, ESCSI_NEEDBUF, "a buffer is " + "required when reading or writing"); + return (NULL); + } + if (buflen > 0 && !(flags & (LIBSCSI_AF_READ | LIBSCSI_AF_WRITE))) { + (void) libscsi_error(hp, ESCSI_BADFLAGS, "one of " + "LIBSCSI_AF_READ and LIBSCSI_AF_WRITE must be specified " + "in order to use a buffer"); + return (NULL); + } + if (cmd == SPC3_CMD_REQUEST_SENSE && (flags & LIBSCSI_AF_RQSENSE)) { + (void) libscsi_error(hp, ESCSI_BADFLAGS, "request sense " + "flag not allowed for request sense command"); + return (NULL); + } + + if ((sz = cdbsz = libscsi_cmd_cdblen(hp, cmd)) == 0) + return (NULL); + + /* + * If the caller has asked for a buffer but has not provided one, we + * will allocate it in our internal buffer along with the CDB and + * request sense space (if requested). + */ + if (buf == NULL) + sz += buflen; + + if (flags & LIBSCSI_AF_RQSENSE) + sz += UINT8_MAX; + + sz += offsetof(libscsi_action_impl_t, lsai_buf[0]); + + if ((aip = libscsi_zalloc(hp, sz)) == NULL) + return (NULL); + + aip->lsai_hdl = hp; + aip->lsai_flags = flags; + + off = 0; + + aip->lsai_cdb = aip->lsai_buf + off; + aip->lsai_cdb_len = cdbsz; + off += cdbsz; + aip->lsai_cdb[0] = (uint8_t)cmd; + + if (buflen > 0) { + if (buf != NULL) { + aip->lsai_data = buf; + } else { + aip->lsai_data = aip->lsai_buf + off; + off += buflen; + } + aip->lsai_data_alloc = buflen; + if (flags & LIBSCSI_AF_WRITE) + aip->lsai_data_len = buflen; + } + + if (flags & LIBSCSI_AF_RQSENSE) { + aip->lsai_sense_data = aip->lsai_buf + off; + off += UINT8_MAX; + } + + aip->lsai_status = LIBSCSI_STATUS_INVALID; + + return ((libscsi_action_t *)aip); +} + +void +libscsi_action_free(libscsi_action_t *ap) +{ + libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap; + + libscsi_free(aip->lsai_hdl, aip); +} + +/* + * For testing purposes, we allow data to be corrupted via an environment + * variable setting. This helps ensure that higher level software can cope with + * arbitrarily broken targets. The mtbf value represents the number of bytes we + * will see, on average, in between each failure. Therefore, for each N bytes, + * we would expect to see (N / mtbf) bytes of corruption. + */ +static void +scsi_inject_errors(void *data, size_t len, uint_t mtbf) +{ + char *buf = data; + double prob; + size_t index; + + if (len == 0) + return; + + prob = (double)len / mtbf; + + while (prob > 1) { + index = lrand48() % len; + buf[index] = (lrand48() % 256); + prob -= 1; + } + + if (drand48() <= prob) { + index = lrand48() % len; + buf[index] = (lrand48() % 256); + } +} + +int +libscsi_exec(libscsi_action_t *ap, libscsi_target_t *tp) +{ + libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap; + libscsi_hdl_t *hp = aip->lsai_hdl; + int ret; + + if (tp->lst_mtbf_write != 0 && + (aip->lsai_flags & LIBSCSI_AF_WRITE)) { + scsi_inject_errors(aip->lsai_data, aip->lsai_data_len, + tp->lst_mtbf_write); + } + + if (tp->lst_mtbf_cdb != 0) { + scsi_inject_errors(aip->lsai_cdb, aip->lsai_cdb_len, + tp->lst_mtbf_cdb); + } + + ret = tp->lst_engine->lse_ops->lseo_exec(hp, tp->lst_priv, ap); + + if (ret == 0 && tp->lst_mtbf_read != 0 && + (aip->lsai_flags & LIBSCSI_AF_READ)) { + scsi_inject_errors(aip->lsai_data, aip->lsai_data_len, + tp->lst_mtbf_read); + } + + return (ret); +} diff --git a/usr/src/lib/scsi/libscsi/common/scsi_status.c b/usr/src/lib/scsi/libscsi/common/scsi_status.c new file mode 100644 index 0000000000..ab6b23b72b --- /dev/null +++ b/usr/src/lib/scsi/libscsi/common/scsi_status.c @@ -0,0 +1,723 @@ +/* + * 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/scsi/generic/sense.h> +#include <sys/scsi/generic/status.h> + +#include <stddef.h> +#include <stdio.h> + +#include <scsi/libscsi.h> +#include "libscsi_impl.h" + +typedef struct slist { + char *str; + int value; +} slist_t; + +static slist_t sensekey_strings[] = { + { "No sense error", KEY_NO_SENSE }, + { "Recoverable error", KEY_RECOVERABLE_ERROR }, + { "Not ready error", KEY_NOT_READY }, + { "Medium error", KEY_MEDIUM_ERROR }, + { "Hardware error", KEY_HARDWARE_ERROR }, + { "Illegal request", KEY_ILLEGAL_REQUEST }, + { "Unit attention error", KEY_UNIT_ATTENTION }, + { "Write protect error", KEY_WRITE_PROTECT }, + { "Blank check error", KEY_BLANK_CHECK }, + { "Vendor unique error", KEY_VENDOR_UNIQUE }, + { "Copy aborted error", KEY_COPY_ABORTED }, + { "Aborted command", KEY_ABORTED_COMMAND }, + { "Equal error", KEY_EQUAL }, + { "Volume overflow", KEY_VOLUME_OVERFLOW }, + { "Miscompare error", KEY_MISCOMPARE }, + { "Reserved error", KEY_RESERVED }, + { NULL, 0 } +}; + +static struct asq_key_strings { + uint_t asc; + uint_t ascq; + const char *message; +} extended_sense_list[] = { + { 0x00, 0x00, "no additional sense info" }, + { 0x00, 0x01, "filemark detected" }, + { 0x00, 0x02, "end of partition/medium detected" }, + { 0x00, 0x03, "setmark detected" }, + { 0x00, 0x04, "begining of partition/medium detected" }, + { 0x00, 0x05, "end of data detected" }, + { 0x00, 0x06, "i/o process terminated" }, + { 0x00, 0x11, "audio play operation in progress" }, + { 0x00, 0x12, "audio play operation paused" }, + { 0x00, 0x13, "audio play operation successfully completed" }, + { 0x00, 0x14, "audio play operation stopped due to error" }, + { 0x00, 0x15, "no current audio status to return" }, + { 0x00, 0x16, "operation in progress" }, + { 0x00, 0x17, "cleaning requested" }, + { 0x00, 0x18, "erase operation in progress" }, + { 0x00, 0x19, "locate operation in progress" }, + { 0x00, 0x1A, "rewind operation in progress" }, + { 0x00, 0x1B, "set capacity operation in progress" }, + { 0x00, 0x1C, "verify operation in progress" }, + { 0x01, 0x00, "no index/sector signal" }, + { 0x02, 0x00, "no seek complete" }, + { 0x03, 0x00, "peripheral device write fault" }, + { 0x03, 0x01, "no write current" }, + { 0x03, 0x02, "excessive write errors" }, + { 0x04, 0x00, "LUN not ready" }, + { 0x04, 0x01, "LUN is becoming ready" }, + { 0x04, 0x02, "LUN initializing command required" }, + { 0x04, 0x03, "LUN not ready intervention required" }, + { 0x04, 0x04, "LUN not ready format in progress" }, + { 0x04, 0x05, "LUN not ready, rebuild in progress" }, + { 0x04, 0x06, "LUN not ready, recalculation in progress" }, + { 0x04, 0x07, "LUN not ready, operation in progress" }, + { 0x04, 0x08, "LUN not ready, long write in progress" }, + { 0x04, 0x09, "LUN not ready, self-test in progress" }, + { 0x04, 0x0A, "LUN not accessible, asymmetric access state " + "transition" }, + { 0x04, 0x0B, "LUN not accessible, target port in standby state" }, + { 0x04, 0x0C, "LUN not accessible, target port in unavailable state" }, + { 0x04, 0x10, "LUN not ready, auxiliary memory not accessible" }, + { 0x05, 0x00, "LUN does not respond to selection" }, + { 0x06, 0x00, "reference position found" }, + { 0x07, 0x00, "multiple peripheral devices selected" }, + { 0x08, 0x00, "LUN communication failure" }, + { 0x08, 0x01, "LUN communication time-out" }, + { 0x08, 0x02, "LUN communication parity error" }, + { 0x08, 0x03, "LUN communication crc error (ultra-DMA/32)" }, + { 0x08, 0x04, "unreachable copy target" }, + { 0x09, 0x00, "track following error" }, + { 0x09, 0x01, "tracking servo failure" }, + { 0x09, 0x02, "focus servo failure" }, + { 0x09, 0x03, "spindle servo failure" }, + { 0x09, 0x04, "head select fault" }, + { 0x0a, 0x00, "error log overflow" }, + { 0x0b, 0x00, "warning" }, + { 0x0b, 0x01, "warning - specified temperature exceeded" }, + { 0x0b, 0x02, "warning - enclosure degraded" }, + { 0x0c, 0x00, "write error" }, + { 0x0c, 0x01, "write error - recovered with auto reallocation" }, + { 0x0c, 0x02, "write error - auto reallocation failed" }, + { 0x0c, 0x03, "write error - recommend reassignment" }, + { 0x0c, 0x04, "compression check miscompare error" }, + { 0x0c, 0x05, "data expansion occurred during compression" }, + { 0x0c, 0x06, "block not compressible" }, + { 0x0c, 0x07, "write error - recovery needed" }, + { 0x0c, 0x08, "write error - recovery failed" }, + { 0x0c, 0x09, "write error - loss of streaming" }, + { 0x0c, 0x0a, "write error - padding blocks added" }, + { 0x0c, 0x0b, "auxiliary memory write error" }, + { 0x0c, 0x0c, "write error - unexpected unsolicited data" }, + { 0x0c, 0x0d, "write error - not enough unsolicited data" }, + { 0x0d, 0x00, "error detected by third party temporary initiator" }, + { 0x0d, 0x01, "third party device failure" }, + { 0x0d, 0x02, "copy target device not reachable" }, + { 0x0d, 0x03, "incorrect copy target device type" }, + { 0x0d, 0x04, "copy target device data underrun" }, + { 0x0d, 0x05, "copy target device data overrun" }, + { 0x0e, 0x00, "invalid information unit" }, + { 0x0e, 0x01, "information unit too short" }, + { 0x0e, 0x02, "information unit too long" }, + { 0x10, 0x00, "ID CRC or ECC error" }, + { 0x11, 0x00, "unrecovered read error" }, + { 0x11, 0x01, "read retries exhausted" }, + { 0x11, 0x02, "error too long to correct" }, + { 0x11, 0x03, "multiple read errors" }, + { 0x11, 0x04, "unrecovered read error - auto reallocate failed" }, + { 0x11, 0x05, "L-EC uncorrectable error" }, + { 0x11, 0x06, "CIRC unrecovered error" }, + { 0x11, 0x07, "data re-synchronization error" }, + { 0x11, 0x08, "incomplete block read" }, + { 0x11, 0x09, "no gap found" }, + { 0x11, 0x0a, "miscorrected error" }, + { 0x11, 0x0b, "unrecovered read error - recommend reassignment" }, + { 0x11, 0x0c, "unrecovered read error - recommend rewrite the data" }, + { 0x11, 0x0d, "de-compression crc error" }, + { 0x11, 0x0e, "cannot decompress using declared algorithm" }, + { 0x11, 0x0f, "error reading UPC/EAN number" }, + { 0x11, 0x10, "error reading ISRC number" }, + { 0x11, 0x11, "read error - loss of streaming" }, + { 0x11, 0x12, "auxiliary memory read error" }, + { 0x11, 0x13, "read error - failed retransmission request" }, + { 0x12, 0x00, "address mark not found for ID field" }, + { 0x13, 0x00, "address mark not found for data field" }, + { 0x14, 0x00, "recorded entity not found" }, + { 0x14, 0x01, "record not found" }, + { 0x14, 0x02, "filemark or setmark not found" }, + { 0x14, 0x03, "end-of-data not found" }, + { 0x14, 0x04, "block sequence error" }, + { 0x14, 0x05, "record not found - recommend reassignment" }, + { 0x14, 0x06, "record not found - data auto-reallocated" }, + { 0x14, 0x07, "locate operation failure" }, + { 0x15, 0x00, "random positioning error" }, + { 0x15, 0x01, "mechanical positioning error" }, + { 0x15, 0x02, "positioning error detected by read of medium" }, + { 0x16, 0x00, "data sync mark error" }, + { 0x16, 0x01, "data sync error - data rewritten" }, + { 0x16, 0x02, "data sync error - recommend rewrite" }, + { 0x16, 0x03, "data sync error - data auto-reallocated" }, + { 0x16, 0x04, "data sync error - recommend reassignment" }, + { 0x17, 0x00, "recovered data with no error correction" }, + { 0x17, 0x01, "recovered data with retries" }, + { 0x17, 0x02, "recovered data with positive head offset" }, + { 0x17, 0x03, "recovered data with negative head offset" }, + { 0x17, 0x04, "recovered data with retries and/or CIRC applied" }, + { 0x17, 0x05, "recovered data using previous sector id" }, + { 0x17, 0x06, "recovered data without ECC - data auto-reallocated" }, + { 0x17, 0x07, "recovered data without ECC - recommend reassignment" }, + { 0x17, 0x08, "recovered data without ECC - recommend rewrite" }, + { 0x17, 0x09, "recovered data without ECC - data rewritten" }, + { 0x18, 0x00, "recovered data with error correction" }, + { 0x18, 0x01, "recovered data with error corr. & retries applied" }, + { 0x18, 0x02, "recovered data - data auto-reallocated" }, + { 0x18, 0x03, "recovered data with CIRC" }, + { 0x18, 0x04, "recovered data with L-EC" }, + { 0x18, 0x05, "recovered data - recommend reassignment" }, + { 0x18, 0x06, "recovered data - recommend rewrite" }, + { 0x18, 0x07, "recovered data with ECC - data rewritten" }, + { 0x18, 0x08, "recovered data with linking" }, + { 0x19, 0x00, "defect list error" }, + { 0x1a, 0x00, "parameter list length error" }, + { 0x1b, 0x00, "synchronous data xfer error" }, + { 0x1c, 0x00, "defect list not found" }, + { 0x1c, 0x01, "primary defect list not found" }, + { 0x1c, 0x02, "grown defect list not found" }, + { 0x1d, 0x00, "miscompare during verify" }, + { 0x1e, 0x00, "recovered ID with ECC" }, + { 0x1f, 0x00, "partial defect list transfer" }, + { 0x20, 0x00, "invalid command operation code" }, + { 0x20, 0x01, "access denied - initiator pending-enrolled" }, + { 0x20, 0x02, "access denied - no access rights" }, + { 0x20, 0x03, "access denied - invalid mgmt id key" }, + { 0x20, 0x04, "illegal command while in write capable state" }, + { 0x20, 0x06, "illegal command while in explicit address mode" }, + { 0x20, 0x07, "illegal command while in implicit address mode" }, + { 0x20, 0x08, "access denied - enrollment conflict" }, + { 0x20, 0x09, "access denied - invalid lu identifier" }, + { 0x20, 0x0a, "access denied - invalid proxy token" }, + { 0x20, 0x0b, "access denied - ACL LUN conflict" }, + { 0x21, 0x00, "logical block address out of range" }, + { 0x21, 0x01, "invalid element address" }, + { 0x21, 0x02, "invalid address for write" }, + { 0x22, 0x00, "illegal function" }, + { 0x24, 0x00, "invalid field in cdb" }, + { 0x24, 0x01, "cdb decryption error" }, + { 0x25, 0x00, "LUN not supported" }, + { 0x26, 0x00, "invalid field in param list" }, + { 0x26, 0x01, "parameter not supported" }, + { 0x26, 0x02, "parameter value invalid" }, + { 0x26, 0x03, "threshold parameters not supported" }, + { 0x26, 0x04, "invalid release of persistent reservation" }, + { 0x26, 0x05, "data decryption error" }, + { 0x26, 0x06, "too many target descriptors" }, + { 0x26, 0x07, "unsupported target descriptor type code" }, + { 0x26, 0x08, "too many segment descriptors" }, + { 0x26, 0x09, "unsupported segment descriptor type code" }, + { 0x26, 0x0a, "unexpected inexact segment" }, + { 0x26, 0x0b, "inline data length exceeded" }, + { 0x26, 0x0c, "invalid operation for copy source or destination" }, + { 0x26, 0x0d, "copy segment granularity violation" }, + { 0x27, 0x00, "write protected" }, + { 0x27, 0x01, "hardware write protected" }, + { 0x27, 0x02, "LUN software write protected" }, + { 0x27, 0x03, "associated write protect" }, + { 0x27, 0x04, "persistent write protect" }, + { 0x27, 0x05, "permanent write protect" }, + { 0x27, 0x06, "conditional write protect" }, + { 0x28, 0x00, "medium may have changed" }, + { 0x28, 0x01, "import or export element accessed" }, + { 0x29, 0x00, "power on, reset, or bus reset occurred" }, + { 0x29, 0x01, "power on occurred" }, + { 0x29, 0x02, "scsi bus reset occurred" }, + { 0x29, 0x03, "bus device reset message occurred" }, + { 0x29, 0x04, "device internal reset" }, + { 0x29, 0x05, "transceiver mode changed to single-ended" }, + { 0x29, 0x06, "transceiver mode changed to LVD" }, + { 0x29, 0x07, "i_t nexus loss occurred" }, + { 0x2a, 0x00, "parameters changed" }, + { 0x2a, 0x01, "mode parameters changed" }, + { 0x2a, 0x02, "log parameters changed" }, + { 0x2a, 0x03, "reservations preempted" }, + { 0x2a, 0x04, "reservations released" }, + { 0x2a, 0x05, "registrations preempted" }, + { 0x2a, 0x06, "asymmetric access state changed" }, + { 0x2a, 0x07, "implicit asymmetric access state transition failed" }, + { 0x2b, 0x00, "copy cannot execute since host cannot disconnect" }, + { 0x2c, 0x00, "command sequence error" }, + { 0x2c, 0x03, "current program area is not empty" }, + { 0x2c, 0x04, "current program area is empty" }, + { 0x2c, 0x06, "persistent prevent conflict" }, + { 0x2c, 0x07, "previous busy status" }, + { 0x2c, 0x08, "previous task set full status" }, + { 0x2c, 0x09, "previous reservation conflict status" }, + { 0x2d, 0x00, "overwrite error on update in place" }, + { 0x2e, 0x00, "insufficient time for operation" }, + { 0x2f, 0x00, "commands cleared by another initiator" }, + { 0x30, 0x00, "incompatible medium installed" }, + { 0x30, 0x01, "cannot read medium - unknown format" }, + { 0x30, 0x02, "cannot read medium - incompatible format" }, + { 0x30, 0x03, "cleaning cartridge installed" }, + { 0x30, 0x04, "cannot write medium - unknown format" }, + { 0x30, 0x05, "cannot write medium - incompatible format" }, + { 0x30, 0x06, "cannot format medium - incompatible medium" }, + { 0x30, 0x07, "cleaning failure" }, + { 0x30, 0x08, "cannot write - application code mismatch" }, + { 0x30, 0x09, "current session not fixated for append" }, + { 0x30, 0x10, "medium not formatted" }, + { 0x31, 0x00, "medium format corrupted" }, + { 0x31, 0x01, "format command failed" }, + { 0x31, 0x02, "zoned formatting failed due to spare linking" }, + { 0x32, 0x00, "no defect spare location available" }, + { 0x32, 0x01, "defect list update failure" }, + { 0x33, 0x00, "tape length error" }, + { 0x34, 0x00, "enclosure failure" }, + { 0x35, 0x00, "enclosure services failure" }, + { 0x35, 0x01, "unsupported enclosure function" }, + { 0x35, 0x02, "enclosure services unavailable" }, + { 0x35, 0x03, "enclosure services transfer failure" }, + { 0x35, 0x04, "enclosure services transfer refused" }, + { 0x36, 0x00, "ribbon, ink, or toner failure" }, + { 0x37, 0x00, "rounded parameter" }, + { 0x39, 0x00, "saving parameters not supported" }, + { 0x3a, 0x00, "medium not present" }, + { 0x3a, 0x01, "medium not present - tray closed" }, + { 0x3a, 0x02, "medium not present - tray open" }, + { 0x3a, 0x03, "medium not present - loadable" }, + { 0x3a, 0x04, "medium not present - medium auxiliary memory " + "accessible" }, + { 0x3b, 0x00, "sequential positioning error" }, + { 0x3b, 0x01, "tape position error at beginning-of-medium" }, + { 0x3b, 0x02, "tape position error at end-of-medium" }, + { 0x3b, 0x08, "reposition error" }, + { 0x3b, 0x0c, "position past beginning of medium" }, + { 0x3b, 0x0d, "medium destination element full" }, + { 0x3b, 0x0e, "medium source element empty" }, + { 0x3b, 0x0f, "end of medium reached" }, + { 0x3b, 0x11, "medium magazine not accessible" }, + { 0x3b, 0x12, "medium magazine removed" }, + { 0x3b, 0x13, "medium magazine inserted" }, + { 0x3b, 0x14, "medium magazine locked" }, + { 0x3b, 0x15, "medium magazine unlocked" }, + { 0x3b, 0x16, "mechanical positioning or changer error" }, + { 0x3d, 0x00, "invalid bits in indentify message" }, + { 0x3e, 0x00, "LUN has not self-configured yet" }, + { 0x3e, 0x01, "LUN failure" }, + { 0x3e, 0x02, "timeout on LUN" }, + { 0x3e, 0x03, "LUN failed self-test" }, + { 0x3e, 0x04, "LUN unable to update self-test log" }, + { 0x3f, 0x00, "target operating conditions have changed" }, + { 0x3f, 0x01, "microcode has been changed" }, + { 0x3f, 0x02, "changed operating definition" }, + { 0x3f, 0x03, "inquiry data has changed" }, + { 0x3f, 0x04, "component device attached" }, + { 0x3f, 0x05, "device identifier changed" }, + { 0x3f, 0x06, "redundancy group created or modified" }, + { 0x3f, 0x07, "redundancy group deleted" }, + { 0x3f, 0x08, "spare created or modified" }, + { 0x3f, 0x09, "spare deleted" }, + { 0x3f, 0x0a, "volume set created or modified" }, + { 0x3f, 0x0b, "volume set deleted" }, + { 0x3f, 0x0c, "volume set deassigned" }, + { 0x3f, 0x0d, "volume set reassigned" }, + { 0x3f, 0x0e, "reported LUNs data has changed" }, + { 0x3f, 0x0f, "echo buffer overwritten" }, + { 0x3f, 0x10, "medium loadable" }, + { 0x3f, 0x11, "medium auxiliary memory accessible" }, + { 0x40, 0x00, "ram failure" }, + { 0x41, 0x00, "data path failure" }, + { 0x42, 0x00, "power-on or self-test failure" }, + { 0x43, 0x00, "message error" }, + { 0x44, 0x00, "internal target failure" }, + { 0x45, 0x00, "select or reselect failure" }, + { 0x46, 0x00, "unsuccessful soft reset" }, + { 0x47, 0x00, "scsi parity error" }, + { 0x47, 0x01, "data phase crc error detected" }, + { 0x47, 0x02, "scsi parity error detected during st data phase" }, + { 0x47, 0x03, "information unit iucrc error detected" }, + { 0x47, 0x04, "asynchronous information protection error detected" }, + { 0x47, 0x05, "protocol service crc error" }, + { 0x47, 0x7f, "some commands cleared by iscsi protocol event" }, + { 0x48, 0x00, "initiator detected error message received" }, + { 0x49, 0x00, "invalid message error" }, + { 0x4a, 0x00, "command phase error" }, + { 0x4b, 0x00, "data phase error" }, + { 0x4b, 0x01, "invalid target port transfer tag received" }, + { 0x4b, 0x02, "too much write data" }, + { 0x4b, 0x03, "ack/nak timeout" }, + { 0x4b, 0x04, "nak received" }, + { 0x4b, 0x05, "data offset error" }, + { 0x4c, 0x00, "logical unit failed self-configuration" }, + { 0x4d, 0x00, "tagged overlapped commands (ASCQ = queue tag)" }, + { 0x4e, 0x00, "overlapped commands attempted" }, + { 0x50, 0x00, "write append error" }, + { 0x51, 0x00, "erase failure" }, + { 0x52, 0x00, "cartridge fault" }, + { 0x53, 0x00, "media load or eject failed" }, + { 0x53, 0x01, "unload tape failure" }, + { 0x53, 0x02, "medium removal prevented" }, + { 0x54, 0x00, "scsi to host system interface failure" }, + { 0x55, 0x00, "system resource failure" }, + { 0x55, 0x01, "system buffer full" }, + { 0x55, 0x02, "insufficient reservation resources" }, + { 0x55, 0x03, "insufficient resources" }, + { 0x55, 0x04, "insufficient registration resources" }, + { 0x55, 0x05, "insufficient access control resources" }, + { 0x55, 0x06, "auxiliary memory out of space" }, + { 0x57, 0x00, "unable to recover TOC" }, + { 0x58, 0x00, "generation does not exist" }, + { 0x59, 0x00, "updated block read" }, + { 0x5a, 0x00, "operator request or state change input" }, + { 0x5a, 0x01, "operator medium removal request" }, + { 0x5a, 0x02, "operator selected write protect" }, + { 0x5a, 0x03, "operator selected write permit" }, + { 0x5b, 0x00, "log exception" }, + { 0x5b, 0x01, "threshold condition met" }, + { 0x5b, 0x02, "log counter at maximum" }, + { 0x5b, 0x03, "log list codes exhausted" }, + { 0x5c, 0x00, "RPL status change" }, + { 0x5c, 0x01, "spindles synchronized" }, + { 0x5c, 0x02, "spindles not synchronized" }, + { 0x5d, 0x00, "drive operation marginal, service immediately" + " (failure prediction threshold exceeded)" }, + { 0x5d, 0x01, "media failure prediction threshold exceeded" }, + { 0x5d, 0x02, "LUN failure prediction threshold exceeded" }, + { 0x5d, 0x03, "spare area exhaustion prediction threshold exceeded" }, + { 0x5d, 0x10, "hardware impending failure general hard drive failure" }, + { 0x5d, 0x11, "hardware impending failure drive error rate too high" }, + { 0x5d, 0x12, "hardware impending failure data error rate too high" }, + { 0x5d, 0x13, "hardware impending failure seek error rate too high" }, + { 0x5d, 0x14, "hardware impending failure too many block reassigns" }, + { 0x5d, 0x15, "hardware impending failure access times too high" }, + { 0x5d, 0x16, "hardware impending failure start unit times too high" }, + { 0x5d, 0x17, "hardware impending failure channel parametrics" }, + { 0x5d, 0x18, "hardware impending failure controller detected" }, + { 0x5d, 0x19, "hardware impending failure throughput performance" }, + { 0x5d, 0x1a, "hardware impending failure seek time performance" }, + { 0x5d, 0x1b, "hardware impending failure spin-up retry count" }, + { 0x5d, 0x1c, "hardware impending failure drive calibration retry " + "count" }, + { 0x5d, 0x20, "controller impending failure general hard drive " + "failure" }, + { 0x5d, 0x21, "controller impending failure drive error rate too " + "high" }, + { 0x5d, 0x22, "controller impending failure data error rate too high" }, + { 0x5d, 0x23, "controller impending failure seek error rate too high" }, + { 0x5d, 0x24, "controller impending failure too many block reassigns" }, + { 0x5d, 0x25, "controller impending failure access times too high" }, + { 0x5d, 0x26, "controller impending failure start unit times too " + "high" }, + { 0x5d, 0x27, "controller impending failure channel parametrics" }, + { 0x5d, 0x28, "controller impending failure controller detected" }, + { 0x5d, 0x29, "controller impending failure throughput performance" }, + { 0x5d, 0x2a, "controller impending failure seek time performance" }, + { 0x5d, 0x2b, "controller impending failure spin-up retry count" }, + { 0x5d, 0x2c, "controller impending failure drive calibration retry " + "cnt" }, + { 0x5d, 0x30, "data channel impending failure general hard drive " + "failure" }, + { 0x5d, 0x31, "data channel impending failure drive error rate too " + "high" }, + { 0x5d, 0x32, "data channel impending failure data error rate too " + "high" }, + { 0x5d, 0x33, "data channel impending failure seek error rate too " + "high" }, + { 0x5d, 0x34, "data channel impending failure too many block " + "reassigns" }, + { 0x5d, 0x35, "data channel impending failure access times too high" }, + { 0x5d, 0x36, "data channel impending failure start unit times too " + "high" }, + { 0x5d, 0x37, "data channel impending failure channel parametrics" }, + { 0x5d, 0x38, "data channel impending failure controller detected" }, + { 0x5d, 0x39, "data channel impending failure throughput performance" }, + { 0x5d, 0x3a, "data channel impending failure seek time performance" }, + { 0x5d, 0x3b, "data channel impending failure spin-up retry count" }, + { 0x5d, 0x3c, "data channel impending failure drive calibrate retry " + "cnt" }, + { 0x5d, 0x40, "servo impending failure general hard drive failure" }, + { 0x5d, 0x41, "servo impending failure drive error rate too high" }, + { 0x5d, 0x42, "servo impending failure data error rate too high" }, + { 0x5d, 0x43, "servo impending failure seek error rate too high" }, + { 0x5d, 0x44, "servo impending failure too many block reassigns" }, + { 0x5d, 0x45, "servo impending failure access times too high" }, + { 0x5d, 0x46, "servo impending failure start unit times too high" }, + { 0x5d, 0x47, "servo impending failure channel parametrics" }, + { 0x5d, 0x48, "servo impending failure controller detected" }, + { 0x5d, 0x49, "servo impending failure throughput performance" }, + { 0x5d, 0x4a, "servo impending failure seek time performance" }, + { 0x5d, 0x4b, "servo impending failure spin-up retry count" }, + { 0x5d, 0x4c, "servo impending failure drive calibration retry count" }, + { 0x5d, 0x50, "spindle impending failure general hard drive failure" }, + { 0x5d, 0x51, "spindle impending failure drive error rate too high" }, + { 0x5d, 0x52, "spindle impending failure data error rate too high" }, + { 0x5d, 0x53, "spindle impending failure seek error rate too high" }, + { 0x5d, 0x54, "spindle impending failure too many block reassigns" }, + { 0x5d, 0x55, "spindle impending failure access times too high" }, + { 0x5d, 0x56, "spindle impending failure start unit times too high" }, + { 0x5d, 0x57, "spindle impending failure channel parametrics" }, + { 0x5d, 0x58, "spindle impending failure controller detected" }, + { 0x5d, 0x59, "spindle impending failure throughput performance" }, + { 0x5d, 0x5a, "spindle impending failure seek time performance" }, + { 0x5d, 0x5b, "spindle impending failure spin-up retry count" }, + { 0x5d, 0x5c, "spindle impending failure drive calibration retry " + "count" }, + { 0x5d, 0x60, "firmware impending failure general hard drive failure" }, + { 0x5d, 0x61, "firmware impending failure drive error rate too high" }, + { 0x5d, 0x62, "firmware impending failure data error rate too high" }, + { 0x5d, 0x63, "firmware impending failure seek error rate too high" }, + { 0x5d, 0x64, "firmware impending failure too many block reassigns" }, + { 0x5d, 0x65, "firmware impending failure access times too high" }, + { 0x5d, 0x66, "firmware impending failure start unit times too high" }, + { 0x5d, 0x67, "firmware impending failure channel parametrics" }, + { 0x5d, 0x68, "firmware impending failure controller detected" }, + { 0x5d, 0x69, "firmware impending failure throughput performance" }, + { 0x5d, 0x6a, "firmware impending failure seek time performance" }, + { 0x5d, 0x6b, "firmware impending failure spin-up retry count" }, + { 0x5d, 0x6c, "firmware impending failure drive calibration retry " + "count" }, + { 0x5d, 0xff, "failure prediction threshold exceeded (false)" }, + { 0x5e, 0x00, "low power condition active" }, + { 0x5e, 0x01, "idle condition activated by timer" }, + { 0x5e, 0x02, "standby condition activated by timer" }, + { 0x5e, 0x03, "idle condition activated by command" }, + { 0x5e, 0x04, "standby condition activated by command" }, + { 0x60, 0x00, "lamp failure" }, + { 0x61, 0x00, "video aquisition error" }, + { 0x62, 0x00, "scan head positioning error" }, + { 0x63, 0x00, "end of user area encountered on this track" }, + { 0x63, 0x01, "packet does not fit in available space" }, + { 0x64, 0x00, "illegal mode for this track" }, + { 0x64, 0x01, "invalid packet size" }, + { 0x65, 0x00, "voltage fault" }, + { 0x66, 0x00, "automatic document feeder cover up" }, + { 0x67, 0x00, "configuration failure" }, + { 0x67, 0x01, "configuration of incapable LUNs failed" }, + { 0x67, 0x02, "add LUN failed" }, + { 0x67, 0x03, "modification of LUN failed" }, + { 0x67, 0x04, "exchange of LUN failed" }, + { 0x67, 0x05, "remove of LUN failed" }, + { 0x67, 0x06, "attachment of LUN failed" }, + { 0x67, 0x07, "creation of LUN failed" }, + { 0x67, 0x08, "assign failure occurred" }, + { 0x67, 0x09, "multiply assigned LUN" }, + { 0x67, 0x0a, "set target port groups command failed" }, + { 0x68, 0x00, "logical unit not configured" }, + { 0x69, 0x00, "data loss on logical unit" }, + { 0x69, 0x01, "multiple LUN failures" }, + { 0x69, 0x02, "parity/data mismatch" }, + { 0x6a, 0x00, "informational, refer to log" }, + { 0x6b, 0x00, "state change has occured" }, + { 0x6b, 0x01, "redundancy level got better" }, + { 0x6b, 0x02, "redundancy level got worse" }, + { 0x6c, 0x00, "rebuild failure occured" }, + { 0x6d, 0x00, "recalculate failure occured" }, + { 0x6e, 0x00, "command to logical unit failed" }, + { 0x6f, 0x00, "copy protect key exchange failure authentication " + "failure" }, + { 0x6f, 0x01, "copy protect key exchange failure key not present" }, + { 0x6f, 0x02, "copy protect key exchange failure key not established" }, + { 0x6f, 0x03, "read of scrambled sector without authentication" }, + { 0x6f, 0x04, "media region code is mismatched to LUN region" }, + { 0x6f, 0x05, "drive region must be permanent/region reset count " + "error" }, + { 0x70, 0xffff, "decompression exception short algorithm id of ASCQ" }, + { 0x71, 0x00, "decompression exception long algorithm id" }, + { 0x72, 0x00, "session fixation error" }, + { 0x72, 0x01, "session fixation error writing lead-in" }, + { 0x72, 0x02, "session fixation error writing lead-out" }, + { 0x72, 0x03, "session fixation error - incomplete track in session" }, + { 0x72, 0x04, "empty or partially written reserved track" }, + { 0x72, 0x05, "no more track reservations allowed" }, + { 0x73, 0x00, "cd control error" }, + { 0x73, 0x01, "power calibration area almost full" }, + { 0x73, 0x02, "power calibration area is full" }, + { 0x73, 0x03, "power calibration area error" }, + { 0x73, 0x04, "program memory area update failure" }, + { 0x73, 0x05, "program memory area is full" }, + { 0x73, 0x06, "rma/pma is almost full" }, + { 0xffff, 0xffff, NULL } +}; + +static const char * +find_string(slist_t *slist, int match_value) +{ + for (; slist->str != NULL; slist++) { + if (slist->value == match_value) { + return (slist->str); + } + } + + return (NULL); +} + +const char * +libscsi_sense_key_name(uint64_t key) +{ + return (find_string(sensekey_strings, (int)key)); +} + +/* + * Given an asc (Additional Sense Code) and ascq (Additional Sense Code + * Qualifier), return a string describing the error information. + */ +const char * +libscsi_sense_code_name(uint64_t asc, uint64_t ascq) +{ + int i = 0; + + while (extended_sense_list[i].asc != 0xffff) { + if ((asc == extended_sense_list[i].asc) && + ((ascq == extended_sense_list[i].ascq) || + (extended_sense_list[i].ascq == 0xffff))) { + return ((char *)extended_sense_list[i].message); + } + i++; + } + + return (NULL); +} + +/* + * Retrieve "information" field from descriptor format sense data. Iterates + * through each sense descriptor looking for the information descriptor and + * returns the information field from that descriptor. + */ +static diskaddr_t +scsi_extract_sense_info_descr(struct scsi_descr_sense_hdr *sdsp, size_t len) +{ + diskaddr_t result; + uint8_t *descr_offset; + size_t valid_sense_length; + struct scsi_information_sense_descr *isd; + + /* + * Initialize result to -1 indicating there is no information + * descriptor + */ + result = (diskaddr_t)-1; + + /* + * The first descriptor will immediately follow the header + */ + descr_offset = (uint8_t *)(sdsp+1); + + /* + * Calculate the amount of valid sense data + */ + valid_sense_length = + MIN((sizeof (struct scsi_descr_sense_hdr) + + sdsp->ds_addl_sense_length), len); + + /* + * Iterate through the list of descriptors, stopping when we run out of + * sense data + */ + while ((descr_offset + sizeof (struct scsi_information_sense_descr)) <= + (uint8_t *)sdsp + valid_sense_length) { + /* + * Check if this is an information descriptor. We can use the + * scsi_information_sense_descr structure as a template since + * the first two fields are always the same + */ + isd = (struct scsi_information_sense_descr *)descr_offset; + if (isd->isd_descr_type == DESCR_INFORMATION) { + /* + * Found an information descriptor. Copy the + * information field. There will only be one + * information descriptor so we can stop looking. + */ + result = + (((diskaddr_t)isd->isd_information[0] << 56) | + ((diskaddr_t)isd->isd_information[1] << 48) | + ((diskaddr_t)isd->isd_information[2] << 40) | + ((diskaddr_t)isd->isd_information[3] << 32) | + ((diskaddr_t)isd->isd_information[4] << 24) | + ((diskaddr_t)isd->isd_information[5] << 16) | + ((diskaddr_t)isd->isd_information[6] << 8) | + ((diskaddr_t)isd->isd_information[7])); + break; + } + + /* + * Get pointer to the next descriptor. The "additional length" + * field holds the length of the descriptor except for the + * "type" and "additional length" fields, so we need to add 2 to + * get the total length. + */ + descr_offset += (isd->isd_addl_length + 2); + } + + return (result); +} + +int +libscsi_action_parse_sense(const libscsi_action_t *ap, uint64_t *keyp, + uint64_t *ascp, uint64_t *ascqp, diskaddr_t *blkp) +{ + struct scsi_extended_sense *xsp; + struct scsi_descr_sense_hdr *sdsp; + size_t len; + + if (libscsi_action_get_sense(ap, (uint8_t **)&xsp, NULL, &len) != 0) + return (-1); + + sdsp = (struct scsi_descr_sense_hdr *)xsp; + + if (keyp != NULL) + *keyp = (uint64_t)xsp->es_key; + + switch (xsp->es_code) { + case CODE_FMT_DESCR_CURRENT: + case CODE_FMT_DESCR_DEFERRED: + if (blkp != NULL) + *blkp = (diskaddr_t) + scsi_extract_sense_info_descr(sdsp, len); + if (ascp != NULL) + *ascp = (uint64_t)sdsp->ds_add_code; + if (ascqp != NULL) + *ascqp = (uint64_t)sdsp->ds_qual_code; + break; + case CODE_FMT_FIXED_CURRENT: + case CODE_FMT_FIXED_DEFERRED: + default: + if (xsp->es_valid && blkp != NULL) + *blkp = (diskaddr_t) + ((xsp->es_info_1 << 24) | (xsp->es_info_2 << 16) | + (xsp->es_info_3 << 8) | xsp->es_info_4); + if (xsp->es_add_len >= 6) { + if (ascp != NULL) + *ascp = (uint64_t)xsp->es_add_code; + if (ascqp != NULL) + *ascqp = (uint64_t)xsp->es_qual_code; + } + break; + } + + return (0); +} diff --git a/usr/src/lib/scsi/libscsi/common/scsi_subr.c b/usr/src/lib/scsi/libscsi/common/scsi_subr.c new file mode 100644 index 0000000000..fb9a4eb650 --- /dev/null +++ b/usr/src/lib/scsi/libscsi/common/scsi_subr.c @@ -0,0 +1,351 @@ +/* + * 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/scsi/generic/commands.h> +#include <sys/scsi/impl/spc3_types.h> + +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <alloca.h> +#include <stdio.h> +#include <unistd.h> +#include <dlfcn.h> + +#include <scsi/libscsi.h> +#include "libscsi_impl.h" + +int +libscsi_assert(const char *expr, const char *file, int line) +{ + char *msg; + size_t len; + + len = snprintf(NULL, 0, + "ABORT: \"%s\", line %d: assertion failed: %s\n", file, line, expr); + + msg = alloca(len + 1); + + (void) snprintf(msg, len + 1, + "ABORT: \"%s\", line %d: assertion failed: %s\n", file, line, expr); + + (void) write(STDERR_FILENO, msg, strlen(msg)); + + abort(); + _exit(1); + + /*NOTREACHED*/ + return (0); +} + +int +libscsi_set_errno(libscsi_hdl_t *hp, libscsi_errno_t err) +{ + hp->lsh_errno = err; + hp->lsh_errmsg[0] = '\0'; + + return (-1); +} + +/* + * Internal routine for setting both _ue_errno and _ue_errmsg. We save + * and restore the UNIX errno across this routing so the caller can use either + * libscsi_set_errno(), libscsi_error(), or libscsi_verror() without this value + * changing. + */ +int +libscsi_verror(libscsi_hdl_t *hp, libscsi_errno_t err, const char *fmt, + va_list ap) +{ + size_t n; + char *errmsg; + + /* + * To allow the existing error message to itself be used in an error + * message, we put the new error message into a buffer on the stack, + * and then copy it into lsh_errmsg. We also need to set the errno, + * but because the call to libscsi_set_errno() is destructive to + * lsh_errmsg, we do this after we print into our temporary buffer + * (in case _libscsi_errmsg is part of the error message) and before we + * copy the temporary buffer on to _libscsi_errmsg (to prevent our new + * message from being nuked by the call to libscsi_set_errno()). + */ + errmsg = alloca(sizeof (hp->lsh_errmsg)); + (void) vsnprintf(errmsg, sizeof (hp->lsh_errmsg), fmt, ap); + (void) libscsi_set_errno(hp, err); + + n = strlen(errmsg); + + if (n != 0 && errmsg[n - 1] == '\n') + errmsg[n - 1] = '\0'; + + bcopy(errmsg, hp->lsh_errmsg, n + 1); + + return (-1); +} + +/*PRINTFLIKE3*/ +int +libscsi_error(libscsi_hdl_t *hp, libscsi_errno_t err, const char *fmt, ...) +{ + va_list ap; + + if (fmt == NULL) + return (libscsi_set_errno(hp, err)); + + va_start(ap, fmt); + err = libscsi_verror(hp, err, fmt, ap); + va_end(ap); + + return (err); +} + +libscsi_errno_t +libscsi_errno(libscsi_hdl_t *hp) +{ + return (hp->lsh_errno); +} + +const char * +libscsi_errmsg(libscsi_hdl_t *hp) +{ + if (hp->lsh_errmsg[0] == '\0') + (void) strlcpy(hp->lsh_errmsg, libscsi_strerror(hp->lsh_errno), + sizeof (hp->lsh_errmsg)); + + return (hp->lsh_errmsg); +} + +void * +libscsi_alloc(libscsi_hdl_t *hp, size_t size) +{ + void *mem; + + if (size == 0) { + (void) libscsi_set_errno(hp, ESCSI_ZERO_LENGTH); + return (NULL); + } + + if ((mem = malloc(size)) == NULL) + (void) libscsi_set_errno(hp, ESCSI_NOMEM); + + return (mem); +} + +void * +libscsi_zalloc(libscsi_hdl_t *hp, size_t size) +{ + void *mem; + + if ((mem = libscsi_alloc(hp, size)) == NULL) + return (NULL); + + bzero(mem, size); + + return (mem); +} + +char * +libscsi_strdup(libscsi_hdl_t *hp, const char *str) +{ + size_t len = strlen(str); + char *dup = libscsi_alloc(hp, len + 1); + + if (dup == NULL) + return (NULL); + + return (strcpy(dup, str)); +} + +/*ARGSUSED*/ +void +libscsi_free(libscsi_hdl_t *hp, void *ptr) +{ + free(ptr); +} + +libscsi_hdl_t * +libscsi_init(uint_t version, libscsi_errno_t *errp) +{ + libscsi_hdl_t *hp; + + if ((hp = malloc(sizeof (libscsi_hdl_t))) == NULL) { + if (errp != NULL) + *errp = ESCSI_NOMEM; + return (NULL); + } + + bzero(hp, sizeof (libscsi_hdl_t)); + hp->lsh_version = version; + + return (hp); +} + +void +libscsi_fini(libscsi_hdl_t *hp) +{ + libscsi_engine_impl_t *eip, *neip; + + if (hp == NULL) + return; + + ASSERT(hp->lsh_targets == 0); + + for (eip = hp->lsh_engines; eip != NULL; eip = neip) { + neip = eip->lsei_next; + (void) dlclose(eip->lsei_dl_hdl); + libscsi_free(hp, eip); + } + + free(hp); +} + +size_t +libscsi_cmd_cdblen(libscsi_hdl_t *hp, uint8_t cmd) +{ + size_t sz; + + switch (CDB_GROUPID(cmd)) { + case CDB_GROUPID_0: + sz = CDB_GROUP0; + break; + case CDB_GROUPID_1: + sz = CDB_GROUP1; + break; + case CDB_GROUPID_2: + sz = CDB_GROUP2; + break; + case CDB_GROUPID_3: + sz = CDB_GROUP3; + break; + case CDB_GROUPID_4: + sz = CDB_GROUP4; + break; + case CDB_GROUPID_5: + sz = CDB_GROUP5; + break; + case CDB_GROUPID_6: + sz = CDB_GROUP6; + break; + case CDB_GROUPID_7: + sz = CDB_GROUP7; + break; + default: + sz = 0; + } + + if (sz == 0) + (void) libscsi_error(hp, ESCSI_BADCMD, + "unknown or unsupported command %u", cmd); + + return (sz); +} + +static char * +libscsi_process_inquiry_string(libscsi_hdl_t *hp, const char *raw, size_t len) +{ + char *buf; + + buf = alloca(len + 1); + bcopy(raw, buf, len); + + for (; len > 0; len--) { + if (buf[len - 1] != ' ') + break; + } + + buf[len] = '\0'; + + return (libscsi_strdup(hp, buf)); +} + +/* + * As part of basic initialization, we always retrieve the INQUIRY information + * to have the vendor/product/revision information available for all consumers. + */ +int +libscsi_get_inquiry(libscsi_hdl_t *hp, libscsi_target_t *tp) +{ + libscsi_action_t *ap; + spc3_inquiry_cdb_t *cp; + spc3_inquiry_data_t data; + size_t len; + + if ((ap = libscsi_action_alloc(hp, SPC3_CMD_INQUIRY, + LIBSCSI_AF_READ | LIBSCSI_AF_SILENT | LIBSCSI_AF_DIAGNOSE, &data, + sizeof (data))) == NULL) + return (-1); + + cp = (spc3_inquiry_cdb_t *)libscsi_action_get_cdb(ap); + + SCSI_WRITE16(&cp->ic_allocation_length, sizeof (data)); + + if (libscsi_exec(ap, tp) != 0 || + libscsi_action_get_status(ap) != 0) { + libscsi_action_free(ap); + return (libscsi_set_errno(hp, ESCSI_INQUIRY_FAILED)); + } + + (void) libscsi_action_get_buffer(ap, NULL, NULL, &len); + libscsi_action_free(ap); + + if (len < offsetof(spc3_inquiry_data_t, id_vs_36)) + return (libscsi_set_errno(hp, ESCSI_INQUIRY_FAILED)); + + if ((tp->lst_vendor = libscsi_process_inquiry_string(hp, + data.id_vendor_id, sizeof (data.id_vendor_id))) == NULL || + (tp->lst_product = libscsi_process_inquiry_string(hp, + data.id_product_id, sizeof (data.id_product_id))) == NULL || + (tp->lst_revision = libscsi_process_inquiry_string(hp, + data.id_product_revision, + sizeof (data.id_product_revision))) == NULL) { + return (-1); + } + + return (0); +} + +const char * +libscsi_vendor(libscsi_target_t *tp) +{ + return (tp->lst_vendor); +} + +const char * +libscsi_product(libscsi_target_t *tp) +{ + return (tp->lst_product); +} + +const char * +libscsi_revision(libscsi_target_t *tp) +{ + return (tp->lst_revision); +} diff --git a/usr/src/lib/scsi/libscsi/i386/Makefile b/usr/src/lib/scsi/libscsi/i386/Makefile new file mode 100644 index 0000000000..b68583c86f --- /dev/null +++ b/usr/src/lib/scsi/libscsi/i386/Makefile @@ -0,0 +1,30 @@ +# +# 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" + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) diff --git a/usr/src/lib/scsi/libscsi/libscsi_api.map b/usr/src/lib/scsi/libscsi/libscsi_api.map new file mode 100644 index 0000000000..8fbb5ef1ca --- /dev/null +++ b/usr/src/lib/scsi/libscsi/libscsi_api.map @@ -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" + +{ + libscsi_strerror = FUNCTION extern; + libscsi_errname = FUNCTION extern; + libscsi_errcode = FUNCTION extern; + libscsi_alloc = FUNCTION extern; + libscsi_zalloc = FUNCTION extern; + libscsi_strdup = FUNCTION extern; + libscsi_free = FUNCTION extern; + libscsi_set_errno = FUNCTION extern; + libscsi_verror = FUNCTION extern; + libscsi_error = FUNCTION extern; + libscsi_cmd_cdblen = FUNCTION extern; + libscsi_action_get_timeout = FUNCTION extern; + libscsi_action_get_flags = FUNCTION extern; + libscsi_action_get_cdb = FUNCTION extern; + libscsi_action_get_buffer = FUNCTION extern; + libscsi_action_get_sense = FUNCTION extern; + libscsi_action_set_status = FUNCTION extern; + libscsi_action_set_datalen = FUNCTION extern; + libscsi_action_set_senselen = FUNCTION extern; + libscsi_assert = FUNCTION extern; +}; diff --git a/usr/src/lib/scsi/libscsi/llib-lscsi b/usr/src/lib/scsi/libscsi/llib-lscsi new file mode 100644 index 0000000000..2c7111c8d1 --- /dev/null +++ b/usr/src/lib/scsi/libscsi/llib-lscsi @@ -0,0 +1,32 @@ +/* + * 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" + +/*LINTLIBRARY*/ +/*PROTOLIB1*/ + +#include <scsi/libscsi.h> diff --git a/usr/src/lib/scsi/libscsi/mapfile-vers b/usr/src/lib/scsi/libscsi/mapfile-vers new file mode 100644 index 0000000000..d35f144f08 --- /dev/null +++ b/usr/src/lib/scsi/libscsi/mapfile-vers @@ -0,0 +1,72 @@ +# +# 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" + +SUNWprivate_1.1 { + global: + libscsi_init; + libscsi_fini; + libscsi_open; + libscsi_close; + libscsi_action_alloc; + libscsi_action_get_status; + libscsi_action_set_status; + libscsi_action_get_timeout; + libscsi_action_set_timeout; + libscsi_action_get_cdb; + libscsi_action_get_flags; + libscsi_action_get_buffer; + libscsi_action_get_sense; + libscsi_action_set_datalen; + libscsi_action_set_senselen; + libscsi_action_parse_sense; + libscsi_sense_key_name; + libscsi_sense_code_name; + libscsi_action_free; + libscsi_exec; + libscsi_errno; + libscsi_errmsg; + libscsi_strerror; + libscsi_errname; + libscsi_errcode; + libscsi_assert; + libscsi_cmd_cdblen; + libscsi_vendor; + libscsi_product; + libscsi_revision; + libscsi_get_handle; + + libscsi_alloc; + libscsi_zalloc; + libscsi_strdup; + libscsi_free; + libscsi_set_errno; + libscsi_verror; + libscsi_error; + + local: + *; +}; diff --git a/usr/src/lib/scsi/libscsi/sparc/Makefile b/usr/src/lib/scsi/libscsi/sparc/Makefile new file mode 100644 index 0000000000..b68583c86f --- /dev/null +++ b/usr/src/lib/scsi/libscsi/sparc/Makefile @@ -0,0 +1,30 @@ +# +# 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" + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) diff --git a/usr/src/lib/scsi/libscsi/sparcv9/Makefile b/usr/src/lib/scsi/libscsi/sparcv9/Makefile new file mode 100644 index 0000000000..e3fab7e838 --- /dev/null +++ b/usr/src/lib/scsi/libscsi/sparcv9/Makefile @@ -0,0 +1,31 @@ +# +# 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" + +include ../Makefile.com +include ../../../Makefile.lib.64 + +install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64) diff --git a/usr/src/lib/scsi/libses/Makefile b/usr/src/lib/scsi/libses/Makefile new file mode 100644 index 0000000000..abb400b621 --- /dev/null +++ b/usr/src/lib/scsi/libses/Makefile @@ -0,0 +1,61 @@ +# +# 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" + +include ../../Makefile.lib +include ../Makefile.defs + +HDRS = libses.h libses_plugin.h +ROOTHDRDIR = $(ROOTSCSIHDRDIR) +ROOTHDRS = $(HDRS:%=$(ROOTHDRDIR)/%) +CHECKDIRS = $(HDRS:%.h=%.check) +HDRDIR = common + +SUBDIRS = $(MACH) +$(BUILD64)SUBDIRS += $(MACH64) + +all := TARGET= all +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install +lint := TARGET= lint +install_h:= TARGET = install_h + +.KEEP_STATE: + +all install clean clobber lint: $(SUBDIRS) + +install_h: $(ROOTHDRS) + +check: $(CHECKHDRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + +include ../Makefile.rootdirs +include ../../Makefile.targ diff --git a/usr/src/lib/scsi/libses/Makefile.com b/usr/src/lib/scsi/libses/Makefile.com new file mode 100644 index 0000000000..8b27f96d60 --- /dev/null +++ b/usr/src/lib/scsi/libses/Makefile.com @@ -0,0 +1,40 @@ +# +# 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" + +LIBRARY = libses.a +VERS = .1 + +OBJECTS = \ + ses_enclosure.o \ + ses_errno.o \ + ses_node.o \ + ses_plugin.o \ + ses_snap.o \ + ses_subr.o + +include ../../Makefile.defs +include ../../../Makefile.lib diff --git a/usr/src/lib/scsi/libses/Makefile.defs b/usr/src/lib/scsi/libses/Makefile.defs new file mode 100644 index 0000000000..96f5872fba --- /dev/null +++ b/usr/src/lib/scsi/libses/Makefile.defs @@ -0,0 +1,60 @@ +# +# 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" + +SRCS = $(OBJECTS:%.o=../common/%.c) +C99MODE = $(C99_ENABLE) +CPPFLAGS += -I../common -I. -D_REENTRANT +$(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG +CFLAGS += $(CCVERBOSE) + +ROOTLIBDIR = $(ROOTSCSILIBDIR) +ROOTLIBDIR64 = $(ROOTSCSILIBDIR)/$(MACH64) + +DYNFLAGS32 += -R$(SCSILIBDIR) +DYNFLAGS64 += -R$(SCSILIBDIR)/$(MACH64) + +LDLIBS32 += -L$(ROOTSCSILIBDIR) +LDLIBS64 += -L$(ROOTSCSILIBDIR)/$(MACH64) + +LDLIBS += \ + -lnvpair \ + -lscsi \ + -lc + +LIBS = $(DYNLIB) $(LINTLIB) + +CLEANFILES += \ + ../common/ses_errno.c + +# +# On SPARC, gcc emits DWARF assembler directives for TLS data that are not +# understood by the Sun assembler. Until this problem is fixed, we turn down +# the amount of generated debugging information, which seems to do the trick. +# +$(SPARC_BLD)CTF_FLAGS += -_gcc=-g1 + +$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) diff --git a/usr/src/lib/scsi/libses/Makefile.defs.64 b/usr/src/lib/scsi/libses/Makefile.defs.64 new file mode 100644 index 0000000000..a6fe3b77dd --- /dev/null +++ b/usr/src/lib/scsi/libses/Makefile.defs.64 @@ -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 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" + +DYNFLAGS += -R/usr/lib/scsi/$(MACH64) diff --git a/usr/src/lib/scsi/libses/Makefile.targ b/usr/src/lib/scsi/libses/Makefile.targ new file mode 100644 index 0000000000..a73a46eae4 --- /dev/null +++ b/usr/src/lib/scsi/libses/Makefile.targ @@ -0,0 +1,42 @@ +# +# 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" + +.KEEP_STATE: + +all : $(LIBS) + +lint : lintcheck + +../common/ses_errno.c: ../common/mkerrno.sh ../common/libses.h + sh ../common/mkerrno.sh < $(ROOTSCSIHDRDIR)/libses.h > $@ + +pics/%.o: ../common/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +include ../../../Makefile.targ + diff --git a/usr/src/lib/scsi/libses/amd64/Makefile b/usr/src/lib/scsi/libses/amd64/Makefile new file mode 100644 index 0000000000..aaa948e5ae --- /dev/null +++ b/usr/src/lib/scsi/libses/amd64/Makefile @@ -0,0 +1,36 @@ +# +# 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" + +include ../Makefile.com +include ../../../Makefile.lib +include ../../../Makefile.lib.64 +include ../Makefile.defs +include ../Makefile.defs.64 + +install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64) + +include ../Makefile.targ diff --git a/usr/src/lib/scsi/libses/common/libses.h b/usr/src/lib/scsi/libses/common/libses.h new file mode 100644 index 0000000000..7e95cb4b3a --- /dev/null +++ b/usr/src/lib/scsi/libses/common/libses.h @@ -0,0 +1,132 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _LIBSES_H +#define _LIBSES_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> + +#include <stdarg.h> +#include <libnvpair.h> +#include <pthread.h> + +#include <scsi/libscsi.h> +#include <scsi/plugins/ses/framework/ses2.h> +#include <scsi/plugins/ses/framework/libses.h> + +#define LIBSES_VERSION 1 + +typedef enum ses_node_type { + SES_NODE_NONE = 0x0, + SES_NODE_TARGET = 0x1, + SES_NODE_ENCLOSURE = 0x2, + SES_NODE_AGGREGATE = 0x4, + SES_NODE_ELEMENT = 0x8 +} ses_node_type_t; + +typedef enum ses_errno { + ESES_NONE, /* no error */ + ESES_NOMEM, /* no memory */ + ESES_ZERO_LENGTH, /* zero-length allocation requested */ + ESES_VERSION, /* library version mismatch */ + ESES_NVL, /* nvlist manipulation error */ + ESES_BAD_NODE, /* bad node */ + ESES_INVALID_OP, /* invalid operation */ + ESES_RANGE, /* value out of range */ + ESES_INVALID_PROP, /* nonexistent or immutable property */ + ESES_BAD_TYPE, /* incorrect property type */ + ESES_BAD_PAGE, /* bad page number */ + ESES_BAD_RESPONSE, /* bad response from target */ + ESES_BUSY, /* target busy */ + ESES_TOOMUCHCHANGE, /* target configuration changing too rapidly */ + ESES_LIBSCSI, /* SCSI error */ + ESES_NOTSUP, /* operation not supported */ + ESES_UNKNOWN, /* error of unknown type */ + ESES_CHANGED, /* generation count has changed */ + ESES_PLUGIN, /* invalid or missing plugin */ + ESES_MAX /* maximum libses errno value */ +} ses_errno_t; + +struct ses_target; +typedef struct ses_target ses_target_t; + +struct ses_snap; +typedef struct ses_snap ses_snap_t; + +struct ses_node; +typedef struct ses_node ses_node_t; + +extern ses_target_t *ses_open(uint_t, const char *); +extern ses_target_t *ses_open_scsi(uint_t, libscsi_target_t *); +extern void ses_close(ses_target_t *); + +extern libscsi_target_t *ses_scsi_target(ses_target_t *); + +typedef enum ses_walk_action { + SES_WALK_ACTION_CONTINUE, + SES_WALK_ACTION_PRUNE, + SES_WALK_ACTION_TERMINATE +} ses_walk_action_t; + +typedef ses_walk_action_t (*ses_walk_f)(ses_node_t *, void *); + +extern uint64_t ses_node_id(ses_node_t *); +extern ses_node_t *ses_node_lookup(ses_snap_t *, uint64_t); + +extern ses_node_t *ses_root_node(ses_snap_t *); +extern ses_node_t *ses_node_sibling(ses_node_t *); +extern ses_node_t *ses_node_prev_sibling(ses_node_t *); +extern ses_node_t *ses_node_child(ses_node_t *); +extern ses_node_t *ses_node_parent(ses_node_t *); +extern int ses_walk(ses_snap_t *, ses_walk_f, void *); + +extern ses_snap_t *ses_snap_hold(ses_target_t *); +extern void ses_snap_rele(ses_snap_t *); +extern ses_snap_t *ses_snap_new(ses_target_t *); +extern uint32_t ses_snap_generation(ses_snap_t *); + +extern ses_node_type_t ses_node_type(ses_node_t *); +extern nvlist_t *ses_node_props(ses_node_t *); +extern int ses_node_ctl(ses_node_t *, const char *, nvlist_t *); +extern ses_snap_t *ses_node_snapshot(ses_node_t *); +extern ses_target_t *ses_node_target(ses_node_t *); + +extern ses_errno_t ses_errno(void); +extern const char *ses_errmsg(void); +extern const char *ses_strerror(ses_errno_t); +extern const char *ses_nv_error_member(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBSES_H */ diff --git a/usr/src/lib/scsi/libses/common/libses_plugin.h b/usr/src/lib/scsi/libses/common/libses_plugin.h new file mode 100644 index 0000000000..7156da7bdf --- /dev/null +++ b/usr/src/lib/scsi/libses/common/libses_plugin.h @@ -0,0 +1,161 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _LIBSES_PLUGIN_H +#define _LIBSES_PLUGIN_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#define LIBSES_PLUGIN_VERSION 1 + +/* + * These are the primary APIs for plugins to interact with libses. + */ + +struct ses_plugin; +typedef struct ses_plugin ses_plugin_t; + +typedef enum { + SES_PAGE_DIAG, + SES_PAGE_CTL +} ses_pagetype_t; + +typedef struct ses_pagedesc { + int spd_pagenum; + size_t (*spd_ctl_len)(uint_t, int, size_t); + void *(*spd_ctl_fill)(ses_plugin_t *, void *, size_t, + ses_node_t *); + void *(*spd_index)(ses_plugin_t *, ses_node_t *, + void *, size_t, size_t *); + int spd_gcoff; +} ses_pagedesc_t; + +typedef struct ses_plugin_config { + ses_pagedesc_t *spc_pages; + int (*spc_node_parse)(ses_plugin_t *, ses_node_t *); + int (*spc_node_ctl)(ses_plugin_t *, ses_node_t *, + const char *, nvlist_t *); +} ses_plugin_config_t; + +extern int ses_plugin_register(ses_plugin_t *, int, ses_plugin_config_t *); + +extern void *ses_plugin_page_lookup(ses_plugin_t *, ses_snap_t *, int, + ses_node_t *, size_t *); + +extern void *ses_plugin_ctlpage_lookup(ses_plugin_t *, ses_snap_t *, int, + size_t, ses_node_t *, boolean_t); + +extern void ses_plugin_setspecific(ses_plugin_t *, void *); +extern void *ses_plugin_getspecific(ses_plugin_t *); + +/* + * The following are support functions provided by libses. + */ + +extern int ses_assert(const char *, const char *, int); + +#define VERIFY(x) ((void)((x) || ses_assert(#x, __FILE__, __LINE__))) + +#ifdef DEBUG +#define ASSERT(x) VERIFY(x) +#else +#define ASSERT(x) +#endif + +#define SES_NV_ADD(_t, _e, _l, _n, ...) \ + if (((_e) = nvlist_add_##_t((_l), (_n), __VA_ARGS__)) != 0) \ + return (ses_set_nverrno((_e), (_n))) + +#define SES_NV_ADD_OR_FREE(_t, _e, _l, _n, ...) \ + if (((_e) = nvlist_add_##_t((_l), (_n), __VA_ARGS__)) != 0) { \ + nvlist_free(_l); return (ses_set_nverrno((_e), (_n))); } + +#define SES_NV_ADD_FS(_e, _l, _name, _buf) \ + SES_NV_ADD(fixed_string, (_e), (_l), (_name), (_buf), sizeof (_buf)) + +#define SES_NV_ADD_FS_TRUNC(_e, _l, _name, _buf) \ + SES_NV_ADD(fixed_string_trunc, (_e), (_l), (_name), (_buf), \ + sizeof (_buf)) + +#define SES_NV_CTLBOOL(_l, _n, _b) \ + { \ + boolean_t v = B_FALSE; \ + (void) nvlist_lookup_boolean_value((_l), (_n), &v); \ + (_b) = v; \ + } + +#define SES_NV_CTLBOOL_INVERT(_l, _n, _b) \ + { \ + boolean_t v = B_FALSE; \ + (void) nvlist_lookup_boolean_value((_l), (_n), &v); \ + (_b) = !v; \ + } + +#define SES_NV_CTL64(_l, _n, _v) \ + { \ + uint64_t v = 0; \ + (void) nvlist_lookup_uint64((_l), (_n), &v); \ + (_v) = v; \ + } + +#define SES_NV_CTL16(_l, _n, _v) \ + { \ + uint16_t v = 0; \ + (void) nvlist_lookup_uint16((_l), (_n), &v); \ + SCSI_WRITE16(&(_v), v); \ + } + +extern void *ses_alloc(size_t); +extern void *ses_zalloc(size_t); +extern char *ses_strdup(const char *); +extern void *ses_realloc(void *, size_t); +extern void ses_free(void *); + +extern int ses_set_errno(ses_errno_t); +extern int ses_set_nverrno(int, const char *); +extern int ses_error(ses_errno_t, const char *, ...); +extern int ses_nverror(int, const char *, const char *, ...); +extern void ses_panic(const char *, ...) __NORETURN; + +extern int nvlist_add_fixed_string(nvlist_t *, const char *, + const char *, size_t); +extern int nvlist_add_fixed_string_trunc(nvlist_t *, const char *, + const char *, size_t); + +#define SES_WITHIN_PAGE(sp, size, data, len) \ + ((char *)(sp) <= (char *)(data) + (len) - (size)) +#define SES_WITHIN_PAGE_STRUCT(sp, data, len) \ + SES_WITHIN_PAGE((sp), sizeof (*(sp)), (data), (len)) + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBSES_PLUGIN_H */ diff --git a/usr/src/lib/scsi/libses/common/mkerrno.sh b/usr/src/lib/scsi/libses/common/mkerrno.sh new file mode 100644 index 0000000000..a796ddee67 --- /dev/null +++ b/usr/src/lib/scsi/libses/common/mkerrno.sh @@ -0,0 +1,86 @@ +#!/bin/sh +# +# 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" + +echo "/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident\t\"%Z%%M%\t%I%\t%E% SMI\" + +#include <strings.h> +#include <scsi/libses.h> + +static const struct { +\tchar *se_name;\t\t/* error name */ +\tchar *se_msg;\t\t/* error message */ +} _ses_errstr[] = {" + +pattern='^ \(ESES_[A-Z0-9_]*\),*' +replace=' { "\1",' +open=' \/\* ' +openrepl='"' +close=' \*\/$' +closerepl='" },' + +( sed -n "s/$pattern/$replace/p" | sed -n "s/$open/$openrepl/p" | + sed -n "s/$close/$closerepl/p" ) || exit 1 + +echo "\ +};\n\ +\n\ +static int _ses_nerrno = sizeof (_ses_errstr) / sizeof (_ses_errstr[0]);\n\ +\n\ +const char * +ses_strerror(ses_errno_t err) +{ + return (err < 0 || err >= _ses_nerrno ? \"unknown error\" : + _ses_errstr[err].se_msg); +} + +const char * +ses_errname(ses_errno_t err) +{ + return (err < 0 || err >= _ses_nerrno ? NULL : + _ses_errstr[err].se_name); +} + +ses_errno_t +ses_errcode(const char *name) +{ + ses_errno_t err; + + for (err = 0; err < _ses_nerrno; err++) { + if (strcmp(name, _ses_errstr[err].se_name) == 0) + return (err); + } + + return (ESES_UNKNOWN); +}" + +exit 0 diff --git a/usr/src/lib/scsi/libses/common/ses_enclosure.c b/usr/src/lib/scsi/libses/common/ses_enclosure.c new file mode 100644 index 0000000000..4d2af5cc55 --- /dev/null +++ b/usr/src/lib/scsi/libses/common/ses_enclosure.c @@ -0,0 +1,293 @@ +/* + * 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 <scsi/libses.h> +#include "ses_impl.h" + +int +enc_parse_td(ses2_td_hdr_impl_t *tip, const char *tp, nvlist_t *nvl) +{ + int nverr; + + if (tp != NULL) + SES_NV_ADD(fixed_string, nverr, nvl, SES_PROP_CLASS_DESCRIPTION, + tp, tip->sthi_text_len); + + return (0); +} + +static int +enc_eid(const ses2_ed_impl_t *tp, nvlist_t *nvl, const char *name) +{ + int nverr; + + SES_NV_ADD(uint64, nverr, nvl, name, tp->st_hdr.sehi_subenclosure_id); + + return (0); +} + +static int +enc_espid(const ses2_ed_impl_t *tp, nvlist_t *nvl, const char *name) +{ + int nverr; + + SES_NV_ADD(uint64, nverr, nvl, name, tp->st_hdr.sehi_rel_esp_id); + + return (0); +} + +static int +enc_nesp(const ses2_ed_impl_t *tp, nvlist_t *nvl, const char *name) +{ + int nverr; + + SES_NV_ADD(uint64, nverr, nvl, name, tp->st_hdr.sehi_n_esps); + + return (0); +} + +static int +enc_lid(const ses2_ed_impl_t *tp, nvlist_t *nvl, const char *name) +{ + nvlist_t *lid; + int nverr; + + if ((nverr = nvlist_alloc(&lid, NV_UNIQUE_NAME, 0)) != 0) + return (ses_set_nverrno(nverr, NULL)); + + SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_INT, + SCSI_READ64(&tp->st_logical_id)); + + switch (tp->st_logical_id.sni8i_naa) { + case NAA_IEEE_EXT: + SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_ID_TYPE, + NAA_IEEE_EXT); + SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_COMPANY_ID, + NAA_IEEE_EXT_COMPANY_ID(&tp->st_logical_id.sni8i_ext_id)); + SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_VS_A, + NAA_IEEE_EXT_VENDOR_A(&tp->st_logical_id.sni8i_ext_id)); + SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_VS_B, + NAA_IEEE_EXT_VENDOR_B(&tp->st_logical_id.sni8i_ext_id)); + break; + case NAA_IEEE_REG: + SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_ID_TYPE, + NAA_IEEE_REG); + SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_COMPANY_ID, + NAA_IEEE_REG_COMPANY_ID(&tp->st_logical_id.sni8i_reg_id)); + SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_VS_A, + NAA_IEEE_REG_VENDOR_ID(&tp->st_logical_id.sni8i_reg_id)); + break; + default: + break; + } + + if ((nverr = nvlist_add_nvlist(nvl, name, lid)) != 0) { + nvlist_free(lid); + return (ses_set_nverrno(nverr, name)); + } + + nvlist_free(lid); + + return (0); +} + +static int +enc_vid(const ses2_ed_impl_t *tp, nvlist_t *nvl, + const char *name) +{ + int nverr; + + SES_NV_ADD_FS_TRUNC(nverr, nvl, name, tp->st_vendor_id); + + return (0); +} + +static int +enc_pid(const ses2_ed_impl_t *tp, nvlist_t *nvl, + const char *name) +{ + int nverr; + + SES_NV_ADD_FS_TRUNC(nverr, nvl, name, tp->st_product_id); + + return (0); +} + +static int +enc_rev(const ses2_ed_impl_t *tp, nvlist_t *nvl, + const char *name) +{ + int nverr; + + SES_NV_ADD_FS_TRUNC(nverr, nvl, name, tp->st_product_revision); + + return (0); +} + +static int +enc_vs(const ses2_ed_impl_t *tp, nvlist_t *nvl, const char *name) +{ + int nverr; + + SES_NV_ADD(byte_array, nverr, nvl, name, (uchar_t *)tp->st_priv, + tp->st_hdr.sehi_ed_len - offsetof(ses2_ed_impl_t, st_priv[0])); + + return (0); +} + +/* LINTED - unused */ +static const ses2_ed_impl_t __ed = { 0 }; + +#define ED_REQ_LEN(member) \ + (offsetof(ses2_ed_impl_t, member) - sizeof (ses2_ed_hdr_impl_t) + \ + sizeof (__ed.member)) + +static const struct config_member { + const char *name; + size_t minsz; + int (*func)(const ses2_ed_impl_t *, nvlist_t *, const char *); +} config_members[] = { + { SES_EN_PROP_EID, 0, enc_eid }, + { SES_EN_PROP_ESPID, 0, enc_espid }, + { SES_EN_PROP_NESP, 0, enc_nesp }, + { SES_EN_PROP_LID, ED_REQ_LEN(st_logical_id), enc_lid }, + { SES_EN_PROP_VID, ED_REQ_LEN(st_vendor_id), enc_vid }, + { SES_EN_PROP_PID, ED_REQ_LEN(st_product_id), enc_pid }, + { SES_EN_PROP_REV, ED_REQ_LEN(st_product_revision), enc_rev }, + { SES_EN_PROP_VS, ED_REQ_LEN(st_priv), enc_vs }, + { NULL, 0, NULL } +}; + +int +enc_parse_ed(ses2_ed_impl_t *tp, nvlist_t *nvl) +{ + const struct config_member *mp; + int err; + + if (tp == NULL) + return (0); + + for (mp = &config_members[0]; mp->name != NULL; mp++) { + if (mp->func != NULL && tp->st_hdr.sehi_ed_len >= mp->minsz) { + err = mp->func(tp, nvl, mp->name); + if (err != 0) + return (err); + } + } + + return (0); +} + +ses_target_t * +ses_open_scsi(uint_t version, libscsi_target_t *stp) +{ + ses_target_t *tp; + ses_snap_t *sp; + + if (version != LIBSES_VERSION) { + (void) ses_set_errno(ESES_VERSION); + return (NULL); + } + + if ((tp = ses_zalloc(sizeof (ses_target_t))) == NULL) + return (NULL); + + tp->st_target = stp; + tp->st_scsi_hdl = libscsi_get_handle(stp); + tp->st_truncate = (getenv("LIBSES_TRUNCATE") != NULL); + if (tp->st_truncate) + srand48(gethrtime()); + + (void) pthread_mutex_init(&tp->st_lock, NULL); + + if (ses_plugin_load(tp) != 0) { + ses_close(tp); + return (NULL); + } + + if ((sp = ses_snap_new(tp)) == NULL) { + ses_close(tp); + return (NULL); + } + + ses_snap_rele(sp); + + return (tp); +} + +ses_target_t * +ses_open(uint_t version, const char *target) +{ + ses_target_t *tp; + libscsi_errno_t serr; + libscsi_target_t *stp; + libscsi_hdl_t *hp; + + if ((hp = libscsi_init(LIBSCSI_VERSION, &serr)) == NULL) { + (void) ses_error(ESES_LIBSCSI, "failed to initialize " + "libscsi: %s", libscsi_strerror(serr)); + return (NULL); + } + + if ((stp = libscsi_open(hp, NULL, target)) == NULL) { + (void) ses_libscsi_error(hp, "failed to open SES target"); + libscsi_fini(hp); + return (NULL); + } + + if ((tp = ses_open_scsi(version, stp)) == NULL) { + libscsi_close(hp, stp); + libscsi_fini(hp); + return (NULL); + } + + tp->st_closescsi = B_TRUE; + + return (tp); +} + +libscsi_target_t * +ses_scsi_target(ses_target_t *tp) +{ + return (tp->st_target); +} + +void +ses_close(ses_target_t *tp) +{ + if (tp->st_snapshots != NULL) + ses_snap_rele(tp->st_snapshots); + if (tp->st_snapshots != NULL) + ses_panic("attempt to close SES target with active snapshots"); + ses_plugin_unload(tp); + if (tp->st_closescsi) { + libscsi_close(tp->st_scsi_hdl, tp->st_target); + libscsi_fini(tp->st_scsi_hdl); + } + ses_free(tp); +} diff --git a/usr/src/lib/scsi/libses/common/ses_impl.h b/usr/src/lib/scsi/libses/common/ses_impl.h new file mode 100644 index 0000000000..a820f31787 --- /dev/null +++ b/usr/src/lib/scsi/libses/common/ses_impl.h @@ -0,0 +1,170 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SES_IMPL_H +#define _SES_IMPL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <alloca.h> +#include <errno.h> +#include <assert.h> +#include <dirent.h> +#include <dlfcn.h> +#include <limits.h> +#include <pthread.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <libnvpair.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/sysmacros.h> +#include <sys/systeminfo.h> + +#include <scsi/libscsi.h> +#include <scsi/libses_plugin.h> +#include <scsi/plugins/ses/framework/ses2_impl.h> + +#define LIBSES_ERRMSGLEN 512 + +#define LIBSES_DEFAULT_PLUGINDIR "/usr/lib/scsi/plugins/ses" +#define LIBSES_PLUGIN_FRAMEWORK "framework" +#define LIBSES_PLUGIN_VENDOR "vendor" + +#define LIBSES_PLUGIN_EXT ".so" + +struct ses_plugin { + struct ses_plugin *sp_next; /* next plugin in list */ + struct ses_plugin *sp_prev; /* previous plugin in list */ + uint64_t sp_priority; /* plugin priority */ + struct ses_target *sp_target; /* corresponding target */ + void *sp_object; /* shared object */ + void *sp_data; /* module-specific data */ + boolean_t sp_initialized; /* successfully initialized */ + ses_pagedesc_t *sp_pages; /* pages */ + int (*sp_init)(ses_plugin_t *); /* plugin init */ + void (*sp_fini)(ses_plugin_t *); /* plugin fini */ + int (*sp_node_parse)(ses_plugin_t *, ses_node_t *); /* parse node */ + int (*sp_node_ctl)(ses_plugin_t *, ses_node_t *, const char *, + nvlist_t *); /* node control */ +}; + +struct ses_target { + libscsi_hdl_t *st_scsi_hdl; + libscsi_target_t *st_target; + struct ses_plugin *st_plugin_first; + struct ses_plugin *st_plugin_last; + struct ses_snap *st_snapshots; + boolean_t st_closescsi; + boolean_t st_truncate; + pthread_mutex_t st_lock; +}; + +/* + * Maximum number of snapshot retries triggered by generation count changes + */ +#define LIBSES_MAX_GC_RETRIES 10 + +/* + * Maximum number of Enclosure Busy retries + */ +#define LIBSES_MAX_BUSY_RETRIES 3 + +typedef struct ses_snap_page { + ses2_diag_page_t ssp_num; + boolean_t ssp_control; + boolean_t ssp_initialized; + size_t ssp_alloc; + size_t ssp_len; + void *ssp_page; + char *ssp_mmap_base; + size_t ssp_mmap_len; + struct ses_snap_page *ssp_next; + struct ses_snap_page *ssp_unique; +} ses_snap_page_t; + +struct ses_snap { + struct ses_target *ss_target; + uint32_t ss_generation; + hrtime_t ss_time; + struct ses_node *ss_root; + size_t ss_n_elem; + ses_snap_page_t *ss_pages; + size_t ss_n_nodes; + struct ses_node **ss_nodes; + struct ses_snap *ss_next; + struct ses_snap *ss_prev; + uint32_t ss_refcnt; +}; + +struct ses_node { + ses_node_type_t sn_type; + uint64_t sn_rootidx; /* Relative index for enclosure/aggregate */ + size_t sn_id; /* Unique global ID */ + uint64_t sn_enc_num; + struct ses_snap *sn_snapshot; + struct ses_node *sn_parent; + struct ses_node *sn_next_sibling; + struct ses_node *sn_prev_sibling; + struct ses_node *sn_first_child; + struct ses_node *sn_last_child; + nvlist_t *sn_props; +}; + +extern int ses_fill_snap(ses_snap_t *); +extern void ses_node_teardown(ses_node_t *); +extern ses_snap_page_t *ses_snap_find_page(ses_snap_t *, ses2_diag_page_t, + boolean_t); +extern ses_snap_page_t *ses_snap_ctl_page(ses_snap_t *, + ses2_diag_page_t, size_t, boolean_t); +extern int ses_snap_do_ctl(ses_snap_t *); + +extern int ses_libscsi_error(libscsi_hdl_t *, const char *, ...); +extern int ses_scsi_error(libscsi_action_t *, const char *, ...); + +extern int ses_plugin_load(ses_target_t *); +extern void ses_plugin_unload(ses_target_t *); + +extern ses_pagedesc_t *ses_get_pagedesc(ses_target_t *, int, ses_pagetype_t); +extern int ses_fill_node(ses_node_t *); + +extern int enc_parse_ed(ses2_ed_impl_t *, nvlist_t *); +extern int enc_parse_td(ses2_td_hdr_impl_t *, const char *, nvlist_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _SES_IMPL_H */ diff --git a/usr/src/lib/scsi/libses/common/ses_node.c b/usr/src/lib/scsi/libses/common/ses_node.c new file mode 100644 index 0000000000..6e08a20874 --- /dev/null +++ b/usr/src/lib/scsi/libses/common/ses_node.c @@ -0,0 +1,399 @@ +/* + * 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 <scsi/libses.h> +#include "ses_impl.h" + +#define NEXT_ED(eip) \ + ((ses2_ed_impl_t *)((uint8_t *)(eip) + \ + ((eip)->st_hdr.sehi_ed_len + sizeof (ses2_ed_hdr_impl_t)))) + +static ses_node_t * +ses_find_enclosure(ses_snap_t *sp, uint64_t number) +{ + ses_node_t *np; + + for (np = sp->ss_root->sn_first_child; np != NULL; + np = np->sn_next_sibling) { + ASSERT(np->sn_type == SES_NODE_ENCLOSURE); + if (np->sn_enc_num == number) + return ((ses_node_t *)np); + } + + return (NULL); +} + +void +ses_node_teardown(ses_node_t *np) +{ + ses_node_t *rp; + + if (np == NULL) + return; + + for (; np != NULL; np = rp) { + ses_node_teardown(np->sn_first_child); + rp = np->sn_next_sibling; + nvlist_free(np->sn_props); + ses_free(np); + } +} + +static ses_node_t * +ses_node_alloc(ses_snap_t *sp, ses_node_t *pnp) +{ + ses_node_t *np; + + np = ses_zalloc(sizeof (ses_node_t)); + if (np == NULL) + goto fail; + if (nvlist_alloc(&np->sn_props, NV_UNIQUE_NAME, 0) != 0) + goto fail; + + np->sn_snapshot = sp; + np->sn_id = sp->ss_n_nodes++; + + if (pnp == NULL) { + ASSERT(sp->ss_root == NULL); + sp->ss_root = np; + } else { + np->sn_parent = pnp; + np->sn_prev_sibling = pnp->sn_last_child; + + if (pnp->sn_first_child == NULL) + pnp->sn_first_child = np; + else + pnp->sn_last_child->sn_next_sibling = np; + + pnp->sn_last_child = np; + } + + return (np); + +fail: + ses_free(np); + ses_node_teardown(sp->ss_root); + sp->ss_root = NULL; + return (NULL); +} + +/* + * Parse element type descriptor. + */ +static int +elem_parse_td(ses2_td_hdr_impl_t *tip, const char *tp, nvlist_t *nvl) +{ + int nverr; + + if (tp != NULL) + SES_NV_ADD(fixed_string, nverr, nvl, SES_PROP_CLASS_DESCRIPTION, + tp, tip->sthi_text_len); + + return (0); +} + + +/* + * Build a skeleton tree of nodes in the given snapshot. This is the heart of + * libses, and is responsible for parsing the config page into a tree and + * populating nodes with data from the config page. + */ +static int +ses_build_snap_skel(ses_snap_t *sp) +{ + ses2_ed_impl_t *eip; + ses2_td_hdr_impl_t *tip, *ftip; + ses_node_t *np, *pnp, *cnp, *root; + ses_snap_page_t *pp; + ses2_config_page_impl_t *pip; + int i, j, n_etds = 0; + off_t toff; + char *tp, *text; + int err; + uint64_t idx; + + pp = ses_snap_find_page(sp, SES2_DIAGPAGE_CONFIG, B_FALSE); + if (pp == NULL) + return (ses_error(ESES_BAD_RESPONSE, "target does not support " + "configuration diagnostic page")); + pip = (ses2_config_page_impl_t *)pp->ssp_page; + + if (pp->ssp_len < offsetof(ses2_config_page_impl_t, scpi_data)) + return (ses_error(ESES_BAD_RESPONSE, "no enclosure " + "descriptors found")); + + /* + * Start with the root of the tree, which is a target node, containing + * just the SCSI inquiry properties. + */ + if ((root = ses_node_alloc(sp, sp->ss_root)) == NULL) + return (-1); + + root->sn_type = SES_NODE_TARGET; + SES_NV_ADD(string, err, root->sn_props, SCSI_PROP_VENDOR, + libscsi_vendor(sp->ss_target->st_target)); + SES_NV_ADD(string, err, root->sn_props, SCSI_PROP_PRODUCT, + libscsi_product(sp->ss_target->st_target)); + SES_NV_ADD(string, err, root->sn_props, SCSI_PROP_REVISION, + libscsi_revision(sp->ss_target->st_target)); + + for (eip = (ses2_ed_impl_t *)pip->scpi_data, i = 0; + i < pip->scpi_n_subenclosures + 1; + i++, eip = NEXT_ED(eip)) { + if (!SES_WITHIN_PAGE_STRUCT(eip, pp->ssp_page, pp->ssp_len)) + break; + + n_etds += eip->st_hdr.sehi_n_etd_hdrs; + } + ftip = (ses2_td_hdr_impl_t *)eip; + + /* + * There should really be only one Enclosure element possible for a + * give subenclosure ID. The standard never comes out and says this, + * but it does describe this element as "managing the enclosure itself" + * which implies rather strongly that the subenclosure ID field is that + * of, well, the enclosure itself. Since an enclosure can't contain + * itself, it follows logically that each subenclosure has at most one + * Enclosure type descriptor elements matching its ID. Of course, some + * enclosure firmware is buggy, so this may not always work out; in + * this case we just ignore all but the first Enclosure-type element + * with our subenclosure ID. + */ + for (eip = (ses2_ed_impl_t *)pip->scpi_data, i = 0; + i < pip->scpi_n_subenclosures + 1; + i++, eip = NEXT_ED(eip)) { + if (!SES_WITHIN_PAGE_STRUCT(eip, pp->ssp_page, pp->ssp_len)) + break; + + if ((np = ses_node_alloc(sp, root)) == NULL) + return (-1); + + np->sn_type = SES_NODE_ENCLOSURE; + np->sn_enc_num = eip->st_hdr.sehi_subenclosure_id; + + if (!SES_WITHIN_PAGE(eip, eip->st_hdr.sehi_ed_len + + sizeof (ses2_ed_hdr_impl_t), + pp->ssp_page, pp->ssp_len)) + break; + + if (enc_parse_ed(eip, np->sn_props) != 0) + return (-1); + } + + if (root->sn_first_child == NULL) + return (ses_error(ESES_BAD_RESPONSE, "no enclosure " + "descriptors found")); + + tp = (char *)(ftip + n_etds); + + for (i = 0, toff = 0, idx = 0; i < n_etds; i++) { + tip = ftip + i; + + if (!SES_WITHIN_PAGE_STRUCT(tip, pp->ssp_page, pp->ssp_len)) + break; + + pnp = ses_find_enclosure(sp, + tip->sthi_subenclosure_id); + if (pnp == NULL) { + idx += tip->sthi_max_elements + 1; + toff += tip->sthi_text_len; + continue; + } + + if (tip->sthi_element_type == SES_ET_ENCLOSURE) { + if (tip->sthi_max_elements == 0) { + SES_NV_ADD(uint64, err, pnp->sn_props, + SES_PROP_ELEMENT_INDEX, idx); + pnp->sn_rootidx = idx; + } else { + SES_NV_ADD(uint64, err, pnp->sn_props, + SES_PROP_ELEMENT_INDEX, idx + 1); + pnp->sn_rootidx = idx + 1; + } + + if (tip->sthi_text_len > 0 && + SES_WITHIN_PAGE(tp + toff, tip->sthi_text_len, + pp->ssp_page, pp->ssp_len)) { + text = tp + toff; + toff += tip->sthi_text_len; + } else { + text = NULL; + } + + SES_NV_ADD(uint64, err, pnp->sn_props, + SES_PROP_ELEMENT_TYPE, SES_ET_ENCLOSURE); + if (enc_parse_td(tip, text, pnp->sn_props) != 0) + return (-1); + + idx += tip->sthi_max_elements + 1; + continue; + } + + if ((np = ses_node_alloc(sp, pnp)) == NULL) + return (-1); + + np->sn_type = SES_NODE_AGGREGATE; + np->sn_enc_num = tip->sthi_subenclosure_id; + np->sn_parent = pnp; + np->sn_rootidx = idx; + + SES_NV_ADD(uint64, err, np->sn_props, + SES_PROP_ELEMENT_INDEX, idx); + SES_NV_ADD(uint64, err, np->sn_props, + SES_PROP_ELEMENT_TYPE, tip->sthi_element_type); + + if (tip->sthi_text_len > 0 && + SES_WITHIN_PAGE(tp + toff, tip->sthi_text_len, + pp->ssp_page, pp->ssp_len)) { + text = tp + toff; + toff += tip->sthi_text_len; + } else { + text = NULL; + } + + if (elem_parse_td(tip, text, np->sn_props) != 0) + return (-1); + + idx += tip->sthi_max_elements + 1; + + if (tip->sthi_max_elements == 0) + continue; + + for (j = 0; j < tip->sthi_max_elements; j++) { + cnp = ses_node_alloc(sp, np); + if (cnp == NULL) + return (-1); + + cnp->sn_type = SES_NODE_ELEMENT; + SES_NV_ADD(uint64, err, cnp->sn_props, + SES_PROP_ELEMENT_INDEX, np->sn_rootidx + j + 1); + SES_NV_ADD(uint64, err, cnp->sn_props, + SES_PROP_ELEMENT_CLASS_INDEX, j); + SES_NV_ADD(uint64, err, cnp->sn_props, + SES_PROP_ELEMENT_TYPE, tip->sthi_element_type); + } + } + + np->sn_snapshot->ss_n_elem = idx; + + return (0); +} + +static int +ses_fill_tree(ses_node_t *np) +{ + if (np == NULL) + return (0); + + for (; np != NULL; np = np->sn_next_sibling) { + if (ses_fill_node(np) != 0) + return (-1); + if (ses_fill_tree(np->sn_first_child) != 0) + return (-1); + } + + return (0); +} + +int +ses_fill_snap(ses_snap_t *sp) +{ + if (ses_build_snap_skel(sp) != 0) + return (-1); + + if (ses_fill_tree(sp->ss_root) != 0) + return (-1); + + return (0); +} + +ses_node_t * +ses_root_node(ses_snap_t *sp) +{ + return (sp->ss_root); +} + +ses_node_t * +ses_node_sibling(ses_node_t *np) +{ + return (np->sn_next_sibling); +} + +ses_node_t * +ses_node_prev_sibling(ses_node_t *np) +{ + return (np->sn_prev_sibling); +} + +ses_node_t * +ses_node_parent(ses_node_t *np) +{ + return (np->sn_parent); +} + +ses_node_t * +ses_node_child(ses_node_t *np) +{ + return (np->sn_first_child); +} + +ses_node_type_t +ses_node_type(ses_node_t *np) +{ + return (np->sn_type); +} + +ses_snap_t * +ses_node_snapshot(ses_node_t *np) +{ + return ((ses_snap_t *)np->sn_snapshot); +} + +ses_target_t * +ses_node_target(ses_node_t *np) +{ + return (np->sn_snapshot->ss_target); +} + +nvlist_t * +ses_node_props(ses_node_t *np) +{ + return (np->sn_props); +} + +/* + * A node identifier is a (generation, index) tuple that can be used to lookup a + * node within this target at a later point. This will be valid across + * snapshots, though it will return failure if the generation count has changed. + */ +uint64_t +ses_node_id(ses_node_t *np) +{ + return (((uint64_t)np->sn_snapshot->ss_generation << 32) | + np->sn_id); +} diff --git a/usr/src/lib/scsi/libses/common/ses_plugin.c b/usr/src/lib/scsi/libses/common/ses_plugin.c new file mode 100644 index 0000000000..e419a74475 --- /dev/null +++ b/usr/src/lib/scsi/libses/common/ses_plugin.c @@ -0,0 +1,398 @@ +/* + * 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 <scsi/libses.h> +#include "ses_impl.h" + +static boolean_t ses_plugin_dlclose; + +/*ARGSUSED*/ +void * +ses_plugin_ctlpage_lookup(ses_plugin_t *sp, ses_snap_t *snap, int pagenum, + size_t len, ses_node_t *np, boolean_t unique) +{ + ses_target_t *tp = snap->ss_target; + ses_snap_page_t *pp; + ses_pagedesc_t *dp; + + if ((pp = ses_snap_ctl_page(snap, pagenum, len, unique)) == NULL) + return (NULL); + + if ((dp = ses_get_pagedesc(tp, pagenum, SES_PAGE_CTL)) == NULL) + return (NULL); + + if (dp->spd_ctl_fill != NULL) { + return (dp->spd_ctl_fill(sp, pp->ssp_page, + pp->ssp_len, np)); + } else { + return (pp->ssp_page); + } +} + +int +ses_fill_node(ses_node_t *np) +{ + ses_target_t *tp = np->sn_snapshot->ss_target; + ses_plugin_t *sp; + + for (sp = tp->st_plugin_first; sp != NULL; sp = sp->sp_next) { + if (sp->sp_node_parse == NULL) + continue; + + if (sp->sp_node_parse(sp, np) != 0) + return (-1); + } + + return (0); +} + +int +ses_node_ctl(ses_node_t *np, const char *op, nvlist_t *arg) +{ + ses_target_t *tp = np->sn_snapshot->ss_target; + ses_plugin_t *sp; + nvlist_t *nvl; + nvpair_t *nvp; + int ret; + + if (nvlist_dup(arg, &nvl, 0) != 0) + return (ses_set_errno(ESES_NOMEM)); + + /* + * Technically we could get away with a per-snapshot lock while we fill + * the control page contents, but this doesn't take much time and we + * want actual control operations to be protected per-target, so we just + * take the target lock. + */ + (void) pthread_mutex_lock(&tp->st_lock); + + /* + * We walk the list of plugins backwards, so that a product-specific + * plugin can rewrite the nvlist to control operations in terms of the + * standard mechanisms, if desired. + */ + for (sp = tp->st_plugin_first; sp != NULL; sp = sp->sp_next) { + if (sp->sp_node_ctl == NULL) + continue; + + if (sp->sp_node_ctl(sp, np, op, nvl) != 0) { + nvlist_free(nvl); + (void) pthread_mutex_unlock(&tp->st_lock); + return (-1); + } + } + + if ((nvp = nvlist_next_nvpair(nvl, NULL)) != NULL) { + (void) ses_error(ESES_NOTSUP, "property '%s' invalid for " + "this node", nvpair_name(nvp)); + nvlist_free(nvl); + (void) pthread_mutex_unlock(&tp->st_lock); + return (-1); + } + + nvlist_free(nvl); + + ret = ses_snap_do_ctl(np->sn_snapshot); + (void) pthread_mutex_unlock(&tp->st_lock); + + return (ret); +} + +/*ARGSUSED*/ +void * +ses_plugin_page_lookup(ses_plugin_t *sp, ses_snap_t *snap, int pagenum, + ses_node_t *np, size_t *lenp) +{ + ses_snap_page_t *pp; + ses_target_t *tp = sp->sp_target; + ses_pagedesc_t *dp; + + if ((dp = ses_get_pagedesc(tp, pagenum, SES_PAGE_DIAG)) == NULL) + return (NULL); + + if ((pp = ses_snap_find_page(snap, pagenum, B_FALSE)) == NULL) + return (NULL); + + if (dp->spd_index != NULL) { + return (dp->spd_index(sp, np, pp->ssp_page, pp->ssp_len, + lenp)); + } else { + *lenp = pp->ssp_len; + return (pp->ssp_page); + } +} + +ses_pagedesc_t * +ses_get_pagedesc(ses_target_t *tp, int pagenum, ses_pagetype_t type) +{ + ses_plugin_t *sp; + ses_pagedesc_t *dp; + + for (sp = tp->st_plugin_first; sp != NULL; sp = sp->sp_next) { + if (sp->sp_pages == NULL) + continue; + + for (dp = &sp->sp_pages[0]; dp->spd_pagenum != -1; + dp++) { + if ((type == SES_PAGE_CTL && dp->spd_ctl_len == NULL) || + (type == SES_PAGE_DIAG && dp->spd_ctl_len != NULL)) + continue; + + if (dp->spd_pagenum == pagenum) + return (dp); + } + } + + (void) ses_error(ESES_BAD_PAGE, "failed to find page 0x%x", pagenum); + return (NULL); +} + +int +ses_plugin_register(ses_plugin_t *sp, int version, ses_plugin_config_t *scp) +{ + if (version != LIBSES_PLUGIN_VERSION) + return (ses_set_errno(ESES_VERSION)); + + sp->sp_pages = scp->spc_pages; + sp->sp_node_parse = scp->spc_node_parse; + sp->sp_node_ctl = scp->spc_node_ctl; + + return (0); +} + +void +ses_plugin_setspecific(ses_plugin_t *sp, void *data) +{ + sp->sp_data = data; +} + +void * +ses_plugin_getspecific(ses_plugin_t *sp) +{ + return (sp->sp_data); +} + +static void +ses_plugin_cleanstr(char *s) +{ + while (*s != '\0') { + if (*s == ' ' || *s == '/') + *s = '-'; + s++; + } +} + +static void +ses_plugin_destroy(ses_plugin_t *sp) +{ + if (sp->sp_initialized && sp->sp_fini != NULL) + sp->sp_fini(sp); + + if (!ses_plugin_dlclose) + (void) dlclose(sp->sp_object); + + ses_free(sp); +} + +static int +ses_plugin_loadone(ses_target_t *tp, const char *path, uint32_t pass) +{ + ses_plugin_t *sp, **loc; + void *obj; + int (*ses_priority)(void); + + if ((obj = dlopen(path, RTLD_PARENT | RTLD_LOCAL | RTLD_LAZY)) == NULL) + return (0); + + if ((sp = ses_zalloc(sizeof (ses_plugin_t))) == NULL) { + (void) dlclose(obj); + return (-1); + } + + sp->sp_object = obj; + sp->sp_init = (int (*)())dlsym(obj, "_ses_init"); + sp->sp_fini = (void (*)())dlsym(obj, "_ses_fini"); + sp->sp_target = tp; + + if (sp->sp_init == NULL) { + ses_plugin_destroy(sp); + return (0); + } + + /* + * Framework modules can establish an explicit prioritying by declaring + * the '_ses_priority' symbol, which returns an integer used to create + * an explicit ordering between plugins. + */ + if ((ses_priority = (int (*)())dlsym(obj, "_ses_priority")) != NULL) + sp->sp_priority = ses_priority(); + + sp->sp_priority |= (uint64_t)pass << 32; + + for (loc = &tp->st_plugin_first; *loc != NULL; loc = &(*loc)->sp_next) { + if ((*loc)->sp_priority > sp->sp_priority) + break; + } + + if (*loc != NULL) + (*loc)->sp_prev = sp; + else + tp->st_plugin_last = sp; + + sp->sp_next = *loc; + *loc = sp; + + if (sp->sp_init(sp) != 0) + return (-1); + sp->sp_initialized = B_TRUE; + + return (0); +} + +static int +ses_plugin_load_dir(ses_target_t *tp, const char *pluginroot) +{ + char path[PATH_MAX]; + DIR *dirp; + struct dirent64 *dp; + char *vendor, *product, *revision; + char isa[257]; + + (void) snprintf(path, sizeof (path), "%s/%s", + pluginroot, LIBSES_PLUGIN_FRAMEWORK); + +#if defined(_LP64) + if (sysinfo(SI_ARCHITECTURE_64, isa, sizeof (isa)) < 0) + isa[0] = '\0'; +#else + isa[0] = '\0'; +#endif + + if ((dirp = opendir(path)) != NULL) { + while ((dp = readdir64(dirp)) != NULL) { + if (strcmp(dp->d_name, ".") == 0 || + strcmp(dp->d_name, "..") == 0) + continue; + + (void) snprintf(path, sizeof (path), "%s/%s/%s/%s", + pluginroot, LIBSES_PLUGIN_FRAMEWORK, + isa, dp->d_name); + + if (ses_plugin_loadone(tp, path, 0) != 0) { + (void) closedir(dirp); + return (-1); + } + } + + (void) closedir(dirp); + } + + /* + * Create a local copy of the vendor/product/revision, strip out any + * questionable characters, and then attempt to load each plugin. + */ + vendor = alloca(strlen(libscsi_vendor(tp->st_target)) + 1); + product = alloca(strlen(libscsi_product(tp->st_target)) + 1); + revision = alloca(strlen(libscsi_revision(tp->st_target)) + 1); + (void) strcpy(vendor, libscsi_vendor(tp->st_target)); + (void) strcpy(product, libscsi_product(tp->st_target)); + (void) strcpy(revision, libscsi_revision(tp->st_target)); + + ses_plugin_cleanstr(vendor); + ses_plugin_cleanstr(product); + ses_plugin_cleanstr(revision); + + (void) snprintf(path, sizeof (path), "%s/%s/%s/%s%s", pluginroot, + LIBSES_PLUGIN_VENDOR, isa, vendor, + LIBSES_PLUGIN_EXT); + if (ses_plugin_loadone(tp, path, 1) != 0) + return (-1); + + (void) snprintf(path, sizeof (path), "%s/%s/%s/%s-%s%s", pluginroot, + LIBSES_PLUGIN_VENDOR, isa, vendor, product, + LIBSES_PLUGIN_EXT); + if (ses_plugin_loadone(tp, path, 2) != 0) + return (-1); + + (void) snprintf(path, sizeof (path), "%s/%s/%s/%s-%s-%s%s", pluginroot, + LIBSES_PLUGIN_VENDOR, isa, vendor, product, + revision, LIBSES_PLUGIN_EXT); + if (ses_plugin_loadone(tp, path, 3) != 0) + return (-1); + + return (0); +} + +int +ses_plugin_load(ses_target_t *tp) +{ + char pluginroot[PATH_MAX]; + const char *pluginpath, *p, *q; + + if ((pluginpath = getenv("SES_PLUGINPATH")) == NULL) + pluginpath = LIBSES_DEFAULT_PLUGINDIR; + ses_plugin_dlclose = (getenv("SES_NODLCLOSE") == NULL); + + for (p = pluginpath, q = strchr(p, ':'); p != NULL; p = q) { + if (q != NULL) { + ptrdiff_t len = q - p; + (void) strncpy(pluginroot, p, len); + pluginroot[len] = '\0'; + while (*q == ':') + ++q; + if (*q == '\0') + q = NULL; + if (len == 0) + continue; + } else { + (void) strcpy(pluginroot, p); + } + + if (pluginroot[0] != '/') + continue; + + if (ses_plugin_load_dir(tp, pluginpath) != 0) + return (-1); + } + + if (tp->st_plugin_first == NULL) + return (ses_error(ESES_PLUGIN, "no plugins found")); + + return (0); +} + +void +ses_plugin_unload(ses_target_t *tp) +{ + ses_plugin_t *sp; + + while ((sp = tp->st_plugin_first) != NULL) { + tp->st_plugin_first = sp->sp_next; + ses_plugin_destroy(sp); + } +} diff --git a/usr/src/lib/scsi/libses/common/ses_snap.c b/usr/src/lib/scsi/libses/common/ses_snap.c new file mode 100644 index 0000000000..78e7927061 --- /dev/null +++ b/usr/src/lib/scsi/libses/common/ses_snap.c @@ -0,0 +1,700 @@ +/* + * 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 <scsi/libses.h> +#include "ses_impl.h" + +ses_snap_page_t * +ses_snap_find_page(ses_snap_t *sp, ses2_diag_page_t page, boolean_t ctl) +{ + ses_snap_page_t *pp; + + for (pp = sp->ss_pages; pp != NULL; pp = pp->ssp_next) + if (pp->ssp_num == page && pp->ssp_control == ctl && + (pp->ssp_len > 0 || pp->ssp_control)) + return (pp); + + return (NULL); +} + +static int +grow_snap_page(ses_snap_page_t *pp, size_t min) +{ + uint8_t *newbuf; + + if (min == 0 || min < pp->ssp_alloc) + min = pp->ssp_alloc * 2; + + if ((newbuf = ses_realloc(pp->ssp_page, min)) == NULL) + return (-1); + + pp->ssp_page = newbuf; + pp->ssp_alloc = min; + + bzero(newbuf + pp->ssp_len, pp->ssp_alloc - pp->ssp_len); + + return (0); +} + +static ses_snap_page_t * +alloc_snap_page(void) +{ + ses_snap_page_t *pp; + + if ((pp = ses_zalloc(sizeof (ses_snap_page_t))) == NULL) + return (NULL); + + if ((pp->ssp_page = ses_zalloc(SES2_MIN_DIAGPAGE_ALLOC)) == NULL) { + ses_free(pp); + return (NULL); + } + + pp->ssp_num = -1; + pp->ssp_alloc = SES2_MIN_DIAGPAGE_ALLOC; + + return (pp); +} + +static void +free_snap_page(ses_snap_page_t *pp) +{ + if (pp == NULL) + return; + + if (pp->ssp_mmap_base) + (void) munmap(pp->ssp_mmap_base, pp->ssp_mmap_len); + else + ses_free(pp->ssp_page); + ses_free(pp); +} + +static void +free_all_snap_pages(ses_snap_t *sp) +{ + ses_snap_page_t *pp, *np; + + for (pp = sp->ss_pages; pp != NULL; pp = np) { + np = pp->ssp_next; + free_snap_page(pp); + } + + sp->ss_pages = NULL; +} + +/* + * Grow (if needed) the control page buffer, fill in the page code, page + * length, and generation count, and return a pointer to the page. The + * caller is responsible for filling in the rest of the page data. If 'unique' + * is specified, then a new page instance is created instead of sharing the + * current one. + */ +ses_snap_page_t * +ses_snap_ctl_page(ses_snap_t *sp, ses2_diag_page_t page, size_t dlen, + boolean_t unique) +{ + ses_target_t *tp = sp->ss_target; + spc3_diag_page_impl_t *pip; + ses_snap_page_t *pp, *up, **loc; + ses_pagedesc_t *dp; + size_t len; + + pp = ses_snap_find_page(sp, page, B_TRUE); + if (pp == NULL) { + (void) ses_set_errno(ESES_NOTSUP); + return (NULL); + } + + if (pp->ssp_initialized && !unique) + return (pp); + + if (unique) { + /* + * The user has requested a unique instance of the page. Create + * a new ses_snap_page_t instance and chain it off the + * 'ssp_instances' list of the master page. These must be + * appended to the end of the chain, as the order of operations + * may be important (i.e. microcode download). + */ + if ((up = alloc_snap_page()) == NULL) + return (NULL); + + up->ssp_num = pp->ssp_num; + up->ssp_control = B_TRUE; + + for (loc = &pp->ssp_unique; *loc != NULL; + loc = &(*loc)->ssp_next) + ; + + *loc = up; + pp = up; + } + + dp = ses_get_pagedesc(tp, page, SES_PAGE_CTL); + ASSERT(dp != NULL); + + len = dp->spd_ctl_len(sp->ss_n_elem, page, dlen); + if (pp->ssp_alloc < dlen && grow_snap_page(pp, len) != 0) + return (NULL); + pp->ssp_len = len; + bzero(pp->ssp_page, len); + pp->ssp_initialized = B_TRUE; + + pip = (spc3_diag_page_impl_t *)pp->ssp_page; + pip->sdpi_page_code = (uint8_t)page; + SCSI_WRITE16(&pip->sdpi_page_length, + len - offsetof(spc3_diag_page_impl_t, sdpi_data[0])); + if (dp->spd_gcoff != -1) + SCSI_WRITE32((uint8_t *)pip + dp->spd_gcoff, sp->ss_generation); + + return (pp); +} + +static int +read_status_page(ses_snap_t *sp, ses2_diag_page_t page) +{ + libscsi_action_t *ap; + ses_snap_page_t *pp; + ses_target_t *tp; + spc3_diag_page_impl_t *pip; + spc3_receive_diagnostic_results_cdb_t *cp; + uint_t flags; + uint8_t *buf; + size_t alloc; + uint_t retries = 0; + ses2_diag_page_t retpage; + + for (pp = sp->ss_pages; pp != NULL; pp = pp->ssp_next) + if (pp->ssp_num == page && !pp->ssp_control) + break; + + /* + * No matching page. Since the page number is not under consumer or + * device control, this must be a bug. + */ + ASSERT(pp != NULL); + + tp = sp->ss_target; + + flags = LIBSCSI_AF_READ | LIBSCSI_AF_SILENT | LIBSCSI_AF_DIAGNOSE | + LIBSCSI_AF_RQSENSE; + +again: + ap = libscsi_action_alloc(tp->st_scsi_hdl, + SPC3_CMD_RECEIVE_DIAGNOSTIC_RESULTS, flags, pp->ssp_page, + pp->ssp_alloc); + + if (ap == NULL) + return (ses_libscsi_error(tp->st_scsi_hdl, "failed to " + "allocate SCSI action")); + + cp = (spc3_receive_diagnostic_results_cdb_t *) + libscsi_action_get_cdb(ap); + + cp->rdrc_page_code = pp->ssp_num; + cp->rdrc_pcv = 1; + SCSI_WRITE16(&cp->rdrc_allocation_length, + MIN(pp->ssp_alloc, UINT16_MAX)); + + if (libscsi_exec(ap, tp->st_target) != 0) { + libscsi_action_free(ap); + return (ses_libscsi_error(tp->st_scsi_hdl, + "receive diagnostic results failed")); + } + + if (libscsi_action_get_status(ap) != 0) { + (void) ses_scsi_error(ap, + "receive diagnostic results failed"); + libscsi_action_free(ap); + return (-1); + } + + (void) libscsi_action_get_buffer(ap, &buf, &alloc, &pp->ssp_len); + libscsi_action_free(ap); + + ASSERT(buf == pp->ssp_page); + ASSERT(alloc == pp->ssp_alloc); + + if (pp->ssp_len == pp->ssp_alloc && pp->ssp_alloc < UINT16_MAX) { + bzero(pp->ssp_page, pp->ssp_len); + pp->ssp_len = 0; + if (grow_snap_page(pp, 0) != 0) + return (-1); + goto again; + } + + pip = (spc3_diag_page_impl_t *)buf; + + if (pip->sdpi_page_code == page) + return (0); + + retpage = pip->sdpi_page_code; + + bzero(pp->ssp_page, pp->ssp_len); + pp->ssp_len = 0; + + if (retpage == SES2_DIAGPAGE_ENCLOSURE_BUSY) { + if (++retries > LIBSES_MAX_BUSY_RETRIES) + return (ses_error(ESES_BUSY, "too many " + "enclosure busy responses for page 0x%x", page)); + goto again; + } + + return (ses_error(ESES_BAD_RESPONSE, "target returned page 0x%x " + "instead of the requested page 0x%x", retpage, page)); +} + +static int +send_control_page(ses_snap_t *sp, ses_snap_page_t *pp) +{ + ses_target_t *tp; + libscsi_action_t *ap; + spc3_send_diagnostic_cdb_t *cp; + uint_t flags; + + tp = sp->ss_target; + + flags = LIBSCSI_AF_WRITE | LIBSCSI_AF_SILENT | LIBSCSI_AF_DIAGNOSE | + LIBSCSI_AF_RQSENSE; + + ap = libscsi_action_alloc(tp->st_scsi_hdl, SPC3_CMD_SEND_DIAGNOSTIC, + flags, pp->ssp_page, pp->ssp_len); + + if (ap == NULL) + return (ses_libscsi_error(tp->st_scsi_hdl, "failed to " + "allocate SCSI action")); + + cp = (spc3_send_diagnostic_cdb_t *)libscsi_action_get_cdb(ap); + + cp->sdc_pf = 1; + SCSI_WRITE16(&cp->sdc_parameter_list_length, pp->ssp_len); + + if (libscsi_exec(ap, tp->st_target) != 0) { + libscsi_action_free(ap); + return (ses_libscsi_error(tp->st_scsi_hdl, + "SEND DIAGNOSTIC command failed for page 0x%x", + pp->ssp_num)); + } + + if (libscsi_action_get_status(ap) != 0) { + (void) ses_scsi_error(ap, "SEND DIAGNOSTIC command " + "failed for page 0x%x", pp->ssp_num); + libscsi_action_free(ap); + return (-1); + } + + libscsi_action_free(ap); + + return (0); +} + +static int +pages_skel_create(ses_snap_t *sp) +{ + ses_snap_page_t *pp, *np; + ses_target_t *tp = sp->ss_target; + ses2_supported_ses_diag_page_impl_t *pip; + ses2_diag_page_t page; + size_t npages; + size_t pagelen; + off_t i; + + ASSERT(sp->ss_pages == NULL); + + if ((pp = alloc_snap_page()) == NULL) + return (-1); + + pp->ssp_num = SES2_DIAGPAGE_SUPPORTED_PAGES; + pp->ssp_control = B_FALSE; + sp->ss_pages = pp; + + if (read_status_page(sp, SES2_DIAGPAGE_SUPPORTED_PAGES) != 0) { + free_snap_page(pp); + sp->ss_pages = NULL; + return (-1); + } + + pip = pp->ssp_page; + pagelen = pp->ssp_len; + + npages = SCSI_READ16(&pip->sssdpi_page_length); + + for (i = 0; i < npages; i++) { + if (!SES_WITHIN_PAGE(pip->sssdpi_pages + i, 1, pip, + pagelen)) + break; + + page = (ses2_diag_page_t)pip->sssdpi_pages[i]; + /* + * Skip the page we already added during the bootstrap. + */ + if (page == SES2_DIAGPAGE_SUPPORTED_PAGES) + continue; + /* + * The end of the page list may be padded with zeros; ignore + * them all. + */ + if (page == 0 && i > 0) + break; + if ((np = alloc_snap_page()) == NULL) { + free_all_snap_pages(sp); + return (-1); + } + np->ssp_num = page; + pp->ssp_next = np; + pp = np; + + /* + * Allocate a control page as well, if we can use it. + */ + if (ses_get_pagedesc(tp, page, SES_PAGE_CTL) != NULL) { + if ((np = alloc_snap_page()) == NULL) { + free_all_snap_pages(sp); + return (-1); + } + np->ssp_num = page; + np->ssp_control = B_TRUE; + pp->ssp_next = np; + pp = np; + } + } + + return (0); +} + +static void +ses_snap_free(ses_snap_t *sp) +{ + free_all_snap_pages(sp); + ses_node_teardown(sp->ss_root); + ses_free(sp->ss_nodes); + ses_free(sp); +} + +static void +ses_snap_rele_unlocked(ses_snap_t *sp) +{ + ses_target_t *tp = sp->ss_target; + + if (--sp->ss_refcnt != 0) + return; + + if (sp->ss_next != NULL) + sp->ss_next->ss_prev = sp->ss_prev; + + if (sp->ss_prev != NULL) + sp->ss_prev->ss_next = sp->ss_next; + else + tp->st_snapshots = sp->ss_next; + + ses_snap_free(sp); +} + +ses_snap_t * +ses_snap_hold(ses_target_t *tp) +{ + ses_snap_t *sp; + + (void) pthread_mutex_lock(&tp->st_lock); + sp = tp->st_snapshots; + sp->ss_refcnt++; + (void) pthread_mutex_unlock(&tp->st_lock); + + return (sp); +} + +void +ses_snap_rele(ses_snap_t *sp) +{ + ses_target_t *tp = sp->ss_target; + + (void) pthread_mutex_lock(&tp->st_lock); + ses_snap_rele_unlocked(sp); + (void) pthread_mutex_unlock(&tp->st_lock); +} + +ses_snap_t * +ses_snap_new(ses_target_t *tp) +{ + ses_snap_t *sp; + ses_snap_page_t *pp; + uint32_t gc; + uint_t retries = 0; + ses_pagedesc_t *dp; + size_t pages, pagesize, pagelen; + char *scratch; + + if ((sp = ses_zalloc(sizeof (ses_snap_t))) == NULL) + return (NULL); + + sp->ss_target = tp; + +again: + free_all_snap_pages(sp); + + if (pages_skel_create(sp) != 0) { + free(sp); + return (NULL); + } + + sp->ss_generation = (uint32_t)-1; + sp->ss_time = gethrtime(); + + for (pp = sp->ss_pages; pp != NULL; pp = pp->ssp_next) { + /* + * We skip all of: + * + * - Control pages + * - Pages we've already filled in + * - Pages we don't understand (those with no descriptor) + */ + if (pp->ssp_len > 0 || pp->ssp_control) + continue; + if ((dp = ses_get_pagedesc(tp, pp->ssp_num, + SES_PAGE_DIAG)) == NULL) + continue; + + if (read_status_page(sp, pp->ssp_num) != 0) + continue; + + /* + * If the generation code has changed, we don't have a valid + * snapshot. Start over. + */ + if (dp->spd_gcoff != -1 && + dp->spd_gcoff + 4 <= pp->ssp_len) { + gc = SCSI_READ32((uint8_t *)pp->ssp_page + + dp->spd_gcoff); + if (sp->ss_generation == (uint32_t)-1) { + sp->ss_generation = gc; + } else if (sp->ss_generation != gc) { + if (++retries > LIBSES_MAX_GC_RETRIES) { + (void) ses_error(ESES_TOOMUCHCHANGE, + "too many generation count " + "mismatches: page 0x%x gc %u " + "previous page %u", dp->spd_gcoff, + gc, sp->ss_generation); + ses_snap_free((ses_snap_t *)sp); + return (NULL); + } + goto again; + } + } + } + + /* + * The LIBSES_TRUNCATE environment variable is a debugging tool which, + * if set, randomly truncates all pages (except + * SES2_DIAGPAGE_SUPPORTED_PAGES). In order to be truly evil, we + * mmap() each page with enough space after it so we can move the data + * up to the end of a page and unmap the following page so that any + * attempt to read past the end of the page results in a segfault. + */ + if (sp->ss_target->st_truncate) { + pagesize = PAGESIZE; + + /* + * Count the maximum number of pages we will need and allocate + * the necessary space. + */ + pages = 0; + for (pp = sp->ss_pages; pp != NULL; pp = pp->ssp_next) { + if (pp->ssp_control || pp->ssp_len == 0) + continue; + + pages += (P2ROUNDUP(pp->ssp_len, pagesize) / + pagesize) + 1; + } + + if ((scratch = mmap(NULL, pages * pagesize, + PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, + -1, 0)) == MAP_FAILED) { + (void) ses_error(ESES_NOMEM, + "failed to mmap() pages for truncation"); + ses_snap_free(sp); + return (NULL); + } + + for (pp = sp->ss_pages; pp != NULL; pp = pp->ssp_next) { + if (pp->ssp_control || pp->ssp_len == 0) + continue; + + pages = P2ROUNDUP(pp->ssp_len, pagesize) / pagesize; + pp->ssp_mmap_base = scratch; + pp->ssp_mmap_len = pages * pagesize; + + pagelen = lrand48() % pp->ssp_len; + (void) memcpy(pp->ssp_mmap_base + pp->ssp_mmap_len - + pagelen, pp->ssp_page, pagelen); + ses_free(pp->ssp_page); + pp->ssp_page = pp->ssp_mmap_base + pp->ssp_mmap_len - + pagelen; + pp->ssp_len = pagelen; + + (void) munmap(pp->ssp_mmap_base + pages * pagesize, + pagesize); + scratch += (pages + 1) * pagesize; + } + } + + + if (ses_fill_snap(sp) != 0) { + ses_snap_free(sp); + return (NULL); + } + + (void) pthread_mutex_lock(&tp->st_lock); + if (tp->st_snapshots != NULL) + ses_snap_rele_unlocked(tp->st_snapshots); + sp->ss_next = tp->st_snapshots; + if (tp->st_snapshots != NULL) + tp->st_snapshots->ss_prev = sp; + tp->st_snapshots = sp; + sp->ss_refcnt = 2; + (void) pthread_mutex_unlock(&tp->st_lock); + + return (sp); +} + +int +ses_snap_do_ctl(ses_snap_t *sp) +{ + ses_snap_page_t *pp, *up; + int ret = -1; + + for (pp = sp->ss_pages; pp != NULL; pp = pp->ssp_next) { + if (!pp->ssp_control) + continue; + + if (pp->ssp_initialized && send_control_page(sp, pp) != 0) + goto error; + + for (up = pp->ssp_unique; up != NULL; up = up->ssp_next) { + if (send_control_page(sp, up) != 0) + goto error; + } + } + + ret = 0; +error: + for (pp = sp->ss_pages; pp != NULL; pp = pp->ssp_next) { + if (!pp->ssp_control) + continue; + + pp->ssp_initialized = B_FALSE; + while ((up = pp->ssp_unique) != NULL) { + pp->ssp_unique = up->ssp_next; + free_snap_page(up); + } + } + + + return (ret); +} + +uint32_t +ses_snap_generation(ses_snap_t *sp) +{ + return (sp->ss_generation); +} + +static ses_walk_action_t +ses_walk_node(ses_node_t *np, ses_walk_f func, void *arg) +{ + ses_walk_action_t action; + + for (; np != NULL; np = ses_node_sibling(np)) { + action = func(np, arg); + if (action == SES_WALK_ACTION_TERMINATE) + return (SES_WALK_ACTION_TERMINATE); + if (action == SES_WALK_ACTION_PRUNE || + ses_node_child(np) == NULL) + continue; + if (ses_walk_node(ses_node_child(np), func, arg) == + SES_WALK_ACTION_TERMINATE) + return (SES_WALK_ACTION_TERMINATE); + } + + return (SES_WALK_ACTION_CONTINUE); +} + +int +ses_walk(ses_snap_t *sp, ses_walk_f func, void *arg) +{ + (void) ses_walk_node(ses_root_node(sp), func, arg); + + return (0); +} + +/*ARGSUSED*/ +static ses_walk_action_t +ses_fill_nodes(ses_node_t *np, void *unused) +{ + np->sn_snapshot->ss_nodes[np->sn_id] = np; + + return (SES_WALK_ACTION_CONTINUE); +} + +/* + * Given an ID returned by ses_node_id(), lookup and return the corresponding + * node in the snapshot. If the snapshot generation count has changed, then + * return failure. + */ +ses_node_t * +ses_node_lookup(ses_snap_t *sp, uint64_t id) +{ + uint32_t gen = (id >> 32); + uint32_t idx = (id & 0xFFFFFFFF); + + if (sp->ss_generation != gen) { + (void) ses_set_errno(ESES_CHANGED); + return (NULL); + } + + if (idx >= sp->ss_n_nodes) { + (void) ses_error(ESES_BAD_NODE, + "no such node in snapshot"); + return (NULL); + } + + /* + * If this is our first lookup attempt, construct the array for fast + * lookups. + */ + if (sp->ss_nodes == NULL) { + if ((sp->ss_nodes = ses_zalloc( + sp->ss_n_nodes * sizeof (void *))) == NULL) + return (NULL); + + (void) ses_walk(sp, ses_fill_nodes, NULL); + } + + if (sp->ss_nodes[idx] == NULL) + (void) ses_error(ESES_BAD_NODE, + "no such node in snapshot"); + return (sp->ss_nodes[idx]); +} diff --git a/usr/src/lib/scsi/libses/common/ses_subr.c b/usr/src/lib/scsi/libses/common/ses_subr.c new file mode 100644 index 0000000000..aa1013e678 --- /dev/null +++ b/usr/src/lib/scsi/libses/common/ses_subr.c @@ -0,0 +1,376 @@ +/* + * 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 <scsi/libses.h> +#include "ses_impl.h" + +__thread ses_errno_t _ses_errno; +__thread char _ses_errmsg[1024]; +__thread char _ses_nverr_member[256]; + +static void ses_vpanic(const char *, va_list) __NORETURN; + +static void +ses_vpanic(const char *fmt, va_list ap) +{ + int oserr = errno; + char msg[BUFSIZ]; + size_t len; + + (void) snprintf(msg, sizeof (msg), "ABORT: "); + len = strlen(msg); + (void) vsnprintf(msg + len, sizeof (msg) - len, fmt, ap); + + if (strchr(fmt, '\n') == NULL) { + len = strlen(msg); + (void) snprintf(msg + len, sizeof (msg) - len, ": %s\n", + strerror(oserr)); + } + + (void) write(STDERR_FILENO, msg, strlen(msg)); + +abort: + abort(); + _exit(1); +} + +/*PRINTFLIKE1*/ +void +ses_panic(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + ses_vpanic(fmt, ap); + va_end(ap); +} + +int +ses_assert(const char *expr, const char *file, int line) +{ + ses_panic("\"%s\", line %d: assertion failed: %s\n", file, line, expr); + + /*NOTREACHED*/ + return (0); +} + +int +nvlist_add_fixed_string(nvlist_t *nvl, const char *name, + const char *buf, size_t len) +{ + char *str = alloca(len + 1); + bcopy(buf, str, len); + str[len] = '\0'; + + return (nvlist_add_string(nvl, name, str)); +} + +/* + * Like fixed_string, but clears any leading or trailing spaces. + */ +int +nvlist_add_fixed_string_trunc(nvlist_t *nvl, const char *name, + const char *buf, size_t len) +{ + while (buf[0] == ' ' && len > 0) { + buf++; + len--; + } + + while (len > 0 && buf[len - 1] == ' ') + len--; + + return (nvlist_add_fixed_string(nvl, name, buf, len)); +} + +ses_errno_t +ses_errno(void) +{ + return (_ses_errno); +} + +const char * +ses_errmsg(void) +{ + if (_ses_errmsg[0] == '\0') + (void) snprintf(_ses_errmsg, sizeof (_ses_errmsg), "%s", + ses_strerror(_ses_errno)); + + return (_ses_errmsg); +} + +const char * +ses_nv_error_member(void) +{ + if (_ses_nverr_member[0] != '\0') + return (_ses_nverr_member); + else + return (NULL); +} + +static int +__ses_set_errno(ses_errno_t err, const char *nvm) +{ + if (nvm == NULL) { + _ses_nverr_member[0] = '\0'; + } else { + (void) strlcpy(_ses_nverr_member, nvm, + sizeof (_ses_nverr_member)); + } + _ses_errmsg[0] = '\0'; + _ses_errno = err; + + return (-1); +} + +int +ses_set_errno(ses_errno_t err) +{ + return (__ses_set_errno(err, NULL)); +} + +int +ses_set_nverrno(int err, const char *member) +{ + ses_errno_t se = (err == ENOMEM || err == EAGAIN) ? + ESES_NOMEM : ESES_NVL; + + /* + * If the error is ESES_NVL, then we should always have a member + * available. The only time 'member' is NULL is when nvlist_alloc() + * fails, which should only be possible if memory allocation fails. + */ + assert(se == ESES_NOMEM || member != NULL); + + return (__ses_set_errno(se, member)); +} + +static int +ses_verror(ses_errno_t err, const char *fmt, va_list ap) +{ + int syserr = errno; + size_t n; + char *errmsg; + + errmsg = alloca(sizeof (_ses_errmsg)); + (void) vsnprintf(errmsg, sizeof (_ses_errmsg), fmt, ap); + (void) ses_set_errno(err); + + n = strlen(errmsg); + + while (n != 0 && errmsg[n - 1] == '\n') + errmsg[--n] = '\0'; + + bcopy(errmsg, _ses_errmsg, sizeof (_ses_errmsg)); + errno = syserr; + + return (-1); +} + +static int +ses_vnverror(int err, const char *member, const char *fmt, + va_list ap) +{ + int syserr = errno; + size_t n; + char *errmsg; + + errmsg = alloca(sizeof (_ses_errmsg)); + (void) vsnprintf(errmsg, sizeof (_ses_errmsg), fmt, ap); + (void) ses_set_nverrno(err, member); + + n = strlen(errmsg); + + while (n != 0 && errmsg[n - 1] == '\n') + errmsg[--n] = '\0'; + + (void) snprintf(errmsg + n, sizeof (_ses_errmsg) - n, ": %s", + strerror(err)); + + bcopy(errmsg, _ses_errmsg, sizeof (_ses_errmsg)); + errno = syserr; + + return (-1); +} + +int +ses_error(ses_errno_t err, const char *fmt, ...) +{ + va_list ap; + int rv; + + va_start(ap, fmt); + rv = ses_verror(err, fmt, ap); + va_end(ap); + + return (rv); +} + +int +ses_nverror(int err, const char *member, const char *fmt, ...) +{ + va_list ap; + int rv; + + va_start(ap, fmt); + rv = ses_vnverror(err, member, fmt, ap); + va_end(ap); + + return (rv); +} + +int +ses_libscsi_error(libscsi_hdl_t *shp, const char *fmt, ...) +{ + va_list ap; + char errmsg[LIBSES_ERRMSGLEN]; + libscsi_errno_t se = libscsi_errno(shp); + ses_errno_t e; + + switch (se) { + case ESCSI_NONE: + return (0); + case ESCSI_NOMEM: + e = ESES_NOMEM; + break; + case ESCSI_NOTSUP: + e = ESES_NOTSUP; + break; + case ESCSI_ZERO_LENGTH: + case ESCSI_VERSION: + case ESCSI_BADFLAGS: + case ESCSI_BOGUSFLAGS: + case ESCSI_BADLENGTH: + case ESCSI_NEEDBUF: + va_start(ap, fmt); + (void) vsnprintf(errmsg, sizeof (errmsg), fmt, ap); + va_end(ap); + ses_panic("%s: unexpected libscsi error %s: %s", errmsg, + libscsi_errname(se), libscsi_errmsg(shp)); + break; + case ESCSI_UNKNOWN: + e = ESES_UNKNOWN; + break; + default: + e = ESES_LIBSCSI; + break; + } + + va_start(ap, fmt); + (void) vsnprintf(errmsg, sizeof (errmsg), fmt, ap); + va_end(ap); + + return (ses_error(e, "%s: %s", errmsg, libscsi_errmsg(shp))); +} + +int +ses_scsi_error(libscsi_action_t *ap, const char *fmt, ...) +{ + va_list args; + char errmsg[LIBSES_ERRMSGLEN]; + uint64_t asc = 0, ascq = 0, key = 0; + const char *code, *keystr; + + va_start(args, fmt); + (void) vsnprintf(errmsg, sizeof (errmsg), fmt, args); + va_end(args); + + if (libscsi_action_parse_sense(ap, &key, &asc, &ascq, NULL) != 0) + return (ses_error(ESES_LIBSCSI, + "%s: SCSI status %d (no sense data available)", errmsg, + libscsi_action_get_status(ap))); + + code = libscsi_sense_code_name(asc, ascq); + keystr = libscsi_sense_key_name(key); + + return (ses_error(ESES_LIBSCSI, "%s: SCSI status %d sense key %llu " + "(%s) additional sense code 0x%llx/0x%llx (%s)", errmsg, + libscsi_action_get_status(ap), key, keystr ? keystr : "<unknown>", + asc, ascq, code ? code : "<unknown>")); +} + +void * +ses_alloc(size_t sz) +{ + void *p; + + if (sz == 0) + ses_panic("attempted zero-length allocation"); + + if ((p = malloc(sz)) == NULL) + (void) ses_set_errno(ESES_NOMEM); + + return (p); +} + +void * +ses_zalloc(size_t sz) +{ + void *p; + + if ((p = ses_alloc(sz)) != NULL) + bzero(p, sz); + + return (p); +} + +char * +ses_strdup(const char *s) +{ + char *p; + size_t len; + + if (s == NULL) + ses_panic("attempted zero-length allocation"); + + len = strlen(s) + 1; + + if ((p = ses_alloc(len)) != NULL) + bcopy(s, p, len); + + return (p); +} + +void * +ses_realloc(void *p, size_t sz) +{ + if (sz == 0) + ses_panic("attempted zero-length allocation"); + + if ((p = realloc(p, sz)) == NULL) + (void) ses_set_errno(ESES_NOMEM); + + return (p); +} + +/*ARGSUSED*/ +void +ses_free(void *p) +{ + free(p); +} diff --git a/usr/src/lib/scsi/libses/i386/Makefile b/usr/src/lib/scsi/libses/i386/Makefile new file mode 100644 index 0000000000..b2454048f0 --- /dev/null +++ b/usr/src/lib/scsi/libses/i386/Makefile @@ -0,0 +1,36 @@ +# +# 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" + +include ../Makefile.com +include ../../../Makefile.lib +include ../Makefile.defs + +DYNFLAGS += $(DYNFLAGS32) + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) + +include ../Makefile.targ diff --git a/usr/src/lib/scsi/libses/libses_api.map b/usr/src/lib/scsi/libses/libses_api.map new file mode 100644 index 0000000000..a66e641061 --- /dev/null +++ b/usr/src/lib/scsi/libses/libses_api.map @@ -0,0 +1,69 @@ +# +# 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" + +{ + ses_close = FUNCTION extern; + ses_errno = FUNCTION extern; + ses_errmsg = FUNCTION extern; + ses_node_child = FUNCTION extern; + ses_node_id = FUNCTION extern; + ses_node_lookup = FUNCTION extern; + ses_node_parent = FUNCTION extern; + ses_node_props = FUNCTION extern; + ses_node_prev_sibling = FUNCTION extern; + ses_node_sibling = FUNCTION extern; + ses_node_snapshot = FUNCTION extern; + ses_node_target = FUNCTION extern; + ses_node_type = FUNCTION extern; + ses_open = FUNCTION extern; + ses_root_node = FUNCTION extern; + ses_scsi_target = FUNCTION extern; + ses_snap_generation = FUNCTION extern; + ses_strerror = FUNCTION extern; + ses_walk = FUNCTION extern; + + nvlist_add_fixed_string = FUNCTION extern; + nvlist_add_fixed_string_trunc = FUNCTION extern; + + ses_alloc = FUNCTION extern; + ses_assert = FUNCTION extern; + ses_error = FUNCTION extern; + ses_free = FUNCTION extern; + ses_nverror = FUNCTION extern; + ses_panic = FUNCTION extern; + ses_realloc = FUNCTION extern; + ses_set_nverrno = FUNCTION extern; + ses_set_errno = FUNCTION extern; + ses_strdup = FUNCTION extern; + ses_zalloc = FUNCTION extern; + + ses_plugin_ctlpage_lookup = FUNCTION extern; + ses_plugin_page_lookup = FUNCTION extern; + ses_plugin_register = FUNCTION extern; + ses_plugin_setspecific = FUNCTION extern; + ses_plugin_getspecific = FUNCTION extern; +}; diff --git a/usr/src/lib/scsi/libses/llib-lses b/usr/src/lib/scsi/libses/llib-lses new file mode 100644 index 0000000000..c274b8ad3b --- /dev/null +++ b/usr/src/lib/scsi/libses/llib-lses @@ -0,0 +1,32 @@ +/* + * 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" + +/*LINTLIBRARY*/ +/*PROTOLIB1*/ + +#include <scsi/libses.h> diff --git a/usr/src/lib/scsi/libses/mapfile-vers b/usr/src/lib/scsi/libses/mapfile-vers new file mode 100644 index 0000000000..9048c11068 --- /dev/null +++ b/usr/src/lib/scsi/libses/mapfile-vers @@ -0,0 +1,77 @@ +# +# 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" + +SUNWprivate_1.1 { + global: + ses_close; + ses_errno; + ses_errmsg; + ses_node_child; + ses_node_ctl; + ses_node_id; + ses_node_lookup; + ses_node_parent; + ses_node_props; + ses_node_prev_sibling; + ses_node_sibling; + ses_node_snapshot; + ses_node_target; + ses_node_type; + ses_open; + ses_open_scsi; + ses_root_node; + ses_scsi_target; + ses_snap_generation; + ses_snap_hold; + ses_snap_new; + ses_snap_rele; + ses_strerror; + ses_walk; + + nvlist_add_fixed_string; + nvlist_add_fixed_string_trunc; + + ses_alloc; + ses_assert; + ses_error; + ses_free; + ses_nverror; + ses_panic; + ses_realloc; + ses_set_errno; + ses_set_nverrno; + ses_strdup; + ses_zalloc; + + ses_plugin_ctlpage_lookup; + ses_plugin_page_lookup; + ses_plugin_register; + ses_plugin_setspecific; + ses_plugin_getspecific; + local: + *; +}; diff --git a/usr/src/lib/scsi/libses/sparc/Makefile b/usr/src/lib/scsi/libses/sparc/Makefile new file mode 100644 index 0000000000..b2454048f0 --- /dev/null +++ b/usr/src/lib/scsi/libses/sparc/Makefile @@ -0,0 +1,36 @@ +# +# 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" + +include ../Makefile.com +include ../../../Makefile.lib +include ../Makefile.defs + +DYNFLAGS += $(DYNFLAGS32) + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) + +include ../Makefile.targ diff --git a/usr/src/lib/scsi/libses/sparcv9/Makefile b/usr/src/lib/scsi/libses/sparcv9/Makefile new file mode 100644 index 0000000000..aaa948e5ae --- /dev/null +++ b/usr/src/lib/scsi/libses/sparcv9/Makefile @@ -0,0 +1,36 @@ +# +# 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" + +include ../Makefile.com +include ../../../Makefile.lib +include ../../../Makefile.lib.64 +include ../Makefile.defs +include ../Makefile.defs.64 + +install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64) + +include ../Makefile.targ diff --git a/usr/src/lib/scsi/plugins/Makefile b/usr/src/lib/scsi/plugins/Makefile new file mode 100644 index 0000000000..3541ca3744 --- /dev/null +++ b/usr/src/lib/scsi/plugins/Makefile @@ -0,0 +1,36 @@ +# +# 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" + +SUBDIRS = \ + scsi \ + ses + +.KEEP_STATE: + +.PARALLEL: + +include ../Makefile.subdirs diff --git a/usr/src/lib/scsi/plugins/scsi/Makefile b/usr/src/lib/scsi/plugins/scsi/Makefile new file mode 100644 index 0000000000..cc22333827 --- /dev/null +++ b/usr/src/lib/scsi/plugins/scsi/Makefile @@ -0,0 +1,35 @@ +# +# 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" + +SUBDIRS = \ + engines + +.KEEP_STATE: + +.PARALLEL: + +include ../../Makefile.subdirs diff --git a/usr/src/lib/scsi/plugins/scsi/engines/Makefile b/usr/src/lib/scsi/plugins/scsi/engines/Makefile new file mode 100644 index 0000000000..ffde5cc3ed --- /dev/null +++ b/usr/src/lib/scsi/plugins/scsi/engines/Makefile @@ -0,0 +1,32 @@ +# +# 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" +# + +SUBDIRS = \ + uscsi + +include ../../../Makefile.subdirs diff --git a/usr/src/lib/scsi/plugins/scsi/engines/Makefile.engine b/usr/src/lib/scsi/plugins/scsi/engines/Makefile.engine new file mode 100644 index 0000000000..f48357fef2 --- /dev/null +++ b/usr/src/lib/scsi/plugins/scsi/engines/Makefile.engine @@ -0,0 +1,76 @@ +# +# 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" + +.KEEP_STATE: +.SUFFIXES: + +include ../../../../../../../cmd/Makefile.cmd +include ../../../../../Makefile.defs + +# +# Set PROG and OBJS based on the values of MODULE and SRCS. We expect that +# these macros to be defined by the Makefile that is including this file. +# +PROG = $(MODULE:%=%.so) +YOBJS = $(YSRCS:%.y=%.o) +OBJS = $(YOBJS) $(SRCS:%.c=%.o) + +# +# A module may set DMOD and DMOD_SRCS if it has a mdb proc module. +# DMOD, if set, must match PROG above (for mdb autoloading) so it will +# be built in a subdirectory. +# +ROOTDMOD = $(DMOD:%.so=$(ROOT)/usr/lib/mdb/proc/%.so) +ROOTDMOD64 = $(DMOD:%.so=$(ROOT)/usr/lib/mdb/proc/$(MACH64)/%.so) +DMODPROG = $(DMOD:%=dmod/%) +DMOD_OBJS = $(DMOD_SRCS:%.c=%.o) + +ROOTPROG = $(ROOTPLUGINLIBDIR)/scsi/engines/$(PROG) +ROOTPROG64 = $(ROOTPLUGINLIBDIR)/scsi/engines/$(MACH64)/$(PROG) + +LINTFLAGS += -mu +LINTFILES = $(SRCS:%.c=%.ln) + +DMODLINTTGT = $(DMOD:%=lint_dmod) +DMODLINTFILES = $(DMOD_SRCS:%.c=%.ln) + +APIMAP = ../../../../../libscsi/libscsi_api.map + +C99MODE = $(C99_ENABLE) +CFLAGS += $(CTF_FLAGS) $(CCVERBOSE) $(XSTRCONST) $(CC_PICFLAGS) +CFLAGS += -G $(XREGSFLAG) +CFLAGS64 += $(CTF_FLAGS) $(CCVERBOSE) $(XSTRCONST) $(CC_PICFLAGS) +CFLAGS64 += -G $(XREGSFLAG) +CPPFLAGS += -D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT +CPPFLAGS += -I../../../../../libscsi/common +$(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG +LDFLAGS += $(ZTEXT) $(ZCOMBRELOC) $(ZIGNORE) + +$(PROG) := LDFLAGS += $(ZDEFS) -M$(APIMAP) +$(PROG) := LDLIBS += -lc + +$(DMODPROG) := LDFLAGS += $(ZNODEFS) diff --git a/usr/src/lib/scsi/plugins/scsi/engines/Makefile.targ b/usr/src/lib/scsi/plugins/scsi/engines/Makefile.targ new file mode 100644 index 0000000000..69a1ce2a30 --- /dev/null +++ b/usr/src/lib/scsi/plugins/scsi/engines/Makefile.targ @@ -0,0 +1,82 @@ +# +# 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" + +all: $(PROG) $(DMODPROG) + +.NO_PARALLEL: +.PARALLEL: $(OBJS) $(LINTFILES) $(DMOD_OBJS) $(DMODLINTFILES) + +$(PROG): $(OBJS) $(APIMAP) + $(LINK.c) $(OBJS) -o $@ $(LDLIBS) + $(CTFMERGE) -L VERSION -o $@ $(OBJS) + $(POST_PROCESS_SO) + +$(DMODPROG): $(DMOD_OBJS) + -@mkdir -p $(@D) + $(LINK.c) $(DMOD_OBJS) -o $@ + $(POST_PROCESS) + +%.o: %.c + $(COMPILE.c) $< + $(CTFCONVERT_O) + +%.o: ../%.c + $(COMPILE.c) $< + $(CTFCONVERT_O) + +clean: + $(RM) $(OBJS) $(DMOD_OBJS) $(LINTFILES) $(DMODLINTFILES) $(CLEANFILES) + +clobber: clean + $(RM) $(PROG) $(DMODPROG) + +%.ln: %.c + $(LINT.c) -c $< + +%.ln: ../%.c + $(LINT.c) -c $< + +lint_prog: $(LINTFILES) + $(LINT) $(LINTFLAGS) $(LINTFILES) $(LDLIBS) + +lint_dmod: $(DMODLINTFILES) + $(LINT) $(LINTFLAGS) $(DMODLINTFILES) $(LDLIBS) + +lint: lint_prog $(DMODLINTTGT) + +install_h: + +$(ROOTPROG): $$(@D) $(PROG) + $(RM) $@; $(INS) -s -m 0755 -f $(@D) $(PROG) + +$(ROOTPROG64): $$(@D) $(PROG) + $(RM) $@; $(INS) -s -m 0755 -f $(@D) $(PROG) + +$(ROOTDMOD): $$(@D) $(DMODPROG) + $(RM) $@; $(INS) -s -m 0755 -f $(@D) $(DMODPROG) + +include ../../../../../Makefile.rootdirs diff --git a/usr/src/lib/scsi/plugins/scsi/engines/uscsi/Makefile b/usr/src/lib/scsi/plugins/scsi/engines/uscsi/Makefile new file mode 100644 index 0000000000..ae7db6b449 --- /dev/null +++ b/usr/src/lib/scsi/plugins/scsi/engines/uscsi/Makefile @@ -0,0 +1,51 @@ +# +# 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" + +include $(SRC)/Makefile.master + +SUBDIRS = $(MACH) +$(BUILD64)SUBDIRS += $(MACH64) + +all := TARGET= all +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install +lint := TARGET= lint +install_h:= TARGET = install_h + +.KEEP_STATE: + +all install clean clobber lint: $(SUBDIRS) + +install_h check: + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + +include ../../../../../Makefile.targ diff --git a/usr/src/lib/scsi/plugins/scsi/engines/uscsi/Makefile.com b/usr/src/lib/scsi/plugins/scsi/engines/uscsi/Makefile.com new file mode 100644 index 0000000000..ed98d38b11 --- /dev/null +++ b/usr/src/lib/scsi/plugins/scsi/engines/uscsi/Makefile.com @@ -0,0 +1,31 @@ +# +# 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" + +MODULE = uscsi +SRCS = uscsi.c + +include ../../Makefile.engine diff --git a/usr/src/lib/scsi/plugins/scsi/engines/uscsi/amd64/Makefile b/usr/src/lib/scsi/plugins/scsi/engines/uscsi/amd64/Makefile new file mode 100644 index 0000000000..79a0acb9a2 --- /dev/null +++ b/usr/src/lib/scsi/plugins/scsi/engines/uscsi/amd64/Makefile @@ -0,0 +1,33 @@ +# +# 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" + +include ../Makefile.com +include $(SRC)/Makefile.master.64 + +install: all $(ROOTPROG64) + +include ../../Makefile.targ diff --git a/usr/src/lib/scsi/plugins/scsi/engines/uscsi/i386/Makefile b/usr/src/lib/scsi/plugins/scsi/engines/uscsi/i386/Makefile new file mode 100644 index 0000000000..9dd4af0d55 --- /dev/null +++ b/usr/src/lib/scsi/plugins/scsi/engines/uscsi/i386/Makefile @@ -0,0 +1,32 @@ +# +# 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" + +include ../Makefile.com + +install: all $(ROOTPROG) + +include ../../Makefile.targ diff --git a/usr/src/lib/scsi/plugins/scsi/engines/uscsi/sparc/Makefile b/usr/src/lib/scsi/plugins/scsi/engines/uscsi/sparc/Makefile new file mode 100644 index 0000000000..9dd4af0d55 --- /dev/null +++ b/usr/src/lib/scsi/plugins/scsi/engines/uscsi/sparc/Makefile @@ -0,0 +1,32 @@ +# +# 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" + +include ../Makefile.com + +install: all $(ROOTPROG) + +include ../../Makefile.targ diff --git a/usr/src/lib/scsi/plugins/scsi/engines/uscsi/sparcv9/Makefile b/usr/src/lib/scsi/plugins/scsi/engines/uscsi/sparcv9/Makefile new file mode 100644 index 0000000000..79a0acb9a2 --- /dev/null +++ b/usr/src/lib/scsi/plugins/scsi/engines/uscsi/sparcv9/Makefile @@ -0,0 +1,33 @@ +# +# 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" + +include ../Makefile.com +include $(SRC)/Makefile.master.64 + +install: all $(ROOTPROG64) + +include ../../Makefile.targ diff --git a/usr/src/lib/scsi/plugins/scsi/engines/uscsi/uscsi.c b/usr/src/lib/scsi/plugins/scsi/engines/uscsi/uscsi.c new file mode 100644 index 0000000000..06cdb0b339 --- /dev/null +++ b/usr/src/lib/scsi/plugins/scsi/engines/uscsi/uscsi.c @@ -0,0 +1,235 @@ +/* + * 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/scsi/impl/uscsi.h> +#include <sys/scsi/generic/commands.h> + +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include <strings.h> +#include <stdio.h> +#include <limits.h> + +#include <scsi/libscsi.h> +#include "libscsi_impl.h" + +struct uscsi_dev { + int fd; + char *dev; +}; + +static void * +uscsi_open(libscsi_hdl_t *hp, const void *target) +{ + struct uscsi_dev *dp; + const char *target_name = (const char *)target; + + if ((dp = libscsi_zalloc(hp, sizeof (struct uscsi_dev))) == NULL) + return (NULL); + + if ((dp->dev = libscsi_strdup(hp, target_name)) == NULL) { + libscsi_free(hp, dp); + return (NULL); + } + + if ((dp->fd = open(target_name, O_RDONLY)) < 0) { + (void) libscsi_error(hp, ESCSI_BADTARGET, "failed to open %s " + "for reading: %s", target_name, strerror(errno)); + libscsi_free(hp, dp->dev); + libscsi_free(hp, dp); + return (NULL); + } + + return (dp); +} + +static void +uscsi_close(libscsi_hdl_t *hp, void *private) +{ + struct uscsi_dev *dp = (struct uscsi_dev *)private; + + if (dp == NULL) + return; + + if (dp->fd > 0) + (void) close(dp->fd); + + libscsi_free(hp, dp->dev); + libscsi_free(hp, dp); +} + +static int +xlate_flags(libscsi_hdl_t *hp, uint_t flags, int *uf) +{ + uint_t f; + int i; + + f = 0; + + for (i = 0; i < sizeof (flags) * 8; i++) { + switch (flags & (1 << i)) { + case 0: + continue; + case LIBSCSI_AF_READ: + f |= USCSI_READ; + break; + case LIBSCSI_AF_WRITE: + f |= USCSI_WRITE; + break; + case LIBSCSI_AF_SILENT: + f |= USCSI_SILENT; + break; + case LIBSCSI_AF_DIAGNOSE: + f |= USCSI_DIAGNOSE; + break; + case LIBSCSI_AF_ISOLATE: + f = USCSI_ISOLATE; + break; + case LIBSCSI_AF_RQSENSE: + f = USCSI_RQENABLE; + break; + default: + return (libscsi_error(hp, ESCSI_BOGUSFLAGS, + "flag 0x%x is unknown", 1 << i)); + } + } + + *uf = f; + + return (0); +} + +static int +uscsi_exec(libscsi_hdl_t *hp, void *private, libscsi_action_t *ap) +{ + struct uscsi_dev *dp = (struct uscsi_dev *)private; + struct uscsi_cmd cmd; + size_t data_a, data_v; + uint8_t *cp; + uint_t flags; + + bzero(&cmd, sizeof (cmd)); + + cp = libscsi_action_get_cdb(ap); + if (cp == NULL) + return (-1); + + flags = libscsi_action_get_flags(ap); + if (xlate_flags(hp, flags, &cmd.uscsi_flags) != 0) + return (-1); + + cmd.uscsi_status = (short)-1; + cmd.uscsi_timeout = (short)libscsi_action_get_timeout(ap); + + cmd.uscsi_cdb = (caddr_t)cp; + cmd.uscsi_cdblen = libscsi_cmd_cdblen(hp, *cp); + if (cmd.uscsi_cdblen == 0) + return (-1); + + if (flags & (LIBSCSI_AF_READ | LIBSCSI_AF_WRITE)) { + if (libscsi_action_get_buffer(ap, + (uint8_t **)&cmd.uscsi_bufaddr, &data_a, &data_v) != 0) + return (-1); + if (flags & LIBSCSI_AF_READ) + cmd.uscsi_buflen = data_a; + else + cmd.uscsi_buflen = data_v; + } + if (flags & LIBSCSI_AF_RQSENSE) { + if (libscsi_action_get_sense(ap, (uint8_t **)&cmd.uscsi_rqbuf, + &data_a, NULL) != 0) + return (-1); + if (data_a > UCHAR_MAX) + data_a = UCHAR_MAX; + cmd.uscsi_rqlen = (uchar_t)data_a; + cmd.uscsi_rqstatus = (uchar_t)-1; + } + + if (ioctl(dp->fd, USCSICMD, &cmd) < 0) { + ASSERT(errno != EFAULT); + switch (errno) { + case EINVAL: + return (libscsi_error(hp, ESCSI_BADCMD, "internal " + "uscsi error")); + case EPERM: + return (libscsi_error(hp, ESCSI_PERM, "insufficient " + "privileges ")); + case EIO: + /* Command never executed at all */ + if (cmd.uscsi_status == (short)-1) + return (libscsi_error(hp, ESCSI_IO, "I/O " + "error", strerror(errno))); + break; + default: + return (libscsi_error(hp, ESCSI_SYS, "uscsi ioctl " + "failed: %s", strerror(errno))); + } + } + + libscsi_action_set_status(ap, cmd.uscsi_status); + if ((flags & LIBSCSI_AF_READ) && libscsi_action_set_datalen(ap, + cmd.uscsi_buflen - cmd.uscsi_resid) != 0) + return (-1); + if ((flags & LIBSCSI_AF_RQSENSE) && libscsi_action_set_senselen(ap, + cmd.uscsi_rqlen - cmd.uscsi_rqresid) != 0) + return (-1); + + return (0); +} + +/*ARGSUSED*/ +static void +uscsi_target_name(libscsi_hdl_t *hp, void *private, char *buf, size_t len) +{ + struct uscsi_dev *dp = (struct uscsi_dev *)private; + + (void) snprintf(buf, len, "%s", dp->dev); +} + +static const libscsi_engine_ops_t uscsi_ops = { + .lseo_open = uscsi_open, + .lseo_close = uscsi_close, + .lseo_exec = uscsi_exec, + .lseo_target_name = uscsi_target_name +}; + +static const libscsi_engine_t uscsi_engine = { + .lse_name = "uscsi", + .lse_libversion = LIBSCSI_VERSION, + .lse_ops = &uscsi_ops +}; + +/*ARGSUSED*/ +const libscsi_engine_t * +libscsi_uscsi_init(libscsi_hdl_t *hp) +{ + return (&uscsi_engine); +} diff --git a/usr/src/lib/scsi/plugins/ses/Makefile b/usr/src/lib/scsi/plugins/ses/Makefile new file mode 100644 index 0000000000..d89a1ee090 --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/Makefile @@ -0,0 +1,37 @@ +# +# 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" + +SUBDIRS = \ + libses \ + ses2 \ + SUN-StorageTek-J4400 + +.KEEP_STATE: + +.PARALLEL: + +include ../../Makefile.subdirs diff --git a/usr/src/lib/scsi/plugins/ses/Makefile.lib b/usr/src/lib/scsi/plugins/ses/Makefile.lib new file mode 100644 index 0000000000..a2831198fc --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/Makefile.lib @@ -0,0 +1,75 @@ +# +# 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" + +.KEEP_STATE: +.SUFFIXES: + +include ../../../../../../cmd/Makefile.cmd +include ../../../../Makefile.defs + +# +# Set PROG and OBJS based on the values of MODULE and SRCS. We expect that +# these macros to be defined by the Makefile that is including this file. +# +PROG = $(MODULE:%=%.so) +YOBJS = $(YSRCS:%.y=%.o) +OBJS = $(YOBJS) $(SRCS:%.c=%.o) + +# +# A module may set DMOD and DMOD_SRCS if it has a mdb proc module. +# DMOD, if set, must match PROG above (for mdb autoloading) so it will +# be built in a subdirectory. +# +ROOTDMOD = $(DMOD:%.so=$(ROOT)/usr/lib/mdb/proc/%.so) +ROOTDMOD64 = $(DMOD:%.so=$(ROOT)/usr/lib/mdb/proc/$(MACH64)/%.so) +DMODPROG = $(DMOD:%=dmod/%) +DMOD_OBJS = $(DMOD_SRCS:%.c=%.o) + +ROOTPROG = $(ROOTPLUGINLIBDIR)/ses/$(PLUGINTYPE)/$(PROG) +ROOTPROG64 = $(ROOTPLUGINLIBDIR)/ses/$(PLUGINTYPE)/$(MACH64)/$(PROG) + +LINTFLAGS += -mu +LINTFILES = $(SRCS:%.c=%.ln) + +DMODLINTTGT = $(DMOD:%=lint_dmod) +DMODLINTFILES = $(DMOD_SRCS:%.c=%.ln) + +APIMAP = ../../../../libses/libses_api.map + +C99MODE = $(C99_ENABLE) +CFLAGS += $(CTF_FLAGS) $(CCVERBOSE) $(XSTRCONST) $(CC_PICFLAGS) +CFLAGS += -G $(XREGSFLAG) +CFLAGS64 += $(CTF_FLAGS) $(CCVERBOSE) $(XSTRCONST) $(CC_PICFLAGS) +CFLAGS64 += -G $(XREGSFLAG) +CPPFLAGS += -D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT +$(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG +LDFLAGS += $(ZTEXT) $(ZCOMBRELOC) $(ZIGNORE) + +$(PROG) := LDFLAGS += $(ZDEFS) -M$(APIMAP) +$(PROG) := LDLIBS += -lc -lnvpair + +$(DMODPROG) := LDFLAGS += $(ZNODEFS) diff --git a/usr/src/lib/scsi/plugins/ses/Makefile.plugin b/usr/src/lib/scsi/plugins/ses/Makefile.plugin new file mode 100644 index 0000000000..fe0f796fd2 --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/Makefile.plugin @@ -0,0 +1,59 @@ +# +# 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" + +include $(SRC)/Makefile.master + +SUBDIRS = $(MACH) +$(BUILD64)SUBDIRS += $(MACH64) + +include ../../../Makefile.defs + +ROOTHDRDIR = $(ROOTPLUGINHDRDIR)/ses/$(PLUGINTYPE) +ROOTHDRS = $(HDRS:%=$(ROOTHDRDIR)/%) + +all := TARGET= all +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install +lint := TARGET= lint +install_h:= TARGET = install_h + +.KEEP_STATE: + +all install clean clobber lint: $(SUBDIRS) + +install_h: $(ROOTHDRDIR) $(ROOTHDRS) + +check: + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + +include ../../../Makefile.rootdirs +include ../../../../Makefile.targ diff --git a/usr/src/lib/scsi/plugins/ses/Makefile.targ b/usr/src/lib/scsi/plugins/ses/Makefile.targ new file mode 100644 index 0000000000..c8d0dab5b0 --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/Makefile.targ @@ -0,0 +1,82 @@ +# +# 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" + +all: $(PROG) $(DMODPROG) + +.NO_PARALLEL: +.PARALLEL: $(OBJS) $(LINTFILES) $(DMOD_OBJS) $(DMODLINTFILES) + +$(PROG): $(OBJS) $(APIMAP) + $(LINK.c) $(OBJS) -o $@ $(LDLIBS) + $(CTFMERGE) -L VERSION -o $@ $(OBJS) + $(POST_PROCESS_SO) + +$(DMODPROG): $(DMOD_OBJS) + -@mkdir -p $(@D) + $(LINK.c) $(DMOD_OBJS) -o $@ + $(POST_PROCESS) + +%.o: %.c + $(COMPILE.c) $< + $(CTFCONVERT_O) + +%.o: $(SRCDIR)/%.c + $(COMPILE.c) $< + $(CTFCONVERT_O) + +clean: + $(RM) $(OBJS) $(DMOD_OBJS) $(LINTFILES) $(DMODLINTFILES) $(CLEANFILES) + +clobber: clean + $(RM) $(PROG) $(DMODPROG) + +%.ln: %.c + $(LINT.c) -c $< + +%.ln: $(SRCDIR)/%.c + $(LINT.c) -c $< + +lint_prog: $(LINTFILES) + $(LINT) $(LINTFLAGS) $(LINTFILES) $(LDLIBS) + +lint_dmod: $(DMODLINTFILES) + $(LINT) $(LINTFLAGS) $(DMODLINTFILES) $(LDLIBS) + +lint: lint_prog $(DMODLINTTGT) + +install_h: + +$(ROOTPROG): $$(@D) $(PROG) + $(RM) $@; $(INS) -s -m 0755 -f $(@D) $(PROG) + +$(ROOTPROG64): $$(@D) $(PROG) + $(RM) $@; $(INS) -s -m 0755 -f $(@D) $(PROG) + +$(ROOTDMOD): $$(@D) $(DMODPROG) + $(RM) $@; $(INS) -s -m 0755 -f $(@D) $(DMODPROG) + +include ../../../../Makefile.rootdirs diff --git a/usr/src/lib/scsi/plugins/ses/SUN-StorageTek-J4400/Makefile b/usr/src/lib/scsi/plugins/ses/SUN-StorageTek-J4400/Makefile new file mode 100644 index 0000000000..b39b55f14b --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/SUN-StorageTek-J4400/Makefile @@ -0,0 +1,32 @@ +# +# 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" + +HDRS = +HDRDIR = common +PLUGINTYPE = vendor + +include ../Makefile.plugin diff --git a/usr/src/lib/scsi/plugins/ses/SUN-StorageTek-J4400/Makefile.com b/usr/src/lib/scsi/plugins/ses/SUN-StorageTek-J4400/Makefile.com new file mode 100644 index 0000000000..d6f6a781e5 --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/SUN-StorageTek-J4400/Makefile.com @@ -0,0 +1,33 @@ +# +# 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" + +MODULE = SUN-StorageTek-J4400 +SRCS = riverwalk.c +SRCDIR = ../common +PLUGINTYPE = vendor + +include ../../Makefile.lib diff --git a/usr/src/lib/scsi/plugins/ses/SUN-StorageTek-J4400/amd64/Makefile b/usr/src/lib/scsi/plugins/ses/SUN-StorageTek-J4400/amd64/Makefile new file mode 100644 index 0000000000..fbf98db77f --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/SUN-StorageTek-J4400/amd64/Makefile @@ -0,0 +1,33 @@ +# +# 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" + +include ../Makefile.com +include $(SRC)/Makefile.master.64 + +install: all $(ROOTPROG64) + +include ../../Makefile.targ diff --git a/usr/src/lib/scsi/plugins/ses/SUN-StorageTek-J4400/common/riverwalk.c b/usr/src/lib/scsi/plugins/ses/SUN-StorageTek-J4400/common/riverwalk.c new file mode 100644 index 0000000000..bdfe61b737 --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/SUN-StorageTek-J4400/common/riverwalk.c @@ -0,0 +1,211 @@ +/* + * 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 <string.h> +#include <strings.h> + +#include <scsi/libses.h> +#include <scsi/libses_plugin.h> + +#pragma pack(1) + +typedef struct ses_riverwalk_stringin { + uint8_t rws_download_status; + uint8_t rws_descriptor_start; + uint16_t rws_descriptor_length; + char rws_sim0_id[4]; + char rws_sim0_pn[15]; + char rws_sim0_sn[20]; + char rws_sim1_id[4]; + char rws_sim1_pn[15]; + char rws_sim1_sn[20]; + char rws_mid_id[4]; + char rws_mid_pn[15]; + char rws_mid_sn[20]; + char rws_ps0_id[4]; + char rws_ps0_pn[15]; + char rws_ps0_sn[20]; + char rws_ps1_id[4]; + char rws_ps1_pn[15]; + char rws_ps1_sn[20]; + char __reserved1[29]; + uint8_t rws_diag_start; + uint8_t rws_eid; + uint16_t rws_diag_length; + uint8_t rws_sim_id; + uint8_t rws_numport; + uint16_t __reserved2; + uint8_t rws_sasaddr[8]; + uint8_t rws_sys_sn[8]; + char rws_port0[16]; + char rws_port1[16]; + char rws_port2[16]; +} ses_riverwalk_stringin_t; + +#pragma pack() + +/*ARGSUSED*/ +static int +sun_riverwalk_parse_node(ses_plugin_t *sp, ses_node_t *np) +{ + nvlist_t *props = ses_node_props(np); + int nverr; + ses_riverwalk_stringin_t *strp; + char buf[32]; + uint64_t type, index; + char *pn, *sn; + ses_node_t *encp; + nvlist_t *encprops; + uint8_t *stringin; + uint_t len; + + if (ses_node_type(np) != SES_NODE_ENCLOSURE && + ses_node_type(np) != SES_NODE_ELEMENT) + return (0); + + /* + * Find the containing enclosure node and extract the STRING IN + * information. + */ + for (encp = np; ses_node_type(encp) != SES_NODE_ENCLOSURE; + encp = ses_node_parent(encp)) + ; + + encprops = ses_node_props(encp); + if (nvlist_lookup_byte_array(encprops, SES_EN_PROP_STRING, + &stringin, &len) != 0) + return (0); + + if (len < sizeof (ses_riverwalk_stringin_t)) + return (0); + + strp = (ses_riverwalk_stringin_t *)stringin; + + switch (ses_node_type(np)) { + case SES_NODE_ELEMENT: + /* + * We can get part and serial information for power supplies and + * the SIM cards (ESC_ELECTRONICS elements). + */ + VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_TYPE, + &type) == 0); + VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_CLASS_INDEX, + &index) == 0); + + sn = pn = NULL; + switch (type) { + case SES_ET_POWER_SUPPLY: + switch (index) { + case 0: + if (strncmp(strp->rws_ps0_id, "SPS0", 4) != 0) + break; + + pn = strp->rws_ps0_pn; + sn = strp->rws_ps0_sn; + break; + + case 1: + if (strncmp(strp->rws_ps1_id, "SPS1", 4) != 0) + break; + + pn = strp->rws_ps1_pn; + sn = strp->rws_ps1_sn; + break; + } + break; + + case SES_ET_ESC_ELECTRONICS: + switch (index) { + case 0: + if (strncmp(strp->rws_sim0_id, "SIM0", 4) != 0) + break; + + pn = strp->rws_sim0_pn; + sn = strp->rws_sim0_sn; + break; + + case 1: + if (strncmp(strp->rws_sim1_id, "SIM1", 4) != 0) + break; + + pn = strp->rws_sim1_pn; + sn = strp->rws_sim1_sn; + break; + } + break; + } + + if (pn == NULL) + return (0); + + if (pn[0] != '\0') { + (void) bcopy(pn, buf, sizeof (strp->rws_ps0_pn)); + buf[sizeof (strp->rws_ps0_pn)] = '\0'; + SES_NV_ADD(string, nverr, props, LIBSES_PROP_PART, + buf); + } + + if (sn[0] != '\0') { + (void) bcopy(sn, buf, sizeof (strp->rws_ps0_sn)); + buf[sizeof (strp->rws_ps0_sn)] = '\0'; + SES_NV_ADD(string, nverr, props, LIBSES_PROP_SERIAL, + sn); + } + + break; + + case SES_NODE_ENCLOSURE: + /* + * The chassis serial number is derived from the MID FRU + * descriptor. + */ + if (strncmp(strp->rws_mid_id, "MID ", 4) == 0 && + strp->rws_mid_sn[0] != '\0') { + (void) bcopy(strp->rws_mid_sn, buf, + sizeof (strp->rws_mid_sn)); + buf[sizeof (strp->rws_mid_sn)] = '\0'; + SES_NV_ADD(string, nverr, props, LIBSES_EN_PROP_CSN, + buf); + } + + break; + } + + return (0); +} + +int +_ses_init(ses_plugin_t *sp) +{ + ses_plugin_config_t config = { + .spc_node_parse = sun_riverwalk_parse_node + }; + + return (ses_plugin_register(sp, LIBSES_PLUGIN_VERSION, + &config) != 0); +} diff --git a/usr/src/lib/scsi/plugins/ses/SUN-StorageTek-J4400/i386/Makefile b/usr/src/lib/scsi/plugins/ses/SUN-StorageTek-J4400/i386/Makefile new file mode 100644 index 0000000000..447a346278 --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/SUN-StorageTek-J4400/i386/Makefile @@ -0,0 +1,32 @@ +# +# 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" + +include ../Makefile.com + +install: all $(ROOTPROG) + +include ../../Makefile.targ diff --git a/usr/src/lib/scsi/plugins/ses/SUN-StorageTek-J4400/sparc/Makefile b/usr/src/lib/scsi/plugins/ses/SUN-StorageTek-J4400/sparc/Makefile new file mode 100644 index 0000000000..447a346278 --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/SUN-StorageTek-J4400/sparc/Makefile @@ -0,0 +1,32 @@ +# +# 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" + +include ../Makefile.com + +install: all $(ROOTPROG) + +include ../../Makefile.targ diff --git a/usr/src/lib/scsi/plugins/ses/SUN-StorageTek-J4400/sparcv9/Makefile b/usr/src/lib/scsi/plugins/ses/SUN-StorageTek-J4400/sparcv9/Makefile new file mode 100644 index 0000000000..fbf98db77f --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/SUN-StorageTek-J4400/sparcv9/Makefile @@ -0,0 +1,33 @@ +# +# 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" + +include ../Makefile.com +include $(SRC)/Makefile.master.64 + +install: all $(ROOTPROG64) + +include ../../Makefile.targ diff --git a/usr/src/lib/scsi/plugins/ses/libses/Makefile b/usr/src/lib/scsi/plugins/ses/libses/Makefile new file mode 100644 index 0000000000..fbee544774 --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/libses/Makefile @@ -0,0 +1,32 @@ +# +# 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" + +HDRS = libses.h +HDRDIR = common +PLUGINTYPE = framework + +include ../Makefile.plugin diff --git a/usr/src/lib/scsi/plugins/ses/libses/Makefile.com b/usr/src/lib/scsi/plugins/ses/libses/Makefile.com new file mode 100644 index 0000000000..104909fce5 --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/libses/Makefile.com @@ -0,0 +1,39 @@ +# +# 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" + +MODULE = libses +SRCS = libses.c \ + libses_elemtype.c +SRCDIR = ../common +PLUGINTYPE = framework + +include ../../Makefile.lib + +SES2HDR = $(ROOTPLUGINHDRDIR)/ses/framework/ses2.h + +../common/libses_elemtype.c: ../common/mkelemtype.sh $(SES2HDR) + sh ../common/mkelemtype.sh < $(SES2HDR) > $@ diff --git a/usr/src/lib/scsi/plugins/ses/libses/amd64/Makefile b/usr/src/lib/scsi/plugins/ses/libses/amd64/Makefile new file mode 100644 index 0000000000..fbf98db77f --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/libses/amd64/Makefile @@ -0,0 +1,33 @@ +# +# 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" + +include ../Makefile.com +include $(SRC)/Makefile.master.64 + +install: all $(ROOTPROG64) + +include ../../Makefile.targ diff --git a/usr/src/lib/scsi/plugins/ses/libses/common/libses.c b/usr/src/lib/scsi/plugins/ses/libses/common/libses.c new file mode 100644 index 0000000000..28b1b80f60 --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/libses/common/libses.c @@ -0,0 +1,93 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <scsi/libses.h> +#include <scsi/libses_plugin.h> + +#include "libses_impl.h" + +/*ARGSUSED*/ +static int +libses_parse_node(ses_plugin_t *sp, ses_node_t *np) +{ + nvlist_t *lid; + nvlist_t *props; + uint64_t id, type; + char csn[17]; + const char *name; + int nverr; + + props = ses_node_props(np); + + if (nvlist_lookup_uint64(props, SES_PROP_ELEMENT_TYPE, + &type) == 0 && + (name = ses_element_type_name(type)) != NULL) { + /* + * Add a standard human-readable name for the element type. + */ + SES_NV_ADD(string, nverr, props, + LIBSES_PROP_ELEMENT_TYPE_NAME, name); + } + + if (ses_node_type(np) != SES_NODE_ENCLOSURE) + return (0); + + /* + * The only thing we do for all targets is fill in the default chassis + * number from the enclosure logical ID. + */ + if (nvlist_lookup_nvlist(props, SES_EN_PROP_LID, &lid) != 0) + return (0); + + VERIFY(nvlist_lookup_uint64(lid, SPC3_NAA_INT, &id) == 0); + + (void) snprintf(csn, sizeof (csn), "%llx", id); + SES_NV_ADD(string, nverr, props, LIBSES_EN_PROP_CSN, csn); + + return (0); +} + +int +_ses_init(ses_plugin_t *sp) +{ + ses_plugin_config_t config = { + .spc_node_parse = libses_parse_node + }; + + return (ses_plugin_register(sp, LIBSES_PLUGIN_VERSION, + &config) != 0); +} + +/* + * libses must be loaded after ses2. + */ +int +_ses_priority(void) +{ + return (1); +} diff --git a/usr/src/lib/scsi/plugins/ses/libses/common/libses.h b/usr/src/lib/scsi/plugins/ses/libses/common/libses.h new file mode 100644 index 0000000000..081bb94e5e --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/libses/common/libses.h @@ -0,0 +1,72 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _FRAMEWORK_LIBSES_H +#define _FRAMEWORK_LIBSES_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * These are properties attached to the root target node of the enclosure, and + * represent the SCSI inquiry data. + */ +#define SCSI_PROP_VENDOR "scsi-inquiry-vendor" +#define SCSI_PROP_PRODUCT "scsi-inquiry-product" +#define SCSI_PROP_REVISION "scsi-inquiry-revision" + +/* + * This property provides a human-readable name for the element type. This is + * constant, and not derived from the enclosure data. + */ +#define LIBSES_PROP_ELEMENT_TYPE_NAME "libses-element-type-name" + +/* + * The following properties can be added to any node. There is no provision in + * the specification for these properties, but they can be derived from vendor + * specific data for some enclosures. + */ +#define LIBSES_PROP_PART "libses-part-number" +#define LIBSES_PROP_SERIAL "libses-serial-number" + +/* + * The chassis serial number is a pseudo property that doesn't exist in SES + * spec. A single physical chassis may present several logically different SES + * targets that are connected to the same or different elements. These targets + * can extract the chassis serial number in a vendor-specific way so that + * consumers know these SES targets refer to the same device. This defaults to + * to the logical-id, and is always present. + */ +#define LIBSES_EN_PROP_CSN "libses-chassis-serial" + +#ifdef __cplusplus +} +#endif + +#endif /* _FRAMEWORK_LIBSES_H */ diff --git a/usr/src/lib/scsi/plugins/ses/libses/common/libses_impl.h b/usr/src/lib/scsi/plugins/ses/libses/common/libses_impl.h new file mode 100644 index 0000000000..a3fe7af480 --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/libses/common/libses_impl.h @@ -0,0 +1,42 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _PLUGIN_LIBSES_IMPL_H +#define _PLUGIN_LIBSES_IMPL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +extern const char *ses_element_type_name(uint64_t); + +#ifdef __cplusplus +} +#endif + +#endif /* _PLUGIN_LIBSES_IMPL_H */ diff --git a/usr/src/lib/scsi/plugins/ses/libses/common/mkelemtype.sh b/usr/src/lib/scsi/plugins/ses/libses/common/mkelemtype.sh new file mode 100644 index 0000000000..f9f294d69b --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/libses/common/mkelemtype.sh @@ -0,0 +1,69 @@ +#!/bin/sh +# +# 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" + +echo "/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident\t\"@(#)mkelemtype.sh\t1.1\t07/01/19 SMI\" + +#include <sys/types.h> +#include <string.h> +#include <scsi/libses.h> + +static const struct { +\tses2_element_type_t se_type;\t/* element type */ +\tconst char *se_name;\t\t/* element type name */ +} _ses_elemtypestr[] = {" + +pattern='^ \(SES_ET_\([A-Z0-9_]*\)\).*' +replace=' { \1, "\2" },' + +( sed -n "s/$pattern/$replace/p" ) || exit 1 + +echo "\ +};\n\ +\n\ +static uint_t _ses_nelemtypes =\n\ + sizeof (_ses_elemtypestr) / sizeof (_ses_elemtypestr[0]);\n\ +\n\ +const char * +ses_element_type_name(uint64_t type) +{ + uint_t t; + + for (t = 0; t < _ses_nelemtypes; t++) { + if (_ses_elemtypestr[t].se_type == type) + return (_ses_elemtypestr[t].se_name); + } + + return (NULL); +}" + +exit 0 diff --git a/usr/src/lib/scsi/plugins/ses/libses/i386/Makefile b/usr/src/lib/scsi/plugins/ses/libses/i386/Makefile new file mode 100644 index 0000000000..447a346278 --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/libses/i386/Makefile @@ -0,0 +1,32 @@ +# +# 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" + +include ../Makefile.com + +install: all $(ROOTPROG) + +include ../../Makefile.targ diff --git a/usr/src/lib/scsi/plugins/ses/libses/sparc/Makefile b/usr/src/lib/scsi/plugins/ses/libses/sparc/Makefile new file mode 100644 index 0000000000..447a346278 --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/libses/sparc/Makefile @@ -0,0 +1,32 @@ +# +# 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" + +include ../Makefile.com + +install: all $(ROOTPROG) + +include ../../Makefile.targ diff --git a/usr/src/lib/scsi/plugins/ses/libses/sparcv9/Makefile b/usr/src/lib/scsi/plugins/ses/libses/sparcv9/Makefile new file mode 100644 index 0000000000..fbf98db77f --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/libses/sparcv9/Makefile @@ -0,0 +1,33 @@ +# +# 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" + +include ../Makefile.com +include $(SRC)/Makefile.master.64 + +install: all $(ROOTPROG64) + +include ../../Makefile.targ diff --git a/usr/src/lib/scsi/plugins/ses/ses2/Makefile b/usr/src/lib/scsi/plugins/ses/ses2/Makefile new file mode 100644 index 0000000000..7c713b4077 --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/ses2/Makefile @@ -0,0 +1,32 @@ +# +# 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" + +HDRS = ses2.h ses2_impl.h +HDRDIR = common +PLUGINTYPE = framework + +include ../Makefile.plugin diff --git a/usr/src/lib/scsi/plugins/ses/ses2/Makefile.com b/usr/src/lib/scsi/plugins/ses/ses2/Makefile.com new file mode 100644 index 0000000000..2f020ac65a --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/ses2/Makefile.com @@ -0,0 +1,39 @@ +# +# 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" + +MODULE = ses2 +SRCS = ses2.c \ + ses2_element.c \ + ses2_element_ctl.c \ + ses2_enclosure.c \ + ses2_enclosure_ctl.c \ + ses2_pages.c + +SRCDIR = ../common +PLUGINTYPE = framework + +include ../../Makefile.lib diff --git a/usr/src/lib/scsi/plugins/ses/ses2/amd64/Makefile b/usr/src/lib/scsi/plugins/ses/ses2/amd64/Makefile new file mode 100644 index 0000000000..fbf98db77f --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/ses2/amd64/Makefile @@ -0,0 +1,33 @@ +# +# 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" + +include ../Makefile.com +include $(SRC)/Makefile.master.64 + +install: all $(ROOTPROG64) + +include ../../Makefile.targ diff --git a/usr/src/lib/scsi/plugins/ses/ses2/common/ses2.c b/usr/src/lib/scsi/plugins/ses/ses2/common/ses2.c new file mode 100644 index 0000000000..e7d00dfc88 --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/ses2/common/ses2.c @@ -0,0 +1,137 @@ +/* + * 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 <scsi/libses.h> +#include <scsi/libses_plugin.h> +#include <string.h> +#include <strings.h> + +#include "ses2_impl.h" + +/* + * Given an nvlist of properties and an array of property handlers, invoke the + * appropriate handler for all supported properties. + */ +int +ses2_setprop(ses_plugin_t *sp, ses_node_t *np, + const ses2_ctl_prop_t *ctlprops, nvlist_t *props) +{ + const ses2_ctl_prop_t *cpp; + nvpair_t *nvp; + + for (nvp = nvlist_next_nvpair(props, NULL); nvp != NULL; + nvp = nvlist_next_nvpair(props, nvp)) { + for (cpp = ctlprops; cpp->scp_name != NULL; cpp++) + if (strcmp(cpp->scp_name, nvpair_name(nvp)) == 0) + break; + if (cpp == NULL) + continue; + + if (cpp->scp_setprop(sp, np, cpp->scp_num, nvp) != 0) + return (-1); + + (void) nvlist_remove(props, nvpair_name(nvp), + nvpair_type(nvp)); + } + + return (0); +} + +int +ses2_ctl_common_setprop(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, + nvpair_t *nvp) +{ + ses2_cmn_elem_ctl_impl_t *eip; + const char *name; + boolean_t v; + + ASSERT(page == SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS); + + if ((eip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + page, 0, np, B_FALSE)) == NULL) + return (-1); + + name = nvpair_name(nvp); + (void) nvpair_value_boolean_value(nvp, &v); + + if (strcmp(name, SES_PROP_SWAP) == 0) + eip->seci_rst_swap = !v; + else if (strcmp(name, SES_PROP_DISABLED) == 0) + eip->seci_disable = v; + else if (strcmp(name, SES_PROP_PRDFAIL) == 0) + eip->seci_prdfail = v; + else + ses_panic("Bad property %s", name); + + return (0); +} + +static int +ses2_node_parse(ses_plugin_t *sp, ses_node_t *np) +{ + switch (ses_node_type(np)) { + case SES_NODE_ENCLOSURE: + return (ses2_fill_enclosure_node(sp, np)); + + case SES_NODE_AGGREGATE: + case SES_NODE_ELEMENT: + return (ses2_fill_element_node(sp, np)); + + default: + return (0); + } +} + +static int +ses2_node_ctl(ses_plugin_t *sp, ses_node_t *np, const char *op, + nvlist_t *nvl) +{ + switch (ses_node_type(np)) { + case SES_NODE_ENCLOSURE: + return (ses2_enclosure_ctl(sp, np, op, nvl)); + + case SES_NODE_AGGREGATE: + case SES_NODE_ELEMENT: + return (ses2_element_ctl(sp, np, op, nvl)); + } + + return (0); +} + +int +_ses_init(ses_plugin_t *sp) +{ + ses_plugin_config_t config = { + .spc_pages = ses2_pages, + .spc_node_parse = ses2_node_parse, + .spc_node_ctl = ses2_node_ctl + }; + + return (ses_plugin_register(sp, LIBSES_PLUGIN_VERSION, + &config) != 0); +} diff --git a/usr/src/lib/scsi/plugins/ses/ses2/common/ses2.h b/usr/src/lib/scsi/plugins/ses/ses2/common/ses2.h new file mode 100644 index 0000000000..f1ddd0dc1a --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/ses2/common/ses2.h @@ -0,0 +1,528 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _FRAMEWORK_SES_H +#define _FRAMEWORK_SES_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Node properties + */ +#define SES_PROP_ELEMENT_TYPE "ses-element-type" +typedef enum ses2_element_type { + SES_ET_UNSPECIFIED = 0, + SES_ET_DEVICE = 0x1, + SES_ET_POWER_SUPPLY = 0x2, + SES_ET_COOLING = 0x3, + SES_ET_TEMPERATURE_SENSOR = 0x4, + SES_ET_DOOR_LOCK = 0x5, + SES_ET_AUDIBLE_ALARM = 0x6, + SES_ET_ESC_ELECTRONICS = 0x7, + SES_ET_SCC_ELECTRONICS = 0x8, + SES_ET_NONVOLATILE_CACHE = 0x9, + SES_ET_INVALID_OPERATION_REASON = 0xa, + SES_ET_UPS = 0xb, + SES_ET_DISPLAY = 0xc, + SES_ET_KEY_PAD_ENTRY = 0xd, + SES_ET_ENCLOSURE = 0xe, + SES_ET_SCSI_PORT_XCVR = 0xf, + SES_ET_LANGUAGE = 0x10, + SES_ET_COMMUNICATION_PORT = 0x11, + SES_ET_VOLTAGE_SENSOR = 0x12, + SES_ET_CURRENT_SENSOR = 0x13, + SES_ET_SCSI_TARGET_PORT = 0x14, + SES_ET_SCSI_INITIATOR_PORT = 0x15, + SES_ET_SIMPLE_SUBENCLOSURE = 0x16, + SES_ET_ARRAY_DEVICE = 0x17, + SES_ET_SAS_EXPANDER = 0x18, + SES_ET_SAS_CONNECTOR = 0x19 +} ses2_element_type_t; + +#define SES_PROP_STATUS_CODE "ses-status-code" +typedef enum ses_element_status_code { + SES_ESC_UNSUPPORTED = 0, + SES_ESC_OK = 1, + SES_ESC_CRITICAL = 2, + SES_ESC_NONCRITICAL = 3, + SES_ESC_UNRECOVERABLE = 4, + SES_ESC_NOT_INSTALLED = 5, + SES_ESC_UNKNOWN = 6, + SES_ESC_UNAVAIL = 7, + SES_ESC_NO_ACCESS = 8 +} ses_element_status_code_t; + +#define SES_PROP_ELEMENT_CLASS_INDEX "ses-element-class-index" /* U64 */ +#define SES_PROP_ELEMENT_INDEX "ses-element-index" /* U64 */ +#define SES_PROP_BAY_NUMBER "ses-bay-number" /* U64 */ +#define SES_PROP_PRDFAIL "ses-failure-predicted" +#define SES_PROP_SWAP "ses-swapped" +#define SES_PROP_DISABLED "ses-disabled" +#define SES_PROP_IDENT "ses-identify" +#define SES_PROP_WARN "ses-warning" +#define SES_PROP_FAIL "ses-failed" +#define SES_PROP_WARN_REQ "ses-warning-indicator-requested" +#define SES_PROP_FAIL_REQ "ses-failure-indicator-requested" +#define SES_PROP_REPORT "ses-reported-via" +#define SES_PROP_RMV "ses-ready-to-remove" +#define SES_PROP_OFF "ses-off" +#define SES_PROP_REQUESTED_ON "ses-requested-on" +#define SES_PROP_CLASS_DESCRIPTION "ses-class-description" /* S */ +#define SES_PROP_DESCRIPTION "ses-description" /* S */ +#define SES_PROP_HOT_SWAP "ses-hot-swappable" + +#define SES_FC_PROP_NODE_NAME "ses-fc-node-name" /* U64 */ +#define SES_FC_PROP_LOOP_POS "ses-fc-loop-position" /* U64 */ +#define SES_FC_PROP_REQ_HARDADDR "ses-fc-requested-hard-address" +#define SES_FC_PROP_N_PORT_ID "ses-fc-n_port-identifier" /* U64 */ +#define SES_FC_PROP_N_PORT_NAME "ses-fc-n_port-name" /* U64 */ +#define SES_FC_PROP_PORTS "ses-fc-ports" /* NVA */ + +#define SES_SAS_PROP_DEVICE_TYPE "ses-sas-device-type" /* U64 */ +/* + * SAS2r11 7.8.2 Table 123 + */ +typedef enum sas_device_type { + SAS_DT_END_DEVICE = 0x01, + SAS_DT_EXPANDER = 0x02, + SAS_DT_LEGACY_EXPANDER = 0x3 +} sas_device_type_t; + +#define SES_SAS_PROP_SMPI_PORT "ses-sas-smp-initiator-port" +#define SES_SAS_PROP_STPI_PORT "ses-sas-stp-initiator-port" +#define SES_SAS_PROP_SSPI_PORT "ses-sas-ssp-initiator-port" +#define SES_SAS_PROP_SATA_DEVICE "ses-sas-sata-device" +#define SES_SAS_PROP_SMPT_PORT "ses-sas-smp-target-port" +#define SES_SAS_PROP_STPT_PORT "ses-sas-stp-target-port" +#define SES_SAS_PROP_SSPT_PORT "ses-sas-ssp-target-port" +#define SES_SAS_PROP_ATT_ADDR "ses-sas-attached-address" /* U64 */ +#define SES_SAS_PROP_ADDR "ses-sas-address" /* U64 */ +#define SES_SAS_PROP_PHY_ID "ses-sas-phy-identifier" /* U64 */ +#define SES_SAS_PROP_PHYS "ses-sas-phys" /* NVA */ +#define SES_PROP_CE_IDX "ses-connector-element-index" /* U64 */ +#define SES_PROP_OE_IDX "ses-other-element-index" /* U64 */ + +#define SES_PROP_THRESH_CRIT_HI "ses-high-critical-threshold" /* U64 */ +#define SES_PROP_THRESH_WARN_HI "ses-high-warning-threshold" /* U64 */ +#define SES_PROP_THRESH_CRIT_LO "ses-low-critical-threshold" /* U64 */ +#define SES_PROP_THRESH_WARN_LO "ses-low-warning-threshold" /* U64 */ + +/* + * Audible Alarm properties + */ +#define SES_ALARM_PROP_UNRECOV "ses-indicating-unrecoverable" +#define SES_ALARM_PROP_CRIT "ses-indicating-critical" +#define SES_ALARM_PROP_NONCRIT "ses-indicating-noncritical" +#define SES_ALARM_PROP_INFO "ses-indicating-informational" +#define SES_ALARM_PROP_REMIND "ses-reminder-mode" +#define SES_ALARM_PROP_MUTED "ses-muted" +#define SES_ALARM_PROP_RQST_MUTE "ses-mute-requested" + +/* + * Nonvolatile Cache properties + */ +#define SES_CACHE_PROP_SIZE "ses-cache-size" /* U64 */ + +/* + * Cooling Element properties + */ +#define SES_COOLING_PROP_FAN_SPEED "ses-fan-speed" /* U64 */ +#define SES_COOLING_PROP_SPEED_CODE "ses-fan-speed-code" /* U64 */ +typedef enum ses_cooling_fan_speed { + SES_COOLING_FAN_SPEED_STOPPED = 0, + SES_COOLING_FAN_SPEED_LOWEST = 1, + SES_COOLING_FAN_SPEED_LOWER = 2, + SES_COOLING_FAN_SPEED_LOW = 3, + SES_COOLING_FAN_SPEED_INTERMEDIATE = 4, + SES_COOLING_FAN_SPEED_HIGH = 5, + SES_COOLING_FAN_SPEED_HIGHER = 6, + SES_COOLING_FAN_SPEED_HIGHEST = 7 +} ses_cooling_fan_speed_t; + +/* + * Device/Array Device properties + */ +#define SES_DEV_PROP_SLOT_ADDR "ses-slot-address" /* U64 */ +#define SES_DEV_PROP_PRDFAIL "ses-failure-predicted" +#define SES_DEV_PROP_READY_TO_INSERT "ses-ready-to-insert" +#define SES_DEV_PROP_ENC_BYP_A "ses-enclosure-bypassed-a" +#define SES_DEV_PROP_ENC_BYP_B "ses-enclosure-bypassed-b" +#define SES_DEV_PROP_DO_NOT_REMOVE "ses-do-not-remove" +#define SES_DEV_PROP_APP_BYP_A "ses-app-client-bypassed-a" +#define SES_DEV_PROP_APP_BYP_B "ses-app-client-bypassed-b" +#define SES_DEV_PROP_DEV_BYP_A "ses-device-bypassed-a" +#define SES_DEV_PROP_DEV_BYP_B "ses-device-bypassed-b" +#define SES_DEV_PROP_BYP_A "ses-bypassed-a" +#define SES_DEV_PROP_BYP_B "ses-bypassed-b" +#define SES_DEV_PROP_FAULT_RQSTD "ses-fault-requested" +#define SES_DEV_PROP_FAULT_SENSED "ses-fault-sensed" +#define SES_DEV_PROP_SAS_NOT_ALL_PHYS "ses-sas-not-all-phys" + +/* Control only */ +#define SES_DEV_PROP_REQ_MISSING "ses-request-missing" +#define SES_DEV_PROP_REQ_ACTIVE "ses-request-activity" + +#define SES_AD_PROP_RR_ABORT "ses-remap-rebuild-abort" +#define SES_AD_PROP_REBUILD "ses-remap-rebuild" +#define SES_AD_PROP_IN_FAILED_ARRAY "ses-in-failed-array" +#define SES_AD_PROP_IN_CRIT_ARRAY "ses-in-critical-array" +#define SES_AD_PROP_CONS_CHK "ses-consistency-check" +#define SES_AD_PROP_HOT_SPARE "ses-hot-spare" +#define SES_AD_PROP_RSVD_DEVICE "ses-reserved-device" +#define SES_AD_PROP_OK "ses-ok" + +/* + * Display Element properties + */ +#define SES_DPY_PROP_CHAR "ses-displayed-character" /* U16 */ +#define SES_DPY_PROP_MODE "ses-display-mode" /* U64 */ +/* + * SES-2r17 Table 96, 7.3.14 + */ +typedef enum ses_display_mode_ctl { + SES_DISPLAY_MC_NOCHG = 0, + SES_DISPLAY_MC_ESP = 1, + SES_DISPLAY_MC_SET = 2 +} ses_display_mode_ctl_t; + +typedef enum ses2_display_mode_status { + SES_DISPLAY_MS_NOTSUP = 0, + SES_DISPLAY_MS_ESP = 1, + SES_DISPLAY_MS_SET = 2 +} ses_display_mode_status_t; + +/* + * Current Sensor properties + */ +#define SES_CS_PROP_CRIT_OVER "ses-overcurrent-critical" +#define SES_CS_PROP_WARN_OVER "ses-overcurrent-warning" +#define SES_CS_PROP_CURRENT_MA "ses-current" /* I64 */ + +/* + * Door Lock properties + */ +#define SES_LOCK_PROP_UNLOCKED "ses-unlocked" + +/* + * SCSI Initiator or Target Port properties + */ +#define SES_ITP_PROP_ENABLED "ses-enabled" + +/* + * Language Module properties + */ +#define SES_LANG_PROP_LANGCODE "ses-language-code" /* U64 */ + +/* + * SCSI Port/Transceiver properties + */ +#define SES_PX_PROP_XMIT_FAIL "ses-transmitter-failure" +#define SES_PX_PROP_LOL "ses-loss-of-link" + +/* + * Power Supply properties + */ +#define SES_PSU_PROP_DC_OVER_CURRENT "ses-dc-over-current" +#define SES_PSU_PROP_DC_UNDER_VOLTAGE "ses-dc-under-voltage" +#define SES_PSU_PROP_DC_OVER_VOLTAGE "ses-dc-over-voltage" +#define SES_PSU_PROP_DC_FAIL "ses-dc-fail" +#define SES_PSU_PROP_AC_FAIL "ses-ac-fail" +#define SES_PSU_PROP_TEMP_WARN "ses-temperature-warning" /* I64 */ +#define SES_PSU_PROP_OVERTEMP_FAIL "ses-overtemperature-failure" + +/* + * SAS Expander properties + */ +#define SES_EXP_PROP_SAS_ADDR "ses-expander-sas-address" /* U64 */ + +/* + * SAS Connector properties + */ +#define SES_SC_PROP_PHYSICAL_LINK "ses-sas-physical-link" /* U64 */ +#define SES_SC_PROP_CONNECTOR_TYPE "ses-sas-connector-type" /* U64 */ +/* + * SES2r17 Table 122, 7.3.26 + */ +typedef enum ses_sasconn_type { + SES_SASCONN_T_UNKNOWN = 0, + SES_SASCONN_T_SFF_8470 = 0x1, + SES_SASCONN_T_SFF_8088 = 0x2, + SES_SASCONN_T_VENDOR_EXT = 0xf, + SES_SASCONN_T_SFF_8484 = 0x10, + SES_SASCONN_T_SFF_8087 = 0x11, + SES_SASCONN_T_SFF_8482_R = 0x20, + SES_SASCONN_T_SATA_HOST = 0x21, + SES_SASCONN_T_SFF_8482_P = 0x22, + SES_SASCONN_T_SATA_DEV = 0x23, + SES_SASCONN_T_VIRTUAL = 0x2f, + SES_SASCONN_T_VENDOR_INT = 0x3f, + SES_SASCONN_T_VENDOR_70 = 0x70, + SES_SASCONN_T_VENDOR_71 = 0x71, + SES_SASCONN_T_VENDOR_72 = 0x72, + SES_SASCONN_T_VENDOR_73 = 0x73, + SES_SASCONN_T_VENDOR_74 = 0x74, + SES_SASCONN_T_VENDOR_75 = 0x75, + SES_SASCONN_T_VENDOR_76 = 0x76, + SES_SASCONN_T_VENDOR_77 = 0x77, + SES_SASCONN_T_VENDOR_78 = 0x78, + SES_SASCONN_T_VENDOR_79 = 0x79, + SES_SASCONN_T_VENDOR_7A = 0x7a, + SES_SASCONN_T_VENDOR_7B = 0x7b, + SES_SASCONN_T_VENDOR_7C = 0x7c, + SES_SASCONN_T_VENDOR_7D = 0x7d, + SES_SASCONN_T_VENDOR_7E = 0x7e, + SES_SASCONN_T_VENDOR_7F = 0x7f +} ses_sasconn_type_t; + +/* + * Simple Subenclosure properties + */ +#define SES_SS_PROP_SHORT_STATUS "ses-short-status" /* U64 */ + +/* + * Temperature Sensor properties + */ +#define SES_TEMP_PROP_TEMP "ses-temperature" /* I64 */ +#define SES_TEMP_PROP_UNDERTEMP_WARN "ses-undertemperature-warning" +#define SES_TEMP_PROP_UNDERTEMP_FAIL "ses-undertemperature-failure" +#define SES_TEMP_PROP_OVERTEMP_WARN "ses-overtemperature-warning" +#define SES_TEMP_PROP_OVERTEMP_FAIL "ses-overtemperature-failure" + +/* + * Uninterruptible Power Supply properties + */ +#define SES_UPS_PROP_TIMELEFT "ses-battery-time-remaining" /* U64 */ +#define SES_UPS_PROP_INTF_FAIL "ses-interface-failure" +#define SES_UPS_PROP_WARN "ses-low-battery-warning" +#define SES_UPS_PROP_UPS_FAIL "ses-ups-failure" +#define SES_UPS_PROP_DC_FAIL "ses-dc-failure" +#define SES_UPS_PROP_AC_FAIL "ses-ac-failure" +#define SES_UPS_PROP_AC_QUAL "ses-ac-quality-exception" +#define SES_UPS_PROP_AC_HI "ses-ac-overvoltage-exception" +#define SES_UPS_PROP_AC_LO "ses-ac-undervoltage-exception" +#define SES_UPS_PROP_BPF "ses-battery-failure-predicted" +#define SES_UPS_PROP_BATT_FAIL "ses-battery-failure" + +/* + * Voltage Sensor properties + */ +#define SES_VS_PROP_CRIT_UNDER "ses-undervoltage-critical" +#define SES_VS_PROP_CRIT_OVER "ses-overvoltage-critical" +#define SES_VS_PROP_WARN_UNDER "ses-undervoltage-warning" +#define SES_VS_PROP_WARN_OVER "ses-overvoltage-warning" +#define SES_VS_PROP_VOLTAGE_MV "ses-voltage" /* I64 */ + +/* + * Enclosure Services Controller properties (Control only) + */ +#define SES_ESC_PROP_SELECT "ses-select-element" + +/* + * Primary/Subenclosure properties + */ +#define SES_EN_PROP_EID "ses-enclosure-id" /* U64 */ +#define SES_EN_PROP_ESPID "ses-enclosure-service-proc-id" +#define SES_EN_PROP_NESP "ses-enclosure-service-proc-count" +#define SES_EN_PROP_LID "ses-logical-id" /* NV */ +#define SES_EN_PROP_VID "ses-vendor-id" /* S */ +#define SES_EN_PROP_PID "ses-product-id" /* S */ +#define SES_EN_PROP_REV "ses-product-revision" /* S */ +#define SES_EN_PROP_VS "ses-product-vendor-specific" /* BA */ + +#define SES_EN_PROP_UNRECOV "ses-status-unrecoverable" +#define SES_EN_PROP_CRIT "ses-status-critical" +#define SES_EN_PROP_NONCRIT "ses-status-noncritical" +#define SES_EN_PROP_INFO "ses-status-informational" +#define SES_EN_PROP_INVOP "ses-status-invalid-operation" +#define SES_EN_PROP_HELP "ses-help-text" /* S */ +#define SES_EN_PROP_STRING "ses-string-in-data" /* BA */ +#define SES_EN_PROP_SHORT "ses-short-status" /* U64 */ +#define SES_EN_PROP_UCODE "ses-microcode-dl-status" /* U64 */ +typedef enum ses2_dl_ucode_status { + SES2_DLUCODE_S_NOP = 0, + SES2_DLUCODE_S_INPROGRESS = 0x1, + SES2_DLUCODE_S_SAVING = 0x2, + SES2_DLUCODE_S_INTERIM_3 = 0x3, + SES2_DLUCODE_S_INTERIM_4 = 0x4, + SES2_DLUCODE_S_INTERIM_5 = 0x5, + SES2_DLUCODE_S_INTERIM_6 = 0x6, + SES2_DLUCODE_S_INTERIM_7 = 0x7, + SES2_DLUCODE_S_INTERIM_8 = 0x8, + SES2_DLUCODE_S_INTERIM_9 = 0x9, + SES2_DLUCODE_S_INTERIM_A = 0xa, + SES2_DLUCODE_S_INTERIM_B = 0xb, + SES2_DLUCODE_S_INTERIM_C = 0xc, + SES2_DLUCODE_S_INTERIM_D = 0xd, + SES2_DLUCODE_S_INTERIM_E = 0xe, + SES2_DLUCODE_S_INTERIM_F = 0xf, + SES2_DLUCODE_S_COMPLETE_NOW = 0x10, + SES2_DLUCODE_S_COMPLETE_AT_RESET = 0x11, + SES2_DLUCODE_S_COMPLETE_AT_POWERON = 0x12, + SES2_DLUCODE_S_VENDOR_70 = 0x70, + SES2_DLUCODE_S_VENDOR_71 = 0x71, + SES2_DLUCODE_S_VENDOR_72 = 0x72, + SES2_DLUCODE_S_VENDOR_73 = 0x73, + SES2_DLUCODE_S_VENDOR_74 = 0x74, + SES2_DLUCODE_S_VENDOR_75 = 0x75, + SES2_DLUCODE_S_VENDOR_76 = 0x76, + SES2_DLUCODE_S_VENDOR_77 = 0x77, + SES2_DLUCODE_S_VENDOR_78 = 0x78, + SES2_DLUCODE_S_VENDOR_79 = 0x79, + SES2_DLUCODE_S_VENDOR_7A = 0x7a, + SES2_DLUCODE_S_VENDOR_7B = 0x7b, + SES2_DLUCODE_S_VENDOR_7C = 0x7c, + SES2_DLUCODE_S_VENDOR_7D = 0x7d, + SES2_DLUCODE_S_VENDOR_7E = 0x7e, + SES2_DLUCODE_S_VENDOR_7F = 0x7f, + SES2_DLUCODE_S_PAGE_ERR = 0x80, + SES2_DLUCODE_S_IMAGE_ERR = 0x81, + SES2_DLUCODE_S_TIMEOUT = 0x82, + SES2_DLUCODE_S_INTERNAL_NEEDIMAGE = 0x83, + SES2_DLUCODE_S_INTERNAL_SAFE = 0x84, + SES2_DLUCODE_S_VENDOR_ERR_F0 = 0xf0, + SES2_DLUCODE_S_VENDOR_ERR_F1 = 0xf1, + SES2_DLUCODE_S_VENDOR_ERR_F2 = 0xf2, + SES2_DLUCODE_S_VENDOR_ERR_F3 = 0xf3, + SES2_DLUCODE_S_VENDOR_ERR_F4 = 0xf4, + SES2_DLUCODE_S_VENDOR_ERR_F5 = 0xf5, + SES2_DLUCODE_S_VENDOR_ERR_F6 = 0xf6, + SES2_DLUCODE_S_VENDOR_ERR_F7 = 0xf7, + SES2_DLUCODE_S_VENDOR_ERR_F8 = 0xf8, + SES2_DLUCODE_S_VENDOR_ERR_F9 = 0xf9, + SES2_DLUCODE_S_VENDOR_ERR_FA = 0xfa, + SES2_DLUCODE_S_VENDOR_ERR_FB = 0xfb, + SES2_DLUCODE_S_VENDOR_ERR_FC = 0xfc, + SES2_DLUCODE_S_VENDOR_ERR_FD = 0xfd, + SES2_DLUCODE_S_VENDOR_ERR_FE = 0xfe, + SES2_DLUCODE_S_VENDOR_ERR_FF = 0xff +} ses2_dl_ucode_status_t; + +typedef enum ses_dl_ucode_mode { + SES_DLUCODE_M_WITH_OFFS = 6, + SES_DLUCODE_M_WITH_OFFS_SAVE = 7 +} ses_dl_ucode_mode_t; + +#define SES_EN_PROP_UCODE_A "ses-microcode-dl-addl-status" /* U64 */ +#define SES_EN_PROP_UCODE_SZ "ses-microcode-maximum-size" /* U64 */ +#define SES_EN_PROP_UCODE_BUF "ses-microcode-buffer-id" /* U64 */ +#define SES_EN_PROP_UCODE_OFF "ses-microcode-buffer-offset" /* U64 */ + +#define SES_EN_PROP_NICK "ses-nickname" /* S */ +#define SES_EN_PROP_NICK_STATUS "ses-nickname-status" /* U64 */ +typedef enum ses_subnick_status { + SES_SNS_NO_ERROR = 0x0, + SES_SNS_ERR_PAGE = 0x80, + SES_SNS_ERR_INT_NICKLOST = 0x81, + SES_SNS_ERR_INT_PRESERVED = 0x82 +} ses_subnick_status_t; + +#define SES_EN_PROP_NICK_ADDL_STATUS "ses-nickname-additional-status" +#define SES_EN_PROP_NICK_LANG "ses-nickname-language" /* U64 */ + +#define SES_EN_PROP_POWER_DELAY "ses-power-cycle-delay" /* U64 */ +#define SES_EN_PROP_POWER_DURATION "ses-power-cycle-duration" /* U64 */ +#define SES_EN_PROP_POWER_REQUEST "ses-power-cycle-request" /* U64 */ + +typedef enum ses_power_delay { + SES_PDL_NONE = 0x0, + SES_PDL_IMMEDIATE = 0x3f +} ses_power_delay_t; + +typedef enum ses_power_duration { + SES_PDR_NONE = 0x0, + SES_PDR_MANUAL = 0x3f +} ses_power_duration_t; + +typedef enum ses_power_request { + SES_PRQ_NONE = 0x0, + SES_PRQ_SET = 0x1, + SES_PRQ_CANCEL = 0x2 +} ses_power_request_t; + +/* + * IEEE logical IDs (for SES_EN_PROP_LID) + */ +#define SPC3_NAA_INT "naa-id-integer" /* U64 */ +#define SPC3_NAA_ID_TYPE "naa-id-type" /* U64 */ +#define SPC3_NAA_COMPANY_ID "naa-company-id" /* U64 */ +#define SPC3_NAA_VS_A "naa-vendor-specific-a" /* U64 */ +#define SPC3_NAA_VS_B "naa-vendor-specific-b" /* U64 */ + +/* + * SES-2 Diagnostic page codes (Table 5, 6.1.1). The set of exported pages + * constitutes an inter-plugin interface and is therefore part of the public + * header file. + */ +typedef enum ses2_diag_page { + SES2_DIAGPAGE_SUPPORTED_PAGES = 0x00, + SES2_DIAGPAGE_CONFIG = 0x01, + SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS = 0x02, + SES2_DIAGPAGE_HELP_TEXT = 0x03, + SES2_DIAGPAGE_STRING_IO = 0x04, + SES2_DIAGPAGE_THRESHOLD_IO = 0x05, + SES2_DIAGPAGE_ELEMENT_DESC = 0x07, + SES2_DIAGPAGE_SHORT_STATUS = 0x08, + SES2_DIAGPAGE_ENCLOSURE_BUSY = 0x09, + SES2_DIAGPAGE_ADDL_ELEM_STATUS = 0x0a, + SES2_DIAGPAGE_SUBENCLOSURE_HELP_TEXT = 0x0b, + SES2_DIAGPAGE_SUBENCLOSURE_STRING_IO = 0x0c, + SES2_DIAGPAGE_SUPPORTED_SES_PAGES = 0x0d, + SES2_DIAGPAGE_DL_MICROCODE_CTL_STATUS = 0x0e, + SES2_DIAGPAGE_SUBENCLOSURE_NICKNAME_CTL_STATUS = 0x0f, + SES2_DIAGPAGE_VENDOR_0 = 0x10, + SES2_DIAGPAGE_VENDOR_1 = 0x11, + SES2_DIAGPAGE_VENDOR_2 = 0x12, + SES2_DIAGPAGE_VENDOR_3 = 0x13, + SES2_DIAGPAGE_VENDOR_4 = 0x14, + SES2_DIAGPAGE_VENDOR_5 = 0x15, + SES2_DIAGPAGE_VENDOR_6 = 0x16, + SES2_DIAGPAGE_VENDOR_7 = 0x17, + SES2_DIAGPAGE_VENDOR_8 = 0x18, + SES2_DIAGPAGE_VENDOR_9 = 0x19, + SES2_DIAGPAGE_VENDOR_A = 0x1a, + SES2_DIAGPAGE_VENDOR_B = 0x1b, + SES2_DIAGPAGE_VENDOR_C = 0x1c, + SES2_DIAGPAGE_VENDOR_D = 0x1d, + SES2_DIAGPAGE_VENDOR_E = 0x1e, + SES2_DIAGPAGE_VENDOR_F = 0x1f +} ses2_diag_page_t; + +#define SES_CTL_OP_SETPROP "ses-ctl-setprop" +#define SES_CTL_OP_DL_UCODE "ses-ctl-dl-ucode" + +#define SES_CTL_PROP_UCODE_DATA "ses-ctl-ucode-data" +#define SES_CTL_PROP_UCODE_BUFID "ses-ctl-ucode-bufid" +#define SES_CTL_PROP_UCODE_MODE "ses-ctl-ucode-mode" + +#ifdef __cplusplus +} +#endif + +#endif /* _FRAMEWORK_SES_H */ diff --git a/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_element.c b/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_element.c new file mode 100644 index 0000000000..b0fe97d6d5 --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_element.c @@ -0,0 +1,1008 @@ +/* + * 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 <stddef.h> +#include <stdio.h> +#include <string.h> +#include <libnvpair.h> + +#include <scsi/libses.h> +#include "ses2_impl.h" + +static int +elem_parse_device(const ses2_elem_status_impl_t *esip, nvlist_t *nvl) +{ + ses2_device_status_impl_t *dip = (ses2_device_status_impl_t *)esip; + int nverr; + + SES_NV_ADD(uint64, nverr, nvl, SES_DEV_PROP_SLOT_ADDR, + dip->sdsi_slot_addr); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_REPORT, + dip->sdsi_report); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, + dip->sdsi_ident); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_RMV, dip->sdsi_rmv); + SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_READY_TO_INSERT, + dip->sdsi_ready_to_insert); + SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_ENC_BYP_B, + dip->sdsi_enclosure_bypassed_b); + SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_ENC_BYP_A, + dip->sdsi_enclosure_bypassed_a); + SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_DO_NOT_REMOVE, + dip->sdsi_do_not_remove); + SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_APP_BYP_A, + dip->sdsi_app_client_bypassed_a); + SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_DEV_BYP_B, + dip->sdsi_device_bypassed_b); + SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_DEV_BYP_A, + dip->sdsi_device_bypassed_a); + SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_BYP_B, + dip->sdsi_bypassed_b); + SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_BYP_A, + dip->sdsi_bypassed_a); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_OFF, + dip->sdsi_device_off); + SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_FAULT_RQSTD, + dip->sdsi_fault_reqstd); + SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_FAULT_SENSED, + dip->sdsi_fault_sensed); + SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_APP_BYP_B, + dip->sdsi_app_client_bypassed_b); + + return (0); +} + +static int +elem_parse_psu(const ses2_elem_status_impl_t *esip, nvlist_t *nvl) +{ + ses2_psu_status_impl_t *pip = (ses2_psu_status_impl_t *)esip; + int nverr; + + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, + pip->spsi_ident); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PSU_PROP_DC_OVER_CURRENT, + pip->spsi_dc_over_current); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PSU_PROP_DC_UNDER_VOLTAGE, + pip->spsi_dc_under_voltage); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PSU_PROP_DC_OVER_VOLTAGE, + pip->spsi_dc_over_voltage); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PSU_PROP_DC_FAIL, + pip->spsi_dc_fail); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PSU_PROP_AC_FAIL, + pip->spsi_ac_fail); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PSU_PROP_TEMP_WARN, + pip->spsi_temp_warn); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PSU_PROP_OVERTEMP_FAIL, + pip->spsi_overtmp_fail); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_OFF, pip->spsi_off); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_REQUESTED_ON, + pip->spsi_rqsted_on); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, pip->spsi_fail); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_HOT_SWAP, + pip->spsi_hot_swap); + + return (0); +} + +static int +elem_parse_cooling(const ses2_elem_status_impl_t *esip, nvlist_t *nvl) +{ + ses2_cooling_status_impl_t *cip = (ses2_cooling_status_impl_t *)esip; + int nverr; + + SES_NV_ADD(uint64, nverr, nvl, SES_COOLING_PROP_FAN_SPEED, + SES2_ES_COOLING_ST_FAN_SPEED(cip)); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, + cip->scsi_ident); + SES_NV_ADD(uint64, nverr, nvl, SES_COOLING_PROP_SPEED_CODE, + cip->scsi_actual_speed_code); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_OFF, cip->scsi_off); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_REQUESTED_ON, + cip->scsi_requested_on); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, cip->scsi_fail); + + return (0); +} + +static int +elem_parse_temp(const ses2_elem_status_impl_t *esip, nvlist_t *nvl) +{ + ses2_temp_status_impl_t *tip = (ses2_temp_status_impl_t *)esip; + int nverr; + + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, tip->stsi_ident); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, tip->stsi_fail); + SES_NV_ADD(int64, nverr, nvl, SES_TEMP_PROP_TEMP, + SES2_ES_TEMP_ST_TEMPERATURE(tip)); + SES_NV_ADD(boolean_value, nverr, nvl, SES_TEMP_PROP_UNDERTEMP_WARN, + tip->stsi_ut_warn); + SES_NV_ADD(boolean_value, nverr, nvl, SES_TEMP_PROP_UNDERTEMP_FAIL, + tip->stsi_ut_fail); + SES_NV_ADD(boolean_value, nverr, nvl, SES_TEMP_PROP_OVERTEMP_WARN, + tip->stsi_ot_warn); + SES_NV_ADD(boolean_value, nverr, nvl, SES_TEMP_PROP_OVERTEMP_FAIL, + tip->stsi_ot_fail); + + return (0); +} + +static int +elem_parse_lock(const ses2_elem_status_impl_t *esip, nvlist_t *nvl) +{ + ses2_lock_status_impl_t *lip = (ses2_lock_status_impl_t *)esip; + int nverr; + + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, + lip->slsi_fail); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, + lip->slsi_ident); + SES_NV_ADD(boolean_value, nverr, nvl, SES_LOCK_PROP_UNLOCKED, + lip->slsi_unlocked); + + return (0); +} + +static int +elem_parse_alarm(const ses2_elem_status_impl_t *esip, nvlist_t *nvl) +{ + ses2_alarm_status_impl_t *aip = (ses2_alarm_status_impl_t *)esip; + int nverr; + + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, aip->sasi_fail); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, + aip->sasi_ident); + SES_NV_ADD(boolean_value, nverr, nvl, SES_ALARM_PROP_UNRECOV, + aip->sasi_unrecov); + SES_NV_ADD(boolean_value, nverr, nvl, SES_ALARM_PROP_CRIT, + aip->sasi_crit); + SES_NV_ADD(boolean_value, nverr, nvl, SES_ALARM_PROP_NONCRIT, + aip->sasi_noncrit); + SES_NV_ADD(boolean_value, nverr, nvl, SES_ALARM_PROP_INFO, + aip->sasi_info); + SES_NV_ADD(boolean_value, nverr, nvl, SES_ALARM_PROP_REMIND, + aip->sasi_remind); + SES_NV_ADD(boolean_value, nverr, nvl, SES_ALARM_PROP_MUTED, + aip->sasi_muted); + SES_NV_ADD(boolean_value, nverr, nvl, SES_ALARM_PROP_RQST_MUTE, + aip->sasi_rqst_mute); + + return (0); +} + +static int +elem_parse_esc(const ses2_elem_status_impl_t *esip, nvlist_t *nvl) +{ + ses2_controller_status_impl_t *cip = + (ses2_controller_status_impl_t *)esip; + int nverr; + + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, cip->scsi_fail); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, cip->scsi_ident); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_REPORT, + cip->scsi_report); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_HOT_SWAP, + cip->scsi_hot_swap); + + return (0); +} + +static int +elem_parse_scc(const ses2_elem_status_impl_t *esip, nvlist_t *nvl) +{ + ses2_scc_status_impl_t *sip = (ses2_scc_status_impl_t *)esip; + int nverr; + + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, sip->sss_fail); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, sip->sss_ident); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_REPORT, + sip->sss_report); + + return (0); +} + +static int +elem_parse_cache(const ses2_elem_status_impl_t *esip, nvlist_t *nvl) +{ + ses2_nvcache_status_impl_t *np = (ses2_nvcache_status_impl_t *)esip; + int nverr; + + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, np->snsi_fail); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, + np->snsi_ident); + SES_NV_ADD(uint64, nverr, nvl, SES_CACHE_PROP_SIZE, + SES2_NVCACHE_SIZE(np)); + + return (0); +} + +static int +elem_parse_ups(const ses2_elem_status_impl_t *esip, nvlist_t *nvl) +{ + ses2_ups_status_impl_t *uip = (ses2_ups_status_impl_t *)esip; + int nverr; + + SES_NV_ADD(uint64, nverr, nvl, SES_UPS_PROP_TIMELEFT, + uip->susi_battery_status); + SES_NV_ADD(boolean_value, nverr, nvl, SES_UPS_PROP_INTF_FAIL, + uip->susi_intf_fail); + SES_NV_ADD(boolean_value, nverr, nvl, SES_UPS_PROP_WARN, + uip->susi_warn); + SES_NV_ADD(boolean_value, nverr, nvl, SES_UPS_PROP_UPS_FAIL, + uip->susi_ups_fail); + SES_NV_ADD(boolean_value, nverr, nvl, SES_UPS_PROP_DC_FAIL, + uip->susi_dc_fail); + SES_NV_ADD(boolean_value, nverr, nvl, SES_UPS_PROP_AC_FAIL, + uip->susi_ac_fail); + SES_NV_ADD(boolean_value, nverr, nvl, SES_UPS_PROP_AC_QUAL, + uip->susi_ac_qual); + SES_NV_ADD(boolean_value, nverr, nvl, SES_UPS_PROP_AC_HI, + uip->susi_ac_hi); + SES_NV_ADD(boolean_value, nverr, nvl, SES_UPS_PROP_AC_LO, + uip->susi_ac_lo); + SES_NV_ADD(boolean_value, nverr, nvl, SES_UPS_PROP_BPF, uip->susi_bpf); + SES_NV_ADD(boolean_value, nverr, nvl, SES_UPS_PROP_BATT_FAIL, + uip->susi_batt_fail); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, uip->susi_fail); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, uip->susi_ident); + + return (0); +} + +static int +elem_parse_display(const ses2_elem_status_impl_t *esip, nvlist_t *nvl) +{ + ses2_display_status_impl_t *dip = (ses2_display_status_impl_t *)esip; + int nverr; + + SES_NV_ADD(uint64, nverr, nvl, SES_DPY_PROP_MODE, + dip->sdsi_display_mode_status); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, dip->sdsi_fail); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, dip->sdsi_ident); + SES_NV_ADD(uint16, nverr, nvl, SES_DPY_PROP_CHAR, + dip->sdsi_display_character_status); + + return (0); +} + +static int +elem_parse_keypad(const ses2_elem_status_impl_t *esip, nvlist_t *nvl) +{ + ses2_keypad_status_impl_t *kip = (ses2_keypad_status_impl_t *)esip; + int nverr; + + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, kip->sksi_fail); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, kip->sksi_ident); + + return (0); +} + +static int +elem_parse_px(const ses2_elem_status_impl_t *esip, nvlist_t *nvl) +{ + ses2_port_status_impl_t *pip = (ses2_port_status_impl_t *)esip; + int nverr; + + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, pip->spsi_fail); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, pip->spsi_ident); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_REPORT, + pip->spsi_report); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PX_PROP_XMIT_FAIL, + pip->spsi_xmit_fail); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PX_PROP_LOL, pip->spsi_lol); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_DISABLED, + pip->spsi_disabled); + + return (0); +} + +static int +elem_parse_lang(const ses2_elem_status_impl_t *esip, nvlist_t *nvl) +{ + ses2_lang_status_impl_t *lip = (ses2_lang_status_impl_t *)esip; + int nverr; + + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, + lip->slsi_ident); + SES_NV_ADD(uint64, nverr, nvl, SES_LANG_PROP_LANGCODE, + SCSI_READ16(&lip->slsi_language_code)); + + return (0); +} + +static int +elem_parse_comm(const ses2_elem_status_impl_t *esip, nvlist_t *nvl) +{ + ses2_comm_status_impl_t *cip = (ses2_comm_status_impl_t *)esip; + int nverr; + + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, cip->scsi_fail); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, + cip->scsi_ident); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_DISABLED, + cip->scsi_disabled); + + return (0); +} + +static int +elem_parse_voltage(const ses2_elem_status_impl_t *esip, nvlist_t *nvl) +{ + ses2_voltage_status_impl_t *vip = (ses2_voltage_status_impl_t *)esip; + int nverr; + + SES_NV_ADD(boolean_value, nverr, nvl, SES_VS_PROP_CRIT_UNDER, + vip->svsi_crit_under); + SES_NV_ADD(boolean_value, nverr, nvl, SES_VS_PROP_CRIT_OVER, + vip->svsi_crit_over); + SES_NV_ADD(boolean_value, nverr, nvl, SES_VS_PROP_WARN_UNDER, + vip->svsi_warn_under); + SES_NV_ADD(boolean_value, nverr, nvl, SES_VS_PROP_WARN_OVER, + vip->svsi_warn_over); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, vip->svsi_fail); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, vip->svsi_ident); + SES_NV_ADD(int64, nverr, nvl, SES_VS_PROP_VOLTAGE_MV, + SCSI_READ16(&vip->svsi_voltage)); + + return (0); +} + +static int +elem_parse_current(const ses2_elem_status_impl_t *esip, nvlist_t *nvl) +{ + ses2_current_status_impl_t *cip = (ses2_current_status_impl_t *)esip; + int nverr; + + SES_NV_ADD(boolean_value, nverr, nvl, SES_CS_PROP_CRIT_OVER, + cip->scsi_crit_over); + SES_NV_ADD(boolean_value, nverr, nvl, SES_CS_PROP_WARN_OVER, + cip->scsi_warn_over); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, cip->scsi_fail); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, cip->scsi_ident); + SES_NV_ADD(int64, nverr, nvl, SES_CS_PROP_CURRENT_MA, + SCSI_READ16(&cip->scsi_current)); + + return (0); +} + +static int +elem_parse_itp(const ses2_elem_status_impl_t *esip, nvlist_t *nvl) +{ + ses2_itp_status_impl_t *iip = (ses2_itp_status_impl_t *)esip; + int nverr; + + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, iip->sisi_fail); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, + iip->sisi_ident); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_REPORT, + iip->sisi_report); + SES_NV_ADD(boolean_value, nverr, nvl, SES_ITP_PROP_ENABLED, + iip->sisi_enabled); + + return (0); +} + +static int +elem_parse_sse(const ses2_elem_status_impl_t *esip, nvlist_t *nvl) +{ + ses2_ss_status_impl_t *sip = (ses2_ss_status_impl_t *)esip; + int nverr; + + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, sip->sss_fail); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, sip->sss_ident); + SES_NV_ADD(uint64, nverr, nvl, SES_SS_PROP_SHORT_STATUS, + sip->sss_short_status); + + return (0); +} + +static int +elem_parse_arraydev(const ses2_elem_status_impl_t *esip, nvlist_t *nvl) +{ + ses2_array_device_status_impl_t *aip = + (ses2_array_device_status_impl_t *)esip; + int nverr; + + SES_NV_ADD(boolean_value, nverr, nvl, SES_AD_PROP_RR_ABORT, + aip->sadsi_rr_abort); + SES_NV_ADD(boolean_value, nverr, nvl, SES_AD_PROP_REBUILD, + aip->sadsi_rebuild); + SES_NV_ADD(boolean_value, nverr, nvl, SES_AD_PROP_IN_FAILED_ARRAY, + aip->sadsi_in_failed_array); + SES_NV_ADD(boolean_value, nverr, nvl, SES_AD_PROP_IN_CRIT_ARRAY, + aip->sadsi_in_crit_array); + SES_NV_ADD(boolean_value, nverr, nvl, SES_AD_PROP_CONS_CHK, + aip->sadsi_cons_chk); + SES_NV_ADD(boolean_value, nverr, nvl, SES_AD_PROP_HOT_SPARE, + aip->sadsi_hot_spare); + SES_NV_ADD(boolean_value, nverr, nvl, SES_AD_PROP_RSVD_DEVICE, + aip->sadsi_rsvd_device); + SES_NV_ADD(boolean_value, nverr, nvl, SES_AD_PROP_OK, aip->sadsi_ok); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_REPORT, + aip->sadsi_report); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, aip->sadsi_ident); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_RMV, aip->sadsi_rmv); + SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_READY_TO_INSERT, + aip->sadsi_ready_to_insert); + SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_ENC_BYP_B, + aip->sadsi_enclosure_bypassed_b); + SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_ENC_BYP_A, + aip->sadsi_enclosure_bypassed_a); + SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_DO_NOT_REMOVE, + aip->sadsi_do_not_remove); + SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_APP_BYP_A, + aip->sadsi_app_client_bypassed_a); + SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_DEV_BYP_B, + aip->sadsi_device_bypassed_b); + SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_DEV_BYP_A, + aip->sadsi_device_bypassed_a); + SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_BYP_B, + aip->sadsi_bypassed_b); + SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_BYP_A, + aip->sadsi_bypassed_a); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_OFF, + aip->sadsi_device_off); + SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_FAULT_RQSTD, + aip->sadsi_fault_reqstd); + SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_FAULT_SENSED, + aip->sadsi_fault_sensed); + SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_APP_BYP_B, + aip->sadsi_app_client_bypassed_b); + + return (0); +} + +static int +elem_parse_expander(const ses2_elem_status_impl_t *esip, nvlist_t *nvl) +{ + ses2_expander_status_impl_t *eip = (ses2_expander_status_impl_t *)esip; + int nverr; + + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, eip->sesi_fail); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, eip->sesi_ident); + + return (0); +} + +static int +elem_parse_sasconn(const ses2_elem_status_impl_t *esip, nvlist_t *nvl) +{ + ses2_sasconn_status_impl_t *sip = (ses2_sasconn_status_impl_t *)esip; + int nverr; + + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, sip->sss_fail); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, sip->sss_ident); + SES_NV_ADD(uint64, nverr, nvl, SES_SC_PROP_CONNECTOR_TYPE, + sip->sss_connector_type); + SES_NV_ADD(uint64, nverr, nvl, SES_SC_PROP_PHYSICAL_LINK, + sip->sss_connector_physical_link); + + return (0); +} + +static const struct status_parser { + ses2_element_type_t type; + int (*func)(const ses2_elem_status_impl_t *, nvlist_t *); +} status_parsers[] = { + { SES_ET_DEVICE, elem_parse_device }, + { SES_ET_POWER_SUPPLY, elem_parse_psu }, + { SES_ET_COOLING, elem_parse_cooling }, + { SES_ET_TEMPERATURE_SENSOR, elem_parse_temp }, + { SES_ET_DOOR_LOCK, elem_parse_lock }, + { SES_ET_AUDIBLE_ALARM, elem_parse_alarm }, + { SES_ET_ESC_ELECTRONICS, elem_parse_esc }, + { SES_ET_SCC_ELECTRONICS, elem_parse_scc }, + { SES_ET_NONVOLATILE_CACHE, elem_parse_cache }, + { SES_ET_UPS, elem_parse_ups }, + { SES_ET_DISPLAY, elem_parse_display }, + { SES_ET_KEY_PAD_ENTRY, elem_parse_keypad }, + { SES_ET_SCSI_PORT_XCVR, elem_parse_px }, + { SES_ET_LANGUAGE, elem_parse_lang }, + { SES_ET_COMMUNICATION_PORT, elem_parse_comm }, + { SES_ET_VOLTAGE_SENSOR, elem_parse_voltage }, + { SES_ET_CURRENT_SENSOR, elem_parse_current }, + { SES_ET_SCSI_TARGET_PORT, elem_parse_itp }, + { SES_ET_SCSI_INITIATOR_PORT, elem_parse_itp }, + { SES_ET_SIMPLE_SUBENCLOSURE, elem_parse_sse }, + { SES_ET_ARRAY_DEVICE, elem_parse_arraydev }, + { SES_ET_SAS_EXPANDER, elem_parse_expander }, + { SES_ET_SAS_CONNECTOR, elem_parse_sasconn }, + { (ses2_element_type_t)-1, NULL } +}; + +static int +elem_parse_sd(ses_plugin_t *spp, ses_node_t *np) +{ + ses2_elem_status_impl_t *esip; + const struct status_parser *sp; + nvlist_t *nvl = ses_node_props(np); + size_t len; + int nverr; + uint64_t type; + + if ((esip = ses_plugin_page_lookup(spp, + ses_node_snapshot(np), SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + np, &len)) == NULL) + return (0); + + VERIFY(nvlist_lookup_uint64(nvl, SES_PROP_ELEMENT_TYPE, + &type) == 0); + + SES_NV_ADD(uint64, nverr, nvl, SES_PROP_STATUS_CODE, + esip->sesi_common.sesi_status_code); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_SWAP, + esip->sesi_common.sesi_swap); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_DISABLED, + esip->sesi_common.sesi_disabled); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_PRDFAIL, + esip->sesi_common.sesi_prdfail); + + for (sp = &status_parsers[0]; sp->type != (ses2_element_type_t)-1; sp++) + if (sp->type == type && sp->func != NULL) + return (sp->func(esip, nvl)); + + return (0); +} + +static int +elem_parse_descr(ses_plugin_t *sp, ses_node_t *np) +{ + char *desc; + size_t len; + nvlist_t *props = ses_node_props(np); + int nverr; + + if ((desc = ses_plugin_page_lookup(sp, ses_node_snapshot(np), + SES2_DIAGPAGE_ELEMENT_DESC, np, &len)) == NULL) + return (0); + + SES_NV_ADD(fixed_string, nverr, props, SES_PROP_DESCRIPTION, + desc, len); + + return (0); +} + +static int +elem_parse_aes_fc(const ses2_aes_descr_fc_eip_impl_t *fp, + nvlist_t *nvl, size_t len) +{ + int nverr, i; + nvlist_t **nva; + int nports; + + if (len < offsetof(ses2_aes_descr_fc_eip_impl_t, + sadfi_ports)) + return (0); + + SES_NV_ADD(uint64, nverr, nvl, SES_PROP_BAY_NUMBER, + fp->sadfi_bay_number); + SES_NV_ADD(uint64, nverr, nvl, SES_FC_PROP_NODE_NAME, + SCSI_READ64(&fp->sadfi_node_name)); + + nports = MIN(fp->sadfi_n_ports, + (len - offsetof(ses2_aes_descr_fc_eip_impl_t, + sadfi_ports)) / sizeof (ses2_aes_port_descr_impl_t)); + + if (nports == 0) + return (0); + + nva = ses_zalloc(nports * sizeof (nvlist_t *)); + if (nva == NULL) + return (-1); + + for (i = 0; i < nports; i++) { + if ((nverr = nvlist_alloc(&nva[i], NV_UNIQUE_NAME, 0)) != 0) + goto fail; + if ((nverr = nvlist_add_uint64(nva[i], SES_FC_PROP_LOOP_POS, + fp->sadfi_ports[i].sapdi_port_loop_position)) != 0) + goto fail; + if ((nverr = nvlist_add_uint64(nva[i], SES_FC_PROP_REQ_HARDADDR, + fp->sadfi_ports[i].sapdi_port_requested_hard_address)) != 0) + goto fail; + nverr = nvlist_add_uint64(nva[i], SES_FC_PROP_N_PORT_ID, + SCSI_READ24(fp->sadfi_ports[i].sapdi_n_port_identifier)); + if (nverr != 0) + goto fail; + if ((nverr = nvlist_add_uint64(nva[i], SES_FC_PROP_N_PORT_NAME, + SCSI_READ64(&fp->sadfi_ports[i].sapdi_n_port_name))) != 0) + goto fail; + } + + if ((nverr = nvlist_add_nvlist_array(nvl, SES_FC_PROP_PORTS, + nva, nports)) != 0) + goto fail; + + for (i = 0; i < nports && nva[i] != NULL; i++) + nvlist_free(nva[i]); + ses_free(nva); + return (0); + +fail: + for (i = 0; i < nports && nva[i] != NULL; i++) + nvlist_free(nva[i]); + ses_free(nva); + return (ses_set_nverrno(nverr, NULL)); +} + +static int +elem_parse_aes_device(const ses2_aes_descr_eip_impl_t *dep, nvlist_t *nvl, + size_t len) +{ + ses2_aes_descr_fc_eip_impl_t *fp; + ses2_aes_descr_sas0_eip_impl_t *s0ep; + ses2_aes_descr_sas0_impl_t *s0p; + ses2_aes_descr_impl_t *dip; + nvlist_t **nva; + int nverr, i; + size_t nphy; + + if (dep->sadei_eip) { + s0ep = (ses2_aes_descr_sas0_eip_impl_t *) + dep->sadei_protocol_specific; + s0p = (ses2_aes_descr_sas0_impl_t *) + dep->sadei_protocol_specific; + } else { + dip = (ses2_aes_descr_impl_t *)dep; + s0ep = NULL; + s0p = (ses2_aes_descr_sas0_impl_t *) + dip->sadei_protocol_specific; + } + + if (dep->sadei_invalid) + return (0); + + if (dep->sadei_protocol_identifier == SPC4_PROTO_FIBRE_CHANNEL) { + fp = (ses2_aes_descr_fc_eip_impl_t *) + dep->sadei_protocol_specific; + + if (!SES_WITHIN_PAGE_STRUCT(fp, dep, len)) + return (0); + + return (elem_parse_aes_fc(fp, nvl, len - + offsetof(ses2_aes_descr_eip_impl_t, + sadei_protocol_specific))); + } else if (dep->sadei_protocol_identifier != SPC4_PROTO_SAS) { + return (0); + } + + if (s0p->sadsi_descriptor_type != SES2_AESD_SAS_DEVICE) + return (0); + + SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_SAS_NOT_ALL_PHYS, + s0p->sadsi_not_all_phys); + if (s0ep != NULL) { + SES_NV_ADD(uint64, nverr, nvl, SES_PROP_BAY_NUMBER, + s0ep->sadsi_bay_number); + nphy = MIN(s0ep->sadsi_n_phy_descriptors, + (len - offsetof(ses2_aes_descr_sas0_eip_impl_t, + sadsi_phys)) / sizeof (ses2_aes_phy0_descr_impl_t)); + } else { + nphy = MIN(s0p->sadsi_n_phy_descriptors, + (len - offsetof(ses2_aes_descr_sas0_impl_t, + sadsi_phys)) / sizeof (ses2_aes_phy0_descr_impl_t)); + } + + if (nphy == 0) + return (0); + + nva = ses_zalloc(nphy * sizeof (nvlist_t *)); + if (nva == NULL) + return (-1); + + for (i = 0; i < nphy; i++) { + ses2_aes_phy0_descr_impl_t *pp; + pp = s0ep != NULL ? &s0ep->sadsi_phys[i] : &s0p->sadsi_phys[i]; + if ((nverr = nvlist_alloc(&nva[i], NV_UNIQUE_NAME, 0)) != 0) + goto fail; + if ((nverr = nvlist_add_uint64(nva[i], SES_SAS_PROP_DEVICE_TYPE, + pp->sapdi_device_type)) != 0) + goto fail; + if ((nverr = nvlist_add_boolean_value(nva[i], + SES_SAS_PROP_SMPI_PORT, pp->sapdi_smp_initiator_port)) != 0) + goto fail; + if ((nverr = nvlist_add_boolean_value(nva[i], + SES_SAS_PROP_STPI_PORT, pp->sapdi_stp_initiator_port)) != 0) + goto fail; + if ((nverr = nvlist_add_boolean_value(nva[i], + SES_SAS_PROP_SSPI_PORT, pp->sapdi_ssp_initiator_port)) != 0) + goto fail; + if ((nverr = nvlist_add_boolean_value(nva[i], + SES_SAS_PROP_SATA_DEVICE, pp->sapdi_sata_device)) != 0) + goto fail; + if ((nverr = nvlist_add_boolean_value(nva[i], + SES_SAS_PROP_SMPT_PORT, pp->sapdi_smp_target_port)) != 0) + goto fail; + if ((nverr = nvlist_add_boolean_value(nva[i], + SES_SAS_PROP_STPT_PORT, pp->sapdi_stp_target_port)) != 0) + goto fail; + if ((nverr = nvlist_add_boolean_value(nva[i], + SES_SAS_PROP_SSPT_PORT, pp->sapdi_ssp_target_port)) != 0) + goto fail; + nverr = nvlist_add_uint64(nva[i], SES_SAS_PROP_ATT_ADDR, + SCSI_READ64(&pp->sapdi_attached_sas_address)); + if (nverr != 0) + goto fail; + nverr = nvlist_add_uint64(nva[i], SES_SAS_PROP_ADDR, + SCSI_READ64(&pp->sapdi_sas_address)); + if (nverr != 0) + goto fail; + if ((nverr = nvlist_add_uint64(nva[i], SES_SAS_PROP_PHY_ID, + pp->sapdi_phy_identifier)) != 0) + goto fail; + } + + if ((nverr = nvlist_add_nvlist_array(nvl, SES_SAS_PROP_PHYS, + nva, nphy)) != 0) + goto fail; + + for (i = 0; i < nphy && nva[i] != NULL; i++) + nvlist_free(nva[i]); + ses_free(nva); + return (0); + +fail: + for (i = 0; i < nphy && nva[i] != NULL; i++) + nvlist_free(nva[i]); + ses_free(nva); + return (ses_set_nverrno(nverr, NULL)); +} + +static int +elem_parse_aes_expander(const ses2_aes_descr_eip_impl_t *dep, nvlist_t *nvl, + size_t len) +{ + ses2_aes_descr_exp_impl_t *sep; + nvlist_t **nva; + int nverr, i; + size_t nphy; + + if (dep->sadei_invalid) + return (0); + + /* + * This should never happen; no current SAS expander can have any + * other kind of ports. But maybe someday - one could envision a + * SAS expander with iSCSI target ports, for example. + */ + if (dep->sadei_protocol_identifier != SPC4_PROTO_SAS) + return (0); + + sep = (ses2_aes_descr_exp_impl_t *)dep->sadei_protocol_specific; + if (sep->sadei_descriptor_type != SES2_AESD_SAS_OTHER) + return (0); + + SES_NV_ADD(uint64, nverr, nvl, SES_EXP_PROP_SAS_ADDR, + SCSI_READ64(&sep->sadei_sas_address)); + + nphy = MIN(sep->sadei_n_exp_phy_descriptors, + (len - offsetof(ses2_aes_descr_exp_impl_t, + sadei_phys)) / sizeof (ses2_aes_exp_phy_descr_impl_t)); + + if (nphy == 0) + return (0); + + nva = ses_zalloc(nphy * sizeof (nvlist_t *)); + if (nva == NULL) + return (-1); + + for (i = 0; i < nphy; i++) { + if ((nverr = nvlist_alloc(&nva[i], NV_UNIQUE_NAME, 0)) != 0) + goto fail; + if ((nverr = nvlist_add_uint64(nva[i], SES_PROP_CE_IDX, + sep->sadei_phys[i].saepdi_connector_element_index)) != 0) + goto fail; + if ((nverr = nvlist_add_uint64(nva[i], SES_PROP_OE_IDX, + sep->sadei_phys[i].saepdi_other_element_index)) != 0) + goto fail; + } + + if ((nverr = nvlist_add_nvlist_array(nvl, SES_SAS_PROP_PHYS, + nva, nphy)) != 0) + goto fail; + + for (i = 0; i < nphy && nva[i] != NULL; i++) + nvlist_free(nva[i]); + ses_free(nva); + return (0); + +fail: + for (i = 0; i < nphy && nva[i] != NULL; i++) + nvlist_free(nva[i]); + ses_free(nva); + return (ses_set_nverrno(nverr, NULL)); +} + +static int +elem_parse_aes_misc(const ses2_aes_descr_eip_impl_t *dep, nvlist_t *nvl, + size_t len) +{ + ses2_aes_descr_fc_eip_impl_t *fp; + ses2_aes_descr_sas1_impl_t *s1p; + nvlist_t **nva; + int nverr, i; + size_t nphy; + + if (dep->sadei_invalid) + return (0); + + if (dep->sadei_protocol_identifier == SPC4_PROTO_FIBRE_CHANNEL) { + fp = (ses2_aes_descr_fc_eip_impl_t *) + dep->sadei_protocol_specific; + + if (!SES_WITHIN_PAGE_STRUCT(fp, dep, len)) + return (0); + + return (elem_parse_aes_fc(fp, nvl, len - + offsetof(ses2_aes_descr_eip_impl_t, + sadei_protocol_specific))); + } else if (dep->sadei_protocol_identifier != SPC4_PROTO_SAS) { + return (0); + } + + s1p = (ses2_aes_descr_sas1_impl_t *)dep->sadei_protocol_specific; + if (s1p->sadsi_descriptor_type == SES2_AESD_SAS_DEVICE) + return (0); + + nphy = MIN(s1p->sadsi_n_phy_descriptors, + (len - offsetof(ses2_aes_descr_sas1_impl_t, + sadsi_phys)) / sizeof (ses2_aes_phy1_descr_impl_t)); + + nva = ses_zalloc(nphy * sizeof (nvlist_t *)); + if (nva == NULL) + return (-1); + + for (i = 0; i < nphy; i++) { + if ((nverr = nvlist_alloc(&nva[i], NV_UNIQUE_NAME, 0)) != 0) + goto fail; + if ((nverr = nvlist_add_uint64(nva[i], SES_PROP_CE_IDX, + s1p->sadsi_phys[i].sapdi_connector_element_index)) != 0) + goto fail; + if ((nverr = nvlist_add_uint64(nva[i], SES_PROP_OE_IDX, + s1p->sadsi_phys[i].sapdi_other_element_index)) != 0) + goto fail; + if ((nverr = nvlist_add_uint64(nva[i], SES_SAS_PROP_ADDR, + SCSI_READ64(&s1p->sadsi_phys[i].sapdi_sas_address))) != 0) + goto fail; + } + + if ((nverr = nvlist_add_nvlist_array(nvl, SES_SAS_PROP_PHYS, + nva, nphy)) != 0) + goto fail; + + for (i = 0; i < nphy && nva[i] != NULL; i++) + nvlist_free(nva[i]); + + ses_free(nva); + return (0); + +fail: + for (i = 0; i < nphy && nva[i] != NULL; i++) + nvlist_free(nva[i]); + ses_free(nva); + return (nverr); +} + +static const struct aes_parser { + ses2_element_type_t type; + int (*func)(const ses2_aes_descr_eip_impl_t *, nvlist_t *, size_t); +} aes_parsers[] = { + { SES_ET_DEVICE, elem_parse_aes_device }, + { SES_ET_SCSI_TARGET_PORT, elem_parse_aes_misc }, + { SES_ET_SCSI_INITIATOR_PORT, elem_parse_aes_misc }, + { SES_ET_ESC_ELECTRONICS, elem_parse_aes_misc }, + { SES_ET_ARRAY_DEVICE, elem_parse_aes_device }, + { SES_ET_SAS_EXPANDER, elem_parse_aes_expander }, + { (ses2_element_type_t)-1, NULL } +}; + +static int +elem_parse_aes(ses_plugin_t *sp, ses_node_t *np) +{ + ses2_aes_descr_eip_impl_t *dep; + nvlist_t *props = ses_node_props(np); + const struct aes_parser *app; + uint64_t type; + size_t len; + + if (ses_node_type(np) == SES_NODE_AGGREGATE) + return (0); + + VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_TYPE, + &type) == 0); + + for (app = &aes_parsers[0]; app->func != NULL; app++) + if (app->type == type) + break; + if (app->func == NULL) + return (0); + + if ((dep = ses_plugin_page_lookup(sp, ses_node_snapshot(np), + SES2_DIAGPAGE_ADDL_ELEM_STATUS, np, &len)) == NULL) + return (0); + + return (app->func(dep, props, len)); +} + +static int +elem_parse_threshold(ses_plugin_t *sp, ses_node_t *np) +{ + ses_snap_t *snap = ses_node_snapshot(np); + ses2_threshold_impl_t *tp; + nvlist_t *nvl = ses_node_props(np); + int nverr; + uint64_t type; + size_t len; + + VERIFY(nvlist_lookup_uint64(nvl, SES_PROP_ELEMENT_TYPE, + &type) == 0); + + switch (type) { + case SES_ET_TEMPERATURE_SENSOR: + case SES_ET_UPS: + case SES_ET_VOLTAGE_SENSOR: + case SES_ET_CURRENT_SENSOR: + break; + default: + return (0); + } + + if ((tp = ses_plugin_page_lookup(sp, snap, + SES2_DIAGPAGE_THRESHOLD_IO, np, &len)) == NULL) + return (0); + + SES_NV_ADD(uint64, nverr, nvl, SES_PROP_THRESH_CRIT_HI, + tp->sti_high_crit); + SES_NV_ADD(uint64, nverr, nvl, SES_PROP_THRESH_WARN_HI, + tp->sti_high_warn); + SES_NV_ADD(uint64, nverr, nvl, SES_PROP_THRESH_CRIT_LO, + tp->sti_low_crit); + SES_NV_ADD(uint64, nverr, nvl, SES_PROP_THRESH_WARN_LO, + tp->sti_low_warn); + + return (0); +} + +int +ses2_fill_element_node(ses_plugin_t *sp, ses_node_t *np) +{ + int err; + + if ((err = elem_parse_sd(sp, np)) != 0) + return (err); + + if ((err = elem_parse_descr(sp, np)) != 0) + return (err); + + if ((err = elem_parse_aes(sp, np)) != 0) + return (err); + + if ((err = elem_parse_threshold(sp, np)) != 0) + return (err); + + return (0); +} diff --git a/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_element_ctl.c b/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_element_ctl.c new file mode 100644 index 0000000000..6868f0ea7f --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_element_ctl.c @@ -0,0 +1,1856 @@ +/* + * 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 <stddef.h> +#include <stdio.h> +#include <string.h> +#include <libnvpair.h> + +#include <scsi/libses.h> +#include "ses2_impl.h" + +static int +elem_setprop_device(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, + nvpair_t *nvp) +{ + ses2_device_ctl_impl_t *dip; + const char *name; + boolean_t v; + + if ((dip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + page, 0, np, B_FALSE)) == NULL) + return (-1); + + name = nvpair_name(nvp); + (void) nvpair_value_boolean_value(nvp, &v); + + if (strcmp(name, SES_PROP_IDENT) == 0) + dip->sdci_rqst_ident = v; + else if (strcmp(name, SES_PROP_RMV) == 0) + dip->sdci_rqst_remove = v; + else if (strcmp(name, SES_DEV_PROP_READY_TO_INSERT) == 0) + dip->sdci_rqst_insert = v; + else if (strcmp(name, SES_DEV_PROP_REQ_MISSING) == 0) + dip->sdci_rqst_missing = v; + else if (strcmp(name, SES_DEV_PROP_DO_NOT_REMOVE) == 0) + dip->sdci_do_not_remove = v; + else if (strcmp(name, SES_DEV_PROP_REQ_ACTIVE) == 0) + dip->sdci_rqst_active = v; + else if (strcmp(name, SES_DEV_PROP_BYP_B) == 0) + dip->sdci_enable_byp_b = v; + else if (strcmp(name, SES_DEV_PROP_BYP_A) == 0) + dip->sdci_enable_byp_a = v; + else if (strcmp(name, SES_PROP_OFF) == 0) + dip->sdci_device_off = v; + else if (strcmp(name, SES_DEV_PROP_FAULT_RQSTD) == 0) + dip->sdci_rqst_fault = v; + else + ses_panic("Bad property %s", name); + + return (0); +} + +static int +elem_setprop_psu(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, + nvpair_t *nvp) +{ + ses2_psu_ctl_impl_t *pip; + const char *name; + boolean_t v; + + if ((pip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + page, 0, np, B_FALSE)) == NULL) + return (-1); + + name = nvpair_name(nvp); + (void) nvpair_value_boolean_value(nvp, &v); + + if (strcmp(name, SES_PROP_IDENT) == 0) + pip->spci_rqst_ident = v; + else if (strcmp(name, SES_PROP_REQUESTED_ON) == 0) + pip->spci_rqst_on = v; + else if (strcmp(name, SES_PROP_FAIL) == 0) + pip->spci_rqst_fail = v; + else + ses_panic("Bad property %s", name); + + return (0); +} + +static int +elem_setprop_cooling(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, + nvpair_t *nvp) +{ + ses2_cooling_ctl_impl_t *cip; + const char *name; + boolean_t v1; + uint64_t v64; + + if ((cip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + page, 0, np, B_FALSE)) == NULL) + return (-1); + + name = nvpair_name(nvp); + + if (strcmp(name, SES_COOLING_PROP_SPEED_CODE) == 0) { + (void) nvpair_value_uint64(nvp, &v64); + cip->scci_requested_speed_code = v64; + return (0); + } + + (void) nvpair_value_boolean_value(nvp, &v1); + + if (strcmp(name, SES_PROP_IDENT) == 0) + cip->scci_rqst_ident = v1; + else if (strcmp(name, SES_PROP_REQUESTED_ON) == 0) + cip->scci_rqst_on = v1; + else if (strcmp(name, SES_PROP_FAIL) == 0) + cip->scci_rqst_fail = v1; + else + ses_panic("Bad property %s", name); + + return (0); +} + +static int +elem_setprop_temp(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, + nvpair_t *nvp) +{ + ses2_temp_ctl_impl_t *tip; + const char *name; + boolean_t v; + + if ((tip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + page, 0, np, B_FALSE)) == NULL) + return (-1); + + name = nvpair_name(nvp); + (void) nvpair_value_boolean_value(nvp, &v); + + if (strcmp(name, SES_PROP_FAIL) == 0) + tip->stci_rqst_fail = v; + else if (strcmp(name, SES_PROP_IDENT) == 0) + tip->stci_rqst_ident = v; + else + ses_panic("Bad property %s", name); + + return (0); +} + +static int +elem_setprop_lock(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, + nvpair_t *nvp) +{ + ses2_lock_ctl_impl_t *lip; + const char *name; + boolean_t v; + + if ((lip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + page, 0, np, B_FALSE)) == NULL) + return (-1); + + name = nvpair_name(nvp); + (void) nvpair_value_boolean_value(nvp, &v); + + if (strcmp(name, SES_PROP_FAIL) == 0) + lip->slci_rqst_fail = v; + else if (strcmp(name, SES_PROP_IDENT) == 0) + lip->slci_rqst_ident = v; + else if (strcmp(name, SES_LOCK_PROP_UNLOCKED) == 0) + lip->slci_unlock = v; + else + ses_panic("Bad property %s", name); + + return (0); +} + +static int +elem_setprop_alarm(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, + nvpair_t *nvp) +{ + ses2_alarm_ctl_impl_t *aip; + const char *name; + boolean_t v; + + if ((aip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + page, 0, np, B_FALSE)) == NULL) + return (-1); + + name = nvpair_name(nvp); + (void) nvpair_value_boolean_value(nvp, &v); + + if (strcmp(name, SES_PROP_FAIL) == 0) + aip->saci_rqst_fail = v; + else if (strcmp(name, SES_PROP_IDENT) == 0) + aip->saci_rqst_ident = v; + else if (strcmp(name, SES_ALARM_PROP_UNRECOV) == 0) + aip->saci_unrecov = v; + else if (strcmp(name, SES_ALARM_PROP_CRIT) == 0) + aip->saci_crit = v; + else if (strcmp(name, SES_ALARM_PROP_NONCRIT) == 0) + aip->saci_noncrit = v; + else if (strcmp(name, SES_ALARM_PROP_INFO) == 0) + aip->saci_info = v; + else if (strcmp(name, SES_ALARM_PROP_REMIND) == 0) + aip->saci_set_remind = v; + else if (strcmp(name, SES_ALARM_PROP_MUTED) == 0) + aip->saci_set_mute = v; + else + ses_panic("Bad property %s", name); + + return (0); +} + +static int +elem_setprop_esc(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, + nvpair_t *nvp) +{ + ses2_controller_ctl_impl_t *cip; + const char *name; + boolean_t v; + + if ((cip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + page, 0, np, B_FALSE)) == NULL) + return (-1); + + name = nvpair_name(nvp); + (void) nvpair_value_boolean_value(nvp, &v); + + if (strcmp(name, SES_PROP_FAIL) == 0) + cip->scci_rqst_fail = v; + else if (strcmp(name, SES_PROP_IDENT) == 0) + cip->scci_rqst_ident = v; + else if (strcmp(name, SES_ESC_PROP_SELECT) == 0) + cip->scci_select_element = v; + else + ses_panic("Bad property %s", name); + + return (0); +} + +static int +elem_setprop_scc(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, + nvpair_t *nvp) +{ + ses2_scc_ctl_impl_t *sip; + const char *name; + boolean_t v; + + if ((sip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + page, 0, np, B_FALSE)) == NULL) + return (-1); + + name = nvpair_name(nvp); + (void) nvpair_value_boolean_value(nvp, &v); + + if (strcmp(name, SES_PROP_FAIL) == 0) + sip->ssci_rqst_fail = v; + else if (strcmp(name, SES_PROP_IDENT) == 0) + sip->ssci_rqst_ident = v; + else + ses_panic("Bad property %s", name); + + return (0); +} + +static int +elem_setprop_ups(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, + nvpair_t *nvp) +{ + ses2_ups_ctl_impl_t *uip; + const char *name; + boolean_t v; + + if ((uip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + page, 0, np, B_FALSE)) == NULL) + return (-1); + + name = nvpair_name(nvp); + (void) nvpair_value_boolean_value(nvp, &v); + + if (strcmp(name, SES_PROP_FAIL) == 0) + uip->suci_rqst_fail = v; + else if (strcmp(name, SES_PROP_IDENT) == 0) + uip->suci_rqst_ident = v; + else + ses_panic("Bad property %s", name); + + return (0); +} + +static int +elem_setprop_cache(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, + nvpair_t *nvp) +{ + ses2_nvcache_ctl_impl_t *cip; + const char *name; + boolean_t v; + + if ((cip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + page, 0, np, B_FALSE)) == NULL) + return (-1); + + name = nvpair_name(nvp); + (void) nvpair_value_boolean_value(nvp, &v); + + if (strcmp(name, SES_PROP_FAIL) == 0) + cip->snci_rqst_fail = v; + else if (strcmp(name, SES_PROP_IDENT) == 0) + cip->snci_rqst_ident = v; + else + ses_panic("Bad property %s", name); + + return (0); +} + +static int +elem_setprop_keypad(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, + nvpair_t *nvp) +{ + ses2_keypad_ctl_impl_t *kip; + const char *name; + boolean_t v; + + if ((kip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + page, 0, np, B_FALSE)) == NULL) + return (-1); + + name = nvpair_name(nvp); + (void) nvpair_value_boolean_value(nvp, &v); + + if (strcmp(name, SES_PROP_FAIL) == 0) + kip->skci_rqst_fail = v; + else if (strcmp(name, SES_PROP_IDENT) == 0) + kip->skci_rqst_ident = v; + else + ses_panic("Bad property %s", name); + + return (0); +} + +static int +elem_setprop_display(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, + nvpair_t *nvp) +{ + ses2_display_ctl_impl_t *dip; + const char *name; + boolean_t v1; + uint16_t v16; + uint64_t v64; + + if ((dip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + page, 0, np, B_FALSE)) == NULL) + return (-1); + + + name = nvpair_name(nvp); + + if (strcmp(name, SES_DPY_PROP_MODE) == 0) { + (void) nvpair_value_uint64(nvp, &v64); + dip->sdci_display_mode = v64; + return (0); + } else if (strcmp(name, SES_DPY_PROP_CHAR) == 0) { + (void) nvpair_value_uint16(nvp, &v16); + SCSI_WRITE16(&dip->sdci_display_character, v16); + return (0); + } + + (void) nvpair_value_boolean_value(nvp, &v1); + + if (strcmp(name, SES_PROP_FAIL) == 0) + dip->sdci_rqst_fail = v1; + else if (strcmp(name, SES_PROP_IDENT) == 0) + dip->sdci_rqst_ident = v1; + else + ses_panic("Bad property %s", name); + return (0); +} + +static int +elem_setprop_px(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, + nvpair_t *nvp) +{ + ses2_port_ctl_impl_t *pip; + const char *name; + boolean_t v; + + if ((pip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + page, 0, np, B_FALSE)) == NULL) + return (-1); + + name = nvpair_name(nvp); + + (void) nvpair_value_boolean_value(nvp, &v); + + if (strcmp(name, SES_PROP_FAIL) == 0) + pip->spci_rqst_fail = v; + else if (strcmp(name, SES_PROP_IDENT) == 0) + pip->spci_rqst_ident = v; + else if (strcmp(name, SES_PROP_DISABLED) == 0) + pip->spci_disable = v; + else + ses_panic("Bad property %s", name); + + return (0); +} + +static int +elem_setprop_lang(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, + nvpair_t *nvp) +{ + ses2_lang_ctl_impl_t *lip; + const char *name; + boolean_t v1; + uint64_t v64; + + if ((lip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + page, 0, np, B_FALSE)) == NULL) + return (-1); + + name = nvpair_name(nvp); + + if (strcmp(name, SES_LANG_PROP_LANGCODE) == 0) { + (void) nvpair_value_uint64(nvp, &v64); + SCSI_WRITE16(&lip->slci_language_code, v64); + return (0); + } + + (void) nvpair_value_boolean_value(nvp, &v1); + + if (strcmp(name, SES_PROP_IDENT) == 0) + lip->slci_rqst_ident = v1; + else + ses_panic("Bad property %s", name); + + return (0); +} + +static int +elem_setprop_comm(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, + nvpair_t *nvp) +{ + ses2_comm_ctl_impl_t *cip; + const char *name; + boolean_t v; + + if ((cip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + page, 0, np, B_FALSE)) == NULL) + return (-1); + + name = nvpair_name(nvp); + (void) nvpair_value_boolean_value(nvp, &v); + + if (strcmp(name, SES_PROP_FAIL) == 0) + cip->scci_rqst_fail = v; + else if (strcmp(name, SES_PROP_IDENT) == 0) + cip->scci_rqst_ident = v; + else if (strcmp(name, SES_PROP_DISABLED) == 0) + cip->scci_disable = v; + else + ses_panic("Bad property %s", name); + + return (0); +} + +static int +elem_setprop_voltage(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, + nvpair_t *nvp) +{ + ses2_voltage_ctl_impl_t *vip; + const char *name; + boolean_t v; + + if ((vip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + page, 0, np, B_FALSE)) == NULL) + return (-1); + + name = nvpair_name(nvp); + (void) nvpair_value_boolean_value(nvp, &v); + + if (strcmp(name, SES_PROP_FAIL) == 0) + vip->svci_rqst_fail = v; + else if (strcmp(name, SES_PROP_IDENT) == 0) + vip->svci_rqst_ident = v; + else + ses_panic("Bad property %s", name); + + return (0); +} + +static int +elem_setprop_current(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, + nvpair_t *nvp) +{ + ses2_current_ctl_impl_t *cip; + const char *name; + boolean_t v; + + if ((cip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + page, 0, np, B_FALSE)) == NULL) + return (-1); + + name = nvpair_name(nvp); + (void) nvpair_value_boolean_value(nvp, &v); + + if (strcmp(name, SES_PROP_FAIL) == 0) + cip->scci_rqst_fail = v; + else if (strcmp(name, SES_PROP_IDENT) == 0) + cip->scci_rqst_ident = v; + else + ses_panic("Bad property %s", name); + + return (0); +} + +static int +elem_setprop_itp(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, + nvpair_t *nvp) +{ + ses2_itp_ctl_impl_t *iip; + const char *name; + boolean_t v; + + if ((iip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + page, 0, np, B_FALSE)) == NULL) + return (-1); + + name = nvpair_name(nvp); + (void) nvpair_value_boolean_value(nvp, &v); + + if (strcmp(name, SES_PROP_FAIL) == 0) + iip->sici_rqst_fail = v; + else if (strcmp(name, SES_PROP_IDENT) == 0) + iip->sici_rqst_ident = v; + else if (strcmp(name, SES_ITP_PROP_ENABLED) == 0) + iip->sici_enable = v; + else + ses_panic("Bad property %s", name); + + return (0); +} + +static int +elem_setprop_sse(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, + nvpair_t *nvp) +{ + ses2_ss_ctl_impl_t *sip; + const char *name; + boolean_t v; + + if ((sip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + page, 0, np, B_FALSE)) == NULL) + return (-1); + + name = nvpair_name(nvp); + (void) nvpair_value_boolean_value(nvp, &v); + + if (strcmp(name, SES_PROP_FAIL) == 0) + sip->ssci_rqst_fail = v; + else if (strcmp(name, SES_PROP_IDENT) == 0) + sip->ssci_rqst_ident = v; + else + ses_panic("Bad property %s", name); + + return (0); +} + +static int +elem_setprop_arraydev(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, + nvpair_t *nvp) +{ + ses2_array_device_ctl_impl_t *aip; + const char *name; + boolean_t v; + + if ((aip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + page, 0, np, B_FALSE)) == NULL) + return (-1); + + name = nvpair_name(nvp); + (void) nvpair_value_boolean_value(nvp, &v); + + if (strcmp(name, SES_AD_PROP_RR_ABORT) == 0) + aip->sadci_rqst_rr_abort = v; + else if (strcmp(name, SES_AD_PROP_REBUILD) == 0) + aip->sadci_rqst_rebuild = v; + else if (strcmp(name, SES_AD_PROP_IN_FAILED_ARRAY) == 0) + aip->sadci_rqst_in_failed_array = v; + else if (strcmp(name, SES_AD_PROP_IN_CRIT_ARRAY) == 0) + aip->sadci_rqst_in_crit_array = v; + else if (strcmp(name, SES_AD_PROP_CONS_CHK) == 0) + aip->sadci_rqst_cons_check = v; + else if (strcmp(name, SES_AD_PROP_HOT_SPARE) == 0) + aip->sadci_rqst_hot_spare = v; + else if (strcmp(name, SES_AD_PROP_RSVD_DEVICE) == 0) + aip->sadci_rqst_rsvd_device = v; + else if (strcmp(name, SES_PROP_IDENT) == 0) + aip->sadci_rqst_ident = v; + else if (strcmp(name, SES_PROP_RMV) == 0) + aip->sadci_rqst_remove = v; + else if (strcmp(name, SES_DEV_PROP_READY_TO_INSERT) == 0) + aip->sadci_rqst_insert = v; + else if (strcmp(name, SES_DEV_PROP_REQ_MISSING) == 0) + aip->sadci_rqst_missing = v; + else if (strcmp(name, SES_DEV_PROP_DO_NOT_REMOVE) == 0) + aip->sadci_do_not_remove = v; + else if (strcmp(name, SES_DEV_PROP_REQ_ACTIVE) == 0) + aip->sadci_rqst_active = v; + else if (strcmp(name, SES_DEV_PROP_BYP_B) == 0) + aip->sadci_enable_byp_b = v; + else if (strcmp(name, SES_DEV_PROP_BYP_A) == 0) + aip->sadci_enable_byp_a = v; + else if (strcmp(name, SES_PROP_OFF) == 0) + aip->sadci_device_off = v; + else if (strcmp(name, SES_DEV_PROP_FAULT_RQSTD) == 0) + aip->sadci_rqst_fault = v; + else + ses_panic("Bad property %s", name); + + return (0); +} + +static int +elem_setprop_expander(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, + nvpair_t *nvp) +{ + ses2_expander_ctl_impl_t *eip; + const char *name; + boolean_t v; + + if ((eip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + page, 0, np, B_FALSE)) == NULL) + return (-1); + + name = nvpair_name(nvp); + (void) nvpair_value_boolean_value(nvp, &v); + + if (strcmp(name, SES_PROP_FAIL) == 0) + eip->seci_rqst_fail = v; + else if (strcmp(name, SES_PROP_IDENT) == 0) + eip->seci_rqst_ident = v; + else + ses_panic("Bad property %s", name); + + return (0); +} + +static int +elem_setprop_sasconn(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, + nvpair_t *nvp) +{ + ses2_sasconn_ctl_impl_t *sip; + const char *name; + boolean_t v; + + if ((sip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + page, 0, np, B_FALSE)) == NULL) + return (-1); + + name = nvpair_name(nvp); + (void) nvpair_value_boolean_value(nvp, &v); + + if (strcmp(name, SES_PROP_IDENT) == 0) + sip->ssci_rqst_ident = v; + else if (strcmp(name, SES_PROP_FAIL) == 0) + sip->ssci_rqst_fail = v; + else + ses_panic("Bad property %s", name); + + return (0); +} + +static int +elem_common_setprop_threshold(ses_plugin_t *sp, ses_node_t *np, + ses2_diag_page_t page, nvpair_t *nvp) +{ + ses2_threshold_impl_t *tip; + const char *name; + uint64_t v; + + ASSERT(page == SES2_DIAGPAGE_THRESHOLD_IO); + + if ((tip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + page, 0, np, B_FALSE)) == NULL) + return (-1); + + name = nvpair_name(nvp); + (void) nvpair_value_uint64(nvp, &v); + + if (strcmp(name, SES_PROP_THRESH_CRIT_HI) == 0) + tip->sti_high_crit = v; + else if (strcmp(name, SES_PROP_THRESH_CRIT_LO) == 0) + tip->sti_low_crit = v; + else if (strcmp(name, SES_PROP_THRESH_WARN_HI) == 0) + tip->sti_high_warn = v; + else if (strcmp(name, SES_PROP_THRESH_WARN_LO) == 0) + tip->sti_low_warn = v; + else + ses_panic("Bad property %s", name); + + return (0); +} + +#define SES_THRESHOLD_CTL_PROPS \ +{ \ + .scp_name = SES_PROP_THRESH_CRIT_HI, \ + .scp_type = DATA_TYPE_UINT64, \ + .scp_num = SES2_DIAGPAGE_THRESHOLD_IO, \ + .scp_setprop = elem_common_setprop_threshold \ +}, \ +{ \ + .scp_name = SES_PROP_THRESH_WARN_HI, \ + .scp_type = DATA_TYPE_UINT64, \ + .scp_num = SES2_DIAGPAGE_THRESHOLD_IO, \ + .scp_setprop = elem_common_setprop_threshold \ +}, \ +{ \ + .scp_name = SES_PROP_THRESH_CRIT_LO, \ + .scp_type = DATA_TYPE_UINT64, \ + .scp_num = SES2_DIAGPAGE_THRESHOLD_IO, \ + .scp_setprop = elem_common_setprop_threshold \ +}, \ +{ \ + .scp_name = SES_PROP_THRESH_WARN_LO, \ + .scp_type = DATA_TYPE_UINT64, \ + .scp_num = SES2_DIAGPAGE_THRESHOLD_IO, \ + .scp_setprop = elem_common_setprop_threshold \ +} + +static const ses2_ctl_prop_t device_props[] = { + SES_COMMON_CTL_PROPS, +{ + .scp_name = SES_PROP_IDENT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_device, +}, +{ + .scp_name = SES_PROP_RMV, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_device, +}, +{ + .scp_name = SES_DEV_PROP_READY_TO_INSERT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_device, +}, +{ + .scp_name = SES_DEV_PROP_REQ_MISSING, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_device, +}, +{ + .scp_name = SES_DEV_PROP_DO_NOT_REMOVE, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_device, +}, +{ + .scp_name = SES_DEV_PROP_REQ_ACTIVE, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_device, +}, +{ + .scp_name = SES_DEV_PROP_BYP_B, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_device, +}, +{ + .scp_name = SES_DEV_PROP_BYP_A, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_device, +}, +{ + .scp_name = SES_PROP_OFF, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_device, +}, +{ + .scp_name = SES_DEV_PROP_FAULT_RQSTD, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_device, +}, +{ + NULL +} +}; + +static const ses2_ctl_prop_t psu_props[] = { + SES_COMMON_CTL_PROPS, +{ + .scp_name = SES_PROP_IDENT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_psu +}, +{ + .scp_name = SES_PROP_REQUESTED_ON, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_psu +}, +{ + .scp_name = SES_PROP_FAIL, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_psu +}, +{ + NULL +} +}; + +static const ses2_ctl_prop_t cooling_props[] = { + SES_COMMON_CTL_PROPS, +{ + .scp_name = SES_PROP_IDENT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_cooling +}, +{ + .scp_name = SES_COOLING_PROP_SPEED_CODE, + .scp_type = DATA_TYPE_UINT64, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_cooling +}, +{ + .scp_name = SES_PROP_REQUESTED_ON, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_cooling +}, +{ + .scp_name = SES_PROP_FAIL, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_cooling +}, +{ + NULL +} +}; + +static const ses2_ctl_prop_t temp_props[] = { + SES_COMMON_CTL_PROPS, + SES_THRESHOLD_CTL_PROPS, +{ + .scp_name = SES_PROP_FAIL, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_temp +}, +{ + .scp_name = SES_PROP_IDENT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_temp +}, +{ + NULL +} +}; + +static const ses2_ctl_prop_t lock_props[] = { + SES_COMMON_CTL_PROPS, +{ + .scp_name = SES_PROP_FAIL, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_lock +}, +{ + .scp_name = SES_PROP_IDENT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_lock +}, +{ + .scp_name = SES_LOCK_PROP_UNLOCKED, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_lock +}, +{ + NULL +} +}; + +static const ses2_ctl_prop_t alarm_props[] = { + SES_COMMON_CTL_PROPS, +{ + .scp_name = SES_PROP_FAIL, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_alarm +}, +{ + .scp_name = SES_PROP_IDENT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_alarm +}, +{ + .scp_name = SES_ALARM_PROP_UNRECOV, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_alarm +}, +{ + .scp_name = SES_ALARM_PROP_CRIT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_alarm +}, +{ + .scp_name = SES_ALARM_PROP_NONCRIT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_alarm +}, +{ + .scp_name = SES_ALARM_PROP_INFO, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_alarm +}, +{ + .scp_name = SES_ALARM_PROP_REMIND, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_alarm +}, +{ + .scp_name = SES_ALARM_PROP_MUTED, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_alarm +}, +{ + NULL +} +}; + +static const ses2_ctl_prop_t esc_props[] = { + SES_COMMON_CTL_PROPS, +{ + .scp_name = SES_PROP_FAIL, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_esc +}, +{ + .scp_name = SES_PROP_IDENT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_esc +}, +{ + .scp_name = SES_ESC_PROP_SELECT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_esc +}, +{ + NULL +} +}; + +static const ses2_ctl_prop_t scc_props[] = { + SES_COMMON_CTL_PROPS, +{ + .scp_name = SES_PROP_FAIL, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_scc +}, +{ + .scp_name = SES_PROP_IDENT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_scc +}, +{ + NULL +} +}; + +static const ses2_ctl_prop_t cache_props[] = { + SES_COMMON_CTL_PROPS, +{ + .scp_name = SES_PROP_FAIL, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_cache +}, +{ + .scp_name = SES_PROP_IDENT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_cache +}, +{ + NULL +} +}; + +static const ses2_ctl_prop_t ups_props[] = { + SES_COMMON_CTL_PROPS, + SES_THRESHOLD_CTL_PROPS, +{ + .scp_name = SES_PROP_FAIL, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_ups +}, +{ + .scp_name = SES_PROP_IDENT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_ups +}, +{ + NULL +} +}; + +static const ses2_ctl_prop_t display_props[] = { + SES_COMMON_CTL_PROPS, +{ + .scp_name = SES_DPY_PROP_MODE, + .scp_type = DATA_TYPE_UINT64, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_display +}, +{ + .scp_name = SES_PROP_FAIL, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_display +}, +{ + .scp_name = SES_PROP_IDENT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_display +}, +{ + .scp_name = SES_DPY_PROP_CHAR, + .scp_type = DATA_TYPE_UINT16, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_display +}, +{ + NULL +} +}; + +static const ses2_ctl_prop_t keypad_props[] = { + SES_COMMON_CTL_PROPS, +{ + .scp_name = SES_PROP_FAIL, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_keypad +}, +{ + .scp_name = SES_PROP_IDENT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_keypad +}, +{ + NULL +} +}; + +static const ses2_ctl_prop_t px_props[] = { + SES_COMMON_CTL_PROPS, +{ + .scp_name = SES_PROP_FAIL, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_px +}, +{ + .scp_name = SES_PROP_IDENT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_px +}, +{ + .scp_name = SES_PROP_DISABLED, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_px +}, +{ + NULL +} +}; + +static const ses2_ctl_prop_t lang_props[] = { + SES_COMMON_CTL_PROPS, +{ + .scp_name = SES_PROP_IDENT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_lang +}, +{ + .scp_name = SES_LANG_PROP_LANGCODE, + .scp_type = DATA_TYPE_UINT64, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_lang +}, +{ + NULL +} +}; + +static const ses2_ctl_prop_t comm_props[] = { + SES_COMMON_CTL_PROPS, +{ + .scp_name = SES_PROP_FAIL, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_comm +}, +{ + .scp_name = SES_PROP_IDENT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_comm +}, +{ + .scp_name = SES_PROP_DISABLED, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_comm +}, +{ + NULL +} +}; + +static const ses2_ctl_prop_t voltage_props[] = { + SES_COMMON_CTL_PROPS, + SES_THRESHOLD_CTL_PROPS, +{ + .scp_name = SES_PROP_FAIL, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_voltage +}, +{ + .scp_name = SES_PROP_IDENT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_voltage +}, +{ + NULL +} +}; + +static const ses2_ctl_prop_t current_props[] = { + SES_COMMON_CTL_PROPS, + SES_THRESHOLD_CTL_PROPS, +{ + .scp_name = SES_PROP_FAIL, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_current +}, +{ + .scp_name = SES_PROP_IDENT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_current +}, +{ + NULL +} +}; + +static const ses2_ctl_prop_t itp_props[] = { + SES_COMMON_CTL_PROPS, +{ + .scp_name = SES_PROP_FAIL, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_itp +}, +{ + .scp_name = SES_PROP_IDENT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_itp +}, +{ + .scp_name = SES_ITP_PROP_ENABLED, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_itp +}, +{ + NULL +} +}; + +static const ses2_ctl_prop_t sse_props[] = { + SES_COMMON_CTL_PROPS, +{ + .scp_name = SES_PROP_FAIL, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_sse +}, +{ + .scp_name = SES_PROP_IDENT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_sse +}, +{ + NULL +} +}; + +static const ses2_ctl_prop_t arraydev_props[] = { + SES_COMMON_CTL_PROPS, +{ + .scp_name = SES_AD_PROP_RR_ABORT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_arraydev +}, +{ + .scp_name = SES_AD_PROP_REBUILD, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_arraydev +}, +{ + .scp_name = SES_AD_PROP_IN_FAILED_ARRAY, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_arraydev +}, +{ + .scp_name = SES_AD_PROP_IN_CRIT_ARRAY, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_arraydev +}, +{ + .scp_name = SES_AD_PROP_CONS_CHK, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_arraydev +}, +{ + .scp_name = SES_AD_PROP_HOT_SPARE, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_arraydev +}, +{ + .scp_name = SES_AD_PROP_RSVD_DEVICE, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_arraydev +}, +{ + .scp_name = SES_AD_PROP_OK, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_arraydev +}, +{ + .scp_name = SES_PROP_IDENT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_arraydev +}, +{ + .scp_name = SES_PROP_RMV, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_arraydev +}, +{ + .scp_name = SES_DEV_PROP_READY_TO_INSERT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_arraydev +}, +{ + .scp_name = SES_DEV_PROP_REQ_MISSING, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_arraydev +}, +{ + .scp_name = SES_DEV_PROP_DO_NOT_REMOVE, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_arraydev +}, +{ + .scp_name = SES_DEV_PROP_REQ_ACTIVE, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_arraydev +}, +{ + .scp_name = SES_DEV_PROP_BYP_B, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_arraydev +}, +{ + .scp_name = SES_DEV_PROP_BYP_A, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_arraydev +}, +{ + .scp_name = SES_PROP_OFF, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_arraydev +}, +{ + .scp_name = SES_DEV_PROP_FAULT_RQSTD, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_arraydev +}, +{ + NULL +} +}; + +static const ses2_ctl_prop_t expander_props[] = { + SES_COMMON_CTL_PROPS, +{ + .scp_name = SES_PROP_FAIL, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_expander +}, +{ + .scp_name = SES_PROP_IDENT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_expander +}, +{ + NULL +} +}; + +static const ses2_ctl_prop_t sasconn_props[] = { + SES_COMMON_CTL_PROPS, +{ + .scp_name = SES_PROP_IDENT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_sasconn +}, +{ + .scp_name = SES_PROP_FAIL, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = elem_setprop_sasconn +}, +{ + NULL +} +}; + +/*ARGSUSED*/ +static int +elem_setdef_threshold(ses_node_t *np, ses2_diag_page_t page, void *data) +{ + ses2_threshold_impl_t *tip = data; + nvlist_t *props = ses_node_props(np); + + SES_NV_CTL64(props, SES_PROP_THRESH_CRIT_HI, tip->sti_high_crit); + SES_NV_CTL64(props, SES_PROP_THRESH_CRIT_LO, tip->sti_low_crit); + SES_NV_CTL64(props, SES_PROP_THRESH_WARN_HI, tip->sti_high_warn); + SES_NV_CTL64(props, SES_PROP_THRESH_WARN_LO, tip->sti_low_warn); + + return (0); +} + +/*ARGSUSED*/ +static int +elem_setdef_device(ses_node_t *np, ses2_diag_page_t page, void *data) +{ + ses2_device_ctl_impl_t *dip = data; + nvlist_t *props = ses_node_props(np); + + SES_NV_CTLBOOL(props, SES_PROP_IDENT, dip->sdci_rqst_ident); + SES_NV_CTLBOOL(props, SES_PROP_RMV, dip->sdci_rqst_remove); + SES_NV_CTLBOOL(props, SES_DEV_PROP_READY_TO_INSERT, + dip->sdci_rqst_insert); + SES_NV_CTLBOOL(props, SES_DEV_PROP_REQ_MISSING, + dip->sdci_rqst_missing); + SES_NV_CTLBOOL(props, SES_DEV_PROP_DO_NOT_REMOVE, + dip->sdci_do_not_remove); + SES_NV_CTLBOOL(props, SES_DEV_PROP_REQ_ACTIVE, + dip->sdci_rqst_active); + SES_NV_CTLBOOL(props, SES_DEV_PROP_BYP_B, dip->sdci_enable_byp_b); + SES_NV_CTLBOOL(props, SES_DEV_PROP_BYP_A, dip->sdci_enable_byp_a); + SES_NV_CTLBOOL(props, SES_PROP_OFF, dip->sdci_device_off); + SES_NV_CTLBOOL(props, SES_DEV_PROP_FAULT_RQSTD, + dip->sdci_rqst_fault); + + return (0); +} + +/*ARGSUSED*/ +static int +elem_setdef_psu(ses_node_t *np, ses2_diag_page_t page, void *data) +{ + ses2_psu_ctl_impl_t *pip = data; + nvlist_t *props = ses_node_props(np); + + SES_NV_CTLBOOL(props, SES_PROP_IDENT, pip->spci_rqst_ident); + SES_NV_CTLBOOL(props, SES_PROP_REQUESTED_ON, pip->spci_rqst_on); + SES_NV_CTLBOOL(props, SES_PROP_FAIL, pip->spci_rqst_fail); + + return (0); +} + +/*ARGSUSED*/ +static int +elem_setdef_cooling(ses_node_t *np, ses2_diag_page_t page, void *data) +{ + ses2_cooling_ctl_impl_t *cip = data; + nvlist_t *props = ses_node_props(np); + + SES_NV_CTLBOOL(props, SES_PROP_IDENT, cip->scci_rqst_ident); + SES_NV_CTL64(props, SES_COOLING_PROP_SPEED_CODE, + cip->scci_requested_speed_code); + SES_NV_CTLBOOL(props, SES_PROP_REQUESTED_ON, cip->scci_rqst_on); + SES_NV_CTLBOOL(props, SES_PROP_FAIL, cip->scci_rqst_fail); + + return (0); +} + +/*ARGSUSED*/ +static int +elem_setdef_temp(ses_node_t *np, ses2_diag_page_t page, void *data) +{ + ses2_temp_ctl_impl_t *tip = data; + nvlist_t *props = ses_node_props(np); + + if (page == SES2_DIAGPAGE_THRESHOLD_IO) + return (elem_setdef_threshold(np, page, data)); + + SES_NV_CTLBOOL(props, SES_PROP_FAIL, tip->stci_rqst_fail); + SES_NV_CTLBOOL(props, SES_PROP_IDENT, tip->stci_rqst_ident); + + return (0); +} + +/*ARGSUSED*/ +static int +elem_setdef_lock(ses_node_t *np, ses2_diag_page_t page, void *data) +{ + ses2_lock_ctl_impl_t *lip = data; + nvlist_t *props = ses_node_props(np); + + SES_NV_CTLBOOL(props, SES_PROP_FAIL, lip->slci_rqst_fail); + SES_NV_CTLBOOL(props, SES_PROP_IDENT, lip->slci_rqst_ident); + SES_NV_CTLBOOL(props, SES_LOCK_PROP_UNLOCKED, lip->slci_unlock); + + return (0); +} + +/*ARGSUSED*/ +static int +elem_setdef_alarm(ses_node_t *np, ses2_diag_page_t page, void *data) +{ + ses2_alarm_ctl_impl_t *aip = data; + nvlist_t *props = ses_node_props(np); + + SES_NV_CTLBOOL(props, SES_PROP_FAIL, aip->saci_rqst_fail); + SES_NV_CTLBOOL(props, SES_PROP_IDENT, aip->saci_rqst_ident); + SES_NV_CTLBOOL(props, SES_ALARM_PROP_UNRECOV, aip->saci_unrecov); + SES_NV_CTLBOOL(props, SES_ALARM_PROP_CRIT, aip->saci_crit); + SES_NV_CTLBOOL(props, SES_ALARM_PROP_NONCRIT, aip->saci_noncrit); + SES_NV_CTLBOOL(props, SES_ALARM_PROP_INFO, aip->saci_info); + SES_NV_CTLBOOL(props, SES_ALARM_PROP_REMIND, aip->saci_set_remind); + SES_NV_CTLBOOL(props, SES_ALARM_PROP_MUTED, aip->saci_set_mute); + + return (0); +} + +/*ARGSUSED*/ +static int +elem_setdef_esc(ses_node_t *np, ses2_diag_page_t page, void *data) +{ + ses2_controller_ctl_impl_t *cip = data; + nvlist_t *props = ses_node_props(np); + + SES_NV_CTLBOOL(props, SES_PROP_FAIL, cip->scci_rqst_fail); + SES_NV_CTLBOOL(props, SES_PROP_IDENT, cip->scci_rqst_ident); + SES_NV_CTLBOOL(props, SES_ESC_PROP_SELECT, + cip->scci_select_element); + + return (0); +} + +/*ARGSUSED*/ +static int +elem_setdef_scc(ses_node_t *np, ses2_diag_page_t page, void *data) +{ + ses2_scc_ctl_impl_t *sip = data; + nvlist_t *props = ses_node_props(np); + + SES_NV_CTLBOOL(props, SES_PROP_FAIL, sip->ssci_rqst_fail); + SES_NV_CTLBOOL(props, SES_PROP_IDENT, sip->ssci_rqst_ident); + + return (0); +} + +/*ARGSUSED*/ +static int +elem_setdef_cache(ses_node_t *np, ses2_diag_page_t page, void *data) +{ + ses2_nvcache_ctl_impl_t *cip = data; + nvlist_t *props = ses_node_props(np); + + SES_NV_CTLBOOL(props, SES_PROP_FAIL, cip->snci_rqst_fail); + SES_NV_CTLBOOL(props, SES_PROP_IDENT, cip->snci_rqst_ident); + + return (0); +} + +static int +elem_setdef_ups(ses_node_t *np, ses2_diag_page_t page, void *data) +{ + ses2_ups_ctl_impl_t *uip = data; + nvlist_t *props = ses_node_props(np); + + if (page == SES2_DIAGPAGE_THRESHOLD_IO) + return (elem_setdef_threshold(np, page, data)); + + SES_NV_CTLBOOL(props, SES_PROP_FAIL, uip->suci_rqst_fail); + SES_NV_CTLBOOL(props, SES_PROP_IDENT, uip->suci_rqst_ident); + + return (0); +} + +/*ARGSUSED*/ +static int +elem_setdef_display(ses_node_t *np, ses2_diag_page_t page, void *data) +{ + ses2_display_ctl_impl_t *dip = data; + nvlist_t *props = ses_node_props(np); + + SES_NV_CTL64(props, SES_DPY_PROP_MODE, dip->sdci_display_mode); + SES_NV_CTLBOOL(props, SES_PROP_FAIL, dip->sdci_rqst_fail); + SES_NV_CTLBOOL(props, SES_PROP_IDENT, dip->sdci_rqst_ident); + SES_NV_CTL16(props, SES_DPY_PROP_CHAR, + dip->sdci_display_character); + + return (0); +} + +/*ARGSUSED*/ +static int +elem_setdef_keypad(ses_node_t *np, ses2_diag_page_t page, void *data) +{ + ses2_keypad_ctl_impl_t *kip = data; + nvlist_t *props = ses_node_props(np); + + SES_NV_CTLBOOL(props, SES_PROP_FAIL, kip->skci_rqst_fail); + SES_NV_CTLBOOL(props, SES_PROP_IDENT, kip->skci_rqst_ident); + + return (0); +} + +/*ARGSUSED*/ +static int +elem_setdef_px(ses_node_t *np, ses2_diag_page_t page, void *data) +{ + ses2_port_ctl_impl_t *pip = data; + nvlist_t *props = ses_node_props(np); + + SES_NV_CTLBOOL(props, SES_PROP_FAIL, pip->spci_rqst_fail); + SES_NV_CTLBOOL(props, SES_PROP_IDENT, pip->spci_rqst_ident); + SES_NV_CTLBOOL(props, SES_PROP_DISABLED, pip->spci_disable); + + return (0); +} + +/*ARGSUSED*/ +static int +elem_setdef_lang(ses_node_t *np, ses2_diag_page_t page, void *data) +{ + ses2_lang_ctl_impl_t *lip = data; + nvlist_t *props = ses_node_props(np); + + SES_NV_CTLBOOL(props, SES_PROP_IDENT, lip->slci_rqst_ident); + SES_NV_CTL16(props, SES_LANG_PROP_LANGCODE, + lip->slci_language_code); + + return (0); +} + +/*ARGSUSED*/ +static int +elem_setdef_comm(ses_node_t *np, ses2_diag_page_t page, void *data) +{ + ses2_comm_ctl_impl_t *cip = data; + nvlist_t *props = ses_node_props(np); + + SES_NV_CTLBOOL(props, SES_PROP_FAIL, cip->scci_rqst_fail); + SES_NV_CTLBOOL(props, SES_PROP_IDENT, cip->scci_rqst_ident); + SES_NV_CTLBOOL(props, SES_PROP_DISABLED, cip->scci_disable); + + return (0); +} + +static int +elem_setdef_voltage(ses_node_t *np, ses2_diag_page_t page, void *data) +{ + ses2_voltage_ctl_impl_t *vip = data; + nvlist_t *props = ses_node_props(np); + + if (page == SES2_DIAGPAGE_THRESHOLD_IO) + return (elem_setdef_threshold(np, page, data)); + + SES_NV_CTLBOOL(props, SES_PROP_FAIL, vip->svci_rqst_fail); + SES_NV_CTLBOOL(props, SES_PROP_IDENT, vip->svci_rqst_ident); + + return (0); +} + +static int +elem_setdef_current(ses_node_t *np, ses2_diag_page_t page, void *data) +{ + ses2_current_ctl_impl_t *cip = data; + nvlist_t *props = ses_node_props(np); + + if (page == SES2_DIAGPAGE_THRESHOLD_IO) + return (elem_setdef_threshold(np, page, data)); + + SES_NV_CTLBOOL(props, SES_PROP_FAIL, cip->scci_rqst_fail); + SES_NV_CTLBOOL(props, SES_PROP_IDENT, cip->scci_rqst_ident); + + return (0); +} + +/*ARGSUSED*/ +static int +elem_setdef_itp(ses_node_t *np, ses2_diag_page_t page, void *data) +{ + ses2_itp_ctl_impl_t *iip = data; + nvlist_t *props = ses_node_props(np); + + SES_NV_CTLBOOL(props, SES_PROP_FAIL, iip->sici_rqst_fail); + SES_NV_CTLBOOL(props, SES_PROP_IDENT, iip->sici_rqst_ident); + SES_NV_CTLBOOL(props, SES_ITP_PROP_ENABLED, iip->sici_enable); + + return (0); +} + +/*ARGSUSED*/ +static int +elem_setdef_sse(ses_node_t *np, ses2_diag_page_t page, void *data) +{ + ses2_ss_ctl_impl_t *sip = data; + nvlist_t *props = ses_node_props(np); + + SES_NV_CTLBOOL(props, SES_PROP_FAIL, sip->ssci_rqst_fail); + SES_NV_CTLBOOL(props, SES_PROP_IDENT, sip->ssci_rqst_ident); + + return (0); +} + +/*ARGSUSED*/ +static int +elem_setdef_arraydev(ses_node_t *np, ses2_diag_page_t page, void *data) +{ + ses2_array_device_ctl_impl_t *aip = data; + nvlist_t *props = ses_node_props(np); + + SES_NV_CTLBOOL(props, SES_AD_PROP_RR_ABORT, + aip->sadci_rqst_rr_abort); + SES_NV_CTLBOOL(props, SES_AD_PROP_REBUILD, + aip->sadci_rqst_rebuild); + SES_NV_CTLBOOL(props, SES_AD_PROP_IN_FAILED_ARRAY, + aip->sadci_rqst_in_failed_array); + SES_NV_CTLBOOL(props, SES_AD_PROP_IN_CRIT_ARRAY, + aip->sadci_rqst_in_crit_array); + SES_NV_CTLBOOL(props, SES_AD_PROP_CONS_CHK, + aip->sadci_rqst_cons_check); + SES_NV_CTLBOOL(props, SES_AD_PROP_HOT_SPARE, + aip->sadci_rqst_hot_spare); + SES_NV_CTLBOOL(props, SES_AD_PROP_RSVD_DEVICE, + aip->sadci_rqst_rsvd_device); + + SES_NV_CTLBOOL(props, SES_PROP_IDENT, aip->sadci_rqst_ident); + SES_NV_CTLBOOL(props, SES_PROP_RMV, aip->sadci_rqst_remove); + SES_NV_CTLBOOL(props, SES_DEV_PROP_READY_TO_INSERT, + aip->sadci_rqst_insert); + SES_NV_CTLBOOL(props, SES_DEV_PROP_REQ_MISSING, + aip->sadci_rqst_missing); + SES_NV_CTLBOOL(props, SES_DEV_PROP_DO_NOT_REMOVE, + aip->sadci_do_not_remove); + SES_NV_CTLBOOL(props, SES_DEV_PROP_REQ_ACTIVE, + aip->sadci_rqst_active); + + SES_NV_CTLBOOL(props, SES_DEV_PROP_BYP_B, aip->sadci_enable_byp_b); + SES_NV_CTLBOOL(props, SES_DEV_PROP_BYP_A, aip->sadci_enable_byp_a); + SES_NV_CTLBOOL(props, SES_PROP_OFF, aip->sadci_device_off); + SES_NV_CTLBOOL(props, SES_DEV_PROP_FAULT_RQSTD, + aip->sadci_rqst_fault); + + return (0); +} + +/*ARGSUSED*/ +static int +elem_setdef_expander(ses_node_t *np, ses2_diag_page_t page, void *data) +{ + ses2_expander_ctl_impl_t *eip = data; + nvlist_t *props = ses_node_props(np); + + SES_NV_CTLBOOL(props, SES_PROP_FAIL, eip->seci_rqst_fail); + SES_NV_CTLBOOL(props, SES_PROP_IDENT, eip->seci_rqst_ident); + + return (0); +} + +/*ARGSUSED*/ +static int +elem_setdef_sasconn(ses_node_t *np, ses2_diag_page_t page, void *data) +{ + ses2_sasconn_ctl_impl_t *sip = data; + nvlist_t *props = ses_node_props(np); + + SES_NV_CTLBOOL(props, SES_PROP_IDENT, sip->ssci_rqst_ident); + SES_NV_CTLBOOL(props, SES_PROP_FAIL, sip->ssci_rqst_fail); + + return (0); +} + +#define CTL_DESC(_e, _n) \ + { \ + .scd_et = _e, \ + .scd_props = _n##_props, \ + .scd_setdef = elem_setdef_##_n \ + } + +static const ses2_ctl_desc_t ctl_descs[] = { + CTL_DESC(SES_ET_DEVICE, device), + CTL_DESC(SES_ET_POWER_SUPPLY, psu), + CTL_DESC(SES_ET_COOLING, cooling), + CTL_DESC(SES_ET_TEMPERATURE_SENSOR, temp), + CTL_DESC(SES_ET_DOOR_LOCK, lock), + CTL_DESC(SES_ET_AUDIBLE_ALARM, alarm), + CTL_DESC(SES_ET_ESC_ELECTRONICS, esc), + CTL_DESC(SES_ET_SCC_ELECTRONICS, scc), + CTL_DESC(SES_ET_NONVOLATILE_CACHE, cache), + CTL_DESC(SES_ET_UPS, ups), + CTL_DESC(SES_ET_DISPLAY, display), + CTL_DESC(SES_ET_KEY_PAD_ENTRY, keypad), + CTL_DESC(SES_ET_SCSI_PORT_XCVR, px), + CTL_DESC(SES_ET_LANGUAGE, lang), + CTL_DESC(SES_ET_COMMUNICATION_PORT, comm), + CTL_DESC(SES_ET_VOLTAGE_SENSOR, voltage), + CTL_DESC(SES_ET_CURRENT_SENSOR, current), + CTL_DESC(SES_ET_SCSI_TARGET_PORT, itp), + CTL_DESC(SES_ET_SCSI_INITIATOR_PORT, itp), + CTL_DESC(SES_ET_SIMPLE_SUBENCLOSURE, sse), + CTL_DESC(SES_ET_ARRAY_DEVICE, arraydev), + CTL_DESC(SES_ET_SAS_EXPANDER, expander), + CTL_DESC(SES_ET_SAS_CONNECTOR, sasconn), + { .scd_et = -1 } +}; + +int +ses2_element_ctl(ses_plugin_t *sp, ses_node_t *np, const char *op, + nvlist_t *nvl) +{ + const ses2_ctl_desc_t *dp; + nvlist_t *props = ses_node_props(np); + uint64_t type; + + if (strcmp(op, SES_CTL_OP_SETPROP) != 0) + return (0); + + VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_TYPE, + &type) == 0); + + for (dp = &ctl_descs[0]; dp->scd_et != -1; dp++) + if (dp->scd_et == type) + break; + + if (dp->scd_et == -1) + return (0); + + return (ses2_setprop(sp, np, dp->scd_props, nvl)); +} + +int +ses2_element_setdef(ses_node_t *np, ses2_diag_page_t page, void *data) +{ + const ses2_ctl_desc_t *dp; + nvlist_t *props = ses_node_props(np); + uint64_t type; + + VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_TYPE, &type) == 0); + + for (dp = &ctl_descs[0]; dp->scd_et != -1; dp++) + if (dp->scd_et == type) + break; + + if (dp->scd_et == -1) + return (0); + + if (dp->scd_setdef(np, page, data) != 0) + return (-1); + + return (0); +} diff --git a/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_enclosure.c b/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_enclosure.c new file mode 100644 index 0000000000..099d1a5777 --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_enclosure.c @@ -0,0 +1,328 @@ +/* + * 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 <stddef.h> +#include <string.h> +#include <strings.h> +#include <libnvpair.h> + +#include <scsi/libses.h> +#include <scsi/plugins/ses/framework/ses2_impl.h> + +static int +enc_parse_sd(ses2_elem_status_impl_t *esip, nvlist_t *nvl) +{ + ses2_enclosure_status_impl_t *sdp; + int nverr; + + sdp = (ses2_enclosure_status_impl_t *)esip; + + SES_NV_ADD(uint64, nverr, nvl, SES_PROP_STATUS_CODE, + sdp->sesi_common.sesi_status_code); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_SWAP, + sdp->sesi_common.sesi_swap); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_DISABLED, + sdp->sesi_common.sesi_disabled); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_PRDFAIL, + sdp->sesi_common.sesi_prdfail); + + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, sdp->sesi_ident); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_WARN, + sdp->sesi_warning_indication); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, + sdp->sesi_failure_indication); + SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_POWER_DELAY, + sdp->sesi_power_delay); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_WARN_REQ, + sdp->sesi_warning_requested); + SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL_REQ, + sdp->sesi_warning_requested); + SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_POWER_DURATION, + sdp->sesi_power_duration); + + return (0); +} + +static int +enc_parse_help(ses_plugin_t *sp, ses_node_t *np) +{ + ses_snap_t *snap = ses_node_snapshot(np); + ses2_help_page_impl_t *hpip; + ses2_subhelp_page_impl_t *shpip; + ses2_subhelp_text_impl_t *tip; + nvlist_t *nvl = ses_node_props(np); + uint64_t eid; + size_t len; + off_t pos; + int nverr; + + if (nvlist_lookup_uint64(nvl, SES_EN_PROP_EID, &eid) != 0) + return (0); + + if ((shpip = ses_plugin_page_lookup(sp, snap, + SES2_DIAGPAGE_SUBENCLOSURE_HELP_TEXT, np, &len)) != NULL) { + pos = 0; + for (tip = (ses2_subhelp_text_impl_t *)shpip->sspi_data; + pos < SCSI_READ16(&shpip->sspi_page_length); + pos += SES2_SUBHELP_LEN(tip), + tip = (ses2_subhelp_text_impl_t *)((uint8_t *)tip + pos)) { + if (!SES_WITHIN_PAGE_STRUCT(tip, shpip, len)) + break; + + if (tip->ssti_subenclosure_identifier != eid) + continue; + + if (!SES_WITHIN_PAGE(tip->ssti_subenclosure_help_text, + tip->ssti_subenclosure_help_text_length, shpip, + len)) + break; + + SES_NV_ADD(fixed_string, nverr, nvl, SES_EN_PROP_HELP, + tip->ssti_subenclosure_help_text, + tip->ssti_subenclosure_help_text_length); + return (0); + } + } + + if (eid == 0 && (hpip = ses_plugin_page_lookup(sp, snap, + SES2_DIAGPAGE_HELP_TEXT, np, &len)) != NULL) { + if (!SES_WITHIN_PAGE_STRUCT(hpip, hpip, len)) + return (0); + + if (!SES_WITHIN_PAGE(hpip->shpi_help_text, + SCSI_READ16(&hpip->shpi_page_length), hpip, len)) + return (0); + + SES_NV_ADD(fixed_string, nverr, nvl, SES_EN_PROP_HELP, + hpip->shpi_help_text, SCSI_READ16(&hpip->shpi_page_length)); + } + + return (0); +} + +static int +enc_parse_string_in(ses_plugin_t *sp, ses_node_t *np) +{ + ses_snap_t *snap = ses_node_snapshot(np); + ses2_string_in_page_impl_t *sip; + ses2_substring_in_page_impl_t *ssip; + ses2_substring_in_data_impl_t *dip; + nvlist_t *nvl = ses_node_props(np); + uint64_t eid; + off_t pos; + size_t len, textlen; + int nverr; + + if (nvlist_lookup_uint64(nvl, SES_EN_PROP_EID, &eid) != 0) + return (0); + + if ((ssip = ses_plugin_page_lookup(sp, snap, + SES2_DIAGPAGE_SUBENCLOSURE_STRING_IO, np, &len)) != NULL) { + pos = 0; + for (dip = (ses2_substring_in_data_impl_t *)ssip->ssipi_data; + pos < SCSI_READ16(&ssip->ssipi_page_length); + pos += SES2_SUBSTR_LEN(dip), + dip = (ses2_substring_in_data_impl_t *) + ((uint8_t *)dip + pos)) { + if (!SES_WITHIN_PAGE_STRUCT(dip, ssip, len)) + break; + + if (dip->ssidi_subenclosure_identifier != eid) + continue; + + if (!SES_WITHIN_PAGE(dip->ssidi_data, + dip->ssidi_substring_data_length, ssip, len)) + break; + + SES_NV_ADD(fixed_string, nverr, nvl, SES_EN_PROP_STRING, + (char *)dip->ssidi_data, + dip->ssidi_substring_data_length); + return (0); + } + } + + if (eid == 0 && (sip = ses_plugin_page_lookup(sp, snap, + SES2_DIAGPAGE_STRING_IO, np, &len)) != NULL) { + if (!SES_WITHIN_PAGE_STRUCT(sip, sip, len)) + return (0); + + textlen = SCSI_READ16(&sip->ssipi_page_length); + + if (!SES_WITHIN_PAGE(sip->ssipi_data, textlen, sip, len)) + return (0); + + SES_NV_ADD(byte_array, nverr, nvl, SES_EN_PROP_STRING, + sip->ssipi_data, textlen); + } + + return (0); +} + +static int +enc_parse_descr(ses_plugin_t *sp, ses_node_t *np) +{ + char *desc; + nvlist_t *props = ses_node_props(np); + int nverr; + size_t len; + + if ((desc = ses_plugin_page_lookup(sp, ses_node_snapshot(np), + SES2_DIAGPAGE_ELEMENT_DESC, np, &len)) == NULL) + return (0); + + SES_NV_ADD(fixed_string, nverr, props, SES_PROP_DESCRIPTION, + desc, len); + + return (0); +} + +static int +enc_parse_dlucode(ses_plugin_t *sp, ses_node_t *np) +{ + ses_snap_t *snap = ses_node_snapshot(np); + ses2_ucode_status_page_impl_t *upip; + ses2_ucode_status_descr_impl_t *dip; + nvlist_t *nvl = ses_node_props(np); + int nverr, i; + size_t len; + uint64_t eid; + + if ((upip = ses_plugin_page_lookup(sp, snap, + SES2_DIAGPAGE_DL_MICROCODE_CTL_STATUS, np, &len)) == NULL) + return (0); + + if (nvlist_lookup_uint64(nvl, SES_EN_PROP_EID, &eid) != 0) + return (0); + + if (!SES_WITHIN_PAGE_STRUCT(upip, upip, len)) + return (0); + + /* + * The number of subenclosures excludes the primary subenclosure, which + * is always part of the response. + */ + for (dip = &upip->suspi_descriptors[0], i = 0; + i <= upip->suspi_n_subenclosures; + i++, dip++) { + if (!SES_WITHIN_PAGE_STRUCT(dip, upip, len)) + break; + + if (dip->susdi_subenclosure_identifier != eid) + continue; + SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_UCODE, + dip->susdi_subenclosure_dl_status); + SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_UCODE_A, + dip->susdi_subenclosure_dl_addl_status); + SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_UCODE_SZ, + SCSI_READ32(&dip->susdi_subenclosure_dl_max_size)); + SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_UCODE_BUF, + dip->susdi_subenclosure_dl_buffer_id); + SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_UCODE_OFF, + dip->susdi_subenclosure_dl_buffer_offset); + break; + } + + return (0); +} + +static int +enc_parse_subnick(ses_plugin_t *sp, ses_node_t *np) +{ + ses_snap_t *snap = ses_node_snapshot(np); + ses2_subnick_status_page_impl_t *spip; + ses2_subnick_descr_impl_t *dip; + nvlist_t *nvl = ses_node_props(np); + int nverr, i; + size_t len; + uint64_t eid; + + if (nvlist_lookup_uint64(nvl, SES_EN_PROP_EID, &eid) != 0) + return (0); + + if ((spip = ses_plugin_page_lookup(sp, snap, + SES2_DIAGPAGE_SUBENCLOSURE_NICKNAME_CTL_STATUS, + np, &len)) == NULL) + return (0); + + if (!SES_WITHIN_PAGE_STRUCT(spip, spip, len)) + return (0); + + for (dip = &spip->sspci_subnicks[0], i = 0; + i < spip->sspci_n_subenclosures; + i++, dip++) { + if (!SES_WITHIN_PAGE_STRUCT(dip, spip, len)) + break; + + if (dip->ssdi_subenclosure_identifier != eid) + continue; + SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_NICK_STATUS, + dip->ssdi_subenclosure_nick_status); + SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_NICK_ADDL_STATUS, + dip->ssdi_subenclosure_nick_addl_status); + SES_NV_ADD_FS(nverr, nvl, SES_EN_PROP_NICK, + dip->ssdi_subenclosure_nickname); + SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_NICK_LANG, + dip->ssdi_subenclosure_nick_lang_code); + break; + } + + return (0); +} + +int +ses2_fill_enclosure_node(ses_plugin_t *sp, ses_node_t *np) +{ + ses_snap_t *snap = ses_node_snapshot(np); + nvlist_t *props = ses_node_props(np); + ses2_elem_status_impl_t *esip; + int err; + size_t len; + + if ((esip = ses_plugin_page_lookup(sp, snap, + SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, np, &len)) != NULL) { + if ((err = enc_parse_sd(esip, props)) != 0) + return (err); + } + + if ((err = enc_parse_help(sp, np)) != 0) + return (err); + + if ((err = enc_parse_string_in(sp, np)) != 0) + return (err); + + if ((err = enc_parse_descr(sp, np)) != 0) + return (err); + + if ((err = enc_parse_dlucode(sp, np)) != 0) + return (err); + + if ((err = enc_parse_subnick(sp, np)) != 0) + return (err); + + return (0); +} diff --git a/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_enclosure_ctl.c b/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_enclosure_ctl.c new file mode 100644 index 0000000000..8b162e11e3 --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_enclosure_ctl.c @@ -0,0 +1,330 @@ +/* + * 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. + */ + +/* + * 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 <stddef.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <libnvpair.h> + +#include <scsi/libses.h> +#include "ses2_impl.h" + +#define SES_UCODE_CHUNK_SIZE (32 * 1024) + +/*ARGSUSED*/ +static int +enc_do_ucode(ses_plugin_t *sp, ses_node_t *np, nvlist_t *nvl) +{ + nvlist_t *props = ses_node_props(np); + uint64_t maxlen, bufid = 0; + uint8_t *data; + ses2_ucode_ctl_page_impl_t *uip; + size_t offset, len, pagelen; + uint_t datalen; + uint64_t mode; + + /* + * Get the data and check the length. + */ + if (nvlist_lookup_byte_array(nvl, SES_CTL_PROP_UCODE_DATA, + &data, &datalen) != 0) + return (ses_error(ESES_INVALID_PROP, + "missing or invalid %s property", SES_CTL_PROP_UCODE_DATA)); + + if (nvlist_lookup_uint64(nvl, SES_CTL_PROP_UCODE_MODE, + &mode) != 0) + return (ses_error(ESES_INVALID_PROP, + "missing or invalid %s property", SES_CTL_PROP_UCODE_MODE)); + + if (nvlist_lookup_uint64(props, SES_EN_PROP_UCODE_SZ, + &maxlen) != 0 || datalen > maxlen) + return (ses_error(ESES_RANGE, + "microcode image length (%u) exceeds maximum length (%llu)", + datalen, maxlen)); + + /* + * Get the expected buffer ID, but allow the user to override it. + */ + (void) nvlist_lookup_uint64(props, SES_EN_PROP_UCODE_BUF, + &bufid); + + if (bufid == 0xFF) + bufid = 0; + + (void) nvlist_lookup_uint64(nvl, SES_CTL_PROP_UCODE_BUFID, &bufid); + + for (offset = 0; offset < datalen; offset += SES_UCODE_CHUNK_SIZE) { + + len = MIN(datalen - offset, SES_UCODE_CHUNK_SIZE); + if (len & 0x3) + pagelen = (len + 4) & 0x3; + else + pagelen = len; + + if ((uip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + SES2_DIAGPAGE_DL_MICROCODE_CTL_STATUS, pagelen, + np, B_TRUE)) == NULL) + return (-1); + + uip->sucpi_buffer_id = (uint8_t)bufid; + uip->sucpi_dl_ucode_mode = mode; + SCSI_WRITE32(&uip->sucpi_buffer_offset, offset); + SCSI_WRITE32(&uip->sucpi_ucode_image_length, datalen); + SCSI_WRITE32(&uip->sucpi_ucode_data_length, len); + + bcopy(data + offset, &uip->sucpi_ucode_data[0], + len); + + if (len != pagelen) + bzero(&uip->sucpi_ucode_data[0] + len, + pagelen - len); + } + + (void) nvlist_remove_all(nvl, SES_CTL_PROP_UCODE_DATA); + (void) nvlist_remove_all(nvl, SES_CTL_PROP_UCODE_MODE); + (void) nvlist_remove_all(nvl, SES_CTL_PROP_UCODE_BUFID); + + return (0); +} + +static int +enc_ctl_common(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, + nvpair_t *nvp) +{ + ses2_enclosure_ctl_impl_t *tp; + const char *name; + boolean_t boolval; + uint64_t intval; + + ASSERT(page == SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS); + + if ((tp = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + page, 0, np, B_FALSE)) == NULL) + return (-1); + + name = nvpair_name(nvp); + (void) nvpair_value_boolean_value(nvp, &boolval); + (void) nvpair_value_uint64(nvp, &intval); + + if (strcmp(name, SES_PROP_IDENT) == 0) + tp->seci_rqst_ident = boolval; + else if (strcmp(name, SES_PROP_WARN_REQ) == 0) + tp->seci_request_warning = boolval; + else if (strcmp(name, SES_PROP_FAIL_REQ) == 0) + tp->seci_request_failure = boolval; + else if (strcmp(name, SES_EN_PROP_POWER_DELAY) == 0) + tp->seci_power_cycle_delay = intval; + else if (strcmp(name, SES_EN_PROP_POWER_REQUEST) == 0) + tp->seci_power_cycle_request = intval; + else if (strcmp(name, SES_EN_PROP_POWER_DURATION) == 0) + tp->seci_power_off_duration = intval; + else + ses_panic("bad property %s", name); + + return (0); +} + +/*ARGSUSED*/ +static int +enc_ctl_string(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, + nvpair_t *nvp) +{ + ses2_substring_out_page_impl_t *spip; + ses2_string_out_page_impl_t *pip; + const uint8_t *data; + size_t datalen; + uint_t nvlen; + nvlist_t *props = ses_node_props(np); + uint64_t eid; + + ASSERT(strcmp(nvpair_name(nvp), SES_EN_PROP_STRING) == 0); + + VERIFY(nvlist_lookup_uint64(props, SES_EN_PROP_EID, &eid) == 0); + + (void) nvpair_value_byte_array(nvp, (uint8_t **)&data, &nvlen); + datalen = (size_t)nvlen; + + if ((spip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + SES2_DIAGPAGE_SUBENCLOSURE_STRING_IO, datalen, np, + B_FALSE)) != NULL) { + spip->ssopi_subenclosure_identifier = eid; + bcopy(data, spip->ssopi_data, datalen); + } else { + if (eid != 0) + return (ses_error(ESES_NOTSUP, "target does not " + "support string data for secondary subenclosures")); + + if ((pip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + SES2_DIAGPAGE_STRING_IO, datalen, np, B_FALSE)) == NULL) + return (-1); + + bcopy(data, pip->ssopi_data, datalen); + } + + return (0); +} + +static int +enc_ctl_nick(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page, + nvpair_t *nvp) +{ + /* LINTED - dummy variable for sizeof */ + ses2_subnick_ctl_page_impl_t *pip, dummy; + const char *nick; + size_t len, max; + nvlist_t *props = ses_node_props(np); + uint64_t eid; + + ASSERT(strcmp(nvpair_name(nvp), SES_EN_PROP_NICK) == 0); + ASSERT(page == SES2_DIAGPAGE_SUBENCLOSURE_NICKNAME_CTL_STATUS); + + (void) nvpair_value_string(nvp, (char **)&nick); + len = strlen(nick); + + VERIFY(nvlist_lookup_uint64(props, SES_EN_PROP_EID, &eid) == 0); + + max = sizeof (dummy.sspci_subenclosure_nickname); + if (len > max) + return (ses_error(ESES_RANGE, "nickname '%s' exceeds " + "maximum length %lu", nick, max)); + + if ((pip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np), + page, len, np, B_FALSE)) == NULL) + return (-1); + + pip->sspci_subenclosure_identifier = eid; + bcopy(nick, pip->sspci_subenclosure_nickname, len); + + return (0); +} + +static const ses2_ctl_prop_t enc_props[] = { + SES_COMMON_CTL_PROPS, +{ + .scp_name = SES_PROP_IDENT, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = enc_ctl_common +}, +{ + .scp_name = SES_PROP_WARN_REQ, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = enc_ctl_common +}, +{ + .scp_name = SES_PROP_FAIL_REQ, + .scp_type = DATA_TYPE_BOOLEAN_VALUE, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = enc_ctl_common +}, +{ + .scp_name = SES_EN_PROP_POWER_DELAY, + .scp_type = DATA_TYPE_UINT64, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = enc_ctl_common +}, +{ + .scp_name = SES_EN_PROP_POWER_DURATION, + .scp_type = DATA_TYPE_UINT64, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = enc_ctl_common +}, +{ + .scp_name = SES_EN_PROP_POWER_REQUEST, + .scp_type = DATA_TYPE_UINT64, + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .scp_setprop = enc_ctl_common +}, +{ + .scp_name = SES_EN_PROP_STRING, + .scp_type = DATA_TYPE_BYTE_ARRAY, + .scp_num = -1, + .scp_setprop = enc_ctl_string +}, +{ + .scp_name = SES_EN_PROP_NICK, + .scp_type = DATA_TYPE_STRING, + .scp_num = SES2_DIAGPAGE_SUBENCLOSURE_NICKNAME_CTL_STATUS, + .scp_setprop = enc_ctl_nick +}, +{ + NULL +} +}; + +static int +enc_setdef_one(ses_node_t *np, ses2_diag_page_t page, void *data) +{ + ses2_enclosure_ctl_impl_t *tp = data; + nvlist_t *props = ses_node_props(np); + + if (page != SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS) + return (0); + + SES_NV_CTLBOOL(props, SES_PROP_IDENT, tp->seci_rqst_ident); + SES_NV_CTLBOOL(props, SES_PROP_WARN_REQ, + tp->seci_request_warning); + SES_NV_CTLBOOL(props, SES_PROP_FAIL_REQ, + tp->seci_request_failure); + + return (0); +} + +int +ses2_enclosure_ctl(ses_plugin_t *sp, ses_node_t *np, const char *op, + nvlist_t *nvl) +{ + if (strcmp(op, SES_CTL_OP_SETPROP) == 0) + return (ses2_setprop(sp, np, enc_props, nvl)); + else if (strcmp(op, SES_CTL_OP_DL_UCODE) == 0) + return (enc_do_ucode(sp, np, nvl)); + + return (0); +} + +int +ses2_enclosure_setdef(ses_node_t *np, ses2_diag_page_t page, void *data) +{ + nvlist_t *props = ses_node_props(np); + uint64_t type; + + VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_TYPE, &type) == 0); + + if (type == SES_ET_ENCLOSURE && + enc_setdef_one(np, page, data) != 0) + return (-1); + + return (0); +} diff --git a/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_impl.h b/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_impl.h new file mode 100644 index 0000000000..11f6d5739a --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_impl.h @@ -0,0 +1,1549 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _PLUGIN_SES_IMPL_H +#define _PLUGIN_SES_IMPL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> +#include <sys/sysmacros.h> +#include <sys/scsi/impl/uscsi.h> +#include <sys/scsi/generic/commands.h> +#include <sys/scsi/impl/spc3_types.h> +#include <sys/ccompile.h> +#include <stdarg.h> +#include <libnvpair.h> + +#include <scsi/libscsi.h> +#include <scsi/libses_plugin.h> + +#pragma pack(1) + +/* + * Generic IO timeout in seconds, from <sys/scsi/targets/ses.h>. + */ +#define SES2_TIMEOUT 60 + +/* + * SES-2 Enclosure Descriptor Header (Table 8, 6.1.2.2) + */ +typedef struct ses2_ed_hdr_impl { + DECL_BITFIELD4( + sehi_n_esps :3, + _reserved1 :1, + sehi_rel_esp_id :3, + _reserved2 :1); + uint8_t sehi_subenclosure_id; + uint8_t sehi_n_etd_hdrs; + uint8_t sehi_ed_len; +} ses2_ed_hdr_impl_t; + +/* + * SES-2 Enclosure Descriptor (Table 8, 6.1.2.2) + */ +typedef struct ses2_ed_impl { + ses2_ed_hdr_impl_t st_hdr; + spc3_naa_id_8_impl_t st_logical_id; + char st_vendor_id[8]; + char st_product_id[16]; + char st_product_revision[4]; + uint8_t st_priv[1]; +} ses2_ed_impl_t; + +/* + * SES-2 Type Descriptor Header (Table 9, 6.1.2.3) + */ +typedef struct ses2_td_hdr_impl { + uint8_t sthi_element_type; + uint8_t sthi_max_elements; + uint8_t sthi_subenclosure_id; + uint8_t sthi_text_len; +} ses2_td_hdr_impl_t; + +/* + * SES-2 Configuration diagnostic page (Table 7, 6.1.2.1) + */ +typedef struct ses2_config_page_impl { + uint8_t scpi_page_code; + uint8_t scpi_n_subenclosures; + uint16_t scpi_page_length; + uint32_t scpi_generation_code; + uint8_t scpi_data[1]; +} ses2_config_page_impl_t; + +/* + * Logically we should be able to use 4 or 8 bytes for a minimum allocation; + * however, it seems at least some devices will fail the request in that case. + */ +#define SES2_MIN_DIAGPAGE_ALLOC 512 + +/* + * SES-2 Element Control and Overall Control fields (Table 59, 7.2.2) + */ +typedef struct ses2_cmn_elem_ctl_impl { + DECL_BITFIELD5( + _reserved1 :4, + seci_rst_swap :1, + seci_disable :1, + seci_prdfail :1, + seci_select :1); +} ses2_cmn_elem_ctl_impl_t; + +typedef struct ses2_elem_ctl_impl { + ses2_cmn_elem_ctl_impl_t seci_common; + uint8_t seci_data[3]; +} ses2_elem_ctl_impl_t; + +/* + * SES-2 Element Status and Overall Status fields (Table 60, 7.2.3) + */ +typedef struct ses2_cmn_elem_status_impl { + DECL_BITFIELD5( + sesi_status_code :4, + sesi_swap :1, + sesi_disabled :1, + sesi_prdfail :1, + _reserved1 :1); +} ses2_cmn_elem_status_impl_t; + +typedef struct ses2_elem_status_impl { + ses2_cmn_elem_status_impl_t sesi_common; + uint8_t sesi_data[3]; +} ses2_elem_status_impl_t; + +/* + * SES-2 Device element for the Enclosure Control diagnostic page. + */ +typedef struct ses2_device_ctl_impl { + ses2_cmn_elem_ctl_impl_t sdci_common; + uint8_t _reserved1; + DECL_BITFIELD8( + _reserved2 :1, + sdci_rqst_ident :1, + sdci_rqst_remove :1, + sdci_rqst_insert :1, + sdci_rqst_missing :1, + _reserved3 :1, + sdci_do_not_remove :1, + sdci_rqst_active :1); + DECL_BITFIELD6( + _reserved4 :2, + sdci_enable_byp_b :1, + sdci_enable_byp_a :1, + sdci_device_off :1, + sdci_rqst_fault :1, + _reserved5 :2); +} ses2_device_ctl_impl_t; + +/* + * SES-2 Device element for the Enclosure Status diagnostic page + * (Table 64, 7.3.2). + */ +typedef struct ses2_device_status_impl { + ses2_cmn_elem_status_impl_t sdsi_common; + uint8_t sdsi_slot_addr; + DECL_BITFIELD8( + sdsi_report :1, + sdsi_ident :1, + sdsi_rmv :1, + sdsi_ready_to_insert :1, + sdsi_enclosure_bypassed_b :1, + sdsi_enclosure_bypassed_a :1, + sdsi_do_not_remove :1, + sdsi_app_client_bypassed_a :1); + DECL_BITFIELD8( + sdsi_device_bypassed_b :1, + sdsi_device_bypassed_a :1, + sdsi_bypassed_b :1, + sdsi_bypassed_a :1, + sdsi_device_off :1, + sdsi_fault_reqstd :1, + sdsi_fault_sensed :1, + sdsi_app_client_bypassed_b :1); +} ses2_device_status_impl_t; + +typedef struct ses2_array_device_ctl_impl { + ses2_cmn_elem_ctl_impl_t sadci_common; + DECL_BITFIELD8( + sadci_rqst_rr_abort :1, + sadci_rqst_rebuild :1, + sadci_rqst_in_failed_array :1, + sadci_rqst_in_crit_array :1, + sadci_rqst_cons_check :1, + sadci_rqst_hot_spare :1, + sadci_rqst_rsvd_device :1, + sadci_rqst_ok :1); + DECL_BITFIELD8( + _reserved1 :1, + sadci_rqst_ident :1, + sadci_rqst_remove :1, + sadci_rqst_insert :1, + sadci_rqst_missing :1, + _reserved2 :1, + sadci_do_not_remove :1, + sadci_rqst_active :1); + DECL_BITFIELD6( + _reserved3 :2, + sadci_enable_byp_b :1, + sadci_enable_byp_a :1, + sadci_device_off :1, + sadci_rqst_fault :1, + _reserved4 :2); +} ses2_array_device_ctl_impl_t; + +/* + * SES-2 Array Device element for the Enclosure Status diagnostic page + * (Table 66, 7.3.3) + */ +typedef struct ses2_array_device_status_impl { + ses2_cmn_elem_status_impl_t sadsi_common; + DECL_BITFIELD8( + sadsi_rr_abort :1, + sadsi_rebuild :1, + sadsi_in_failed_array :1, + sadsi_in_crit_array :1, + sadsi_cons_chk :1, + sadsi_hot_spare :1, + sadsi_rsvd_device :1, + sadsi_ok :1); + DECL_BITFIELD8( + sadsi_report :1, + sadsi_ident :1, + sadsi_rmv :1, + sadsi_ready_to_insert :1, + sadsi_enclosure_bypassed_b :1, + sadsi_enclosure_bypassed_a :1, + sadsi_do_not_remove :1, + sadsi_app_client_bypassed_a :1); + DECL_BITFIELD8( + sadsi_device_bypassed_b :1, + sadsi_device_bypassed_a :1, + sadsi_bypassed_b :1, + sadsi_bypassed_a :1, + sadsi_device_off :1, + sadsi_fault_reqstd :1, + sadsi_fault_sensed :1, + sadsi_app_client_bypassed_b :1); +} ses2_array_device_status_impl_t; + +/* + * SES-2 Power Supply element for control-type diagnostic pages (T68). + */ +typedef struct ses2_psu_ctl_impl { + ses2_cmn_elem_ctl_impl_t spci_common; + DECL_BITFIELD2( + _reserved1 :7, + spci_rqst_ident :1); + uint8_t _reserved2; + DECL_BITFIELD4( + _reserved3 :5, + spci_rqst_on :1, + spci_rqst_fail :1, + _reserved4 :1); +} ses2_psu_ctl_impl_t; + +/* + * SES-2 Power Supply element for status-type diagnostic pages (Table 69, 7.3.4) + */ +typedef struct ses2_psu_status_impl { + ses2_cmn_elem_status_impl_t spsi_common; + DECL_BITFIELD2( + _reserved1 :7, + spsi_ident :1); + DECL_BITFIELD5( + _reserved2 :1, + spsi_dc_over_current :1, + spsi_dc_under_voltage :1, + spsi_dc_over_voltage :1, + _reserved3 :4); + DECL_BITFIELD8( + spsi_dc_fail :1, + spsi_ac_fail :1, + spsi_temp_warn :1, + spsi_overtmp_fail :1, + spsi_off :1, + spsi_rqsted_on :1, + spsi_fail :1, + spsi_hot_swap :1); +} ses2_psu_status_impl_t; + +/* + * SES-2 Cooling element for control-type diagnostic pages (Table 70). + */ +typedef struct ses2_cooling_ctl_impl { + ses2_cmn_elem_ctl_impl_t scci_common; + DECL_BITFIELD2( + _reserved1 :7, + scci_rqst_ident :1); + uint8_t _reserved2; + DECL_BITFIELD5( + scci_requested_speed_code :3, + _reserved3 :2, + scci_rqst_on :1, + scci_rqst_fail :1, + _reserved4 :1); +} ses2_cooling_ctl_impl_t; + +/* + * SES-2 Cooling element for status-type diagnostic pages (Table 71, 7.3.5) + */ +typedef struct ses2_cooling_status_impl { + ses2_cmn_elem_status_impl_t scsi_common; + DECL_BITFIELD3( + scsi_fan_speed_ms3 :3, + _reserved1 :4, + scsi_ident :1); + uint8_t scsi_fan_speed_lsb; + DECL_BITFIELD6( + scsi_actual_speed_code :3, + _reserved2 :1, + scsi_off :1, + scsi_requested_on :1, + scsi_fail :1, + _reserved3 :1); +} ses2_cooling_status_impl_t; + +/* + * The fan_speed fields are multiplied by this factor to obtain the actual + * number of RPMs. + */ +#define SES2_ES_COOLING_SPEED_FACTOR 10 + +#define SES2_ES_COOLING_ST_FAN_SPEED(csip) \ + (((((uint16_t)(csip)->scsi_fan_speed_ms3) << 8) | \ + ((uint16_t)(csip)->scsi_fan_speed_lsb)) * \ + (uint16_t)SES2_ES_COOLING_SPEED_FACTOR) + +/* + * SES-2 Temperature Sensor element for control-type diagnostic pages (T74). + */ +typedef struct ses2_temp_ctl_impl { + ses2_cmn_elem_ctl_impl_t stci_common; + DECL_BITFIELD3( + _reserved1 :6, + stci_rqst_fail :1, + stci_rqst_ident :1); + uint8_t _reserved2[2]; +} ses2_temp_ctl_impl_t; + +/* + * SES-2 Temperature Sensor element for status-type diagnostic pages + * (Table 74, 7.3.6) + */ +typedef struct ses2_temp_status_impl { + ses2_cmn_elem_status_impl_t stsi_common; + DECL_BITFIELD3( + _reserved1 :6, + stsi_fail :1, + stsi_ident :1); + uint8_t stsi_temperature; + DECL_BITFIELD4( + stsi_ut_warn :1, + stsi_ut_fail :1, + stsi_ot_warn :1, + stsi_ot_fail :1); +} ses2_temp_status_impl_t; + +#define SES2_ES_TEMP_OFFSET (-20) + +#define SES2_ES_TEMP_ST_TEMPERATURE(tsip) \ + ((tsip)->stsi_temperature + SES2_ES_TEMP_OFFSET) + +/* + * SES-2 Door Lock element for control-type diagnostic pages (T76). + */ +typedef struct ses2_lock_ctl_impl { + ses2_cmn_elem_ctl_impl_t slci_common; + DECL_BITFIELD3( + _reserved1 :6, + slci_rqst_fail :1, + slci_rqst_ident :1); + uint8_t _reserved2; + DECL_BITFIELD2( + slci_unlock :1, + _reserved3 :7); +} ses2_lock_ctl_impl_t; + +/* + * SES-2 Door Lock element for status-type diagnostic pages (Table 77, 7.3.7) + */ +typedef struct ses2_lock_status_impl { + ses2_cmn_elem_status_impl_t slsi_common; + DECL_BITFIELD3( + _reserved1 :6, + slsi_fail :1, + slsi_ident :1); + uint8_t _reserved2; + DECL_BITFIELD2( + slsi_unlocked :1, + _reserved3 :7); +} ses2_lock_status_impl_t; + +/* + * SES-2 Audible Alarm element for control-type diagnostic pages (T78). + */ +typedef struct ses2_alarm_ctl_impl { + ses2_cmn_elem_ctl_impl_t saci_common; + DECL_BITFIELD3( + _reserved1 :6, + saci_rqst_fail :1, + saci_rqst_ident :1); + uint8_t _reserved2; + DECL_BITFIELD8( + saci_unrecov :1, + saci_crit :1, + saci_noncrit :1, + saci_info :1, + saci_set_remind :1, + _reserved3 :1, + saci_set_mute :1, + _reserved4 :1); +} ses2_alarm_ctl_impl_t; + +/* + * SES-2 Audible Alarm element for status-type diagnostic pages + * (Table 79, 7.3.8) + */ +typedef struct ses2_alarm_status_impl { + ses2_cmn_elem_status_impl_t sasi_common; + DECL_BITFIELD3( + _reserved1 :6, + sasi_fail :1, + sasi_ident :1); + uint8_t _reserved2; + DECL_BITFIELD8( + sasi_unrecov :1, + sasi_crit :1, + sasi_noncrit :1, + sasi_info :1, + sasi_remind :1, + _reserved3 :1, + sasi_muted :1, + sasi_rqst_mute :1); +} ses2_alarm_status_impl_t; + +/* + * SES-2 Enclosure Services Controller Electronics element for control-type + * diagnostic pages (Table 80, 7.3.9). + */ +typedef struct ses2_controller_ctl_impl { + ses2_cmn_elem_ctl_impl_t scci_common; + DECL_BITFIELD3( + _reserved1 :6, + scci_rqst_fail :1, + scci_rqst_ident :1); + DECL_BITFIELD2( + scci_select_element :1, + _reserved2 :7); + uint8_t _reserved3; +} ses2_controller_ctl_impl_t; + +/* + * SES-2 Enclosure Services Controller Electronics element for status-type + * diagnostic pages (Table 81, 7.3.9), + */ +typedef struct ses2_controller_status_impl { + ses2_cmn_elem_status_impl_t scsi_common; + DECL_BITFIELD3( + _reserved1 :6, + scsi_fail :1, + scsi_ident :1); + DECL_BITFIELD2( + scsi_report :1, + _reserved2 :7); + DECL_BITFIELD2( + _reserved3 :7, + scsi_hot_swap :1); +} ses2_controller_status_impl_t; + +/* + * SES-2 SCC Controller Electronics element for control-type diagnostic pages + * (Table 82, 7.3.10). + */ +typedef struct ses2_scc_ctl_impl { + ses2_cmn_elem_ctl_impl_t ssci_common; + DECL_BITFIELD3( + _reserved1 :6, + ssci_rqst_fail :1, + ssci_rqst_ident :1); + uint8_t _reserved2[2]; +} ses2_scc_ctl_impl_t; + +/* + * SES-2 SCC Controller Electronics element for status-type diagnostic pages + * (Table 83, 7.3.10) + */ +typedef struct ses2_scc_status_impl { + ses2_cmn_elem_status_impl_t sss_common; + DECL_BITFIELD3( + _reserved1 :6, + sss_fail :1, + sss_ident :1); + DECL_BITFIELD2( + sss_report :1, + _reserved2 :7); + uint8_t _reserved3; +} ses2_scc_status_impl_t; + +/* + * SES-2 Nonvolatile Cache element for control-type diagnostic pages + * (Table 84, 7.3.11). + */ +typedef struct ses2_nvcache_ctl_impl { + ses2_cmn_elem_ctl_impl_t snci_common; + DECL_BITFIELD3( + _reserved1 :6, + snci_rqst_fail :1, + snci_rqst_ident :1); + uint8_t _reserved2[2]; +} ses2_nvcache_ctl_impl_t; + +/* + * SES-2 Nonvolatile Cache element for status-type diagnostic pages (Table 85, + * 7.3.11) + */ +typedef struct ses2_nvcache_status_impl { + ses2_cmn_elem_status_impl_t snsi_common; + DECL_BITFIELD4( + snsi_size_multiplier :2, + _reserved1 :4, + snsi_fail :1, + snsi_ident :1); + uint16_t snsi_nvcache_size; +} ses2_nvcache_status_impl_t; + +/* + * Ibid., Table 86 defines the size multipliers as follows: + * + * 00b - bytes + * 01b - 1<<10 bytes + * 10b - 1<<20 bytes + * 11b - 1<<30 bytes + * + * We will calculate the actual size in bytes by doing + * + * nvcache_size << (SES2_NVCACHE_SHIFT * multiplier) + */ +#define SES2_NVCACHE_SHIFT 10 +#define SES2_NVCACHE_SIZE(nsip) \ + ((uint64_t)SCSI_READ16(&(nsip)->snsi_nvcache_size) << \ + (SES2_NVCACHE_SHIFT * (nsip)->snsi_size_multiplier)) + +/* + * SES-2 Invalid Operation Reason element for status-type diagnostic pages + * (Table 88, 7.3.12) + */ +typedef struct ses2_invop_reason_status_impl { + ses2_cmn_elem_status_impl_t sirsi_common; + DECL_BITFIELD2( + sirsi_priv_ms6 :6, + sirsi_invop_type :2); + uint8_t sirsi_priv[2]; +} ses2_invop_reason_status_impl_t; + +/* + * Ibid., Invop Type values (Table 89) + */ +typedef enum ses2_invop_type { + SES2_INVOP_SEND_PAGE_CODE = 0x0, + SES2_INVOP_SEND_PAGE_FORMAT = 0x1, + SES2_INVOP_VENDOR_SPECIFIC = 0x3 +} ses2_invop_type_t; + +/* + * Ibid., Invalid Operation Reason element for status-type diagnostic pages + * with Invop Type of 00b (Table 90) + */ +typedef struct ses2_invop_code_status_impl { + ses2_cmn_elem_status_impl_t sicsi_common; + DECL_BITFIELD3( + sicsi_page_not_supported :1, + _reserved1 :5, + sicsi_invop_type :2); + uint8_t _reserved2[2]; +} ses2_invop_code_status_impl_t; + +/* + * Ibid., Invalid Operation Reason element for status-type diagnostic pages + * with Invop Type of 01b (Table 91) + */ +typedef struct ses2_invop_format_status_impl { + ses2_cmn_elem_status_impl_t sifsi_common; + DECL_BITFIELD3( + sifsi_bit_number :3, + _reserved1 :3, + sifsi_invop_type :2); + uint16_t sifsi_byte_offset[2]; +} ses2_invop_format_status_impl_t; + +/* + * SES-2 Uninterruptible Power Supply element for control-type diagnostic + * pages (Table 93, 7.3.13) + */ +typedef struct ses2_ups_ctl_impl { + ses2_cmn_elem_ctl_impl_t suci_common; + uint8_t _reserved1[2]; + DECL_BITFIELD3( + _reserved2 :6, + suci_rqst_fail :1, + suci_rqst_ident :1); +} ses2_ups_ctl_impl_t; + +/* + * SES-2 Uninterruptible Power Supply element for status-type diagnostic pages + * (Table 94, 7.3.13) + */ +typedef struct ses2_ups_status_impl { + ses2_cmn_elem_status_impl_t susi_common; + uint8_t susi_battery_status; /* Time remaining in minutes */ + DECL_BITFIELD8( + susi_intf_fail :1, + susi_warn :1, + susi_ups_fail :1, + susi_dc_fail :1, + susi_ac_fail :1, + susi_ac_qual :1, + susi_ac_hi :1, + susi_ac_lo :1); + DECL_BITFIELD5( + susi_bpf :1, + susi_batt_fail :1, + _reserved1 :4, + susi_fail :1, + susi_ident :1); +} ses2_ups_status_impl_t; + +/* + * SES-2 Display element for control-type diagnostic pages (Table 95, 7.3.14) + */ +typedef struct ses2_display_ctl_impl { + ses2_cmn_elem_ctl_impl_t sdci_common; + DECL_BITFIELD4( + sdci_display_mode :2, + _reserved1 :4, + sdci_rqst_fail :1, + sdci_rqst_ident :1); + uint16_t sdci_display_character; +} ses2_display_ctl_impl_t; + +/* + * SES-2 Display element for status-type diagnostic pages (Table 97, 7.3.14) + */ +typedef struct ses2_display_status_impl { + ses2_cmn_elem_status_impl_t sdsi_common; + DECL_BITFIELD4( + sdsi_display_mode_status :2, + _reserved1 :3, + sdsi_fail :1, + sdsi_ident :1); + uint16_t sdsi_display_character_status; +} ses2_display_status_impl_t; + +/* + * SES-2 Key Pad Entry element for control-type diagnostic pages (Table 99). + */ +typedef struct ses2_keypad_ctl_impl { + ses2_cmn_elem_ctl_impl_t skci_common; + DECL_BITFIELD3( + _reserved1 :6, + skci_rqst_fail :1, + skci_rqst_ident :1); + uint8_t _reserved2[2]; +} ses2_keypad_ctl_impl_t; + +/* + * SES-2 Key Pad Entry element for status-type diagnostic pages (Table 100, + * 7.3.15) + */ +typedef struct ses2_keypad_status_impl { + ses2_cmn_elem_status_impl_t sksi_common; + DECL_BITFIELD3( + _reserved1 :6, + sksi_fail :1, + sksi_ident :1); + uint8_t _reserved2[2]; +} ses2_keypad_status_impl_t; + +/* + * SES-2 Enclosure element for control-type diagnostic pages (Table 101). + */ +typedef struct ses2_enclosure_ctl_impl { + ses2_cmn_elem_ctl_impl_t seci_common; + DECL_BITFIELD2( + _reserved1 :7, + seci_rqst_ident :1); + DECL_BITFIELD2( + seci_power_cycle_delay :6, + seci_power_cycle_request :2); + DECL_BITFIELD3( + seci_request_warning :1, + seci_request_failure :1, + seci_power_off_duration :6); +} ses2_enclosure_ctl_impl_t; + +/* + * SES-2 Enclosure element for status-type diagnostic pages (Table 101, 7.3.16) + */ +typedef struct ses2_enclosure_status_impl { + ses2_cmn_elem_status_impl_t sesi_common; + DECL_BITFIELD2( + _reserved1 :7, + sesi_ident :1); + DECL_BITFIELD3( + sesi_warning_indication :1, + sesi_failure_indication :1, + sesi_power_delay :6); + DECL_BITFIELD3( + sesi_warning_requested :1, + sesi_failure_requested :1, + sesi_power_duration :6); +} ses2_enclosure_status_impl_t; + +/* + * SES-2 SCSI Port/Transceiver element for control-type diagnostic pages (T103) + */ +typedef struct ses2_port_ctl_impl { + ses2_cmn_elem_ctl_impl_t spci_common; + DECL_BITFIELD3( + _reserved1 :6, + spci_rqst_fail :1, + spci_rqst_ident :1); + uint8_t _reserved2; + DECL_BITFIELD3( + _reserved3 :4, + spci_disable :1, + _reserved4 :3); +} ses2_port_ctl_impl_t; + +/* + * SES-2 SCSI Port/Transceiver element for status-type diagnostic pages + * (Table 104, 7.3.17) + */ +typedef struct ses2_port_status_impl { + ses2_cmn_elem_status_impl_t spsi_common; + DECL_BITFIELD3( + _reserved1 :6, + spsi_fail :1, + spsi_ident :1); + DECL_BITFIELD2( + spsi_report :1, + _reserved2 :7); + DECL_BITFIELD5( + spsi_xmit_fail :1, + spsi_lol :1, + _reserved3 :2, + spsi_disabled :1, + _reserved4 :3); +} ses2_port_status_impl_t; + +/* + * SES-2 Language element for control-type diagnostic pages (T105) + */ +typedef struct ses2_lang_ctl_impl { + ses2_cmn_elem_ctl_impl_t slci_common; + DECL_BITFIELD2( + _reserved1 :7, + slci_rqst_ident :1); + uint16_t slci_language_code; +} ses2_lang_ctl_impl_t; + +/* + * SES-2 Language element for status-type diagnostic pages (Table 105, 7.3.18) + */ +typedef struct ses2_lang_status_impl { + ses2_cmn_elem_status_impl_t slsi_common; + DECL_BITFIELD2( + _reserved1 :7, + slsi_ident :1); + uint16_t slsi_language_code; +} ses2_lang_status_impl_t; + +/* + * SES-2 Communication Port element for control-type diagnostic pages + * (Table 107, 7.3.19). + */ +typedef struct ses2_comm_ctl_impl { + ses2_cmn_elem_ctl_impl_t scci_common; + DECL_BITFIELD3( + _reserved1 :6, + scci_rqst_fail :1, + scci_rqst_ident :1); + uint8_t _reserved2; + DECL_BITFIELD2( + scci_disable :1, + _reserved3 :7); +} ses2_comm_ctl_impl_t; + +/* + * SES-2 Communication Port element for status-type diagnostic pages + * (Table 108, 7.3.19) + */ +typedef struct ses2_comm_status_impl { + ses2_cmn_elem_status_impl_t scsi_common; + DECL_BITFIELD3( + _reserved1 :6, + scsi_fail :1, + scsi_ident :1); + uint8_t _reserved2; + DECL_BITFIELD2( + scsi_disabled :1, + _reserved3 :7); +} ses2_comm_status_impl_t; + +/* + * SES-2 Voltage Sensor element for control-type diagnostic pages + * (Table 109, 7.3.20). + */ +typedef struct ses2_voltage_ctl_impl { + ses2_cmn_elem_ctl_impl_t svci_common; + DECL_BITFIELD3( + _reserved1 :6, + svci_rqst_fail :1, + svci_rqst_ident :1); + uint8_t _reserved2[2]; +} ses2_voltage_ctl_impl_t; + +/* + * SES-2 Voltage Sensor element for status-type diagnostic pages + * (Table 110, 7.3.20). + */ +typedef struct ses2_voltage_status_impl { + ses2_cmn_elem_status_impl_t svsi_common; + DECL_BITFIELD7( + svsi_crit_under :1, + svsi_crit_over :1, + svsi_warn_under :1, + svsi_warn_over :1, + _reserved1 :2, + svsi_fail :1, + svsi_ident :1); + uint16_t svsi_voltage; +} ses2_voltage_status_impl_t; + +/* + * Ibid. defines the svsi_voltage field as a 16-bit signed 2's complement + * integer, represented in units of 10 mV. AC voltages are RMS. + */ +#define SES2_VOLTAGE_MULTIPLIER (0.01) +#define SES2_VOLTAGE(vsip) \ + (SCSI_READ16(&(vsip)->svsi_voltage) * SES2_VOLTAGE_MULTIPLIER) + +/* + * SES-2 Current Sensor element for control-type diagnostic pages + * (Table 111, 7.3.21). + */ +typedef struct ses2_current_ctl_impl { + ses2_cmn_elem_ctl_impl_t scci_common; + DECL_BITFIELD3( + _reserved1 :6, + scci_rqst_fail :1, + scci_rqst_ident :1); + uint8_t _reserved2[2]; +} ses2_current_ctl_impl_t; + +/* + * SES-2 Current Sensor element for status-type diagnostic pages + * (Table 112, 7.3.21) + */ +typedef struct ses2_current_status_impl { + ses2_cmn_elem_status_impl_t scsi_common; + DECL_BITFIELD7( + _reserved1 :1, + scsi_crit_over :1, + _reserved2 :1, + scsi_warn_over :1, + _reserved3 :2, + scsi_fail :1, + scsi_ident :1); + uint16_t scsi_current; +} ses2_current_status_impl_t; + +/* + * Ibid. defines the scsi_voltage field in the same way as for voltage above. + * Units here are 10 mA. AC amperages are RMS. + */ +#define SES2_CURRENT_MULTIPLIER (0.01) +#define SES2_CURRENT(csip) \ + (SCSI_READ16(&(csip)->scsi_current) * SES2_CURRENT_MULTIPLIER) + +/* + * SES-2 SCSI Target Port element for control-type diagnostic pages + * (Table 113, 7.3.22), SCSI Initiator Port element for control-type + * diagnostic pages (Table 115, 7.3.23). + */ +typedef struct ses2_itp_ctl_impl { + ses2_cmn_elem_ctl_impl_t sici_common; + DECL_BITFIELD3( + _reserved1 :6, + sici_rqst_fail :1, + sici_rqst_ident :1); + uint8_t _reserved2; + DECL_BITFIELD2( + sici_enable :1, + _reserved3 :7); +} ses2_itp_ctl_impl_t; + +/* + * SES-2 SCSI Target Port element for status-type diagnostic pages (Table 114, + * 7.3.22), SCSI Initiator Port element for status-type diagnostic pages + * (Table 116, 7.3.23) + */ +typedef struct ses2_itp_status_impl { + ses2_cmn_elem_status_impl_t sisi_common; + DECL_BITFIELD3( + _reserved1 :6, + sisi_fail :1, + sisi_ident :1); + DECL_BITFIELD2( + sisi_report :1, + _reserved2 :7); + DECL_BITFIELD2( + sisi_enabled :1, + _reserved3 :7); +} ses2_itp_status_impl_t; + +/* + * SES-2 Simple Subenclosure element for control-type diagnostic pages + * (Table 117, 7.3.24). + */ +typedef struct ses2_ss_ctl_impl { + ses2_cmn_elem_ctl_impl_t ssci_common; + DECL_BITFIELD3( + _reserved1 :6, + ssci_rqst_fail :1, + ssci_rqst_ident :1); + uint8_t _reserved2[2]; +} ses2_ss_ctl_impl_t; + +/* + * SES-2 Simple Subenclosure element for status-type diagnostic pages + * (Table 117, 7.3.24) + */ +typedef struct ses2_ss_status_impl { + ses2_cmn_elem_status_impl_t sss_common; + DECL_BITFIELD3( + _reserved1 :6, + sss_fail :1, + sss_ident :1); + uint8_t _reserved2; + uint8_t sss_short_status; +} ses2_ss_status_impl_t; + +/* + * SES-2 SAS Expander element for control-type diagnostic pages + * (Table 119, 7.3.25). + */ +typedef struct ses2_expander_ctl_impl { + ses2_cmn_elem_ctl_impl_t seci_common; + DECL_BITFIELD3( + _reserved1 :6, + seci_rqst_fail :1, + seci_rqst_ident :1); + uint8_t _reserved2[2]; +} ses2_expander_ctl_impl_t; + +/* + * SES-2 SAS Expander element for status-type diagnostic pages (Table 120, + * 7.3.25) + */ +typedef struct ses2_expander_status_impl { + ses2_cmn_elem_status_impl_t sesi_common; + DECL_BITFIELD3( + _reserved1 :6, + sesi_fail :1, + sesi_ident :1); + uint8_t _reserved2[2]; +} ses2_expander_status_impl_t; + +/* + * SES-2 SAS Connector element for control-type diagnostic pages (Table 121, + * 7.3.26). + */ +typedef struct ses2_sasconn_ctl_impl { + ses2_cmn_elem_ctl_impl_t ssci_common; + DECL_BITFIELD2( + _reserved1 :7, + ssci_rqst_ident :1); + uint8_t _reserved2; + DECL_BITFIELD3( + _reserved3 :6, + ssci_rqst_fail :1, + _reserved4 :1); +} ses2_sasconn_ctl_impl_t; + +/* + * SES-2 SAS Connector element for status-type diagnostic pages (Table 122, + * 7.3.26) + */ +typedef struct ses2_sasconn_status_impl { + ses2_cmn_elem_status_impl_t sss_common; + DECL_BITFIELD2( + sss_connector_type :7, + sss_ident :1); + uint8_t sss_connector_physical_link; + DECL_BITFIELD3( + _reserved1 :6, + sss_fail :1, + _reserved2 :1); +} ses2_sasconn_status_impl_t; + +/* + * SES-2 Enclosure Control diagnostic page (Table 10, 6.1.3) + */ +typedef struct ses2_control_page_impl { + uint8_t scpi_page_code; + DECL_BITFIELD5( + scpi_unrecov :1, + scpi_crit :1, + scpi_noncrit :1, + scpi_info :1, + _reserved1 :4); + uint16_t scpi_page_length; + uint32_t scpi_generation_code; + ses2_elem_ctl_impl_t scpi_data[1]; +} ses2_control_page_impl_t; + +/* + * SES-2 Enclosure Status (Table 11, 6.1.4) + */ +typedef struct ses2_status_page_impl { + uint8_t sspi_page_code; + DECL_BITFIELD6( + sspi_unrecov :1, + sspi_crit :1, + sspi_noncrit :1, + sspi_info :1, + sspi_invop :1, + _reserved1 :3); + uint16_t sspi_page_length; + uint32_t sspi_generation_code; + uint8_t sspi_data[1]; +} ses2_status_page_impl_t; + +/* + * SES-2 Help Text diagnostic page (Table 13, 6.1.5). + */ +typedef struct ses2_help_page_impl { + uint8_t shpi_page_code; + uint8_t _reserved1; + uint16_t shpi_page_length; + char shpi_help_text[1]; +} ses2_help_page_impl_t; + +/* + * SES-2 String Out diagnostic page (Table 14, 6.1.6). + */ +typedef struct ses2_string_out_page_impl { + uint8_t ssopi_page_code; + uint8_t _reserved1; + uint16_t ssopi_page_length; + uint8_t ssopi_data[1]; +} ses2_string_out_page_impl_t; + +/* + * SES-2 String In diagnostic page (Table 15, 6.1.7). + */ +typedef struct ses2_string_in_page_impl { + uint8_t ssipi_page_code; + uint8_t _reserved1; + uint16_t ssipi_page_length; + uint8_t ssipi_data[1]; +} ses2_string_in_page_impl_t; + +/* + * SES-2 Threshold fields - (Table 17, 6.1.8), (Table 19, 6.1.9). + */ +typedef struct ses2_threshold_impl { + uint8_t sti_high_crit; + uint8_t sti_high_warn; + uint8_t sti_low_warn; + uint8_t sti_low_crit; +} ses2_threshold_impl_t; + +/* + * SES-2 Threshold Out diagnostic page (Table 16, 6.1.8). + */ +typedef struct ses2_threshold_out_page_impl { + uint8_t stopi_page_code; + uint8_t _reserved1; + uint16_t stopi_page_length; + uint32_t stopi_generation_code; + ses2_threshold_impl_t stopi_thresholds[1]; +} ses2_threshold_out_page_impl_t; + +/* + * SES-2 Threshold In diagnostic page (Table 18, 6.1.9). + */ +typedef struct ses2_threshold_in_page_impl { + uint8_t stipi_page_code; + DECL_BITFIELD3( + _reserved1 :4, + stipi_invop :1, + _reserved2 :3); + uint16_t stipi_page_length; + uint32_t stipi_generation_code; + ses2_threshold_impl_t stipi_thresholds[1]; +} ses2_threshold_in_page_impl_t; + +/* + * SES-2 Element Descriptor diagnostic page (Table 20, 6.1.10). + */ +typedef struct ses2_elem_desc_page_impl { + uint8_t sedpi_page_code; + uint8_t _reserved1; + uint16_t sedpi_page_length; + uint32_t sedpi_generation_code; + uint8_t sedpi_data[1]; +} ses2_elem_desc_page_impl_t; + +/* + * SES-2 Overall/element descriptor format (Table 22, 6.1.10). + */ +typedef struct ses2_elem_descriptor_impl { + uint8_t _reserved1[2]; + uint16_t sedi_descriptor_length; + char sedi_descriptor[1]; +} ses2_elem_descriptor_impl_t; + +/* + * SES-2 Short Enclosure Status diagnostic page (Table 23, 6.1.11). + */ +typedef struct ses2_short_status_page_impl { + uint8_t ssspi_page_code; + uint8_t ssspi_short_status; + uint16_t ssspi_page_length; +} ses2_short_status_page_impl_t; + +/* + * SES-2 Enclosure Busy diagnostic page (Table 24, 6.1.12). + */ +typedef struct ses2_enclosure_busy_page_impl { + uint8_t sebpi_page_code; + DECL_BITFIELD2( + sebpi_busy :1, + sebpi_vs_1_1 :7); + uint16_t sebpi_page_length; +} ses2_enclosure_busy_page_impl_t; + +/* + * SES-2 Additional Element Status diagnostic page (Table 25, 6.1.13). + */ +typedef struct ses2_aes_page_impl { + uint8_t sapi_page_code; + uint8_t _reserved1; + uint16_t sapi_page_length; + uint32_t sapi_generation_code; + uint8_t sapi_data[1]; +} ses2_aes_page_impl_t; + +/* + * SES-2 Additional Element Status descriptor (EIP == 1) (Table 26, 6.1.13). + */ +typedef struct ses2_aes_descr_eip_impl { + DECL_BITFIELD4( + sadei_protocol_identifier :4, + sadei_eip :1, + _reserved1 :2, + sadei_invalid :1); + uint8_t sadei_length; + uint8_t _reserved2; + uint8_t sadei_element_index; + uint8_t sadei_protocol_specific[1]; +} ses2_aes_descr_eip_impl_t; + +/* + * SES-2 Additional Element Status descriptor (EIP == 0) (Table 27, 6.1.13). + */ +typedef struct ses2_aes_descr_impl { + DECL_BITFIELD4( + sadei_protocol_identifier :4, + sadei_eip :1, + _reserved1 :2, + sadei_invalid :1); + uint8_t sadei_length; + uint8_t sadei_protocol_specific[1]; +} ses2_aes_descr_impl_t; + +/* + * SES-2 Port descriptor (Table 30, 6.1.13.2). + */ +typedef struct ses2_aes_port_descr_impl { + uint8_t sapdi_port_loop_position; + uint8_t _reserved1[3]; + uint8_t sapdi_port_requested_hard_address; + uint8_t sapdi_n_port_identifier[3]; + uint64_t sapdi_n_port_name; +} ses2_aes_port_descr_impl_t; + +/* + * SES-2 Additional Element Status descriptor for FC (Table 28, 6.1.13.2). + */ +typedef struct ses2_aes_descr_fc_eip_impl { + uint8_t sadfi_n_ports; + uint8_t _reserved1[2]; + uint8_t sadfi_bay_number; + uint64_t sadfi_node_name; + ses2_aes_port_descr_impl_t sadfi_ports[1]; +} ses2_aes_descr_fc_eip_impl_t; + +/* + * SES-2 Additional Element Status descriptor for FC (EIP == 0) + * (Table 29, 6.1.13.2). + */ +typedef struct ses2_aes_descr_fc_impl { + uint8_t sadfi_n_ports; + uint8_t _reserved1; + uint64_t sadfi_node_name; + ses2_aes_port_descr_impl_t sadfi_ports[1]; +} ses2_aes_descr_fc_impl_t; + +/* + * SES-2 Additional Element Status descriptor for SAS (Table 31, 6.1.13.3). + */ +typedef struct ses2_aes_descr_sas_impl { + uint8_t _specific1; + DECL_BITFIELD2( + _specific2 :6, + sadsi_descriptor_type :2); + uint8_t _specific3[1]; +} ses2_aes_descr_sas_impl_t; + +typedef enum ses2_aes_descr_sas_type { + SES2_AESD_SAS_DEVICE = 0, + SES2_AESD_SAS_OTHER = 1 +} ses2_aes_descr_sas_type_t; + +typedef struct ses2_aes_phy0_descr_impl { + DECL_BITFIELD3( + _reserved1 :4, + sapdi_device_type :3, + _reserved2 :1); + uint8_t _reserved3; + DECL_BITFIELD5( + _reserved4 :1, + sapdi_smp_initiator_port :1, + sapdi_stp_initiator_port :1, + sapdi_ssp_initiator_port :1, + _reserved5 :4); + DECL_BITFIELD6( + sapdi_sata_device :1, + sapdi_smp_target_port :1, + sapdi_stp_target_port :1, + sapdi_ssp_target_port :1, + _reserved6 :3, + sapdi_sata_port_selector :1); + uint64_t sapdi_attached_sas_address; + uint64_t sapdi_sas_address; + uint8_t sapdi_phy_identifier; + uint8_t _reserved7[7]; +} ses2_aes_phy0_descr_impl_t; + +typedef struct ses2_aes_descr_sas0_eip_impl { + uint8_t sadsi_n_phy_descriptors; + DECL_BITFIELD3( + sadsi_not_all_phys :1, + _reserved1 :5, + sadsi_descriptor_type :2); + uint8_t _reserved2; + uint8_t sadsi_bay_number; + ses2_aes_phy0_descr_impl_t sadsi_phys[1]; +} ses2_aes_descr_sas0_eip_impl_t; + +typedef struct ses2_aes_descr_sas0_impl { + uint8_t sadsi_n_phy_descriptors; + DECL_BITFIELD3( + sadsi_not_all_phys :1, + _reserved1 :5, + sadsi_descriptor_type :2); + ses2_aes_phy0_descr_impl_t sadsi_phys[1]; +} ses2_aes_descr_sas0_impl_t; + +/* + * SES-2 Additional Element Status for SAS Expander elements + * (Table 36, 6.1.13.3.3). + */ +typedef struct ses2_aes_exp_phy_descr_impl { + uint8_t saepdi_connector_element_index; + uint8_t saepdi_other_element_index; +} ses2_aes_exp_phy_descr_impl_t; + +typedef struct ses2_aes_descr_exp_impl { + uint8_t sadei_n_exp_phy_descriptors; + DECL_BITFIELD2( + _reserved1 :6, + sadei_descriptor_type :2); + uint8_t _reserved2[2]; + uint64_t sadei_sas_address; + ses2_aes_exp_phy_descr_impl_t sadei_phys[1]; +} ses2_aes_descr_exp_impl_t; + +/* + * SES-2 Additional Element Status for SCSI Initiator/Target Port and + * Enclosure Services Controller Electronics elements (Table 38, 6.1.13.3.4). + */ +typedef struct ses2_aes_phy1_descr_impl { + uint8_t sapdi_phy_identifier; + uint8_t _reserved1; + uint8_t sapdi_connector_element_index; + uint8_t sapdi_other_element_index; + uint64_t sapdi_sas_address; +} ses2_aes_phy1_descr_impl_t; + +typedef struct ses2_aes_descr_sas1_impl { + uint8_t sadsi_n_phy_descriptors; + DECL_BITFIELD2( + _reserved1 :6, + sadsi_descriptor_type :2); + uint8_t _reserved2[2]; + ses2_aes_phy1_descr_impl_t sadsi_phys[1]; +} ses2_aes_descr_sas1_impl_t; + +/* + * SES-2 Subenclosure Help Text diagnostic page (Table 40, 6.1.14). + */ +typedef struct ses2_subhelp_page_impl { + uint8_t sspi_page_code; + uint8_t sspi_n_subenclosures; + uint16_t sspi_page_length; + uint32_t sspi_generation_code; + uint8_t sspi_data[1]; +} ses2_subhelp_page_impl_t; + +/* + * SES-2 Subenclosure help text format (Table 41, 6.1.14). + */ +typedef struct ses2_subhelp_text_impl { + uint8_t _reserved1; + uint8_t ssti_subenclosure_identifier; + uint16_t ssti_subenclosure_help_text_length; + char ssti_subenclosure_help_text[1]; +} ses2_subhelp_text_impl_t; + +#define SES2_SUBHELP_LEN(stip) \ + ((stip)->ssti_subenclosure_help_text_length + \ + offsetof(ses2_subhelp_text_impl_t, ssti_subenclosure_help_text[0])) +/* + * SES-2 Subenclosure String Out diagnostic page (Table 42, 6.1.15). + */ +typedef struct ses2_substring_out_page_impl { + uint8_t ssopi_page_code; + uint8_t ssopi_subenclosure_identifier; + uint16_t ssopi_page_length; + uint32_t ssopi_generation_code; + uint8_t ssopi_data[1]; +} ses2_substring_out_page_impl_t; + +/* + * SES-2 Subenclosure String In diagnostic page (Table 43, 6.1.16). + */ +typedef struct ses2_substring_in_page_impl { + uint8_t ssipi_page_code; + uint8_t ssipi_n_subenclosures; + uint16_t ssipi_page_length; + uint32_t ssipi_generation_code; + uint8_t ssipi_data[1]; +} ses2_substring_in_page_impl_t; + +/* + * SES-2 Subenclosure string in data format (Table 44, 6.1.16). + */ +typedef struct ses2_substring_in_data_impl { + uint8_t _reserved1; + uint8_t ssidi_subenclosure_identifier; + uint16_t ssidi_substring_data_length; + uint8_t ssidi_data[1]; +} ses2_substring_in_data_impl_t; + +#define SES2_SUBSTR_LEN(sdip) \ + ((sdip)->ssidi_substring_data_length + \ + offsetof(ses2_substring_in_data_impl_t, ssidi_data[0])) + +/* + * SES-2 Supported SES Diagnostic Pages diagnostic page (Table 45, 6.1.17). + */ +typedef struct ses2_supported_ses_diag_page_impl { + uint8_t sssdpi_page_code; + uint8_t _reserved1; + uint16_t sssdpi_page_length; + uint8_t sssdpi_pages[1]; +} ses2_supported_ses_diag_page_impl_t; + +/* + * SES-2 Download Microcode Control diagnostic page (Table 46, 6.1.18). + */ +typedef struct ses2_ucode_ctl_page_impl { + uint8_t sucpi_page_code; + uint8_t sucpi_subenclosure_identifier; + uint16_t sucpi_page_length; + uint32_t sucpi_generation_code; + uint8_t sucpi_dl_ucode_mode; + uint8_t _reserved1[2]; + uint8_t sucpi_buffer_id; + uint32_t sucpi_buffer_offset; + uint32_t sucpi_ucode_image_length; + uint32_t sucpi_ucode_data_length; + uint8_t sucpi_ucode_data[1]; +} ses2_ucode_ctl_page_impl_t; + +/* + * SES-2 Download Microcode Status diagnostic page (Table 48-49, 6.1.19). + */ +typedef struct ses2_ucode_status_descr_impl { + uint8_t _reserved1; + uint8_t susdi_subenclosure_identifier; + uint8_t susdi_subenclosure_dl_status; + uint8_t susdi_subenclosure_dl_addl_status; + uint32_t susdi_subenclosure_dl_max_size; + uint8_t _reserved2[3]; + uint8_t susdi_subenclosure_dl_buffer_id; + uint32_t susdi_subenclosure_dl_buffer_offset; +} ses2_ucode_status_descr_impl_t; + +typedef struct ses2_ucode_status_page_impl { + uint8_t suspi_page_code; + uint8_t suspi_n_subenclosures; + uint16_t suspi_page_length; + uint32_t suspi_generation_code; + ses2_ucode_status_descr_impl_t suspi_descriptors[1]; +} ses2_ucode_status_page_impl_t; + +/* + * SES-2 Subenclosure Nickname Control diagnostic page (Table 51, 6.1.20). + */ +typedef struct ses2_subnick_ctl_page_impl { + uint8_t sscpi_page_code; + uint8_t sspci_subenclosure_identifier; + uint16_t sspci_page_length; + uint32_t sspci_generation_code; + char sspci_subenclosure_nickname[32]; +} ses2_subnick_ctl_page_impl_t; + +/* + * SES-2 Subenclosure Nickname Status diagnostic page (Table 52-53, 6.1.21). + */ +typedef struct ses2_subnick_descr_impl { + uint8_t _reserved1; + uint8_t ssdi_subenclosure_identifier; + uint8_t ssdi_subenclosure_nick_status; + uint8_t ssdi_subenclosure_nick_addl_status; + uint8_t _reserved2[2]; + uint16_t ssdi_subenclosure_nick_lang_code; + char ssdi_subenclosure_nickname[32]; +} ses2_subnick_descr_impl_t; + +typedef struct ses2_subnick_status_page_impl { + uint8_t sspsi_page_code; + uint8_t sspci_n_subenclosures; + uint16_t sspci_page_length; + uint32_t sspci_generation_code; + ses2_subnick_descr_impl_t sspci_subnicks[1]; +} ses2_subnick_status_page_impl_t; + +/* + * SES-2 Mode page code for enclosure services devices (Table 57, 6.3.2). + */ +typedef struct ses2_esm_mode_page_impl { + DECL_BITFIELD3( + sempi_page_code :6, + _reserved1 :1, + sempi_ps :1); + uint8_t sempi_page_length; + uint8_t _reserved2[3]; + DECL_BITFIELD2( + sempi_enbltc :1, + _reserved3 :7); + uint16_t sempi_max_task_completion_time; +} ses2_esm_mode_page_impl_t; + +#pragma pack() + +extern ses_pagedesc_t ses2_pages[]; + +extern int ses2_fill_element_node(ses_plugin_t *, ses_node_t *); +extern int ses2_fill_enclosure_node(ses_plugin_t *, ses_node_t *); + +typedef int (*ses2_setprop_f)(ses_plugin_t *, ses_node_t *, ses2_diag_page_t, + nvpair_t *); + +typedef struct ses2_ctl_prop { + const char *scp_name; + data_type_t scp_type; + ses2_diag_page_t scp_num; + ses2_setprop_f scp_setprop; +} ses2_ctl_prop_t; + +typedef int (*ses2_setdef_f)(ses_node_t *, ses2_diag_page_t, void *); + +extern int ses2_ctl_common_setprop(ses_plugin_t *sp, ses_node_t *, + ses2_diag_page_t, nvpair_t *); + +#define SES_COMMON_CTL_PROPS \ +{ \ + .scp_name = SES_PROP_SWAP, \ + .scp_type = DATA_TYPE_BOOLEAN_VALUE, \ + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, \ + .scp_setprop = ses2_ctl_common_setprop \ +}, \ +{ \ + .scp_name = SES_PROP_DISABLED, \ + .scp_type = DATA_TYPE_BOOLEAN_VALUE, \ + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, \ + .scp_setprop = ses2_ctl_common_setprop \ +}, \ +{ \ + .scp_name = SES_PROP_PRDFAIL, \ + .scp_type = DATA_TYPE_BOOLEAN_VALUE, \ + .scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, \ + .scp_setprop = ses2_ctl_common_setprop \ +} + +typedef struct ses2_ctl_desc { + ses2_element_type_t scd_et; + const ses2_ctl_prop_t *scd_props; + ses2_setdef_f scd_setdef; +} ses2_ctl_desc_t; + +extern int ses2_setprop(ses_plugin_t *, ses_node_t *, const ses2_ctl_prop_t *, + nvlist_t *); + +extern int ses2_element_setdef(ses_node_t *, ses2_diag_page_t, void *); +extern int ses2_enclosure_setdef(ses_node_t *, ses2_diag_page_t, void *); + +extern int ses2_element_ctl(ses_plugin_t *, ses_node_t *, const char *, + nvlist_t *); +extern int ses2_enclosure_ctl(ses_plugin_t *, ses_node_t *, const char *, + nvlist_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _PLUGIN_SES_IMPL_H */ diff --git a/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_pages.c b/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_pages.c new file mode 100644 index 0000000000..7c6d7726ba --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_pages.c @@ -0,0 +1,462 @@ +/* + * 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 <stddef.h> +#include <strings.h> + +#include <scsi/libses.h> +#include <scsi/libses_plugin.h> +#include <scsi/plugins/ses/framework/ses2.h> + +#include "ses2_impl.h" + +static int +ses2_ctl_common_setdef(ses_node_t *np, ses2_diag_page_t page, void *data) +{ + ses2_cmn_elem_ctl_impl_t *eip = data; + nvlist_t *props = ses_node_props(np); + + if (page != SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS) + return (0); + + SES_NV_CTLBOOL_INVERT(props, SES_PROP_SWAP, eip->seci_rst_swap); + SES_NV_CTLBOOL(props, SES_PROP_DISABLED, eip->seci_disable); + SES_NV_CTLBOOL(props, SES_PROP_PRDFAIL, eip->seci_prdfail); + + eip->seci_select = 1; + + return (0); +} + +/*ARGSUSED*/ +static void * +ses2_aes_index(ses_plugin_t *sp, ses_node_t *np, void *data, size_t pagelen, + size_t *len) +{ + ses2_aes_page_impl_t *apip = data; + uint64_t index, type; + nvlist_t *props = ses_node_props(np); + ses2_aes_descr_eip_impl_t *dep; + size_t desclen; + int i, pos; + ses_node_t *uncle; + + VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_INDEX, + &index) == 0); + VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_TYPE, + &type) == 0); + + if (pagelen < offsetof(ses2_aes_page_impl_t, sapi_data)) + return (0); + + /* + * Because, according to 6.1.13.1, the element index "does not + * include the OVERALL STATUS fields", we have to go recompute the + * index of this element each time. This, naturally, is a linear + * exercise as well. + */ + for (uncle = ses_node_parent(np); uncle != NULL; + uncle = ses_node_prev_sibling(uncle)) + --index; + + for (dep = (ses2_aes_descr_eip_impl_t *)apip->sapi_data, pos = 0, i = 0; + pos < SCSI_READ16(&apip->sapi_page_length); + dep = (ses2_aes_descr_eip_impl_t *)(apip->sapi_data + pos), i++) { + if (!SES_WITHIN_PAGE_STRUCT(dep, data, pagelen)) + break; + + desclen = dep->sadei_length + + offsetof(ses2_aes_descr_eip_impl_t, sadei_length) + + sizeof (dep->sadei_length); + + if (!SES_WITHIN_PAGE(dep, desclen, data, pagelen)) + break; + + pos += desclen; + if (!dep->sadei_eip && + type != SES_ET_DEVICE && + type != SES_ET_ARRAY_DEVICE) { + /* + * We can't really do anything with this, because + * while the standard requires that these descriptors + * be in the same order as those in the status page, + * some element types may optionally include AES + * data. This means we cannot know which element + * this descriptor refers to unless EIP is 1. Sadly, + * the standard only says that this "should" be true. + * It's impossible to guess what use this is supposed + * to have otherwise. See 6.1.13.1. + */ + continue; + } else if (dep->sadei_eip && + dep->sadei_element_index != index) { + continue; + } else if (dep->sadei_eip || i == index) { + *len = desclen; + return (dep); + } + } + + return (NULL); +} + +/*ARGSUSED*/ +static void * +ses2_threshold_index(ses_plugin_t *sp, ses_node_t *np, void *data, + size_t pagelen, size_t *len) +{ + uint64_t index; + nvlist_t *props = ses_node_props(np); + ses2_threshold_in_page_impl_t *tpip = data; + ses2_threshold_impl_t *tp; + + VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_INDEX, + &index) == 0); + + *len = sizeof (ses2_threshold_impl_t); + tp = &tpip->stipi_thresholds[index]; + + if (!SES_WITHIN_PAGE_STRUCT(tp, data, pagelen)) + return (NULL); + + return (&tpip->stipi_thresholds[index]); +} + +/*ARGSUSED*/ +static void * +ses2_element_index(ses_plugin_t *sp, ses_node_t *np, void *data, + size_t pagelen, size_t *len) +{ + uint64_t index; + nvlist_t *props = ses_node_props(np); + ses2_elem_desc_page_impl_t *edip = data; + ses2_elem_descriptor_impl_t *dp; + int i; + uint16_t dlen; + + if (nvlist_lookup_uint64(props, SES_PROP_ELEMENT_INDEX, &index) != 0) + return (NULL); + + if (!SES_WITHIN_PAGE(data, sizeof (*dp), data, pagelen)) + return (NULL); + + /* + * This variable-length list of variable-length strings format sucks + * for performance; we ALWAYS have to walk the whole bloody thing to + * find a particular node's entry. + */ + for (i = 0, dp = (ses2_elem_descriptor_impl_t *)edip->sedpi_data; + i < index; i++) { + + if (!SES_WITHIN_PAGE_STRUCT(dp, data, pagelen)) + return (NULL); + + dlen = SCSI_READ16(&dp->sedi_descriptor_length); + + dp = (ses2_elem_descriptor_impl_t *) + ((uint8_t *)dp->sedi_descriptor + dlen); + } + + if (!SES_WITHIN_PAGE_STRUCT(dp, data, pagelen)) + return (NULL); + + *len = SCSI_READ16(&dp->sedi_descriptor_length); + + if (!SES_WITHIN_PAGE(dp, + *len + offsetof(ses2_elem_descriptor_impl_t, sedi_descriptor), + data, pagelen)) + return (NULL); + + return (dp->sedi_descriptor); +} + +/*ARGSUSED*/ +static void * +ses2_status_index(ses_plugin_t *sp, ses_node_t *np, void *data, + size_t pagelen, size_t *len) +{ + uint64_t index; + nvlist_t *props = ses_node_props(np); + ses2_status_page_impl_t *spip = data; + + if (nvlist_lookup_uint64(props, SES_PROP_ELEMENT_INDEX, + &index) != 0) + return (NULL); + + if ((index + 1) * sizeof (ses2_elem_status_impl_t) + + offsetof(ses2_status_page_impl_t, sspi_data) > pagelen) + return (NULL); + + *len = sizeof (ses2_elem_status_impl_t); + return ((ses2_elem_status_impl_t *)spip->sspi_data + index); +} + +/*ARGSUSED*/ +static size_t +ses2_ctl_len(uint_t nelem, int page, size_t datalen) +{ + ASSERT(page == SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS); + + return (nelem * sizeof (ses2_elem_ctl_impl_t) + + offsetof(ses2_control_page_impl_t, scpi_data[0])); +} + +/*ARGSUSED*/ +static void * +ses2_ctl_fill(ses_plugin_t *sp, void *pagedata, size_t pagelen, + ses_node_t *np) +{ + uint64_t index; + nvlist_t *props = ses_node_props(np); + ses2_control_page_impl_t *pip = pagedata; + void *data; + ses2_diag_page_t page = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS; + + if (nvlist_lookup_uint64(props, SES_PROP_ELEMENT_INDEX, + &index) != 0) { + (void) ses_error(ESES_BAD_RESPONSE, "missing element index " + "for enclosure node"); + return (NULL); + } + + data = &pip->scpi_data[index]; + + if (ses2_ctl_common_setdef(np, page, data) != 0 || + ses2_element_setdef(np, page, data) != 0 || + ses2_enclosure_setdef(np, page, data) != 0) + return (NULL); + + return (data); +} + +/*ARGSUSED*/ +static size_t +ses2_stringout_len(uint_t nelem, int page, size_t datalen) +{ + ASSERT(page == SES2_DIAGPAGE_STRING_IO); + + return (datalen + offsetof(ses2_string_out_page_impl_t, ssopi_data[0])); +} + +/*ARGSUSED*/ +static size_t +ses2_threshout_len(uint_t nelem, int page, size_t datalen) +{ + ASSERT(page == SES2_DIAGPAGE_THRESHOLD_IO); + + return (nelem * sizeof (ses2_threshold_impl_t) + + offsetof(ses2_threshold_out_page_impl_t, stopi_thresholds[0])); +} + +/*ARGSUSED*/ +static void * +ses2_threshout_ctl_fill(ses_plugin_t *sp, void *pagedata, size_t pagelen, + ses_node_t *np) +{ + uint64_t index; + nvlist_t *props = ses_node_props(np); + ses2_threshold_out_page_impl_t *pip = pagedata; + ses2_diag_page_t page = SES2_DIAGPAGE_THRESHOLD_IO; + void *data; + + VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_INDEX, + &index) == 0); + + data = &pip[index]; + + if (ses2_ctl_common_setdef(np, page, data) != 0 || + ses2_element_setdef(np, page, data) != 0 || + ses2_enclosure_setdef(np, page, data) != 0) + return (NULL); + + return (data); +} + +/*ARGSUSED*/ +static size_t +ses2_substrout_len(uint_t nelem, int page, size_t datalen) +{ + ASSERT(page == SES2_DIAGPAGE_SUBENCLOSURE_STRING_IO); + + return (datalen + + offsetof(ses2_substring_out_page_impl_t, ssopi_data[0])); +} + +/*ARGSUSED*/ +static size_t +ses2_ucodeout_len(uint_t nelem, int page, size_t datalen) +{ + size_t len; + + ASSERT(page == SES2_DIAGPAGE_DL_MICROCODE_CTL_STATUS); + + len = datalen + + offsetof(ses2_ucode_ctl_page_impl_t, sucpi_ucode_data[0]); + + return (P2ROUNDUP(len, 4)); +} + +/*ARGSUSED*/ +static void * +ses2_ucodeout_ctl_fill(ses_plugin_t *sp, void *data, size_t pagelen, + ses_node_t *np) +{ + ses_snap_t *snap = ses_node_snapshot(np); + nvlist_t *props = ses_node_props(np); + ses2_ucode_ctl_page_impl_t *uip = data; + uint64_t eid; + + if (ses_node_type(np) != SES_NODE_ENCLOSURE) { + (void) ses_error(ESES_BAD_TYPE, + "microcode download page only valid for enclosure " + "nodes"); + return (NULL); + } + + VERIFY(nvlist_lookup_uint64(props, SES_EN_PROP_EID, &eid) == 0); + + SCSI_WRITE32(&uip->sucpi_generation_code, + ses_snap_generation(snap)); + uip->sucpi_subenclosure_identifier = eid; + + return (data); +} + +/*ARGSUSED*/ +static size_t +ses2_subnickout_len(uint_t nelem, int page, size_t datalen) +{ + ASSERT(page == SES2_DIAGPAGE_SUBENCLOSURE_NICKNAME_CTL_STATUS); + + return (sizeof (ses2_subnick_ctl_page_impl_t)); +} + +ses_pagedesc_t ses2_pages[] = { +{ + .spd_pagenum = SES2_DIAGPAGE_SUPPORTED_PAGES, + .spd_gcoff = -1 +}, +{ + .spd_pagenum = SES2_DIAGPAGE_CONFIG, + .spd_gcoff = offsetof(ses2_config_page_impl_t, scpi_generation_code) +}, +{ + .spd_pagenum = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .spd_index = ses2_status_index, + .spd_gcoff = offsetof(ses2_status_page_impl_t, sspi_generation_code) +}, +{ + .spd_pagenum = SES2_DIAGPAGE_HELP_TEXT, + .spd_gcoff = -1 +}, +{ + .spd_pagenum = SES2_DIAGPAGE_STRING_IO, + .spd_gcoff = -1 +}, +{ + .spd_pagenum = SES2_DIAGPAGE_THRESHOLD_IO, + .spd_index = ses2_threshold_index, + .spd_gcoff = + offsetof(ses2_threshold_in_page_impl_t, stipi_generation_code) +}, +{ + .spd_pagenum = SES2_DIAGPAGE_ELEMENT_DESC, + .spd_index = ses2_element_index, + .spd_gcoff = offsetof(ses2_elem_desc_page_impl_t, sedpi_generation_code) +}, +{ + .spd_pagenum = SES2_DIAGPAGE_ADDL_ELEM_STATUS, + .spd_index = ses2_aes_index, + .spd_gcoff = offsetof(ses2_aes_page_impl_t, sapi_generation_code) +}, +{ + .spd_pagenum = SES2_DIAGPAGE_SUBENCLOSURE_HELP_TEXT, + .spd_gcoff = offsetof(ses2_subhelp_page_impl_t, sspi_generation_code) +}, +{ + .spd_pagenum = SES2_DIAGPAGE_SUBENCLOSURE_STRING_IO, + .spd_gcoff = + offsetof(ses2_substring_in_page_impl_t, ssipi_generation_code) +}, +{ + .spd_pagenum = SES2_DIAGPAGE_SUPPORTED_SES_PAGES, + .spd_gcoff = -1 +}, +{ + .spd_pagenum = SES2_DIAGPAGE_DL_MICROCODE_CTL_STATUS, + .spd_gcoff = + offsetof(ses2_ucode_status_page_impl_t, suspi_generation_code) +}, +{ + .spd_pagenum = SES2_DIAGPAGE_SUBENCLOSURE_NICKNAME_CTL_STATUS, + .spd_gcoff = + offsetof(ses2_subnick_status_page_impl_t, sspci_generation_code) +}, +/* Control pages */ +{ + .spd_pagenum = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .spd_ctl_len = ses2_ctl_len, + .spd_ctl_fill = ses2_ctl_fill, + .spd_gcoff = offsetof(ses2_control_page_impl_t, scpi_generation_code) +}, +{ + .spd_pagenum = SES2_DIAGPAGE_STRING_IO, + .spd_ctl_len = ses2_stringout_len, + .spd_gcoff = -1 +}, +{ + .spd_pagenum = SES2_DIAGPAGE_THRESHOLD_IO, + .spd_ctl_len = ses2_threshout_len, + .spd_ctl_fill = ses2_threshout_ctl_fill, + .spd_gcoff = + offsetof(ses2_threshold_out_page_impl_t, stopi_generation_code) +}, +{ + .spd_pagenum = SES2_DIAGPAGE_SUBENCLOSURE_STRING_IO, + .spd_ctl_len = ses2_substrout_len, + .spd_gcoff = + offsetof(ses2_substring_out_page_impl_t, ssopi_generation_code) +}, +{ + .spd_pagenum = SES2_DIAGPAGE_DL_MICROCODE_CTL_STATUS, + .spd_ctl_len = ses2_ucodeout_len, + .spd_ctl_fill = ses2_ucodeout_ctl_fill, + .spd_gcoff = + offsetof(ses2_ucode_ctl_page_impl_t, sucpi_generation_code) +}, +{ + .spd_pagenum = SES2_DIAGPAGE_SUBENCLOSURE_NICKNAME_CTL_STATUS, + .spd_ctl_len = ses2_subnickout_len, + .spd_gcoff = + offsetof(ses2_subnick_ctl_page_impl_t, sspci_generation_code) +}, +{ + .spd_pagenum = -1, + .spd_gcoff = -1 +} +}; diff --git a/usr/src/lib/scsi/plugins/ses/ses2/i386/Makefile b/usr/src/lib/scsi/plugins/ses/ses2/i386/Makefile new file mode 100644 index 0000000000..447a346278 --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/ses2/i386/Makefile @@ -0,0 +1,32 @@ +# +# 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" + +include ../Makefile.com + +install: all $(ROOTPROG) + +include ../../Makefile.targ diff --git a/usr/src/lib/scsi/plugins/ses/ses2/sparc/Makefile b/usr/src/lib/scsi/plugins/ses/ses2/sparc/Makefile new file mode 100644 index 0000000000..447a346278 --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/ses2/sparc/Makefile @@ -0,0 +1,32 @@ +# +# 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" + +include ../Makefile.com + +install: all $(ROOTPROG) + +include ../../Makefile.targ diff --git a/usr/src/lib/scsi/plugins/ses/ses2/sparcv9/Makefile b/usr/src/lib/scsi/plugins/ses/ses2/sparcv9/Makefile new file mode 100644 index 0000000000..fbf98db77f --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/ses2/sparcv9/Makefile @@ -0,0 +1,33 @@ +# +# 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" + +include ../Makefile.com +include $(SRC)/Makefile.master.64 + +install: all $(ROOTPROG64) + +include ../../Makefile.targ diff --git a/usr/src/pkgdefs/Makefile b/usr/src/pkgdefs/Makefile index b007b79d2a..3445b5c3bc 100644 --- a/usr/src/pkgdefs/Makefile +++ b/usr/src/pkgdefs/Makefile @@ -362,6 +362,7 @@ COMMON_SUBDIRS= \ SUNWscpu \ SUNWscplp \ SUNWscsa1394 \ + SUNWscsip \ SUNWses \ SUNWsfe \ SUNWslpr \ diff --git a/usr/src/pkgdefs/SUNWarc/prototype_com b/usr/src/pkgdefs/SUNWarc/prototype_com index 6aa3ee7b3b..61f806d12c 100644 --- a/usr/src/pkgdefs/SUNWarc/prototype_com +++ b/usr/src/pkgdefs/SUNWarc/prototype_com @@ -257,3 +257,8 @@ f none usr/lib/llib-lpasswdutil 644 root bin f none usr/lib/llib-lpasswdutil.ln 644 root bin f none usr/lib/llib-lgss 644 root bin f none usr/lib/llib-lgss.ln 644 root bin +d none usr/lib/scsi 755 root bin +f none usr/lib/scsi/llib-lscsi 644 root bin +f none usr/lib/scsi/llib-lscsi.ln 644 root bin +f none usr/lib/scsi/llib-lses 644 root bin +f none usr/lib/scsi/llib-lses.ln 644 root bin diff --git a/usr/src/pkgdefs/SUNWarc/prototype_i386 b/usr/src/pkgdefs/SUNWarc/prototype_i386 index c075cea73e..924d200125 100644 --- a/usr/src/pkgdefs/SUNWarc/prototype_i386 +++ b/usr/src/pkgdefs/SUNWarc/prototype_i386 @@ -169,3 +169,6 @@ s none usr/ccs/lib/amd64/values-Xs.o=../../../lib/amd64/values-Xs.o s none usr/ccs/lib/amd64/values-Xt.o=../../../lib/amd64/values-Xt.o s none usr/ccs/lib/amd64/values-xpg4.o=../../../lib/amd64/values-xpg4.o s none usr/ccs/lib/amd64/values-xpg6.o=../../../lib/amd64/values-xpg6.o +d none usr/lib/scsi/amd64 755 root bin +f none usr/lib/scsi/amd64/llib-lscsi.ln 644 root bin +f none usr/lib/scsi/amd64/llib-lses.ln 644 root bin diff --git a/usr/src/pkgdefs/SUNWarc/prototype_sparc b/usr/src/pkgdefs/SUNWarc/prototype_sparc index b6b1d53bdd..fe4b089836 100644 --- a/usr/src/pkgdefs/SUNWarc/prototype_sparc +++ b/usr/src/pkgdefs/SUNWarc/prototype_sparc @@ -165,3 +165,6 @@ s none usr/ccs/lib/sparcv9/values-Xt.o=../../../lib/sparcv9/values-Xt.o s none usr/ccs/lib/sparcv9/values-xpg4.o=../../../lib/sparcv9/values-xpg4.o s none usr/ccs/lib/sparcv9/values-xpg6.o=../../../lib/sparcv9/values-xpg6.o f none usr/lib/sparcv9/llib-lpasswdutil.ln 644 root bin +d none usr/lib/scsi/sparcv9 755 root bin +f none usr/lib/scsi/sparcv9/llib-lscsi.ln 644 root bin +f none usr/lib/scsi/sparcv9/llib-lses.ln 644 root bin diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_com b/usr/src/pkgdefs/SUNWcsl/prototype_com index 6a84023a77..ba6e4109bc 100644 --- a/usr/src/pkgdefs/SUNWcsl/prototype_com +++ b/usr/src/pkgdefs/SUNWcsl/prototype_com @@ -360,6 +360,20 @@ f none usr/lib/security/pkcs11_kernel.so.1 755 root bin s none usr/lib/security/pkcs11_kernel.so=./pkcs11_kernel.so.1 f none usr/lib/security/pkcs11_softtoken.so.1 755 root bin s none usr/lib/security/pkcs11_softtoken.so=./pkcs11_softtoken.so.1 +d none usr/lib/scsi 755 root bin +f none usr/lib/scsi/libscsi.so.1 755 root bin +s none usr/lib/scsi/libscsi.so=./libscsi.so.1 +f none usr/lib/scsi/libses.so.1 755 root bin +s none usr/lib/scsi/libses.so=./libses.so.1 +d none usr/lib/scsi/plugins 755 root bin +d none usr/lib/scsi/plugins/scsi 755 root bin +d none usr/lib/scsi/plugins/scsi/engines 755 root bin +f none usr/lib/scsi/plugins/scsi/engines/uscsi.so 755 root bin +d none usr/lib/scsi/plugins/ses 755 root bin +d none usr/lib/scsi/plugins/ses/framework 755 root bin +f none usr/lib/scsi/plugins/ses/framework/libses.so 755 root bin +f none usr/lib/scsi/plugins/ses/framework/ses2.so 755 root bin +d none usr/lib/scsi/plugins/ses/vendor 755 root bin f none usr/lib/watchmalloc.so.1 755 root bin s none usr/lib/liby.so=./liby.so.1 s none usr/ccs/lib/liby.so=../../lib/liby.so.1 diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_i386 b/usr/src/pkgdefs/SUNWcsl/prototype_i386 index c03e9554f6..19e366699b 100644 --- a/usr/src/pkgdefs/SUNWcsl/prototype_i386 +++ b/usr/src/pkgdefs/SUNWcsl/prototype_i386 @@ -89,6 +89,16 @@ s none usr/lib/lwp/amd64/libthread.so.1=../../amd64/libthread.so.1 s none usr/lib/lwp/amd64/libthread_db.so.1=../../amd64/libthread_db.so.1 d none usr/lib/raidcfg/amd64 755 root bin f none usr/lib/raidcfg/amd64/mpt.so.1 755 root bin +d none usr/lib/scsi/amd64 755 root bin +f none usr/lib/scsi/amd64/libscsi.so.1 755 root bin +s none usr/lib/scsi/amd64/libscsi.so=./libscsi.so.1 +f none usr/lib/scsi/amd64/libses.so.1 755 root bin +s none usr/lib/scsi/amd64/libses.so=./libses.so.1 +d none usr/lib/scsi/plugins/scsi/engines/amd64 755 root bin +f none usr/lib/scsi/plugins/scsi/engines/amd64/uscsi.so 755 root bin +d none usr/lib/scsi/plugins/ses/framework/amd64 755 root bin +f none usr/lib/scsi/plugins/ses/framework/amd64/libses.so 755 root bin +f none usr/lib/scsi/plugins/ses/framework/amd64/ses2.so 755 root bin d none usr/lib/security/amd64 755 root bin s none usr/lib/security/64=amd64 f none usr/lib/security/amd64/crypt_bsdmd5.so.1 755 root bin diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_sparc b/usr/src/pkgdefs/SUNWcsl/prototype_sparc index 22376c5573..3452eca2cf 100644 --- a/usr/src/pkgdefs/SUNWcsl/prototype_sparc +++ b/usr/src/pkgdefs/SUNWcsl/prototype_sparc @@ -81,6 +81,17 @@ s none usr/lib/lwp/sparcv9/libthread.so.1=../../sparcv9/libthread.so.1 s none usr/lib/lwp/sparcv9/libthread_db.so.1=../../sparcv9/libthread_db.so.1 d none usr/lib/raidcfg/sparcv9 755 root bin f none usr/lib/raidcfg/sparcv9/mpt.so.1 755 root bin +d none usr/lib/scsi/sparcv9 755 root bin +f none usr/lib/scsi/sparcv9/libscsi.so.1 755 root bin +s none usr/lib/scsi/sparcv9/libscsi.so=./libscsi.so.1 +f none usr/lib/scsi/sparcv9/libses.so.1 755 root bin +s none usr/lib/scsi/sparcv9/libses.so=./libses.so.1 +d none usr/lib/scsi/plugins/scsi/engines/sparcv9 755 root bin +f none usr/lib/scsi/plugins/scsi/engines/sparcv9/uscsi.so 755 root bin +d none usr/lib/scsi/plugins/ses/framework/sparcv9 755 root bin +f none usr/lib/scsi/plugins/ses/framework/sparcv9/libses.so 755 root bin +f none usr/lib/scsi/plugins/ses/framework/sparcv9/ses2.so 755 root bin +d none usr/lib/scsi/plugins/ses/vendor/sparcv9 755 root bin d none usr/lib/security/sparcv9 755 root bin s none usr/lib/security/64=sparcv9 f none usr/lib/security/sparcv9/crypt_bsdmd5.so.1 755 root bin diff --git a/usr/src/pkgdefs/SUNWhea/prototype_com b/usr/src/pkgdefs/SUNWhea/prototype_com index f723a79fbe..cc72136ac2 100644 --- a/usr/src/pkgdefs/SUNWhea/prototype_com +++ b/usr/src/pkgdefs/SUNWhea/prototype_com @@ -583,6 +583,17 @@ f none usr/include/sasl/prop.h 0644 root bin f none usr/include/sasl/sasl.h 0644 root bin f none usr/include/sasl/saslplug.h 0644 root bin f none usr/include/sasl/saslutil.h 0644 root bin +d none usr/include/scsi 755 root bin +f none usr/include/scsi/libscsi.h 644 root bin +f none usr/include/scsi/libses.h 644 root bin +f none usr/include/scsi/libses_plugin.h 644 root bin +d none usr/include/scsi/plugins 755 root bin +d none usr/include/scsi/plugins/ses 755 root bin +d none usr/include/scsi/plugins/ses/framework 755 root bin +f none usr/include/scsi/plugins/ses/framework/libses.h 644 root bin +f none usr/include/scsi/plugins/ses/framework/ses2.h 644 root bin +f none usr/include/scsi/plugins/ses/framework/ses2_impl.h 644 root bin +d none usr/include/scsi/plugins/ses/vendor 755 root bin f none usr/include/search.h 644 root bin f none usr/include/secdb.h 644 root bin d none usr/include/security 755 root bin @@ -1162,6 +1173,7 @@ f none usr/include/sys/scsi/impl/sas_transport.h 644 root bin f none usr/include/sys/scsi/impl/scsi_reset_notify.h 644 root bin f none usr/include/sys/scsi/impl/sense.h 644 root bin f none usr/include/sys/scsi/impl/services.h 644 root bin +f none usr/include/sys/scsi/impl/spc3_types.h 644 root bin f none usr/include/sys/scsi/impl/status.h 644 root bin f none usr/include/sys/scsi/impl/transport.h 644 root bin f none usr/include/sys/scsi/impl/types.h 644 root bin diff --git a/usr/src/pkgdefs/SUNWiotu/prototype_com b/usr/src/pkgdefs/SUNWiotu/prototype_com index 33132cb385..9df5bc06f5 100644 --- a/usr/src/pkgdefs/SUNWiotu/prototype_com +++ b/usr/src/pkgdefs/SUNWiotu/prototype_com @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# 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. @@ -20,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2005 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" @@ -57,3 +56,6 @@ d none usr/share 755 root sys d none usr/share/man 755 root bin d none usr/share/man/man1m 755 root bin f none usr/share/man/man1m/pcitool.1m 444 root root +d none usr/lib 755 root bin +d none usr/lib/scsi 755 root bin +f none usr/lib/scsi/sestopo 555 root bin diff --git a/usr/src/pkgdefs/SUNWscsip/Makefile b/usr/src/pkgdefs/SUNWscsip/Makefile new file mode 100644 index 0000000000..4db50ab6fc --- /dev/null +++ b/usr/src/pkgdefs/SUNWscsip/Makefile @@ -0,0 +1,36 @@ +# +# 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" + +include ../Makefile.com + +.KEEP_STATE: + +all: $(FILES) depend + +install: all pkg + +include ../Makefile.targ diff --git a/usr/src/pkgdefs/SUNWscsip/depend b/usr/src/pkgdefs/SUNWscsip/depend new file mode 100644 index 0000000000..c4222422df --- /dev/null +++ b/usr/src/pkgdefs/SUNWscsip/depend @@ -0,0 +1,45 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This package information file defines software dependencies associated +# with the pkg. You can define three types of pkg dependencies with this file: +# P indicates a prerequisite for installation +# I indicates an incompatible package +# R indicates a reverse dependency +# <pkg.abbr> see pkginfo(4), PKG parameter +# <name> see pkginfo(4), NAME parameter +# <version> see pkginfo(4), VERSION parameter +# <arch> see pkginfo(4), ARCH parameter +# <type> <pkg.abbr> <name> +# (<arch>)<version> +# (<arch>)<version> +# ... +# <type> <pkg.abbr> <name> +# ... +# + +P SUNWcsl Core Solaris Libraries diff --git a/usr/src/pkgdefs/SUNWscsip/pkginfo.tmpl b/usr/src/pkgdefs/SUNWscsip/pkginfo.tmpl new file mode 100644 index 0000000000..69c26fa4a1 --- /dev/null +++ b/usr/src/pkgdefs/SUNWscsip/pkginfo.tmpl @@ -0,0 +1,52 @@ +# +# 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 required package information file describes characteristics of the +# package, such as package abbreviation, full package name, package version, +# and package architecture. +# +PKG="SUNWscsip" +NAME="SCSI/SES plugins" +ARCH="ISA" +VERSION="ONVERS,REV=0.0.0" +SUNW_PRODNAME="SunOS" +SUNW_PRODVERS="RELEASE/VERSION" +SUNW_PKGTYPE="usr" +MAXINST="1000" +CATEGORY="system" +DESC="Vendor specific SCSI and SES plugins" +VENDOR="Sun Microsystems, Inc." +HOTLINE="Please contact your local service provider" +EMAIL="" +CLASSES="none" +BASEDIR=/ +SUNW_PKGVERS="1.0" +SUNW_PKG_ALLZONES="true" +SUNW_PKG_HOLLOW="false" +SUNW_PKG_THISZONE="false" diff --git a/usr/src/pkgdefs/SUNWscsip/prototype_com b/usr/src/pkgdefs/SUNWscsip/prototype_com new file mode 100644 index 0000000000..3f0a45dbb3 --- /dev/null +++ b/usr/src/pkgdefs/SUNWscsip/prototype_com @@ -0,0 +1,41 @@ +# +# 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" +# + +# packaging files +i copyright +i depend +i pkginfo + +# SUNWscsip +d none usr 755 root sys +d none usr/lib 755 root bin +d none usr/lib/scsi 755 root bin +d none usr/lib/scsi/plugins 755 root bin +d none usr/lib/scsi/plugins/ses 755 root bin +d none usr/lib/scsi/plugins/ses/vendor 755 root bin +f none usr/lib/scsi/plugins/ses/vendor/SUN-StorageTek-J4400.so 755 root bin diff --git a/usr/src/pkgdefs/SUNWscsip/prototype_i386 b/usr/src/pkgdefs/SUNWscsip/prototype_i386 new file mode 100644 index 0000000000..2f5e6389a9 --- /dev/null +++ b/usr/src/pkgdefs/SUNWscsip/prototype_i386 @@ -0,0 +1,32 @@ +# +# 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" +# + +!include prototype_com + +d none usr/lib/scsi/plugins/ses/vendor/amd64 755 root bin +f none usr/lib/scsi/plugins/ses/vendor/amd64/SUN-StorageTek-J4400.so 755 root bin diff --git a/usr/src/pkgdefs/SUNWscsip/prototype_sparc b/usr/src/pkgdefs/SUNWscsip/prototype_sparc new file mode 100644 index 0000000000..62b0826274 --- /dev/null +++ b/usr/src/pkgdefs/SUNWscsip/prototype_sparc @@ -0,0 +1,32 @@ +# +# 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" +# + +!include prototype_com + +d none usr/lib/scsi/plugins/ses/vendor/sparcv9 755 root bin +f none usr/lib/scsi/plugins/ses/vendor/sparcv9/SUN-StorageTek-J4400.so 755 root bin diff --git a/usr/src/tools/scripts/check_rtime.pl b/usr/src/tools/scripts/check_rtime.pl index 85a9cbc376..6c0aa3824e 100644 --- a/usr/src/tools/scripts/check_rtime.pl +++ b/usr/src/tools/scripts/check_rtime.pl @@ -129,6 +129,7 @@ $SkipUndefDirs = qr{ /lib/mdb/ | # mdb modules have callbacks /lib/fm/fmd/plugins/ | # fmd modules have callbacks /lib/fm/fmd/schemes/ | # fmd schemes have callbacks + /lib/scsi/plugins/ | # scsi plugins have callbacks /i86pc/lib/mtst/ # mtst modules have callbacks }x; diff --git a/usr/src/uts/common/io/scsi/targets/ses.c b/usr/src/uts/common/io/scsi/targets/ses.c index 7cee4787bc..d12f291d44 100644 --- a/usr/src/uts/common/io/scsi/targets/ses.c +++ b/usr/src/uts/common/io/scsi/targets/ses.c @@ -21,7 +21,7 @@ /* * Enclosure Services Device target driver * - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -255,23 +255,23 @@ ses_probe(dev_info_t *dip) } /* SES_LOG(NULL, SES_CE_DEBUG1, "ses_probe: OK"); */ if (ddi_dev_is_sid(dip) == DDI_SUCCESS) { - return (DDI_PROBE_DONTCARE); + return (DDI_PROBE_DONTCARE); } devp = ddi_get_driver_private(dip); switch (err = scsi_probe(devp, SLEEP_FUNC)) { case SCSIPROBE_EXISTS: - if (is_enc_dev(NULL, devp->sd_inq, SUN_INQSIZE, &ep)) { - break; - } + if (is_enc_dev(NULL, devp->sd_inq, SUN_INQSIZE, &ep)) { + break; + } /* FALLTHROUGH */ case SCSIPROBE_NORESP: - scsi_unprobe(devp); - return (DDI_PROBE_FAILURE); + scsi_unprobe(devp); + return (DDI_PROBE_FAILURE); default: - SES_LOG(NULL, SES_CE_DEBUG9, - "ses_probe: probe error %d", err); - scsi_unprobe(devp); - return (DDI_PROBE_FAILURE); + SES_LOG(NULL, SES_CE_DEBUG9, + "ses_probe: probe error %d", err); + scsi_unprobe(devp); + return (DDI_PROBE_FAILURE); } scsi_unprobe(devp); return (DDI_PROBE_SUCCESS); @@ -428,7 +428,7 @@ ses_doattach(dev_info_t *dip) devp->sd_private = (opaque_t)ssc; ssc->ses_devp = devp; err = ddi_create_minor_node(dip, "0", S_IFCHR, inst, - DDI_NT_SCSI_ENCLOSURE, NULL); + DDI_NT_SCSI_ENCLOSURE, NULL); if (err == DDI_FAILURE) { ddi_remove_minor_node(dip, NULL); SES_LOG(ssc, CE_NOTE, "minor node creation failed"); @@ -914,6 +914,7 @@ ses_uscsi_cmd(ses_softc_t *ssc, Uscmd *Uc, int Uf) bcopy(uscmd->uscsi_cdb, &ssc->ses_srqcdb, (size_t)(uscmd->uscsi_cdblen)); } + ssc->ses_uscsicmd.uscsi_status = 0; bp = ssc->ses_sbufp; bp->av_back = (struct buf *)NULL; @@ -1022,7 +1023,7 @@ ses_start(struct buf *bp) case TRAN_BUSY: SES_LOG(ssc, SES_CE_DEBUG2, - "ses_start: TRANSPORT BUSY"); + "ses_start: TRANSPORT BUSY"); SES_ENABLE_RESTART(SES_RESTART_TIME, BP_PKT(bp)); return (0); /* break; */ @@ -1094,9 +1095,9 @@ ses_restart(void *arg) SES_LOG(ssc, SES_CE_DEBUG1, "RESTART %d TRANSPORT BUSY\n", ssc->ses_retries); if (ssc->ses_retries > SES_NO_RETRY) { - ssc->ses_retries -= SES_BUSY_RETRY; - SES_ENABLE_RESTART(SES_RESTART_TIME, pkt); - return; + ssc->ses_retries -= SES_BUSY_RETRY; + SES_ENABLE_RESTART(SES_RESTART_TIME, pkt); + return; } SET_BP_ERROR(bp, EBUSY); break; @@ -1138,11 +1139,12 @@ ses_callback(struct scsi_pkt *pkt) if (pkt->pkt_reason == CMD_CMPLT && !SCBP_C(pkt) && !(pkt->pkt_flags & FLAG_SENSING) && - !pkt->pkt_resid) { - scsi_destroy_pkt(pkt); - SET_BP_PKT(bp, NULL); - biodone(bp); - return; + !pkt->pkt_resid && + !(scmd->uscsi_flags & USCSI_READ)) { + scsi_destroy_pkt(pkt); + SET_BP_PKT(bp, NULL); + biodone(bp); + return; } @@ -1167,7 +1169,8 @@ CHECK_PKT: * reset the target. */ if (! (pkt->pkt_statistics & HBA_RESET)) { - (void) scsi_reset(&pkt->pkt_address, RESET_TARGET); + (void) scsi_reset(&pkt->pkt_address, + RESET_TARGET); } err = ETIMEDOUT; break; @@ -1201,7 +1204,7 @@ CHECK_PKT: */ if ((bp->b_bcount - pkt->pkt_resid) > 0) { SES_LOG(ssc, SES_CE_DEBUG6, - "ignoring overrun"); + "ignoring overrun"); pkt->pkt_reason = CMD_CMPLT; err = EOK; goto CHECK_PKT; @@ -1221,17 +1224,17 @@ CHECK_PKT: } if (pkt == ssc->ses_rqpkt) { SES_LOG(ssc, CE_WARN, fail_msg, - "Request Sense ", - scsi_rname(pkt->pkt_reason), - (ssc->ses_retries > 0)? - "retrying": "giving up"); + "Request Sense ", + scsi_rname(pkt->pkt_reason), + (ssc->ses_retries > 0)? + "retrying": "giving up"); pkt = (struct scsi_pkt *)bp->av_back; action = QUE_SENSE; } else { SES_LOG(ssc, CE_WARN, fail_msg, - "", scsi_rname(pkt->pkt_reason), - (ssc->ses_retries > 0)? - "retrying": "giving up"); + "", scsi_rname(pkt->pkt_reason), + (ssc->ses_retries > 0)? + "retrying": "giving up"); action = QUE_COMMAND; } /* Device exists, allow full error recovery. */ @@ -1256,33 +1259,35 @@ CHECK_PKT: case QUE_COMMAND_NOW: /* SES_LOG(ssc, SES_CE_DEBUG1, "retrying cmd now"); */ if (ssc->ses_retries > SES_NO_RETRY) { - ssc->ses_retries -= SES_CMD_RETRY; - scmd->uscsi_status = 0; - if (ssc->ses_arq) - bzero(pkt->pkt_scbp, sizeof (struct scsi_arq_status)); - - if (scsi_transport((struct scsi_pkt *)bp->av_back) - != TRAN_ACCEPT) { - SES_ENABLE_RESTART(SES_RESTART_TIME, - (struct scsi_pkt *)bp->av_back); - } - return; + ssc->ses_retries -= SES_CMD_RETRY; + scmd->uscsi_status = 0; + if (ssc->ses_arq) + bzero(pkt->pkt_scbp, + sizeof (struct scsi_arq_status)); + + if (scsi_transport((struct scsi_pkt *)bp->av_back) + != TRAN_ACCEPT) { + SES_ENABLE_RESTART(SES_RESTART_TIME, + (struct scsi_pkt *)bp->av_back); + } + return; } break; case QUE_COMMAND: SES_LOG(ssc, SES_CE_DEBUG1, "retrying cmd"); if (ssc->ses_retries > SES_NO_RETRY) { - ssc->ses_retries -= - (err == EBUSY)? SES_BUSY_RETRY: SES_CMD_RETRY; - scmd->uscsi_status = 0; - if (ssc->ses_arq) - bzero(pkt->pkt_scbp, sizeof (struct scsi_arq_status)); - - SES_ENABLE_RESTART( - (err == EBUSY)? SES_BUSY_TIME: SES_RESTART_TIME, - (struct scsi_pkt *)bp->av_back); - return; + ssc->ses_retries -= + (err == EBUSY)? SES_BUSY_RETRY: SES_CMD_RETRY; + scmd->uscsi_status = 0; + if (ssc->ses_arq) + bzero(pkt->pkt_scbp, + sizeof (struct scsi_arq_status)); + + SES_ENABLE_RESTART( + (err == EBUSY)? SES_BUSY_TIME: SES_RESTART_TIME, + (struct scsi_pkt *)bp->av_back); + return; } break; @@ -1298,7 +1303,7 @@ CHECK_PKT: SES_ENABLE_RESTART(SES_RESTART_TIME, ssc->ses_rqpkt); } - return; + return; } break; @@ -1307,9 +1312,9 @@ CHECK_PKT: pkt = (struct scsi_pkt *)bp->av_back; bp->b_resid = pkt->pkt_resid; if (bp->b_resid) { - SES_LOG(ssc, SES_CE_DEBUG6, - "transfer residue %ld(%ld)", - bp->b_bcount - bp->b_resid, bp->b_bcount); + SES_LOG(ssc, SES_CE_DEBUG6, + "transfer residue %ld(%ld)", + bp->b_bcount - bp->b_resid, bp->b_bcount); } break; } @@ -1367,7 +1372,7 @@ ses_decode_sense(struct scsi_pkt *pkt, int *err) */ } else if (ssc->ses_arq && pkt->pkt_state & STATE_ARQ_DONE) { struct scsi_arq_status *arq = - (struct scsi_arq_status *)(pkt->pkt_scbp); + (struct scsi_arq_status *)(pkt->pkt_scbp); int amt = min(sizeof (arq->sts_sensedata), SENSE_LENGTH); uchar_t *arq_status = (uchar_t *)&arq->sts_rqpkt_status; @@ -1473,9 +1478,9 @@ ses_decode_sense(struct scsi_pkt *pkt, int *err) break; } SES_LOG(ssc, SES_CE_DEBUG1, - "cdb[0]= 0x%x %s, key=0x%x, ASC/ASCQ=0x%x/0x%x", - scmd->uscsi_cdb[0], err_action, - sense->es_key, sense->es_add_code, sense->es_qual_code); + "cdb[0]= 0x%x %s, key=0x%x, ASC/ASCQ=0x%x/0x%x", + scmd->uscsi_cdb[0], err_action, + sense->es_key, sense->es_add_code, sense->es_qual_code); #ifdef not /* diff --git a/usr/src/uts/common/io/scsi/targets/sgen.c b/usr/src/uts/common/io/scsi/targets/sgen.c index 17d60a7cd3..e4d9640aa3 100644 --- a/usr/src/uts/common/io/scsi/targets/sgen.c +++ b/usr/src/uts/common/io/scsi/targets/sgen.c @@ -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. */ @@ -133,7 +133,7 @@ static void sgen_cleanup_binddb(); */ static int sgen_uscsi_cmd(dev_t, struct uscsi_cmd *, int); static int sgen_start(struct buf *); -static void sgen_hold_cmdbuf(sgen_state_t *); +static int sgen_hold_cmdbuf(sgen_state_t *); static void sgen_rele_cmdbuf(sgen_state_t *); static int sgen_make_uscsi_cmd(sgen_state_t *, struct buf *); static void sgen_restart(void *); @@ -772,7 +772,7 @@ sgen_setup_sense(sgen_state_t *sg_state) /* * sgen_create_errstats() - * create named kstats for tracking occurence of errors. + * create named kstats for tracking occurrence of errors. */ static void sgen_create_errstats(sgen_state_t *sg_state, int instance) @@ -1060,19 +1060,30 @@ sgen_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p) mutex_enter(&sg_state->sgen_mutex); - if (SGEN_IS_OPEN(sg_state)) { + /* + * Don't allow new opens of a suspended device until the last close has + * happened. This is rather simplistic, but keeps the implementation + * straightforward. + */ + if (SGEN_IS_SUSP(sg_state)) { + mutex_exit(&sg_state->sgen_mutex); + return (EIO); + } + + /* + * Enforce exclusive access. + */ + if (SGEN_IS_EXCL(sg_state) || + (SGEN_IS_OPEN(sg_state) && (flag & FEXCL))) { mutex_exit(&sg_state->sgen_mutex); return (EBUSY); } + if (flag & FEXCL) + SGEN_SET_EXCL(sg_state); + SGEN_SET_OPEN(sg_state); - /* - * At this point, sgen cannot have the suspended bit set, - * since each target is exclusive-access; when the previous - * close occurred, it cleared the flag. - */ - ASSERT(!SGEN_IS_SUSP(sg_state)); mutex_exit(&sg_state->sgen_mutex); return (0); @@ -1099,6 +1110,7 @@ sgen_close(dev_t dev, int flag, int otyp, cred_t *cred_p) mutex_enter(&sg_state->sgen_mutex); SGEN_CLR_OPEN(sg_state); + SGEN_CLR_EXCL(sg_state); SGEN_CLR_SUSP(sg_state); /* closing clears the 'I was suspended' bit */ mutex_exit(&sg_state->sgen_mutex); @@ -1186,7 +1198,6 @@ sgen_uscsi_cmd(dev_t dev, struct uscsi_cmd *ucmd, int flag) struct buf *bp; sgen_state_t *sg_state; enum uio_seg uioseg; - int cmdbufhold = 0; int instance; int flags; int err; @@ -1199,9 +1210,19 @@ sgen_uscsi_cmd(dev_t dev, struct uscsi_cmd *ucmd, int flag) sgen_log(sg_state, SGEN_DIAG2, "in sgen_uscsi_cmd(): instance = %d", instance); + /* + * At this point, we start affecting state relevant to the target, + * so access needs to be serialized. + */ + if (sgen_hold_cmdbuf(sg_state) != 0) { + sgen_log(sg_state, SGEN_DIAG1, "sgen_uscsi_cmd: interrupted"); + return (EINTR); + } + err = scsi_uscsi_alloc_and_copyin((intptr_t)ucmd, flag, &sg_state->sgen_scsiaddr, &uscmd); if (err != 0) { + sgen_rele_cmdbuf(sg_state); sgen_log(sg_state, SGEN_DIAG1, "sgen_uscsi_cmd: " "scsi_uscsi_alloc_and_copyin failed\n"); return (err); @@ -1218,13 +1239,6 @@ sgen_uscsi_cmd(dev_t dev, struct uscsi_cmd *ucmd, int flag) uscmd->uscsi_flags = flags; } - /* - * At this point, we start affecting state relevant to the target, - * so access needs to be serialized. - */ - sgen_hold_cmdbuf(sg_state); /* lock command buf for this target */ - cmdbufhold = 1; - if (uscmd->uscsi_cdb != NULL) { sgen_dump_cdb(sg_state, "sgen_uscsi_cmd: ", (union scsi_cdb *)uscmd->uscsi_cdb, uscmd->uscsi_cdblen); @@ -1268,9 +1282,7 @@ sgen_uscsi_cmd(dev_t dev, struct uscsi_cmd *ucmd, int flag) /* * After this point, we can't touch per-target state. */ - if (cmdbufhold) { - sgen_rele_cmdbuf(sg_state); - } + sgen_rele_cmdbuf(sg_state); sgen_log(sg_state, SGEN_DIAG2, "done sgen_uscsi_cmd()"); @@ -1279,16 +1291,23 @@ sgen_uscsi_cmd(dev_t dev, struct uscsi_cmd *ucmd, int flag) /* * sgen_hold_cmdbuf() - * Aquire a lock on the command buffer for the given target. + * Acquire a lock on the command buffer for the given target. Returns + * non-zero if interrupted. */ -static void +static int sgen_hold_cmdbuf(sgen_state_t *sg_state) { mutex_enter(&sg_state->sgen_mutex); - while (SGEN_IS_BUSY(sg_state)) - cv_wait(&sg_state->sgen_cmdbuf_cv, &sg_state->sgen_mutex); + while (SGEN_IS_BUSY(sg_state)) { + if (!cv_wait_sig(&sg_state->sgen_cmdbuf_cv, + &sg_state->sgen_mutex)) { + mutex_exit(&sg_state->sgen_mutex); + return (-1); + } + } SGEN_SET_BUSY(sg_state); mutex_exit(&sg_state->sgen_mutex); + return (0); } /* diff --git a/usr/src/uts/common/sys/Makefile b/usr/src/uts/common/sys/Makefile index 41f8b5c313..9ec961664f 100644 --- a/usr/src/uts/common/sys/Makefile +++ b/usr/src/uts/common/sys/Makefile @@ -843,6 +843,7 @@ SCSIIMPLHDRS= \ status.h \ transport.h \ scsi_reset_notify.h \ + spc3_types.h \ types.h \ uscsi.h \ usmp.h diff --git a/usr/src/uts/common/sys/scsi/impl/commands.h b/usr/src/uts/common/sys/scsi/impl/commands.h index 227e2da724..0001a80ebb 100644 --- a/usr/src/uts/common/sys/scsi/impl/commands.h +++ b/usr/src/uts/common/sys/scsi/impl/commands.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -282,50 +282,109 @@ union scsi_cdb { /* scsi command description block */ #define SCSI_READ16(Sr16_Addr) \ (((uint16_t)*((uint8_t *)(Sr16_Addr)) << 8) | \ - ((uint16_t)*((uint8_t *)((Sr16_Addr)+1)))) + ((uint16_t)*((uint8_t *)(Sr16_Addr)+1))) + +#define SCSI_READ24(Sr32_Addr) \ + (((uint32_t)*((uint8_t *)(Sr32_Addr)) << 16) | \ + ((uint32_t)*((uint8_t *)(Sr32_Addr)+1) << 8) | \ + ((uint32_t)*((uint8_t *)(Sr32_Addr)+2))) #define SCSI_READ32(Sr32_Addr) \ (((uint32_t)*((uint8_t *)(Sr32_Addr)) << 24) | \ - ((uint32_t)*((uint8_t *)((Sr32_Addr)+1)) << 16) | \ - ((uint32_t)*((uint8_t *)((Sr32_Addr)+2)) << 8) | \ - ((uint32_t)*((uint8_t *)((Sr32_Addr)+3)))) + ((uint32_t)*((uint8_t *)(Sr32_Addr)+1) << 16) | \ + ((uint32_t)*((uint8_t *)(Sr32_Addr)+2) << 8) | \ + ((uint32_t)*((uint8_t *)(Sr32_Addr)+3))) + +#define SCSI_READ40(Sr64_Addr) \ + (((uint64_t)*((uint8_t *)(Sr64_Addr)) << 32) | \ + ((uint64_t)*((uint8_t *)(Sr64_Addr)+1) << 24) | \ + ((uint64_t)*((uint8_t *)(Sr64_Addr)+2) << 16) | \ + ((uint64_t)*((uint8_t *)(Sr64_Addr)+3) << 8) | \ + ((uint64_t)*((uint8_t *)(Sr64_Addr)+4))) + +#define SCSI_READ48(Sr64_Addr) \ + (((uint64_t)*((uint8_t *)(Sr64_Addr)) << 40) | \ + ((uint64_t)*((uint8_t *)(Sr64_Addr)+1) << 32) | \ + ((uint64_t)*((uint8_t *)(Sr64_Addr)+2) << 24) | \ + ((uint64_t)*((uint8_t *)(Sr64_Addr)+3) << 16) | \ + ((uint64_t)*((uint8_t *)(Sr64_Addr)+4) << 8) | \ + ((uint64_t)*((uint8_t *)(Sr64_Addr)+5))) #define SCSI_READ64(Sr64_Addr) \ (((uint64_t)*((uint8_t *)(Sr64_Addr)) << 56) | \ - ((uint64_t)*((uint8_t *)((Sr64_Addr)+1)) << 48) | \ - ((uint64_t)*((uint8_t *)((Sr64_Addr)+2)) << 40) | \ - ((uint64_t)*((uint8_t *)((Sr64_Addr)+3)) << 32) | \ - ((uint64_t)*((uint8_t *)((Sr64_Addr)+4)) << 24) | \ - ((uint64_t)*((uint8_t *)((Sr64_Addr)+5)) << 16) | \ - ((uint64_t)*((uint8_t *)((Sr64_Addr)+6)) << 8) | \ - ((uint64_t)*((uint8_t *)((Sr64_Addr)+7)))) + ((uint64_t)*((uint8_t *)(Sr64_Addr)+1) << 48) | \ + ((uint64_t)*((uint8_t *)(Sr64_Addr)+2) << 40) | \ + ((uint64_t)*((uint8_t *)(Sr64_Addr)+3) << 32) | \ + ((uint64_t)*((uint8_t *)(Sr64_Addr)+4) << 24) | \ + ((uint64_t)*((uint8_t *)(Sr64_Addr)+5) << 16) | \ + ((uint64_t)*((uint8_t *)(Sr64_Addr)+6) << 8) | \ + ((uint64_t)*((uint8_t *)(Sr64_Addr)+7))) #define SCSI_WRITE16(Sr16_Addr, Sr16_Val) \ - *((uint8_t *)(Sr16_Addr)) = (((uint16_t)(Sr16_Val) >> 8) & 0xff); \ - *(((uint8_t *)(Sr16_Addr))+1) = ((uint16_t)(Sr16_Val) & 0xff); + *((uint8_t *)(Sr16_Addr)) = (((uint16_t)(Sr16_Val) >> 8) & 0xff), \ + *((uint8_t *)(Sr16_Addr)+1) = ((uint16_t)(Sr16_Val) & 0xff) + +#define SCSI_WRITE24(Sr24_Addr, Sr24_Val) \ + SCSI_WRITE16((Sr24_Addr), ((Sr24_Val) & 0xffff00) >> 8), \ + *((uint8_t *)(Sr24_Addr)+2) = ((uint8_t)((Sr24_Val) & 0xff)) #define SCSI_WRITE32(Sr32_Addr, Sr32_Val) \ - *(uint8_t *)(Sr32_Addr) = (((uint32_t)(Sr32_Val) >> 24) & 0xff); \ - *(((uint8_t *)(Sr32_Addr))+1) = \ - (((uint32_t)(Sr32_Val) >> 16) & 0xff); \ - *(((uint8_t *)(Sr32_Addr))+2) = (((uint32_t)(Sr32_Val) >> 8) & 0xff); \ - *(((uint8_t *)(Sr32_Addr))+3) = (((uint32_t)(Sr32_Val)) & 0xff); + *(uint8_t *)(Sr32_Addr) = (((uint32_t)(Sr32_Val) >> 24) & 0xff), \ + *((uint8_t *)(Sr32_Addr)+1) = \ + (((uint32_t)(Sr32_Val) >> 16) & 0xff), \ + *((uint8_t *)(Sr32_Addr)+2) = (((uint32_t)(Sr32_Val) >> 8) & 0xff), \ + *((uint8_t *)(Sr32_Addr)+3) = (((uint32_t)(Sr32_Val)) & 0xff) + +#define SCSI_WRITE40(Sr40_Addr, Sr40_Val) \ + SCSI_WRITE32((Sr40_Addr), ((Sr40_Val) & 0xffffffff00ULL) >> 8), \ + *((uint8_t *)(Sr40_Addr)+4) = ((uint8_t)(Sr40_Val) & 0xff) + +#define SCSI_WRITE48(Sr48_Addr, Sr40_Val) \ + SCSI_WRITE32((Sr48_Addr), ((Sr48_Val) & 0xffffffff0000ULL) >> 16), \ + SCSI_WRITE16((uint8_t *)(Sr48_Addr)+4, (Sr40_Val) & 0xffff) #define SCSI_WRITE64(Sr64_Addr, Sr64_Val) \ - *(uint8_t *)(Sr64_Addr) = (((uint64_t)(Sr64_Val) >> 56) & 0xff); \ - *(((uint8_t *)(Sr64_Addr))+1) = \ - (((uint64_t)(Sr64_Val) >> 48) & 0xff); \ - *(((uint8_t *)(Sr64_Addr))+2) = \ - (((uint64_t)(Sr64_Val) >> 40) & 0xff); \ - *(((uint8_t *)(Sr64_Addr))+3) = \ - (((uint64_t)(Sr64_Val) >> 32) & 0xff); \ - *(((uint8_t *)(Sr64_Addr))+4) = \ - (((uint64_t)(Sr64_Val) >> 24) & 0xff); \ - *(((uint8_t *)(Sr64_Addr))+5) = \ - (((uint64_t)(Sr64_Val) >> 16) & 0xff); \ - *(((uint8_t *)(Sr64_Addr))+6) = \ - (((uint64_t)(Sr64_Val) >> 8) & 0xff); \ - *(((uint8_t *)(Sr64_Addr))+7) = (((uint64_t)(Sr64_Val)) & 0xff); + *(uint8_t *)(Sr64_Addr) = (((uint64_t)(Sr64_Val) >> 56) & 0xff), \ + *((uint8_t *)(Sr64_Addr)+1) = \ + (((uint64_t)(Sr64_Val) >> 48) & 0xff), \ + *((uint8_t *)(Sr64_Addr)+2) = \ + (((uint64_t)(Sr64_Val) >> 40) & 0xff), \ + *((uint8_t *)(Sr64_Addr)+3) = \ + (((uint64_t)(Sr64_Val) >> 32) & 0xff), \ + *((uint8_t *)(Sr64_Addr)+4) = \ + (((uint64_t)(Sr64_Val) >> 24) & 0xff), \ + *((uint8_t *)(Sr64_Addr)+5) = \ + (((uint64_t)(Sr64_Val) >> 16) & 0xff), \ + *((uint8_t *)(Sr64_Addr)+6) = \ + (((uint64_t)(Sr64_Val) >> 8) & 0xff), \ + *((uint8_t *)(Sr64_Addr)+7) = (((uint64_t)(Sr64_Val)) & 0xff) + +/* + * These macros deal with unaligned data that crosses a byte boundary. + */ +#define SCSI_MK8(ms, ls) \ + (((uint8_t)(ms) << 4) | (uint8_t)ls) + +#define SCSI_MK12_4_8(ms, ls) \ + (((uint16_t)(ms) << 8) | (uint16_t)(ls)) +#define SCSI_MK12_8_4(ms, ls) \ + (((uint16_t)(ms) << 4) | (uint16_t)(ls)) + +#define SCSI_MK16_4_8_4(hi, mid, lo) \ + (((uint16_t)(hi) << 12) | ((uint16_t)(mid) << 4) | (uint16_t)(lo)) + +#define SCSI_MK20_4_16(ms, ls) \ + (((uint32_t)(ms) << 16) | ((uint32_t)(ls))) +#define SCSI_MK20_16_4(ms, ls) \ + (((uint32_t)(ms) << 4) | ((uint32_t)(ls))) + +#define SCSI_MK24_4_16_4(hi, mid, lo) \ + (((uint32_t)(hi) << 20) | ((uint32_t)(mid) << 4) | (uint32_t)(lo)) + +#define SCSI_MK36_4_32(ms, ls) \ + (((uint64_t)(ms) << 32) | (uint64_t)(ls)) +#define SCSI_MK36_32_4(ms, ls) \ + (((uint64_t)(ms) << 4) | (uint64_t)(ls)) /* * defines for getting/setting fields within the various command groups diff --git a/usr/src/uts/common/sys/scsi/impl/spc3_types.h b/usr/src/uts/common/sys/scsi/impl/spc3_types.h new file mode 100644 index 0000000000..f8ad106d23 --- /dev/null +++ b/usr/src/uts/common/sys/scsi/impl/spc3_types.h @@ -0,0 +1,1045 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SPC3_TYPES_H +#define _SPC3_TYPES_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> +#include <sys/cdio.h> +#include <sys/sysmacros.h> +#include <sys/scsi/generic/commands.h> +#include <sys/scsi/impl/commands.h> + +typedef enum spc3_cmd { + SPC3_CMD_TEST_UNIT_READY = SCMD_TEST_UNIT_READY, + SPC3_CMD_REZERO_UNIT = SCMD_REZERO_UNIT, + SPC3_CMD_REWIND = SCMD_REWIND, + SPC3_CMD_VENDOR_2 = 2, + SPC3_CMD_REQUEST_SENSE = SCMD_REQUEST_SENSE, + SPC3_CMD_FORMAT_UNIT = SCMD_FORMAT, + SPC3_CMD_FORMAT_MEDIUM = SCMD_FORMAT, + SPC3_CMD_FORMAT = SCMD_FORMAT, + SPC3_CMD_READ_BLOCK_LIMITS = SCMD_READ_BLKLIM, + SPC3_CMD_VENDOR_6 = 6, + SPC3_CMD_REASSIGN_BLOCKS = SCMD_REASSIGN_BLOCK, + SPC3_CMD_INITIALIZE_ELEMENT_STATUS = SCMD_REASSIGN_BLOCK, + SPC3_CMD_READ = SCMD_READ, + SPC3_CMD_READ6 = SCMD_READ, + SPC3_CMD_RECEIVE = SCMD_RECEIVE, + SPC3_CMD_GET_MESSAGE = SCMD_READ, + SPC3_CMD_VENDOR_9 = 9, + SPC3_CMD_WRITE = SCMD_WRITE, + SPC3_CMD_WRITE6 = SCMD_WRITE, + SPC3_CMD_SEND = SCMD_SEND, + SPC3_CMD_SEND6 = SCMD_SEND, + SPC3_CMD_SEND_MESSAGE = SCMD_SEND, + SPC3_CMD_PRINT = SCMD_PRINT, + SPC3_CMD_SEEK = SCMD_SEEK, + SPC3_CMD_SEEK6 = SCMD_SEEK, + SPC3_CMD_SET_CAPACITY = SCMD_SEEK, + SPC3_CMD_SLEW_AND_PRINT = SCMD_SLEW_PRINT, + SPC3_CMD_VENDOR_C = 0xc, + SPC3_CMD_VENDOR_D = 0xd, + SPC3_CMD_VENDOR_E = 0xe, + SPC3_CMD_READ_REVERSE = SCMD_READ_REVERSE, + SPC3_CMD_READ_REVERSE6 = SCMD_READ_REVERSE, + SPC3_CMD_WRITE_FILEMARKS = SCMD_WRITE_FILE_MARK, + SPC3_CMD_WRITE_FILEMARKS6 = SCMD_WRITE_FILE_MARK, + SPC3_CMD_SYNCHRONIZE_BUFFER = SCMD_FLUSH_PRINT_BUF, + SPC3_CMD_SPACE = SCMD_SPACE, + SPC3_CMD_SPACE6 = SCMD_SPACE, + SPC3_CMD_INQUIRY = SCMD_INQUIRY, + SPC3_CMD_VERIFY = SCMD_VERIFY_G0, + SPC3_CMD_VERIFY6 = SCMD_VERIFY_G0, + SPC3_CMD_RECOVER_BUFFERED_DATA = SCMD_RECOVER_BUF, + SPC3_CMD_MODE_SELECT = SCMD_MODE_SELECT, + SPC3_CMD_MODE_SELECT6 = SCMD_MODE_SELECT, + SPC3_CMD_RESERVE = SCMD_RESERVE, + SPC3_CMD_RESERVE6 = SCMD_RESERVE, + SPC3_CMD_RESERVE_ELEMENT = SCMD_RESERVE, + SPC3_CMD_RESERVE_ELEMENT6 = SCMD_RESERVE, + SPC3_CMD_RELEASE = SCMD_RELEASE, + SPC3_CMD_RELEASE6 = SCMD_RELEASE, + SPC3_CMD_RELEASE_ELEMENT = SCMD_RELEASE, + SPC3_CMD_RELEASE_ELEMENT6 = SCMD_RELEASE, + SPC3_CMD_COPY = SCMD_COPY, + SPC3_CMD_ERASE = SCMD_ERASE, + SPC3_CMD_ERASE6 = SCMD_ERASE, + SPC3_CMD_MODE_SENSE = SCMD_MODE_SENSE, + SPC3_CMD_MODE_SENSE6 = SCMD_MODE_SENSE, + SPC3_CMD_START_STOP_UNIT = SCMD_START_STOP, + SPC3_CMD_LOAD_UNLOAD = SCMD_LOAD, + SPC3_CMD_SCAN = SCMD_START_STOP, + SPC3_CMD_STOP_PRINT = SCMD_STOP_PRINT, + SPC3_CMD_RECEIVE_DIAGNOSTIC_RESULTS = SCMD_GDIAG, + SPC3_CMD_SEND_DIAGNOSTIC = SCMD_SDIAG, + SPC3_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL = SCMD_DOORLOCK, + SPC3_CMD_VENDOR_20 = 0x20, + SPC3_CMD_VENDOR_21 = 0x21, + SPC3_CMD_VENDOR_22 = 0x22, + SPC3_CMD_VENDOR_23 = 0x23, + SPC3_CMD_SET_WINDOW = 0x24, + SPC3_CMD_READ_CAPACITY = SCMD_READ_CAPACITY, + SPC3_CMD_READ_CAPACITY10 = SCMD_READ_CAPACITY, + SPC3_CMD_READ_CARD_CAPACITY = SCMD_READ_CAPACITY, + SPC3_CMD_GET_WINDOW = SCMD_READ_CAPACITY, + SPC3_CMD_VENDOR_26 = 0x26, + SPC3_CMD_VENDOR_27 = 0x27, + SPC3_CMD_READ10 = SCMD_READ_G1, + SPC3_CMD_GET_MESSAGE10 = SCMD_READ_G1, + SPC3_CMD_READ_GENERATION = 0x29, + SPC3_CMD_WRITE10 = SCMD_WRITE_G1, + SPC3_CMD_SEND10 = SCMD_WRITE_G1, + SPC3_CMD_SEND_MESSAGE10 = SCMD_WRITE_G1, + SPC3_CMD_SEEK10 = SCMD_SEEK_G1, + SPC3_CMD_LOCATE = SCMD_LOCATE, + SPC3_CMD_LOCATE10 = SCMD_LOCATE, + SPC3_CMD_POSITION_TO_ELEMENT = SCMD_SEEK_G1, + SPC3_CMD_ERASE10 = 0x2c, + SPC3_CMD_READ_UPDATED_BLOCK = 0x2d, + SPC3_CMD_WRITE_AND_VERIFY = SCMD_WRITE_VERIFY, + SPC3_CMD_WRITE_AND_VERIFY10 = SCMD_WRITE_VERIFY, + SPC3_CMD_VERIFY10 = SCMD_VERIFY, + SPC3_CMD_SEARCH_DATA_HIGH = SCMD_SEARCH_HIGH, + SPC3_CMD_SEARCH_DATA_HIGH10 = SCMD_SEARCH_HIGH, + SPC3_CMD_SEARCH_DATA_EQUAL = SCMD_SEARCH_EQUAL, + SPC3_CMD_SEARCH_DATA_EQUAL10 = SCMD_SEARCH_EQUAL, + SPC3_CMD_OBJECT_POSITION = SCMD_SEARCH_EQUAL, + SPC3_CMD_SEARCH_DATA_LOW = SCMD_SEARCH_LOW, + SPC3_CMD_SEARCH_DATA_LOW10 = SCMD_SEARCH_LOW, + SPC3_CMD_SET_LIMITS = SCMD_SET_LIMITS, + SPC3_CMD_SET_LIMITS10 = SCMD_SET_LIMITS, + SPC3_CMD_PREFETCH = SCMD_READ_POSITION, + SPC3_CMD_PREFETCH10 = SCMD_READ_POSITION, + SPC3_CMD_READ_POSITION = SCMD_READ_POSITION, + SPC3_CMD_GET_DATA_BUFFER_STATUS = SCMD_READ_POSITION, + SPC3_CMD_SYNCHRONIZE_CACHE = SCMD_SYNCHRONIZE_CACHE, + SPC3_CMD_SYNCHRONIZE_CACHE10 = SCMD_SYNCHRONIZE_CACHE, + SPC3_CMD_LOCK_UNLOCK_CACHE = 0x36, + SPC3_CMD_READ_DEFECT_DATA = SCMD_READ_DEFECT_LIST, + SPC3_CMD_READ_DEFECT_DATA10 = SCMD_READ_DEFECT_LIST, + SPC3_CMD_INITIALIZE_ELEMENT_STATUS_WITH_RANGE = SCMD_READ_DEFECT_LIST, + SPC3_CMD_MEDIUM_SCAN = 0x38, + SPC3_CMD_COMPARE = SCMD_COMPARE, + SPC3_CMD_COPY_AND_VERIFY = SCMD_COPY_VERIFY, + SPC3_CMD_WRITE_BUFFER = SCMD_WRITE_BUFFER, + SPC3_CMD_READ_BUFFER = SCMD_READ_BUFFER, + SPC3_CMD_UPDATE_BLOCK = 0x3d, + SPC3_CMD_READ_LONG = SCMD_READ_LONG, + SPC3_CMD_READ_LONG10 = SCMD_READ_LONG, + SPC3_CMD_WRITE_LONG = SCMD_WRITE_LONG, + SPC3_CMD_WRITE_LONG10 = SCMD_WRITE_LONG, + SPC3_CMD_CHANGE_DEFINITION = 0x40, + SPC3_CMD_WRITE_SAME = 0x41, + SPC3_CMD_WRITE_SAME10 = 0x41, + SPC3_CMD_READ_SUBCHANNEL = SCMD_READ_SUBCHANNEL, + SPC3_CMD_READ_TOC = SCMD_READ_TOC, + SPC3_CMD_REPORT_DENSITY_SUPPORT = SCMD_REPORT_DENSITIES, + SPC3_CMD_READ_HEADER = SCMD_READ_HEADER, + SPC3_CMD_PLAY_AUDIO = SCMD_PLAYAUDIO10, + SPC3_CMD_PLAY_AUDIO10 = SCMD_PLAYAUDIO10, + SPC3_CMD_GET_CONFIGURATION = SCMD_GET_CONFIGURATION, + SPC3_CMD_PLAY_AUDIO_MSF = SCMD_PLAYAUDIO_MSF, + /* Not defined by SPC-3 */ + SPC3_CMD_PLAY_AUDIO_TI = SCMD_PLAYAUDIO_TI, + SPC3_CMD_PLAY_TRACK_REL = SCMD_PLAYTRACK_REL10, + SPC3_CMD_PLAY_TRACK_REL10 = SCMD_PLAYTRACK_REL10, + SPC3_CMD_GET_EVENT_STATUS_NOTIFICATION = 0x4a, + SPC3_CMD_PAUSE_RESUME = SCMD_PAUSE_RESUME, + SPC3_CMD_LOG_SELECT = SCMD_LOG_SELECT_G1, + SPC3_CMD_LOG_SENSE = SCMD_LOG_SENSE_G1, + SPC3_CMD_STOP_PLAY_SCAN = 0x4e, + SPC3_CMD_XDWRITE = 0x50, + SPC3_CMD_XDWRITE10 = 0x50, + SPC3_CMD_XPWRITE = 0x51, + SPC3_CMD_XPWRITE10 = 0x51, + SPC3_CMD_READ_DISC_INFORMATION = 0x51, + SPC3_CMD_XDREAD = 0x52, + SPC3_CMD_XDREAD10 = 0x52, + SPC3_CMD_READ_TRACK_INFORMATION = 0x52, + SPC3_CMD_RESERVE_TRACK = 0x53, + SPC3_CMD_SEND_OPC_INFORMATION = 0x54, + SPC3_CMD_MODE_SELECT10 = SCMD_MODE_SELECT_G1, + SPC3_CMD_RESERVE10 = SCMD_RESERVE_G1, + SPC3_CMD_RESERVE_ELEMENT10 = SCMD_RESERVE_G1, + SPC3_CMD_RELEASE10 = SCMD_RELEASE_G1, + SPC3_CMD_RELEASE_ELEMENT10 = SCMD_RELEASE_G1, + SPC3_CMD_REPAIR_TRACK = 0x58, + SPC3_CMD_MODE_SENSE10 = SCMD_MODE_SENSE_G1, + SPC3_CMD_CLOSE_TRACK_SESSION = 0x5b, + SPC3_CMD_READ_BUFFER_CAPACITY = 0x5c, + SPC3_CMD_SEND_CUE_SHEET = 0x5d, + SPC3_CMD_PERSISTENT_RESERVE_IN = SCMD_PERSISTENT_RESERVE_IN, + SPC3_CMD_PERSISTENT_RESERVE_OUT = SCMD_PERSISTENT_RESERVE_OUT, + SPC3_CMD_VARIABLE_LENGTH = SCMD_VAR_LEN, + SPC3_CMD_XDWRITE_EXTENDED = SCMD_WRITE_FILE_MARK_G4, + SPC3_CMD_XDWRITE_EXTENDED16 = SCMD_WRITE_FILE_MARK_G4, + SPC3_CMD_WRITE_FILEMARKS16 = SCMD_WRITE_FILE_MARK_G4, + SPC3_CMD_REBUILD = SCMD_READ_REVERSE_G4, + SPC3_CMD_REBUILD16 = SCMD_READ_REVERSE_G4, + SPC3_CMD_READ_REVERSE16 = SCMD_READ_REVERSE_G4, + SPC3_CMD_REGENERATE = 0x82, + SPC3_CMD_REGENERATE16 = 0x82, + SPC3_CMD_EXTENDED_COPY = SCMD_EXTENDED_COPY, + SPC3_CMD_RECEIVE_COPY_RESULTS = 0x84, + SPC3_CMD_ATA_COMMAND_PASS_THROUGH = 0x85, + SPC3_CMD_ATA_COMMAND_PASS_THROUGH16 = 0x85, + SPC3_CMD_ACCESS_CONTROL_IN = 0x86, + SPC3_CMD_ACCESS_CONTROL_OUT = 0x87, + SPC3_CMD_READ16 = SCMD_READ_G4, + SPC3_CMD_WRITE16 = SCMD_WRITE_G4, + SPC3_CMD_READ_ATTRIBUTE = SCMD_READ_ATTRIBUTE, + SPC3_CMD_WRITE_ATTRIBUTE = SCMD_WRITE_ATTRIBUTE, + SPC3_CMD_WRITE_AND_VERIFY16 = 0x8e, + SPC3_CMD_VERIFY16 = SCMD_VERIFY_G4, + SPC3_CMD_PREFETCH16 = 0x90, + SPC3_CMD_SYNCHRONIZE_CACHE16 = SCMD_SPACE_G4, + SPC3_CMD_SPACE16 = SCMD_SPACE_G4, + SPC3_CMD_LOCK_UNLOCK_CACHE16 = 0x92, + SPC3_CMD_LOCATE16 = 0x92, + SPC3_CMD_WRITE_SAME16 = 0x93, + SPC3_CMD_ERASE16 = 0x93, + SPC3_CMD_SERVICE_ACTION_IN = SCMD_SVC_ACTION_IN_G4, + SPC3_CMD_SERVICE_ACTION_IN16 = SCMD_SVC_ACTION_IN_G4, + SPC3_CMD_SERVICE_ACTION_OUT = SCMD_SVC_ACTION_OUT_G4, + SPC3_CMD_SERVICE_ACTION_OUT16 = SCMD_SVC_ACTION_OUT_G4, + SPC3_CMD_REPORT_LUNS = SCMD_REPORT_LUNS, + SPC3_CMD_BLANK = 0xa1, + SPC3_CMD_ATA_COMMAND_PASS_THROUGH12 = 0xa1, + SPC3_CMD_SECURITY_PROTO_IN = SCMD_SECURITY_PROTO_IN, + SPC3_CMD_MAINTENANCE_IN = SCMD_MAINTENANCE_IN, + SPC3_CMD_SEND_KEY = SCMD_MAINTENANCE_IN, + SPC3_CMD_MAINTENANCE_OUT = SCMD_MAINTENANCE_OUT, + SPC3_CMD_REPORT_KEY = SCMD_MAINTENANCE_OUT, + SPC3_CMD_MOVE_MEDIUM = SCMD_PLAYAUDIO12, + SPC3_CMD_PLAY_AUDIO12 = SCMD_PLAYAUDIO12, + SPC3_CMD_EXCHANGE_MEDIUM = 0xa6, + SPC3_CMD_LOAD_UNLOAD_CD = 0xa6, + SPC3_CMD_MOVE_MEDIUM_ATTACHED = 0xa7, + SPC3_CMD_SET_READ_AHEAD = 0xa7, + SPC3_CMD_READ12 = SCMD_READ_G5, + SPC3_CMD_GET_MESSAGE12 = SCMD_READ_G5, + SPC3_CMD_SERVICE_ACTION_OUT12 = SCMD_SVC_ACTION_OUT_G5, + SPC3_CMD_PLAY_TRACK_REL12 = SCMD_PLAYTRACK_REL12, + SPC3_CMD_WRITE12 = SCMD_WRITE_G5, + SPC3_CMD_SEND_MESSAGE12 = SCMD_WRITE_G5, + SPC3_CMD_SERVICE_ACTION_IN12 = SCMD_SVC_ACTION_IN_G5, + SPC3_CMD_ERASE12 = SCMD_GET_PERFORMANCE, + SPC3_CMD_GET_PERFORMANCE = SCMD_GET_PERFORMANCE, + SPC3_CMD_READ_DVD_STRUCTURE = 0xad, + SPC3_CMD_WRITE_AND_VERIFY12 = 0xae, + SPC3_CMD_VERIFY12 = SCMD_VERIFY_G5, + SPC3_CMD_SEARCH_DATA_HIGH12 = 0xb0, + SPC3_CMD_SEARCH_DATA_EQUAL12 = 0xb1, + SPC3_CMD_SEARCH_DATA_LOW12 = 0xb2, + SPC3_CMD_SET_LIMITS12 = 0xb3, + SPC3_CMD_READ_ELEMENT_STATUS_ATTACHED = 0xb4, + SPC3_CMD_REQUEST_VOLUME_ELEMENT_ADDRESS = 0xb5, + SPC3_CMD_SEND_VOLUME_TAG = 0xb6, + SPC3_CMD_SET_STREAMING = 0xb6, + SPC3_CMD_READ_DEFECT_DATA12 = 0xb7, + SPC3_CMD_READ_ELEMENT_STATUS = 0xb8, + SPC3_CMD_READ_CD_MSF = 0xb9, + SPC3_CMD_REDUNDANCY_GROUP_IN = 0xba, + SPC3_CMD_SCAN12 = 0xba, + SPC3_CMD_REDUNDANCY_GROUP_OUT = SCMD_SET_CDROM_SPEED, + SPC3_CMD_SET_CD_SPEED = SCMD_SET_CDROM_SPEED, + SPC3_CMD_SPARE_IN = 0xbc, + SPC3_CMD_SPARE_OUT = 0xbd, + SPC3_CMD_MECHANISM_STATUS = 0xbd, + SPC3_CMD_VOLUME_SET_IN = SCMD_READ_CD, + SPC3_CMD_READ_CD = SCMD_READ_CD, + SPC3_CMD_VOLUME_SET_OUT = 0xbf, + SPC3_CMD_SEND_DVD_STRUCTURE = 0xbf +} spc3_cmd_t; + +typedef enum spc3_dev_type { + SPC3_DEVTYPE_DIRECT = 0x00, + SPC3_DEVTYPE_SEQUENTIAL = 0x01, + SPC3_DEVTYPE_PRINTER = 0x02, + SPC3_DEVTYPE_PROCESSOR = 0x03, + SPC3_DEVTYPE_WORM = 0x04, + SPC3_DEVTYPE_MMC = 0x05, + SPC3_DEVTYPE_SCANNER = 0x06, + SPC3_DEVTYPE_OPTICAL = 0x07, + SPC3_DEVTYPE_CHANGER = 0x08, + SPC3_DEVTYPE_COMM = 0x09, + SPC3_DEVTYPE_ARRAY_CONTROLLER = 0x0c, + SPC3_DEVTYPE_SES = 0x0d, + SPC3_DEVTYPE_RBC = 0xe, + SPC3_DEVTYPE_OCRW = 0xf, + SPC3_DEVTYPE_BCC = 0x10, + SPC3_DEVTYPE_OSD = 0x11, + SPC3_DEVTYPE_ADC = 0x12 +} spc3_dev_type_t; + +/* + * SAM-4 5.3.1, Table 25 + */ +typedef enum sam4_status { + SAM4_STATUS_GOOD = 0x0, + SAM4_STATUS_CHECK_CONDITION = 0x2, + SAM4_STATUS_CONDITION_MET = 0x4, + SAM4_STATUS_BUSY = 0x8, + SAM4_STATUS_RESERVATION_CONFLICT = 0x18, + SAM4_STATUS_TASK_SET_FULL = 0x28, + SAM4_STATUS_ACA_ACTIVE = 0x30, + SAM4_STATUS_TASK_ABORTED = 0x40 +} sam4_status_t; + +#pragma pack(1) + +typedef union spc3_control { + struct { + DECL_BITFIELD5( + c_link :1, + c_flag :1, + c_naca :1, + _reserved1 :3, + c_vs_6 :2); + } c_bits; + uint8_t c_byte; +} spc3_control_t; + +/* + * SPC-3 6.2.1 CHANGE ALIASES + */ +typedef struct spc3_change_aliases_cdb { + uint8_t cac_opcode; + DECL_BITFIELD2( + cac_service_action :5, + _reserved1 :3); + uint8_t _reserved2[4]; + uint32_t cac_parameter_list_length; + uint8_t _reserved3; + spc3_control_t cac_control; +} spc3_change_aliases_cdb_t; + +typedef struct spc3_alias_entry { + uint64_t ae_alias_value; + uint8_t ae_protocol_identifier; + uint8_t _reserved1[2]; + uint8_t ae_format_code; + uint8_t _reserved2[2]; + uint16_t ae_designation_length; + uint8_t ae_designation[1]; /* Flexible */ +} spc3_alias_entry_t; + +typedef struct spc3_change_aliases_param_list { + uint32_t capl_parameter_data_length; + uint8_t _reserved1[4]; + spc3_alias_entry_t capl_alias_entries[1]; /* Flexible */ +} spc3_change_aliases_param_list_t; + +/* + * SPC-3 6.4.1 INQUIRY + */ +typedef struct spc3_inquiry_cdb { + uint8_t ic_opcode; + DECL_BITFIELD2( + ic_evpd :1, + _reserved1 :7); + uint8_t ic_page_code; + uint16_t ic_allocation_length; + spc3_control_t ic_control; +} spc3_inquiry_cdb_t; + +typedef struct spc3_inquiry_data { + DECL_BITFIELD2( + id_peripheral_device_type :5, + id_peripheral_qualifier :3); + DECL_BITFIELD2( + _reserved1 :7, + id_rmb :1); + uint8_t id_version; + DECL_BITFIELD4( + id_response_data_format :4, + id_hisup :1, + id_naca :1, + _reserved2 :2); + uint8_t additional_length; + DECL_BITFIELD6( + id_protect :1, + _reserved3 :2, + id_3pc :1, + id_tpgs :2, + id_acc :1, + id_sccs :1); + DECL_BITFIELD7( + id_addr16 :1, + _reserved4 :2, + id_mchanger :1, + id_multip :1, + id_vs_6_5 :1, + id_enc_serv :1, + id_b_que :1); + DECL_BITFIELD7( + id_vs_7_0 :1, + id_cmd_que :1, + _reserved5 :1, + id_linked :1, + id_sync :1, + id_wbus16 :1, + _reserved6 :2); + char id_vendor_id[8]; + char id_product_id[16]; + char id_product_revision[4]; + uint8_t id_vs_36[20]; + DECL_BITFIELD4( + id_ius :1, + id_qas :1, + id_clocking :2, + _reserved7 :4); + uint8_t _reserved8; + uint16_t id_version_descriptors[8]; + uint8_t _reserved9[22]; + uint8_t id_vs_96[1]; /* Flexible */ +} spc3_inquiry_data_t; + +/* + * SPC-3 6.5 LOG SELECT + */ +typedef enum spc3_log_page_control { + SPC3_LOG_PC_CUR_THRESHOLD = 0, + SPC3_LOG_PC_CUR_CUMULATIVE = 1, + SPC3_LOG_PC_DEF_THRESHOLD = 2, + SPC3_LOG_PC_DEF_CUMULATIVE = 3 +} spc3_log_page_control_t; + +typedef struct spc3_log_select_cdb { + uint8_t lsc_opcode; + DECL_BITFIELD3( + lsc_sp :1, + lsc_pcr :1, + _reserved1 :6); + DECL_BITFIELD2( + _reserved2 :6, + lsc_pc :2); + uint8_t _reserved3[4]; + uint16_t lsc_parameter_list_length; + spc3_control_t lsc_control; +} spc3_log_select_cdb_t; + +/* + * SPC-3 6.6 LOG SENSE + */ +typedef struct spc3_log_sense_cdb { + uint8_t lsc_opcode; + DECL_BITFIELD3( + lsc_sp :1, + lsc_ppc :1, + _reserved1 :6); + DECL_BITFIELD2( + lsc_page_code :6, + lsc_pc :2); + uint8_t _reserved2[2]; + uint16_t lsc_parameter_ptr; + uint16_t lsc_allocation_length; + spc3_control_t lsc_control; +} spc3_log_sense_cdb_t; + +typedef enum spc3_mode_page_control { + SPC3_MODE_PC_CURRENT = 0, + SPC3_MODE_PC_CHANGEABLE = 1, + SPC3_MODE_PC_DEFAULT = 2, + SPC3_MODE_PC_SAVED = 3 +} spc3_mode_page_control_t; + +typedef struct spc3_mode_param_header6 { + uint8_t mph_mode_data_length; + uint8_t mph_medium_type; + uint8_t mph_device_param; + uint8_t mph_block_descriptor_length; +} spc3_mode_param_header6_t; + +typedef spc3_mode_param_header6_t spc3_mode_param_header_t; + +typedef struct spc3_mode_param_header10 { + uint16_t mph_mode_data_length; + uint8_t mph_medium_type; + uint8_t mph_device_param; + DECL_BITFIELD2( + mph_longlba :1, + _reserved1 :7); + uint8_t _reserved2; + uint16_t mph_block_descriptor_length; +} spc3_mode_param_header10_t; + +typedef struct spc3_mode_param_block_descriptor { + uint8_t mpbd_density_code; + uint8_t mpbd_nblocks[3]; + uint8_t _reserved1; + uint8_t mpbd_block_length[3]; +} spc3_mode_param_block_descriptor_t; + +typedef struct spc3_mode_page_0 { + DECL_BITFIELD3( + mp0_page_code :6, + mp0_spf :1, + mp0_ps :1); + uint8_t mp0_page_length; + uint8_t mp0_mode_parameters[1]; /* Flexible */ +} spc3_mode_page_0_t; + +typedef struct spc3_mode_subpage { + DECL_BITFIELD3( + ms_page_code :6, + ms_spf :1, + ms_ps :1); + uint8_t ms_subpage_code; + uint16_t ms_page_length; + uint8_t ms_mode_parameters[1]; /* Flexible */ +} spc3_mode_subpage_t; + +/* + * SPC-3 7.4.6 Table 246 - TST field + */ +typedef enum spc3_mode_task_set { + SPC3_MODE_TST_ONE = 0, + SPC3_MODE_TST_SEPARATE = 1 +} spc3_mode_task_set_t; + +/* + * SPC-3 7.4.6 Table 247 - Queue Algorithm Modifier field + */ +typedef enum spc3_mode_queue_alg_mod { + SPC3_MODE_QAM_RESTRICTED = 0, + SPC3_MODE_QAM_UNRESTRICTED = 1 +} spc3_mode_queue_alg_mod_t; + +/* + * SPC-3 7.4.6 Table 245 + */ +typedef struct spc3_mode_params_control { + DECL_BITFIELD6( + mpc_rlec :1, + mpc_gltsd :1, + mpc_d_sense :1, + _reserved1 :1, + mpc_tmf_only :1, + mpc_tst :3); + DECL_BITFIELD4( + _reserved2 :1, + mpc_q_err :1, + _reserved3 :1, + mpc_queue_alg_mod :4); + DECL_BITFIELD5( + _reserved4 :3, + mpc_swp :1, + mpc_ua_intlck_ctrl :2, + mpc_rac :1, + mpc_vs_4_7 :1); + DECL_BITFIELD4( + mpc_autoload_mode :3, + _reserved5 :3, + mpc_tas :1, + mpc_ato :1); + uint8_t _reserved6[2]; + uint16_t mpc_busy_timeout_period; + uint16_t mpc_ext_selftest_completion_time; +} spc3_mode_page_params_control_t; + +/* + * SPC-3 7.4.7 Control Extension mode page + */ +typedef struct spc3_mode_params_control_ext { + DECL_BITFIELD4( + mpce_ialuae :1, + mpce_scsip :1, + mpce_tcmos :1, + _reserved1 :5); + DECL_BITFIELD2( + mpce_initial_priority :4, + _reserved2 :4); + uint8_t _reserved3[26]; +} spc3_mode_params_control_ext_t; + +/* + * SPC-3 7.4.8 Disconnect-Reconnect mode page + */ +typedef struct spc3_mode_params_dc_rc { + uint8_t mpdr_buffer_full_ratio; + uint8_t mpdr_buffer_empty_ratio; + uint16_t mpdr_bus_inactivity_limit; + uint16_t mpdr_disconnect_time_limit; + uint16_t mpdr_connect_time_limit; + uint16_t mpdr_max_burst_size; + DECL_BITFIELD4( + mpdr_dtdc :3, + mpdr_di_mm :1, + mpdr_fair_arbitration :3, + mpdr_emdp :1); + uint8_t _reserved1; + uint16_t mpdr_first_burst_size; +} spc3_mode_params_dc_rc_t; + +typedef enum spc3_mode_mrie { + SPC3_MODE_MRIE_NONE = 0, + SPC3_MODE_MRIE_ASYNC = 1, + SPC3_MODE_MRIE_UNIT_ATTN = 2, + SPC3_MODE_MRIE_COND_REC_ERR = 3, + SPC3_MODE_MRIE_UNCOND_REC_ERR = 4, + SPC3_MODE_MRIE_NO_SENSE = 5, + SPC3_MODE_MRIE_REQUEST = 6 +} spc3_mode_mrie_t; + +/* + * SPC-3 7.4.11 Informational Exceptions Control mode page + */ +typedef struct spc3_mode_params_iec { + DECL_BITFIELD8( + mpi_log_err :1, + _reserved1 :1, + mpi_test :1, + mpi_d_excpt :1, + mpi_e_wasc :1, + mpi_ebf :1, + _reserved2 :1, + mpi_perf :1); + DECL_BITFIELD2( + mpi_mrie :4, + _reserved3 :4); + uint32_t mpi_interval_timer; + uint32_t mpi_report_count; +} spc3_mode_params_iec_t; + +/* + * SPC-3 7.4.12 Power Condition mode page + */ +typedef struct spc3_mode_params_pc { + uint8_t _reserved1; + DECL_BITFIELD3( + mpp_standby :1, + mpp_idle :1, + _reserved2 :6); + uint32_t mpp_idle_condition_timer; + uint32_t mpp_standby_condition_timer; +} spc3_mode_params_pc_t; + +/* + * SPC-3 6.7 MODE SELECT(6) + */ +typedef struct spc3_mode_select6_cdb { + uint8_t msc_opcode; + DECL_BITFIELD4( + msc_sp :1, + _reserved1 :3, + msc_pf :1, + _reserved2 :3); + uint8_t _reserved3[2]; + uint8_t msc_parameter_list_length; + spc3_control_t msc_control; +} spc3_mode_select6_cdb_t; + +typedef spc3_mode_select6_cdb_t spc3_mode_select_cdb_t; + +/* + * SPC-3 6.8 MODE SELECT(10) + */ +typedef struct spc3_mode_select10_cdb { + uint8_t msc_opcode; + DECL_BITFIELD4( + msc_sp :1, + _reserved1 :3, + msc_pf :1, + _reserved2 :3); + uint8_t _reserved3[5]; + uint16_t msc_parameter_list_length; + spc3_control_t msc_control; +} spc3_mode_select10_cdb_t; + +/* + * SPC-3 6.9 MODE SENSE(6) + */ +typedef struct spc3_mode_sense6_cdb { + uint8_t msc_opcode; + DECL_BITFIELD3( + _reserved1 :3, + msc_dbd :1, + _reserved2 :4); + DECL_BITFIELD2( + msc_page_code :6, + msc_pc :2); + uint8_t msc_subpage_code; + uint8_t msc_allocation_length; + spc3_control_t msc_control; +} spc3_mode_sense6_cdb_t; + +typedef spc3_mode_sense6_cdb_t spc3_mode_sense_cdb_t; + +/* + * SPC-3 6.10 MODE SENSE(10) + */ +typedef struct spc3_mode_sense10_cdb { + uint8_t msc_opcode; + DECL_BITFIELD4( + _reserved1 :3, + msc_dbd :1, + msc_llbaa :1, + _reserved2 :3); + DECL_BITFIELD2( + msc_page_code :6, + msc_pc :2); + uint8_t msc_subpage_code; + uint8_t _reserved3[3]; + uint16_t msc_allocation_length; + spc3_control_t msc_control; +} spc3_mode_sense10_cdb_t; + +/* + * SPC-3 6.11 PERSISTENT RESERVE IN + */ +typedef enum spc3_persistent_reserve_in_sac { + SPC3_PRI_SAC_READ_KEYS = 0, + SPC3_PRI_SAC_READ_RESERVATION = 1, + SPC3_PRI_SAC_REPORT_CAPABILITIES = 2, + SPC3_PRI_SAC_READ_FULL_STATUS = 3 +} spc3_persistent_reserve_in_sac_t; + +typedef struct spc3_persistent_reserve_in_param_rk { + uint32_t pripr_pr_generation; + uint32_t pripr_additional_length; + uint64_t pripr_keys[1]; /* Flexible */ +} spc3_persistent_reserve_in_param_rk_t; + +typedef enum spc3_persistent_reserve_type { + SPC3_PR_TYPE_WREXCL = 1, + SPC3_PR_TYPE_EXCL = 3, + SPC3_PR_WREXCL_REG_ONLY = 5, + SPC3_PR_EXCL_REG_ONLY = 6, + SPC3_PR_WREXCL_ALL_REG = 7, + SPC3_PR_EXCL_ALL_REG = 8 +} spc3_persistent_reserve_type_t; + +typedef struct spc3_persistent_reserve_in_param_rr { + uint32_t pripr_pr_generation; + uint32_t pripr_additional_length; + uint64_t pripr_key; + uint8_t _reserved1[4]; + uint8_t _reserved2; + DECL_BITFIELD2( + pripr_type :4, + pripr_scope :4); + uint8_t _reserved3[2]; +} spc3_persistent_reserve_in_param_rr_t; + +typedef struct spc3_persistent_reserve_in_param_rc { + uint16_t pripr_length; + DECL_BITFIELD6( + pripr_ptpl_c :1, + _reserved1 :1, + pripr_atp_c :1, + pripr_sip_c :1, + pripr_crh :1, + _reserved2 :3); + DECL_BITFIELD3( + pripr_ptpl_a :1, + _reserved3 :6, + pripr_tmv :1); + DECL_BITFIELD8( + _reserved4 :1, + pripr_wr_ex :1, + _reserved5 :1, + pripr_ex_ac :1, + _reserved6 :1, + pripr_wr_ex_ro :1, + pripr_ex_ac_ro :1, + pripr_wr_ex_ar :1); + DECL_BITFIELD2( + pripr_ex_ac_ar :1, + _reserved7 :7); + uint8_t _reserved8[2]; +} spc3_persistent_reserve_in_param_rc_t; + +typedef struct spc3_persistent_reserve_full_status { + uint64_t prfs_key; + uint8_t _reserved1[4]; + DECL_BITFIELD3( + prfs_r_holder :1, + prfs_all_tg_pt :1, + _reserved2 :6); + DECL_BITFIELD2( + prfs_type :4, + prfs_scope :4); + uint8_t _reserved3[4]; + uint16_t prfs_relative_target_port_identifier; + uint32_t prfs_additional_descriptor_length; + uint8_t prfs_transport_id[1]; /* Flexible */ +} spc3_persistent_reserve_full_status_t; + +typedef struct spc3_persistent_reserve_in_param_rfs { + uint32_t pripr_pr_generation; + uint32_t pripr_additional_length; + uint8_t pripr_status_descriptors[1]; /* Flexible */ +} spc3_persistent_reserve_in_param_rfs_t; + +typedef struct spc3_persistent_reserve_in_cdb { + uint8_t pric_opcode; + DECL_BITFIELD2( + pric_service_action :5, + _reserved1 :3); + uint8_t _reserved2[5]; + uint16_t pric_allocation_length; + spc3_control_t pric_control; +} spc3_persistent_reserve_in_cdb_t; + +/* + * SPC-3 6.16 READ MEDIA SERIAL NUMBER + */ +typedef struct spc3_read_media_serial_number_cdb { + uint8_t rmsnc_opcode; + DECL_BITFIELD2( + rmsnc_service_action :5, + _reserved1 :3); + uint8_t _reserved2[4]; + uint32_t rmsnc_allocation_length; + uint8_t _reserved3; + spc3_control_t rmsnc_control; +} spc3_read_media_serial_number_cdb_t; + +typedef struct spc3_read_media_serial_number_data { + uint32_t msnd_length; + uint8_t msnd_serial_number[1]; /* Flexible */ +} spc3_read_media_serial_number_data_t; + +/* + * SPC-3 6.18 RECEIVE DIAGNOSTIC RESULTS + */ +typedef struct spc3_receive_diagnostic_results_cdb { + uint8_t rdrc_opcode; + DECL_BITFIELD2( + rdrc_pcv :1, + _reserved1 :7); + uint8_t rdrc_page_code; + uint16_t rdrc_allocation_length; + spc3_control_t rdrc_control; +} spc3_receive_diagnostic_results_cdb_t; + +/* + * SPC-3 Diagnostic page format (Table 194, 7.1.1) + */ +typedef struct spc3_diag_page_impl { + uint8_t sdpi_page_code; + uint8_t sdpi_specific; + uint16_t sdpi_page_length; + uint8_t sdpi_data[1]; +} spc3_diag_page_impl_t; + +/* + * SPC-3 Supported diagnostic pages (Table 196, 7.1.2) + */ +typedef struct spc3_supported_diag_page_impl { + uint8_t ssdpi_page_code; + uint8_t _reserved1; + uint16_t ssdpi_page_length; + uint8_t ssdpi_page_list[1]; +} spc3_supported_diag_page_impl_t; + +/* + * SPC-3 6.21 REPORT LUNS + */ +typedef enum spc3_report_luns_select_report { + SPC3_RL_SR_ADDRESSING = 0, + SPC3_RL_SR_WELLKNOWN = 1, + SPC3_RL_SR_ALL = 2 +} spc3_report_luns_select_report_t; + +typedef struct spc3_report_luns_cdb { + uint8_t rlc_opcode; + uint8_t _reserved1; + uint8_t rlc_select_report; + uint8_t _reserved2[3]; + uint32_t rlc_allocation_length; + uint8_t _reserved3; + spc3_control_t rlc_control; +} spc3_report_luns_cdb_t; + +typedef struct spc3_report_luns_data { + uint32_t rld_lun_list_length; + uint8_t _reserved1[4]; + uint64_t rld_luns[1]; /* Flexible */ +} spc3_report_luns_data_t; + +/* + * SPC-3 6.27 REQUEST SENSE + */ +typedef struct spc3_request_sense_cdb { + uint8_t rsc_opcode; + DECL_BITFIELD2( + rsc_desc :1, + _reserved1 :7); + uint8_t _reserved2[2]; + uint8_t rsc_allocation_length; + spc3_control_t rsc_control; +} spc3_request_sense_cdb_t; + +/* + * SPC-3 6.28 SEND DIAGNOSTIC + */ +typedef struct spc3_send_diagnostic_cdb { + uint8_t sdc_opcode; + DECL_BITFIELD6( + sdc_unit_off_l :1, + sdc_dev_off_l :1, + sdc_self_test :1, + _reserved1 :1, + sdc_pf :1, + sdc_selftest_code :3); + uint8_t _reserved2; + uint16_t sdc_parameter_list_length; + spc3_control_t sdc_control; +} spc3_send_diagnostic_cdb_t; + +/* + * SPC-3 6.33 TEST UNIT READY + */ +typedef struct spc3_test_unit_ready_cdb { + uint8_t tur_opcode; + uint8_t _reserved1[4]; + spc3_control_t tur_control; +} spc3_test_unit_ready_cdb_t; + +/* + * SPC-4 7.5.1 Protocol values + */ +typedef enum spc4_protocol_id { + SPC4_PROTO_FIBRE_CHANNEL = 0, + SPC4_PROTO_PARALLEL_SCSI = 1, + SPC4_PROTO_SSA = 2, + SPC4_PROTO_IEEE1394 = 3, + SPC4_PROTO_RDMA = 4, + SPC4_PROTO_ISCSI = 5, + SPC4_PROTO_SAS = 6, + SPC4_PROTO_ADT = 7, + SPC4_PROTO_ATA = 8, + SPC4_PROTO_NONE = 0xf +} spc4_protocol_id_t; + +/* + * SPC-3 NAA identifier format (Table 305, 7.6.3.6.1) + */ +typedef struct spc3_naa_id_impl { + DECL_BITFIELD2( + snii_priv_msn :4, + snii_naa :4); + uint8_t snii_priv[1]; +} spc3_naa_id_impl_t; + +/* + * SPC-3 NAA IEEE Extended Identifier field format (Table 307, 7.6.3.6.2) + */ +typedef struct spc3_naa_ieee_ext_id_impl { + DECL_BITFIELD2( + snieii_vendor_id_a_msn :4, + snieii_naa :4); + uint8_t snieii_vendor_id_a_lsb; + uint8_t snieii_company_id[3]; + uint8_t snieii_vendor_id_b[3]; +} spc3_naa_ieee_ext_id_impl_t; + +#define NAA_IEEE_EXT_VENDOR_A(idp) \ + SCSI_MK12_4_8((idp)->snieii_vendor_id_a_msn, \ + (idp)->snieii_vendor_id_a_lsb) +#define NAA_IEEE_EXT_COMPANY_ID(idp) SCSI_READ24((idp)->snieii_company_id) +#define NAA_IEEE_EXT_VENDOR_B(idp) SCSI_READ24((idp)->snieii_vendor_id_b) + +/* + * Ibid, Table 308 + */ +typedef struct spc3_naa_ieee_reg_id_impl { + DECL_BITFIELD2( + snirii_company_id_msn :4, + snirii_naa :4); + uint16_t snirii_company_id_mid; + DECL_BITFIELD2( + snirii_vendor_id_msn :4, + snirii_company_id_lsn :4); + uint32_t snirii_vendor_id_low; +} spc3_naa_ieee_reg_id_impl_t; + +#define NAA_IEEE_REG_COMPANY_ID(idp) \ + SCSI_MK24_4_16_4((idp)->snirii_company_id_msn, \ + SCSI_READ16(&(idp)->snirii_company_id_mid), \ + (idp)->snirii_company_id_lsn) +#define NAA_IEEE_REG_VENDOR_ID(idp) \ + SCSI_MK36_4_32((idp)->snirii_vendor_id_msn, \ + SCSI_READ32(&(idp)->snirii_vendor_id_low)) + +/* + * Ibid, Table 309 + */ +typedef struct spc3_naa_ieee_reg_ext_id_impl { + DECL_BITFIELD2( + snireii_company_id_msn :4, + snireii_naa :4); + uint16_t snireii_company_id_mid; + DECL_BITFIELD2( + snireii_vendor_id_msn :4, + snireii_company_id_lsn :4); + uint32_t snireii_vendor_id_low; + uint64_t snireii_vendor_id_ext; +} spc3_naa_ieee_reg_ext_id_impl_t; + +#define NAA_IEEE_REG_EXT_COMPANY_ID(idp) \ + SCSI_MK20_4_16_4((idp)->snireii_company_id_msn, \ + SCSI_READ16(&(idp)->snireii_company_id_mid), \ + (idp)->snireii_company_id_lsn) +#define NAA_IEEE_REG_EXT_VENDOR_ID(idp) \ + SCSI_MK36_4_32((idp)->snireii_vendor_id_msn, \ + SCSI_READ32(&(idp)->snireii_vendor_id_low)) + +typedef union spc3_naa_id_8_impl { + struct { + DECL_BITFIELD2( + _reserved1 :4, + sni8i_naa :4); + } sni8i_hdr; + spc3_naa_ieee_ext_id_impl_t sni8i_ext_id; + spc3_naa_ieee_reg_id_impl_t sni8i_reg_id; +} spc3_naa_id_8_impl_t; + +#define sni8i_naa sni8i_hdr.sni8i_naa + +typedef enum naa_id { + NAA_IEEE_EXT = 0x2, + NAA_LOCAL = 0x3, + NAA_IEEE_REG = 0x5, + NAA_IEEE_REG_EXT = 0x6 +} naa_id_t; + +#pragma pack() + +#ifdef __cplusplus +} +#endif + +#endif /* _SPC3_TYPES_H */ diff --git a/usr/src/uts/common/sys/scsi/targets/sgendef.h b/usr/src/uts/common/sys/scsi/targets/sgendef.h index 23e29c0265..7dc7d9c5d4 100644 --- a/usr/src/uts/common/sys/scsi/targets/sgendef.h +++ b/usr/src/uts/common/sys/scsi/targets/sgendef.h @@ -20,7 +20,7 @@ */ /* - * Copyright 2001 by Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -98,6 +98,7 @@ typedef struct sgen_state { #define SGEN_FL_OPEN 0x01 /* instance is open */ #define SGEN_FL_SUSP 0x02 /* instance suspended */ #define SGEN_FL_BUSY 0x04 /* command buffer busy */ +#define SGEN_FL_EXCL 0x08 /* exclusive open */ #define SGEN_SET_OPEN(stp) \ (((sgen_state_t *)(stp))->sgen_flags |= SGEN_FL_OPEN) @@ -120,6 +121,13 @@ typedef struct sgen_state { #define SGEN_IS_BUSY(stp) \ ((((sgen_state_t *)(stp))->sgen_flags & SGEN_FL_BUSY) == SGEN_FL_BUSY) +#define SGEN_SET_EXCL(stp) \ + (((sgen_state_t *)(stp))->sgen_flags |= SGEN_FL_EXCL) +#define SGEN_CLR_EXCL(stp) \ + (((sgen_state_t *)(stp))->sgen_flags &= ~SGEN_FL_EXCL) +#define SGEN_IS_EXCL(stp) \ + ((((sgen_state_t *)(stp))->sgen_flags & SGEN_FL_EXCL) == SGEN_FL_EXCL) + /* * These structures form the driver's database of binding information. * Inquiry strings and device types from the inquiry-config-list and |