diff options
| author | Hyon Kim <Hyon.Kim@Sun.COM> | 2010-04-11 11:20:12 -0700 |
|---|---|---|
| committer | Hyon Kim <Hyon.Kim@Sun.COM> | 2010-04-11 11:20:12 -0700 |
| commit | ac88567a7a5bb7f01cf22cf366bc9d6203e24d7a (patch) | |
| tree | 9fedf1905a420a42d139cf8318d81b0f81e3d841 | |
| parent | 68e180930dea31f741fd809e32c371c0d73129a3 (diff) | |
| download | illumos-joyent-ac88567a7a5bb7f01cf22cf366bc9d6203e24d7a.tar.gz | |
PSARC/2009/019 SAS Management Protocol library
6791689 need a userland mechanism for access to smp(7D) targets
6901865 need to enumerate SAS expanders in storage enclosures
6927621 need to enumerate receptacles around SAS expanders in storage enclosures
6927623 need representation of SAS HBA receptacles in topo tree
6934815 should add scsi-device and smp-device nodes beneath hba/iport nodes in topology
6791643 libses needs to link with libumem
6791646 ses2 ucode upload should allow selection of chunk size
6791730 libscsi and friends mishandle plugin paths with multiple candidates
6831769 fmd dumps core repeatedly in libses with huge enclosure
6863967 substring and subhelp pages ignored due to length mishandling
6900516 add support for SPMS-1 rev 111 SUBCHASSIS ID
6900520 ses topo enumerator ignores some enclosures
6900856 need SES_PROP_INTERNAL workaround for X4275
6901298 libscsi should work around devices intolerant of odd INQUIRY lengths
6900822 SUN libses plugin should support FRUID page
6905410 memory handling problems in libfruraw and libnvfru
6905409 use after free in libfruraw fru_close_container()
95 files changed, 6885 insertions, 458 deletions
diff --git a/exception_lists/packaging b/exception_lists/packaging index aaa788680a..c980d49281 100644 --- a/exception_lists/packaging +++ b/exception_lists/packaging @@ -20,8 +20,7 @@ # # -# Copyright 2010 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. # # @@ -45,6 +44,7 @@ usr/include/security/pam_impl.h usr/include/sys/clock_impl.h usr/include/sys/ieeefp.h usr/include/sys/winlockio.h +usr/include/scsi/plugins/ses/vendor/sun_impl.h # # Private/Internal libraries of the Cryptographic Framework. # diff --git a/usr/src/cmd/scsi/Makefile b/usr/src/cmd/scsi/Makefile index 1f48541baa..1d81821a1a 100644 --- a/usr/src/cmd/scsi/Makefile +++ b/usr/src/cmd/scsi/Makefile @@ -19,14 +19,12 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. # -#ident "%Z%%M% %I% %E% SMI" SUBDIRS = \ - sestopo - + sestopo \ + smp _msg: include ./Makefile.subdirs diff --git a/usr/src/cmd/scsi/smp/Makefile b/usr/src/cmd/scsi/smp/Makefile new file mode 100644 index 0000000000..2aa96a6207 --- /dev/null +++ b/usr/src/cmd/scsi/smp/Makefile @@ -0,0 +1,27 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +SUBDIRS = $(MACH) + +include ../Makefile.subdirs diff --git a/usr/src/cmd/scsi/smp/Makefile.com b/usr/src/cmd/scsi/smp/Makefile.com new file mode 100644 index 0000000000..f22f111c9e --- /dev/null +++ b/usr/src/cmd/scsi/smp/Makefile.com @@ -0,0 +1,67 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +.KEEP_STATE: +.SUFFIXES: + +PROG = smp +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 -lsmp +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/smp/common/smp.c b/usr/src/cmd/scsi/smp/common/smp.c new file mode 100644 index 0000000000..49f07f2b1c --- /dev/null +++ b/usr/src/cmd/scsi/smp/common/smp.c @@ -0,0 +1,215 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ +#include <sys/types.h> +#include <sys/scsi/generic/smp_frames.h> +#include <sys/scsi/generic/commands.h> +#include <sys/scsi/impl/commands.h> +#include <sys/ccompile.h> + +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> +#include <strings.h> +#include <ctype.h> + +#include <scsi/libsmp.h> +#include <scsi/libsmp_plugin.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); +} + +int +main(int argc, char *argv[]) +{ + smp_target_t *tp; + smp_action_t *ap; + smp_errno_t err; + smp_function_t func; + smp_result_t result; + smp_target_def_t tdef; + smp_discover_resp_t *rp; + smp_report_manufacturer_info_resp_t *ip; + uint8_t *resp; + size_t len; + uint_t cap; + void *x; + uint_t i, j; + + if (argc < 3) + fatal(-1, "Usage: %s <device> <function> ...\n", argv[0]); + + errno = 0; + func = strtoul(argv[2], NULL, 0); + if (errno != 0) + fatal(-1, "Usage: %s <device> <function> ...\n", argv[0]); + + if (smp_init(LIBSMP_VERSION) != 0) + fatal(-1, "libsmp initialization failed: %s", smp_errmsg()); + + bzero(&tdef, sizeof (smp_target_def_t)); + tdef.std_def = argv[1]; + + if ((tp = smp_open(&tdef)) == NULL) { + smp_fini(); + fatal(-2, "failed to open %s: %s", argv[1], smp_errmsg()); + } + + cap = smp_target_getcap(tp); + ap = smp_action_alloc(func, tp, 0); + if (ap == NULL) { + smp_close(tp); + smp_fini(); + fatal(-3, "failed to allocate action: %s", smp_errmsg()); + } + + if (func == SMP_FUNC_DISCOVER) { + smp_discover_req_t *dp; + if (argc < 4) + fatal(-1, + "Usage: %s <device> 0x10 <phy identifier>\n", + argv[0]); + + smp_action_get_request(ap, (void **)&dp, NULL); + dp->sdr_phy_identifier = strtoul(argv[3], NULL, 0); + } else if (func == SMP_FUNC_REPORT_ROUTE_INFO) { + smp_report_route_info_req_t *rp; + if (argc < 5) + fatal(-1, "Usage: %s <device> 0x13 <expander route " + "index> <phy identifier>\n", + argv[0]); + + smp_action_get_request(ap, (void **)&rp, NULL); + rp->srrir_exp_route_index = strtoul(argv[3], NULL, 0); + rp->srrir_phy_identifier = strtoul(argv[4], NULL, 0); + } else if (func == SMP_FUNC_ENABLE_DISABLE_ZONING) { + smp_enable_disable_zoning_req_t *rp; + if (argc < 4) + fatal(-1, + "Usage: %s <device> 0x81 " + "[0(no change) | 1(enable)| 2(disable)]\n", + argv[0]); + + smp_action_get_request(ap, (void **)&rp, NULL); + rp->sedzr_enable_disable_zoning = strtoul(argv[3], NULL, 0); + } else if (func == SMP_FUNC_PHY_CONTROL) { + smp_phy_control_req_t *rp; + if (argc < 5) + fatal(-1, + "Usage: %s <device> 0x91 <phy identifier> " + " <phy operation>\n", + argv[0]); + + smp_action_get_request(ap, (void **)&rp, NULL); + + smp_action_get_request(ap, (void **)&rp, NULL); + rp->spcr_phy_identifier = strtoul(argv[3], NULL, 0); + rp->spcr_phy_operation = strtoul(argv[4], NULL, 0); + } else if (func == SMP_FUNC_REPORT_EXP_ROUTE_TABLE_LIST) { + smp_report_exp_route_table_list_req_t *rp; + if (argc < 4) + fatal(-1, + "Usage: %s <device> 0x22 <SAS Address Index> \n", + argv[0]); + + smp_action_get_request(ap, (void **)&rp, NULL); + SCSI_WRITE16(&rp->srertlr_max_descrs, 64); + SCSI_WRITE16(&rp->srertlr_starting_routed_sas_addr_index, + strtoull(argv[3], NULL, 0)); + rp->srertlr_starting_phy_identifier = 0; + } + + (void) printf("%s\n", argv[0]); + (void) printf("\tSAS Address: %016llx\n", smp_target_addr(tp)); + (void) printf("\tVendor: %s\n", smp_target_vendor(tp)); + (void) printf("\tProduct: %s\n", smp_target_product(tp)); + (void) printf("\tRevision: %s\n", smp_target_revision(tp)); + (void) printf("\tExp Vendor: %s\n", smp_target_component_vendor(tp)); + (void) printf("\tExp ID: %04x\n", smp_target_component_id(tp)); + (void) printf("\tExp Rev: %02x\n", smp_target_component_revision(tp)); + + if (smp_exec(ap, tp) != 0) { + smp_close(tp); + smp_action_free(ap); + smp_fini(); + fatal(-4, "exec failed: %s", smp_errmsg()); + } + + smp_close(tp); + smp_action_get_response(ap, &result, (void **)&resp, &len); + + if (result != SMP_RES_FUNCTION_ACCEPTED) { + smp_action_free(ap); + smp_fini(); + fatal(-5, "command failed with status code %d", result); + } + + (void) printf("Response: (len %d)\n", len); + for (i = 0; i < len; i += 8) { + (void) printf("%02x: ", i); + for (j = i; j < i + 8; j++) + if (j < len) + (void) printf("%02x ", resp[j]); + else + (void) printf(" "); + for (j = i; j < i + 8; j++) + (void) printf("%c", + j < len && isprint(resp[j]) ? resp[j] : + j < len ? '.' : '\0'); + (void) printf("\n"); + } + + if (func == SMP_FUNC_DISCOVER) { + rp = (smp_discover_resp_t *)resp; + (void) printf("Addr: %016llx Phy: %02x\n", + SCSI_READ64(&rp->sdr_sas_addr), rp->sdr_phy_identifier); + (void) printf("Peer: %016llx Phy: %02x\n", + SCSI_READ64(&rp->sdr_attached_sas_addr), + rp->sdr_attached_phy_identifier); + (void) printf("Device type: %01x\n", + rp->sdr_attached_device_type); + } + + smp_action_free(ap); + smp_fini(); + + return (0); +} diff --git a/usr/src/cmd/scsi/smp/i386/Makefile b/usr/src/cmd/scsi/smp/i386/Makefile new file mode 100644 index 0000000000..ae61a2c128 --- /dev/null +++ b/usr/src/cmd/scsi/smp/i386/Makefile @@ -0,0 +1,26 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +include ../../../Makefile.cmd +include ../Makefile.com diff --git a/usr/src/cmd/scsi/smp/sparc/Makefile b/usr/src/cmd/scsi/smp/sparc/Makefile new file mode 100644 index 0000000000..ae61a2c128 --- /dev/null +++ b/usr/src/cmd/scsi/smp/sparc/Makefile @@ -0,0 +1,26 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +include ../../../Makefile.cmd +include ../Makefile.com diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile index a458acba3a..8e5e78f303 100644 --- a/usr/src/lib/Makefile +++ b/usr/src/lib/Makefile @@ -659,7 +659,8 @@ smbsrv: libsocket libnsl libmd libxnet libpthread librt \ libv12n: libds libuuid libvrrpadm: libsocket libdladm libscf libvscan: libscf -scsi: libnvpair +libfru: libfruutils +scsi: libnvpair libfru mpapi: libpthread libdevinfo libsysevent libnvpair sun_fc: libdevinfo libsysevent libnvpair libsun_ima: libdevinfo libsysevent libnsl diff --git a/usr/src/lib/fm/Makefile b/usr/src/lib/fm/Makefile index 775aba3fda..c185f7770f 100644 --- a/usr/src/lib/fm/Makefile +++ b/usr/src/lib/fm/Makefile @@ -20,8 +20,7 @@ # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. # include ../Makefile.lib @@ -49,6 +48,6 @@ libldom: libmdesc libfmd_agent libfmd_snmp: libfmd_adm topo -topo: $($(MACH)_SUBDIRS) libfmd_agent +topo: $($(MACH)_SUBDIRS) libfmd_agent libdiskstatus include ./Makefile.subdirs diff --git a/usr/src/lib/fm/topo/libtopo/common/hc.c b/usr/src/lib/fm/topo/libtopo/common/hc.c index c680f3e693..b5d89eaa58 100644 --- a/usr/src/lib/fm/topo/libtopo/common/hc.c +++ b/usr/src/lib/fm/topo/libtopo/common/hc.c @@ -21,8 +21,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <stdio.h> @@ -160,6 +159,7 @@ static const hcc_t hc_canon[] = { { HOSTBRIDGE, TOPO_STABILITY_PRIVATE }, { INTERCONNECT, TOPO_STABILITY_PRIVATE }, { IOBOARD, TOPO_STABILITY_PRIVATE }, + { IPORT, TOPO_STABILITY_PRIVATE }, { MEMBOARD, TOPO_STABILITY_PRIVATE }, { MEMORYBUFFER, TOPO_STABILITY_PRIVATE }, { MEMORYCONTROL, TOPO_STABILITY_PRIVATE }, @@ -179,9 +179,13 @@ static const hcc_t hc_canon[] = { { POWERMODULE, TOPO_STABILITY_PRIVATE }, { PSU, TOPO_STABILITY_PRIVATE }, { RANK, TOPO_STABILITY_PRIVATE }, + { RECEPTACLE, TOPO_STABILITY_PRIVATE }, { RISER, TOPO_STABILITY_PRIVATE }, + { SASEXPANDER, TOPO_STABILITY_PRIVATE }, + { SCSI_DEVICE, TOPO_STABILITY_PRIVATE }, { SHELF, TOPO_STABILITY_PRIVATE }, { SES_ENCLOSURE, TOPO_STABILITY_PRIVATE }, + { SMP_DEVICE, TOPO_STABILITY_PRIVATE }, { SP, TOPO_STABILITY_PRIVATE }, { STRAND, TOPO_STABILITY_PRIVATE }, { SUBCHASSIS, TOPO_STABILITY_PRIVATE }, diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h index db663b1074..67858ffd3e 100644 --- a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h +++ b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h @@ -56,6 +56,7 @@ extern "C" { #define HOSTBRIDGE "hostbridge" #define INTERCONNECT "interconnect" #define IOBOARD "ioboard" +#define IPORT "iport" #define MEMBOARD "memboard" #define MEMORYBUFFER "memory-buffer" #define MEMORYCONTROL "memory-controller" @@ -75,9 +76,13 @@ extern "C" { #define POWERMODULE "powermodule" #define PSU "psu" #define RANK "rank" +#define RECEPTACLE "receptacle" #define RISER "riser" +#define SASEXPANDER "sas-expander" #define SHELF "shelf" +#define SCSI_DEVICE "scsi-device" #define SES_ENCLOSURE "ses-enclosure" +#define SMP_DEVICE "smp-device" #define SP "sp" #define SUBCHASSIS "subchassis" #define SYSTEMBOARD "systemboard" @@ -105,12 +110,28 @@ extern "C" { #define TOPO_PCI_CLASS "class-code" #define TOPO_PCI_AADDR "assigned-addresses" +#define TOPO_PGROUP_BINDING "binding" +#define TOPO_BINDING_OCCUPANT "occupant-path" + #define TOPO_PGROUP_STORAGE "storage" +#define TOPO_STORAGE_INITIATOR_PORT "initiator-port" +#define TOPO_STORAGE_INITIATOR_PORT_PM "initiator-port-pm" +#define TOPO_STORAGE_TARGET_PORT "target-port" #define TOPO_STORAGE_TARGET_PORT_L0ID "target-port-l0id" #define TOPO_STORAGE_TARGET_PORT_L0IDS "target-port-l0ids" - -#define TOPO_PGROUP_BINDING "binding" -#define TOPO_BINDING_OCCUPANT "occupant-path" +#define TOPO_STORAGE_ATTACHED_PORT "attached-port" +#define TOPO_STORAGE_TARGET_PORT_PM "target-port-pm" +#define TOPO_STORAGE_ATTACHED_PORT_PM "attached-port-pm" +#define TOPO_STORAGE_DEVID "devid" +#define TOPO_STORAGE_LUN64 "lun64" +#define TOPO_STORAGE_DEVICE_TYPE "inquiry-device-type" +#define TOPO_STORAGE_MANUFACTURER "manufacturer" +#define TOPO_STORAGE_MODEL "model" +#define TOPO_STORAGE_FIRMWARE_REV "firmware-revision" +#define TOPO_STORAGE_TARGET_PORT_L0ID "target-port-l0id" +#define TOPO_STORAGE_TARGET_PORT_L0IDS "target-port-l0ids" +#define TOPO_STORAGE_SAS_PHY_MASK "receptacle-pm" +#define TOPO_STORAGE_SAS_CONNECTOR_TYPE "sas-connector-type" #ifdef __cplusplus } diff --git a/usr/src/lib/fm/topo/modules/common/disk/disk.c b/usr/src/lib/fm/topo/modules/common/disk/disk.c index c248e90553..427402c934 100644 --- a/usr/src/lib/fm/topo/modules/common/disk/disk.c +++ b/usr/src/lib/fm/topo/modules/common/disk/disk.c @@ -19,10 +19,8 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" #include <strings.h> #include <devid.h> @@ -121,7 +119,7 @@ _topo_init(topo_mod_t *mod, topo_version_t version) return (-1); } - if (disk_list_gather(mod, dlistp) != 0) { + if (dev_list_gather(mod, dlistp) != 0) { topo_mod_unregister(mod); topo_mod_free(mod, dlistp, sizeof (topo_list_t)); topo_mod_dprintf(mod, "_topo_init: " @@ -141,7 +139,7 @@ void _topo_fini(topo_mod_t *mod) { topo_list_t *dlistp = topo_mod_getspecific(mod); - disk_list_free(mod, dlistp); + dev_list_free(mod, dlistp); topo_mod_free(mod, dlistp, sizeof (topo_list_t)); topo_mod_unregister(mod); topo_mod_dprintf(mod, "_topo_fini: " diff --git a/usr/src/lib/fm/topo/modules/common/disk/disk.h b/usr/src/lib/fm/topo/modules/common/disk/disk.h index b758db06e3..298b0cf870 100644 --- a/usr/src/lib/fm/topo/modules/common/disk/disk.h +++ b/usr/src/lib/fm/topo/modules/common/disk/disk.h @@ -27,7 +27,6 @@ #define _DISK_H #include <fm/topo_mod.h> -#include <fm/topo_hc.h> #include <libdevinfo.h> #ifdef __cplusplus @@ -49,11 +48,42 @@ extern "C" { #define TOPO_STORAGE_FIRMWARE_REV "firmware-revision" #define TOPO_STORAGE_CAPACITY "capacity-in-bytes" +/* + * Properties for binding group: The binding group required in platform + * specific xml that describes 'bay' nodes containing internal disks. + */ +#define TOPO_PGROUP_BINDING "binding" +#define TOPO_BINDING_OCCUPANT "occupant-path" + +/* + * device node information. + */ +typedef struct dev_di_node { + topo_list_t ddn_list; /* list of devices */ + + /* the following two fields are always defined */ + char *ddn_devid; /* devid of device */ + char *ddn_dpath; /* path to devinfo (may be vhci) */ + char **ddn_ppath; /* physical path to device (phci) */ + int ddn_ppath_count; + + char *ddn_lpath; /* logical path (public /dev name) */ + + char *ddn_mfg; /* misc information about device */ + char *ddn_model; + char *ddn_serial; + char *ddn_firm; + char *ddn_cap; + + char **ddn_target_port; + int ddn_target_port_count; +} dev_di_node_t; + struct topo_list; /* Methods shared with the ses module (disk_common.c) */ -extern int disk_list_gather(topo_mod_t *, struct topo_list *); -extern void disk_list_free(topo_mod_t *, struct topo_list *); +extern int dev_list_gather(topo_mod_t *, struct topo_list *); +extern void dev_list_free(topo_mod_t *, struct topo_list *); extern int disk_declare_non_enumerated(topo_mod_t *, tnode_t *, tnode_t **); extern int disk_declare_path(topo_mod_t *, tnode_t *, struct topo_list *, const char *); diff --git a/usr/src/lib/fm/topo/modules/common/disk/disk_common.c b/usr/src/lib/fm/topo/modules/common/disk/disk_common.c index 6780e591f8..c3981783ac 100644 --- a/usr/src/lib/fm/topo/modules/common/disk/disk_common.c +++ b/usr/src/lib/fm/topo/modules/common/disk/disk_common.c @@ -47,39 +47,16 @@ #include <fm/topo_list.h> #include <fm/libdiskstatus.h> #include <sys/fm/protocol.h> +#include <sys/scsi/generic/inquiry.h> #include "disk.h" -/* - * disk node information. - */ -typedef struct disk_di_node { - topo_list_t ddn_list; /* list of disks */ - - /* the following two fields are always defined */ - char *ddn_devid; /* devid of disk */ - char *ddn_dpath; /* path to devinfo (may be vhci) */ - char **ddn_ppath; /* physical path to device (phci) */ - int ddn_ppath_count; - - char *ddn_lpath; /* logical path (public /dev name) */ - - char *ddn_mfg; /* misc information about device */ - char *ddn_model; - char *ddn_serial; - char *ddn_firm; - char *ddn_cap; - - char **ddn_target_port; - int ddn_target_port_count; -} disk_di_node_t; - /* common callback information for di_walk_node() and di_devlink_walk */ typedef struct disk_cbdata { topo_mod_t *dcb_mod; topo_list_t *dcb_list; di_devlink_handle_t dcb_devhdl; - disk_di_node_t *dcb_dnode; /* for di_devlink_walk only */ + dev_di_node_t *dcb_dnode; /* for di_devlink_walk only */ } disk_cbdata_t; /* @@ -130,7 +107,7 @@ static const topo_pgroup_info_t storage_pgroup = { }; /* - * Set the properties of the disk node, from disk_di_node_t data. + * Set the properties of the disk node, from dev_di_node_t data. * Properties include: * group: protocol properties: resource, asru, label, fru * group: authority properties: product-id, chasis-id, server-id @@ -145,7 +122,7 @@ static const topo_pgroup_info_t storage_pgroup = { */ static int disk_set_props(topo_mod_t *mod, tnode_t *parent, - tnode_t *dtn, disk_di_node_t *dnode) + tnode_t *dtn, dev_di_node_t *dnode) { nvlist_t *asru = NULL; char *label = NULL; @@ -354,7 +331,7 @@ disk_auth_clean(topo_mod_t *mod, const char *str) /* create the disk topo node */ static int disk_tnode_create(topo_mod_t *mod, tnode_t *parent, - disk_di_node_t *dnode, const char *name, topo_instance_t i, tnode_t **rval) + dev_di_node_t *dnode, const char *name, topo_instance_t i, tnode_t **rval) { int len; nvlist_t *fmri; @@ -431,7 +408,7 @@ disk_tnode_create(topo_mod_t *mod, tnode_t *parent, } static int -disk_declare(topo_mod_t *mod, tnode_t *parent, disk_di_node_t *dnode, +disk_declare(topo_mod_t *mod, tnode_t *parent, dev_di_node_t *dnode, tnode_t **childp) { tnode_t *dtn = NULL; @@ -464,7 +441,7 @@ int disk_declare_path(topo_mod_t *mod, tnode_t *parent, topo_list_t *listp, const char *path) { - disk_di_node_t *dnode; + dev_di_node_t *dnode; int i; /* @@ -491,7 +468,7 @@ int disk_declare_addr(topo_mod_t *mod, tnode_t *parent, topo_list_t *listp, const char *addr, tnode_t **childp) { - disk_di_node_t *dnode; + dev_di_node_t *dnode; int i; /* Check for match using addr. */ @@ -524,13 +501,13 @@ disk_declare_non_enumerated(topo_mod_t *mod, tnode_t *parent, tnode_t **childp) return (disk_declare(mod, parent, NULL, childp)); } -/* di_devlink callback for disk_di_node_add */ +/* di_devlink callback for dev_di_node_add */ static int disk_devlink_callback(di_devlink_t dl, void *arg) { disk_cbdata_t *cbp = (disk_cbdata_t *)arg; topo_mod_t *mod = cbp->dcb_mod; - disk_di_node_t *dnode = cbp->dcb_dnode; + dev_di_node_t *dnode = cbp->dcb_dnode; const char *devpath; char *ctds, *slice; @@ -552,7 +529,7 @@ disk_devlink_callback(di_devlink_t dl, void *arg) } static void -disk_di_node_free(topo_mod_t *mod, disk_di_node_t *dnode) +dev_di_node_free(topo_mod_t *mod, dev_di_node_t *dnode) { int i; @@ -578,14 +555,14 @@ disk_di_node_free(topo_mod_t *mod, disk_di_node_t *dnode) dnode->ddn_target_port_count * sizeof (uintptr_t)); /* free self */ - topo_mod_free(mod, dnode, sizeof (disk_di_node_t)); + topo_mod_free(mod, dnode, sizeof (dev_di_node_t)); } static int -disk_di_node_add(di_node_t node, char *devid, disk_cbdata_t *cbp) +dev_di_node_add(di_node_t node, char *devid, disk_cbdata_t *cbp) { topo_mod_t *mod = cbp->dcb_mod; - disk_di_node_t *dnode; + dev_di_node_t *dnode; di_path_t pnode; char *path; int mlen; @@ -598,6 +575,7 @@ disk_di_node_add(di_node_t node, char *devid, disk_cbdata_t *cbp) uint_t dblksize; char lentry[MAXPATHLEN]; int pathcount, portcount; + int *inq_dtype, itype; int ret, i; if (devid) { @@ -610,14 +588,14 @@ disk_di_node_add(di_node_t node, char *devid, disk_cbdata_t *cbp) dnode != NULL; dnode = topo_list_next(dnode)) { if (dnode->ddn_devid && devid_str_compare(dnode->ddn_devid, devid) == 0) { - topo_mod_dprintf(mod, "disk_di_node_add: " + topo_mod_dprintf(mod, "dev_di_node_add: " "already there %s\n", devid); return (0); } } } - if ((dnode = topo_mod_zalloc(mod, sizeof (disk_di_node_t))) == NULL) + if ((dnode = topo_mod_zalloc(mod, sizeof (dev_di_node_t))) == NULL) return (-1); if (devid) { @@ -740,24 +718,32 @@ disk_di_node_add(di_node_t node, char *devid, disk_cbdata_t *cbp) } /* - * Find the public /dev name by adding a minor name and using + * Find the public /dev name for a disk by adding a minor name and using * di_devlink interface for reverse translation (use devinfo path). */ - mlen = strlen(dnode->ddn_dpath) + strlen(extn) + 1; - if ((minorpath = topo_mod_alloc(mod, mlen)) == NULL) - goto error; - (void) snprintf(minorpath, mlen, "%s%s", dnode->ddn_dpath, extn); - cbp->dcb_dnode = dnode; - (void) di_devlink_walk(cbp->dcb_devhdl, "^dsk/", minorpath, - DI_PRIMARY_LINK, cbp, disk_devlink_callback); - topo_mod_free(mod, minorpath, mlen); - if (dnode->ddn_lpath == NULL) { - topo_mod_dprintf(mod, "disk_di_node_add: " - "failed to determine logical path"); - goto error; + if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "inquiry-device-type", + &inq_dtype) > 0) { + itype = (*inq_dtype) & DTYPE_MASK; + if (itype == DTYPE_DIRECT) { + mlen = strlen(dnode->ddn_dpath) + strlen(extn) + 1; + if ((minorpath = topo_mod_alloc(mod, mlen)) == NULL) + goto error; + (void) snprintf(minorpath, mlen, "%s%s", + dnode->ddn_dpath, extn); + cbp->dcb_dnode = dnode; + (void) di_devlink_walk(cbp->dcb_devhdl, "^dsk/", + minorpath, DI_PRIMARY_LINK, cbp, + disk_devlink_callback); + topo_mod_free(mod, minorpath, mlen); + if (dnode->ddn_lpath == NULL) { + topo_mod_dprintf(mod, "dev_di_node_add: " + "failed to determine logical path"); + goto error; + } + } } - /* cache various bits of optional information about the disk */ + /* cache various bits of optional information about the device. */ if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, INQUIRY_VENDOR_ID, &s) > 0) { if ((dnode->ddn_mfg = disk_trim_whitespace(mod, s)) == NULL) @@ -796,7 +782,7 @@ disk_di_node_add(di_node_t node, char *devid, disk_cbdata_t *cbp) goto error; } - topo_mod_dprintf(mod, "disk_di_node_add: " + topo_mod_dprintf(mod, "dev_di_node_add: " "adding %s\n", devid ? dnode->ddn_devid : "NULL devid"); topo_mod_dprintf(mod, " " " %s\n", dnode->ddn_dpath); @@ -808,13 +794,14 @@ disk_di_node_add(di_node_t node, char *devid, disk_cbdata_t *cbp) return (0); error: - disk_di_node_free(mod, dnode); + dev_di_node_free(mod, dnode); return (-1); } + /* di_walk_node callback for disk_list_gather */ static int -disk_walk_di_nodes(di_node_t node, void *arg) +dev_walk_di_nodes(di_node_t node, void *arg) { char *devidstr = NULL; char *s; @@ -832,13 +819,13 @@ disk_walk_di_nodes(di_node_t node, void *arg) DEVID_PROP_NAME, &devidstr); /* create/find the devid scsi topology node */ - (void) disk_di_node_add(node, devidstr, arg); + (void) dev_di_node_add(node, devidstr, arg); return (DI_WALK_CONTINUE); } int -disk_list_gather(topo_mod_t *mod, topo_list_t *listp) +dev_list_gather(topo_mod_t *mod, topo_list_t *listp) { di_node_t devtree; di_devlink_handle_t devhdl; @@ -862,7 +849,7 @@ disk_list_gather(topo_mod_t *mod, topo_list_t *listp) /* walk the devinfo snapshot looking for disk nodes */ (void) di_walk_node(devtree, DI_WALK_CLDFIRST, &dcb, - disk_walk_di_nodes); + dev_walk_di_nodes); (void) di_devlink_fini(&devhdl); @@ -870,14 +857,14 @@ disk_list_gather(topo_mod_t *mod, topo_list_t *listp) } void -disk_list_free(topo_mod_t *mod, topo_list_t *listp) +dev_list_free(topo_mod_t *mod, topo_list_t *listp) { - disk_di_node_t *dnode; + dev_di_node_t *dnode; while ((dnode = topo_list_next(listp)) != NULL) { /* order of delete/free is important */ topo_list_delete(listp, dnode); - disk_di_node_free(mod, dnode); + dev_di_node_free(mod, dnode); } } diff --git a/usr/src/lib/fm/topo/modules/common/pcibus/did_props.h b/usr/src/lib/fm/topo/modules/common/pcibus/did_props.h index 20ae8a5b3e..5f01b18b69 100644 --- a/usr/src/lib/fm/topo/modules/common/pcibus/did_props.h +++ b/usr/src/lib/fm/topo/modules/common/pcibus/did_props.h @@ -20,8 +20,7 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _DID_PROPS_H @@ -68,6 +67,8 @@ typedef struct txprop { #define DI_PHYSPROP "physical-slot#" #define DI_SLOTPROP "slot-names" #define DI_AADDRPROP "assigned-addresses" +#define DI_RECEPTACLE_PHYMASK "receptacle-pm" +#define DI_RECEPTACLE_LABEL "receptacle-label" extern int did_props_set(tnode_t *, did_t *, txprop_t[], int); extern tnode_t *find_predecessor(tnode_t *, char *); diff --git a/usr/src/lib/fm/topo/modules/common/pcibus/pcibus.c b/usr/src/lib/fm/topo/modules/common/pcibus/pcibus.c index b97ac2656c..1f3ba4478e 100644 --- a/usr/src/lib/fm/topo/modules/common/pcibus/pcibus.c +++ b/usr/src/lib/fm/topo/modules/common/pcibus/pcibus.c @@ -428,7 +428,8 @@ static void declare_dev_and_fn(topo_mod_t *mod, tnode_t *bus, tnode_t **dev, di_node_t din, int board, int bridge, int rc, int devno, int fnno, int depth) { - int dcnt = 0; + int dcnt = 0, rcnt; + char *propstr; tnode_t *fn; uint_t class, subclass; uint_t vid, did; @@ -522,6 +523,28 @@ declare_dev_and_fn(topo_mod_t *mod, tnode_t *bus, tnode_t **dev, di_node_t din, } } } + } else if (class == PCI_CLASS_MASS) { + di_node_t cn; + int niports = 0; + extern void pci_iports_instantiate(topo_mod_t *, tnode_t *, + di_node_t, int); + extern void pci_receptacle_instantiate(topo_mod_t *, tnode_t *, + di_node_t); + + for (cn = di_child_node(din); cn != DI_NODE_NIL; + cn = di_sibling_node(cn)) { + if (strcmp(di_node_name(cn), IPORT) == 0) + niports++; + } + if (niports > 0) + pci_iports_instantiate(mod, fn, din, niports); + + if ((rcnt = di_prop_lookup_strings(DDI_DEV_T_ANY, din, + DI_RECEPTACLE_PHYMASK, &propstr)) > 0) { + if (topo_node_range_create(mod, fn, RECEPTACLE, 0, + rcnt) >= 0) + pci_receptacle_instantiate(mod, fn, din); + } } } diff --git a/usr/src/lib/fm/topo/modules/common/pcibus/pcibus_hba.c b/usr/src/lib/fm/topo/modules/common/pcibus/pcibus_hba.c new file mode 100644 index 0000000000..75cb67dd13 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/common/pcibus/pcibus_hba.c @@ -0,0 +1,317 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#include <sys/fm/protocol.h> +#include <strings.h> +#include <fm/topo_mod.h> +#include <sys/scsi/impl/inquiry.h> +#include <sys/scsi/impl/scsi_sas.h> +#include <sys/scsi/scsi_address.h> +#include <did_props.h> + +static const topo_pgroup_info_t storage_pgroup = + { TOPO_PGROUP_STORAGE, TOPO_STABILITY_PRIVATE, + TOPO_STABILITY_PRIVATE, 1 }; + +void +pci_di_prop_set(tnode_t *tn, di_node_t din, char *dpnm, char *tpnm) +{ + int err; + char *tmpbuf; + + if (di_prop_lookup_strings(DDI_DEV_T_ANY, din, dpnm, &tmpbuf) == 1) + (void) topo_prop_set_string(tn, TOPO_PGROUP_STORAGE, tpnm, + TOPO_PROP_IMMUTABLE, tmpbuf, &err); +} + +void +pci_pi_prop_set(tnode_t *tn, di_path_t din, char *dpnm, char *tpnm) +{ + int err; + char *tmpbuf; + + if (di_path_prop_lookup_strings(din, dpnm, &tmpbuf) == 1) + (void) topo_prop_set_string(tn, TOPO_PGROUP_STORAGE, tpnm, + TOPO_PROP_IMMUTABLE, tmpbuf, &err); +} + +static void +pci_scsi_device_create(topo_mod_t *mod, nvlist_t *auth, tnode_t *parent, + di_node_t cn, int instance, di_path_t pi) +{ + tnode_t *child; + nvlist_t *fmri; + int e, *val; + int64_t *val64; + + fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, SCSI_DEVICE, + instance, NULL, auth, NULL, NULL, NULL); + if (fmri == NULL) + return; + child = topo_node_bind(mod, parent, SCSI_DEVICE, instance, fmri); + nvlist_free(fmri); + if (child == NULL) + return; + if (topo_pgroup_create(child, &storage_pgroup, &e) < 0) + return; + if (pi != NULL) { + pci_pi_prop_set(child, pi, SCSI_ADDR_PROP_TARGET_PORT, + TOPO_STORAGE_TARGET_PORT); + pci_pi_prop_set(child, pi, SCSI_ADDR_PROP_ATTACHED_PORT, + TOPO_STORAGE_ATTACHED_PORT); + pci_pi_prop_set(child, pi, SCSI_ADDR_PROP_TARGET_PORT_PM, + TOPO_STORAGE_TARGET_PORT_PM); + pci_pi_prop_set(child, pi, SCSI_ADDR_PROP_ATTACHED_PORT_PM, + TOPO_STORAGE_ATTACHED_PORT_PM); + if (di_path_prop_lookup_int64s(pi, + SCSI_ADDR_PROP_LUN64, &val64) == 1) + (void) topo_prop_set_int64(child, TOPO_PGROUP_STORAGE, + TOPO_STORAGE_LUN64, TOPO_PROP_IMMUTABLE, *val64, + &e); + } else { + pci_di_prop_set(child, cn, SCSI_ADDR_PROP_TARGET_PORT, + TOPO_STORAGE_TARGET_PORT); + pci_di_prop_set(child, cn, SCSI_ADDR_PROP_ATTACHED_PORT, + TOPO_STORAGE_ATTACHED_PORT); + pci_di_prop_set(child, cn, SCSI_ADDR_PROP_TARGET_PORT_PM, + TOPO_STORAGE_TARGET_PORT_PM); + pci_di_prop_set(child, cn, SCSI_ADDR_PROP_ATTACHED_PORT_PM, + TOPO_STORAGE_ATTACHED_PORT_PM); + if (di_prop_lookup_int64(DDI_DEV_T_ANY, cn, + SCSI_ADDR_PROP_LUN64, &val64) == 1) + (void) topo_prop_set_int64(child, TOPO_PGROUP_STORAGE, + TOPO_STORAGE_LUN64, TOPO_PROP_IMMUTABLE, *val64, + &e); + } + pci_di_prop_set(child, cn, DEVID_PROP_NAME, TOPO_STORAGE_DEVID); + pci_di_prop_set(child, cn, INQUIRY_VENDOR_ID, + TOPO_STORAGE_MANUFACTURER); + pci_di_prop_set(child, cn, INQUIRY_PRODUCT_ID, TOPO_STORAGE_MODEL); + pci_di_prop_set(child, cn, INQUIRY_REVISION_ID, + TOPO_STORAGE_FIRMWARE_REV); + if (di_prop_lookup_ints(DDI_DEV_T_ANY, cn, + INQUIRY_DEVICE_TYPE, &val) == 1) + (void) topo_prop_set_int32(child, TOPO_PGROUP_STORAGE, + TOPO_STORAGE_DEVICE_TYPE, TOPO_PROP_IMMUTABLE, *val, &e); +} + +static void +pci_smp_device_create(topo_mod_t *mod, nvlist_t *auth, tnode_t *parent, + di_node_t cn, int instance) +{ + tnode_t *child; + nvlist_t *fmri; + int e; + + fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, SMP_DEVICE, + instance, NULL, auth, NULL, NULL, NULL); + if (fmri == NULL) + return; + child = topo_node_bind(mod, parent, SMP_DEVICE, instance, fmri); + nvlist_free(fmri); + if (child == NULL) + return; + if (topo_pgroup_create(child, &storage_pgroup, &e) < 0) + return; + pci_di_prop_set(child, cn, SCSI_ADDR_PROP_TARGET_PORT, + TOPO_STORAGE_TARGET_PORT); + pci_di_prop_set(child, cn, SCSI_ADDR_PROP_ATTACHED_PORT, + TOPO_STORAGE_ATTACHED_PORT); + pci_di_prop_set(child, cn, SCSI_ADDR_PROP_TARGET_PORT_PM, + TOPO_STORAGE_TARGET_PORT_PM); + pci_di_prop_set(child, cn, SCSI_ADDR_PROP_ATTACHED_PORT_PM, + TOPO_STORAGE_ATTACHED_PORT_PM); + pci_di_prop_set(child, cn, DEVID_PROP_NAME, TOPO_STORAGE_DEVID); + pci_di_prop_set(child, cn, INQUIRY_VENDOR_ID, + TOPO_STORAGE_MANUFACTURER); + pci_di_prop_set(child, cn, INQUIRY_PRODUCT_ID, TOPO_STORAGE_MODEL); + pci_di_prop_set(child, cn, INQUIRY_REVISION_ID, + TOPO_STORAGE_FIRMWARE_REV); +} + +static tnode_t * +pci_iport_device_create(topo_mod_t *mod, nvlist_t *auth, tnode_t *parent, + di_node_t cn, int instance) +{ + tnode_t *child; + nvlist_t *fmri; + int e; + + fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, IPORT, + instance, NULL, auth, NULL, NULL, NULL); + if (fmri == NULL) + return (NULL); + child = topo_node_bind(mod, parent, IPORT, instance, fmri); + nvlist_free(fmri); + if (child == NULL) + return (NULL); + if (topo_pgroup_create(child, &storage_pgroup, &e) < 0) + return (child); + pci_di_prop_set(child, cn, SCSI_ADDR_PROP_INITIATOR_PORT, + TOPO_STORAGE_INITIATOR_PORT); + (void) topo_prop_set_string(child, TOPO_PGROUP_STORAGE, + TOPO_STORAGE_INITIATOR_PORT_PM, TOPO_PROP_IMMUTABLE, + di_bus_addr(cn), &e); + return (child); +} + +void +pci_iports_instantiate(topo_mod_t *mod, tnode_t *parent, di_node_t pn, + int niports) +{ + di_node_t cn, smp, sd; + di_path_t pi; + tnode_t *iport; + int i, j; + nvlist_t *auth; + + if (topo_node_range_create(mod, parent, IPORT, 0, niports) < 0) + return; + auth = topo_mod_auth(mod, parent); + for (i = 0, cn = di_child_node(pn); cn != DI_NODE_NIL; + cn = di_sibling_node(cn)) { + /* + * First create any iport nodes. + */ + if (strcmp(di_node_name(cn), "iport") != 0) + continue; + iport = pci_iport_device_create(mod, auth, parent, cn, i++); + if (iport == NULL) + continue; + + /* + * Now create any scsi-device nodes. + */ + for (j = 0, sd = di_child_node(cn); sd != DI_NODE_NIL; + sd = di_sibling_node(sd)) + if (strcmp(di_node_name(sd), "smp") != 0) + j++; + for (pi = di_path_phci_next_path(cn, DI_PATH_NIL); + pi != DI_PATH_NIL; pi = di_path_phci_next_path(cn, pi)) + if (strcmp(di_node_name(di_path_client_node(pi)), + "smp") != 0) + j++; + if (topo_node_range_create(mod, iport, SCSI_DEVICE, 0, j) < 0) + continue; + for (j = 0, sd = di_child_node(cn); sd != DI_NODE_NIL; + sd = di_sibling_node(sd)) + if (strcmp(di_node_name(sd), "smp") != 0) + pci_scsi_device_create(mod, auth, iport, sd, + j++, NULL); + for (pi = di_path_phci_next_path(cn, DI_PATH_NIL); + pi != DI_PATH_NIL; pi = di_path_phci_next_path(cn, pi)) + if (strcmp(di_node_name(di_path_client_node(pi)), + "smp") != 0) + pci_scsi_device_create(mod, auth, iport, + di_path_client_node(pi), j++, pi); + + /* + * Now create any smp-device nodes. + */ + for (j = 0, smp = di_child_node(cn); smp != DI_NODE_NIL; + smp = di_sibling_node(smp)) + if (strcmp(di_node_name(smp), "smp") == 0) + j++; + if (topo_node_range_create(mod, iport, SMP_DEVICE, 0, j) < 0) + continue; + for (j = 0, smp = di_child_node(cn); smp != DI_NODE_NIL; + smp = di_sibling_node(smp)) + if (strcmp(di_node_name(smp), "smp") == 0) + pci_smp_device_create(mod, auth, iport, smp, + j++); + } + nvlist_free(auth); +} + +void +pci_receptacle_instantiate(topo_mod_t *mod, tnode_t *parent, di_node_t pnode) +{ + int err, i, rcnt, lcnt; + char *propstrpm, *propstrlabel, *pm, *label; + nvlist_t *fmri, *auth; + tnode_t *recep; + + rcnt = di_prop_lookup_strings(DDI_DEV_T_ANY, pnode, + DI_RECEPTACLE_PHYMASK, &propstrpm); + if ((lcnt = di_prop_lookup_strings(DDI_DEV_T_ANY, pnode, + DI_RECEPTACLE_LABEL, &propstrlabel)) <= 0) { + topo_mod_dprintf(mod, + "pci_receptacle_instanciate: rececptacle label not " + "found for the pci function node.\n"); + return; + } + + if (rcnt != lcnt) { + topo_mod_dprintf(mod, + "pci_receptacle_instantiate: rececptacle label count %d " + "doesn match with phy mask count %d\n", lcnt, rcnt); + } + + label = propstrlabel; + pm = propstrpm; + auth = topo_mod_auth(mod, parent); + for (i = 0; i < rcnt; i++) { + fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, + RECEPTACLE, i, NULL, auth, NULL, NULL, NULL); + if (fmri == NULL) { + topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s", + topo_mod_errmsg(mod)); + continue; + } + recep = topo_node_bind(mod, parent, RECEPTACLE, i, fmri); + nvlist_free(fmri); + if (recep == NULL) { + topo_mod_dprintf(mod, "topo_node_bind() failed: %s", + topo_mod_errmsg(mod)); + continue; + } + + if (label) { + if (topo_node_label_set(recep, label, &err) < 0) { + topo_mod_dprintf(mod, + "topo_receptacle_instantiate: " + "topo_node_label_set error(%s)\n", + topo_strerror(err)); + } + if (i < lcnt) { + label = label + strlen(label) + 1; + } else { + label = NULL; + } + } + + if (topo_pgroup_create(recep, &storage_pgroup, &err) < 0) { + topo_mod_dprintf(mod, "ses_set_expander_props: " + "create storage error %s\n", topo_strerror(err)); + continue; + } + (void) topo_prop_set_string(recep, TOPO_PGROUP_STORAGE, + TOPO_STORAGE_SAS_PHY_MASK, + TOPO_PROP_IMMUTABLE, pm, &err); + pm = pm + strlen(pm) + 1; + } + + nvlist_free(auth); +} diff --git a/usr/src/lib/fm/topo/modules/common/ses/ses.c b/usr/src/lib/fm/topo/modules/common/ses/ses.c index 59e7efd6d1..4edc712c6b 100644 --- a/usr/src/lib/fm/topo/modules/common/ses/ses.c +++ b/usr/src/lib/fm/topo/modules/common/ses/ses.c @@ -30,17 +30,22 @@ #include <inttypes.h> #include <pthread.h> #include <strings.h> +#include <string.h> #include <unistd.h> #include <sys/dkio.h> #include <sys/fm/protocol.h> #include <sys/libdevid.h> #include <sys/scsi/scsi_types.h> +#include <sys/byteorder.h> #include "disk.h" #include "ses.h" #define SES_VERSION 1 +#define SES_STARTING_SUBCHASSIS 256 /* valid subchassis IDs are uint8_t */ +#define NO_SUBCHASSIS ((uint64_t)-1) + static int ses_snap_freq = 250; /* in milliseconds */ #define SES_STATUS_UNAVAIL(s) \ @@ -74,17 +79,17 @@ typedef struct ses_enum_chassis { topo_list_t sec_nodes; topo_list_t sec_targets; const char *sec_csn; - const char *sec_lid; ses_node_t *sec_enclosure; ses_enum_target_t *sec_target; topo_instance_t sec_instance; topo_instance_t sec_scinstance; + topo_instance_t sec_maxinstance; boolean_t sec_hasdev; boolean_t sec_internal; } ses_enum_chassis_t; typedef struct ses_enum_data { - topo_list_t sed_disks; + topo_list_t sed_devs; topo_list_t sed_chassis; ses_enum_chassis_t *sed_current; ses_enum_target_t *sed_target; @@ -94,6 +99,55 @@ typedef struct ses_enum_data { topo_instance_t sed_instance; } ses_enum_data_t; +typedef struct sas_connector_phy_data { + uint64_t index; + uint64_t phy_mask; +} sas_connector_phy_data_t; + +typedef struct sas_connector_type { + uint64_t type; + char *name; +} sas_connector_type_t; + +static const sas_connector_type_t sas_connector_type_list[] = { + { 0x0, "Information unknown" }, + { 0x1, "External SAS 4x receptacle (see SAS-2 and SFF-8470)" }, + { 0x2, "Exteranl Mini SAS 4x receptacle (see SAS-2 and SFF-8088)" }, + { 0xF, "Vendor-specific external connector" }, + { 0x10, "Internal wide SAS 4i plug (see SAS-2 and SFF-8484)" }, + { 0x11, + "Internal wide Mini SAS 4i receptacle (see SAS-2 and SFF-8087)" }, + { 0x20, "Internal SAS Drive receptacle (see SAS-2 and SFF-8482)" }, + { 0x21, "Internal SATA host plug (see SAS-2 and SATA-2)" }, + { 0x22, "Internal SAS Drive plug (see SAS-2 and SFF-8482)" }, + { 0x23, "Internal SATA device plug (see SAS-2 and SATA-2)" }, + { 0x2F, "Internal SAS virtual connector" }, + { 0x3F, "Vendor-specific internal connector" }, + { 0x70, "Other Vendor-specific connector" }, + { 0x71, "Other Vendor-specific connector" }, + { 0x72, "Other Vendor-specific connector" }, + { 0x73, "Other Vendor-specific connector" }, + { 0x74, "Other Vendor-specific connector" }, + { 0x75, "Other Vendor-specific connector" }, + { 0x76, "Other Vendor-specific connector" }, + { 0x77, "Other Vendor-specific connector" }, + { 0x78, "Other Vendor-specific connector" }, + { 0x79, "Other Vendor-specific connector" }, + { 0x7A, "Other Vendor-specific connector" }, + { 0x7B, "Other Vendor-specific connector" }, + { 0x7C, "Other Vendor-specific connector" }, + { 0x7D, "Other Vendor-specific connector" }, + { 0x7E, "Other Vendor-specific connector" }, + { 0x7F, "Other Vendor-specific connector" }, + { 0x80, "Not Defined" } +}; + +#define SAS_CONNECTOR_TYPE_CODE_NOT_DEFINED 0x80 +#define SAS_CONNECTOR_TYPE_NOT_DEFINED \ + "Connector type not definedi by SES-2 standard" +#define SAS_CONNECTOR_TYPE_RESERVED \ + "Connector type reserved by SES-2 standard" + typedef enum { SES_NEW_CHASSIS = 0x1, SES_NEW_SUBCHASSIS = 0x2, @@ -101,6 +155,20 @@ typedef enum { SES_DUP_SUBCHASSIS = 0x8 } ses_chassis_type_e; +static const topo_pgroup_info_t io_pgroup = { + TOPO_PGROUP_IO, + TOPO_STABILITY_PRIVATE, + TOPO_STABILITY_PRIVATE, + 1 +}; + +static const topo_pgroup_info_t storage_pgroup = { + TOPO_PGROUP_STORAGE, + TOPO_STABILITY_PRIVATE, + TOPO_STABILITY_PRIVATE, + 1 +}; + static int ses_present(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, nvlist_t **); static int ses_contains(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, @@ -180,7 +248,7 @@ ses_data_free(ses_enum_data_t *sdp, ses_enum_chassis_t *pcp) } if (pcp == NULL) { - disk_list_free(mod, &sdp->sed_disks); + dev_list_free(mod, &sdp->sed_devs); topo_mod_free(mod, sdp, sizeof (ses_enum_data_t)); } } @@ -401,13 +469,15 @@ ses_present(topo_mod_t *mod, tnode_t *tn, topo_version_t version, } /* - * Sets standard properties for a ses node (enclosure or bay). This includes - * setting the FRU to be the same as the resource, as well as setting the - * authority information. + * Sets standard properties for a ses node (enclosure, bay, controller + * or expander). + * This includes setting the FRU, as well as setting the + * authority information. When the fru topo node(frutn) is not NULL + * its resouce should be used as FRU. */ static int -ses_set_standard_props(topo_mod_t *mod, tnode_t *tn, nvlist_t *auth, - uint64_t nodeid, const char *path) +ses_set_standard_props(topo_mod_t *mod, tnode_t *frutn, tnode_t *tn, + nvlist_t *auth, uint64_t nodeid, const char *path) { int err; char *product, *chassis; @@ -440,11 +510,20 @@ ses_set_standard_props(topo_mod_t *mod, tnode_t *tn, nvlist_t *auth, /* * Copy the resource and set that as the FRU. */ - if (topo_node_resource(tn, &fmri, &err) != 0) { - topo_mod_dprintf(mod, - "topo_node_resource() failed : %s\n", - topo_strerror(err)); - return (topo_mod_seterrno(mod, err)); + if (frutn != NULL) { + if (topo_node_resource(frutn, &fmri, &err) != 0) { + topo_mod_dprintf(mod, + "topo_node_resource() failed : %s\n", + topo_strerror(err)); + return (topo_mod_seterrno(mod, err)); + } + } else { + if (topo_node_resource(tn, &fmri, &err) != 0) { + topo_mod_dprintf(mod, + "topo_node_resource() failed : %s\n", + topo_strerror(err)); + return (topo_mod_seterrno(mod, err)); + } } if (topo_node_fru_set(tn, fmri, 0, &err) != 0) { @@ -518,7 +597,8 @@ ses_create_disk(ses_enum_data_t *sdp, tnode_t *pnode, nvlist_t *props) if (nvlist_lookup_uint64(props, SES_PROP_STATUS_CODE, &status) != 0) return (0); - if (status != SES_ESC_OK && + if (status != SES_ESC_UNSUPPORTED && + status != SES_ESC_OK && status != SES_ESC_CRITICAL && status != SES_ESC_NONCRITICAL && status != SES_ESC_UNRECOVERABLE && @@ -553,7 +633,7 @@ ses_create_disk(ses_enum_data_t *sdp, tnode_t *pnode, nvlist_t *props) err = 0; for (s = 0; s < nsas; s++) { - ret = disk_declare_addr(mod, pnode, &sdp->sed_disks, paths[s], + ret = disk_declare_addr(mod, pnode, &sdp->sed_devs, paths[s], &child); if (ret == 0) { break; @@ -675,11 +755,11 @@ error: } /* - * Callback to create a basic node (bay, psu, fan, or controller). + * Callback to create a basic node (bay, psu, fan, or controller and expander). */ static int ses_create_generic(ses_enum_data_t *sdp, ses_enum_node_t *snp, - tnode_t *pnode, const char *nodename, const char *labelname) + tnode_t *pnode, const char *nodename, const char *labelname, tnode_t **node) { ses_node_t *np = snp->sen_node; ses_node_t *parent; @@ -687,7 +767,7 @@ ses_create_generic(ses_enum_data_t *sdp, ses_enum_node_t *snp, topo_mod_t *mod = sdp->sed_mod; nvlist_t *props, *aprops; nvlist_t *auth = NULL, *fmri = NULL; - tnode_t *tn; + tnode_t *tn = NULL, *frutn = NULL; char label[128]; int err; char *part = NULL, *serial = NULL, *revision = NULL; @@ -758,8 +838,8 @@ ses_create_generic(ses_enum_data_t *sdp, ses_enum_node_t *snp, parent = ses_node_parent(np); aprops = ses_node_props(parent); if (nvlist_lookup_string(aprops, SES_PROP_CLASS_DESCRIPTION, - &desc) == 0 && desc[0] != '\0') - labelname = desc; + &desc) != 0 || desc[0] == '\0') + desc = (char *)labelname; (void) snprintf(label, sizeof (label), "%s %llu", desc, instance); desc = label; @@ -768,11 +848,21 @@ ses_create_generic(ses_enum_data_t *sdp, ses_enum_node_t *snp, if (topo_node_label_set(tn, desc, &err) != 0) goto error; - if (ses_set_standard_props(mod, tn, NULL, ses_node_id(np), + /* + * For an expander node, set the FRU to its parent(controller). + * For a connector node, set the FRU to its grand parent(controller). + */ + if (strcmp(nodename, SASEXPANDER) == 0) { + frutn = pnode; + } else if (strcmp(nodename, RECEPTACLE) == 0) { + frutn = topo_node_parent(pnode); + } + + if (ses_set_standard_props(mod, frutn, tn, NULL, ses_node_id(np), snp->sen_target->set_devpath) != 0) goto error; - if (strcmp(nodename, "bay") == 0) { + if (strcmp(nodename, BAY) == 0) { if (ses_add_bay_props(mod, tn, snp) != 0) goto error; @@ -785,11 +875,15 @@ ses_create_generic(ses_enum_data_t *sdp, ses_enum_node_t *snp, topo_mod_errmsg(mod)); goto error; } - } else { + } else if ((strcmp(nodename, FAN) == 0) || + (strcmp(nodename, PSU) == 0) || + (strcmp(nodename, CONTROLLER) == 0)) { /* * Only fan, psu, and controller nodes have a 'present' method. * Bay nodes are always present, and disk nodes are present by - * virtue of being enumerated. + * virtue of being enumerated and SAS expander nodes and + * SAS connector nodes are also always present once + * the parent controller is found. */ if (topo_method_register(mod, tn, ses_component_methods) != 0) { topo_mod_dprintf(mod, @@ -805,6 +899,189 @@ ses_create_generic(ses_enum_data_t *sdp, ses_enum_node_t *snp, nvlist_free(auth); nvlist_free(fmri); + if (node != NULL) *node = tn; + return (0); + +error: + nvlist_free(auth); + nvlist_free(fmri); + return (-1); +} + +/* + * Create SAS expander specific props. + */ +/*ARGSUSED*/ +static int +ses_set_expander_props(ses_enum_data_t *sdp, ses_enum_node_t *snp, + tnode_t *ptnode, tnode_t *tnode, int *phycount, int64_t *connlist) +{ + ses_node_t *np = snp->sen_node; + topo_mod_t *mod = sdp->sed_mod; + nvlist_t *auth = NULL, *fmri = NULL; + nvlist_t *props, **phylist; + int err, i; + uint_t pcount; + uint64_t sasaddr, connidx; + char sasaddr_str[17]; + boolean_t found = B_FALSE; + dev_di_node_t *dnode; + + props = ses_node_props(np); + + /* + * the uninstalled expander is not enumerated by checking + * the element status code. No present present' method provided. + */ + /* + * Get the Expander SAS address. It should exist. + */ + if (nvlist_lookup_uint64(props, SES_EXP_PROP_SAS_ADDR, + &sasaddr) != 0) { + topo_mod_dprintf(mod, + "Failed to get prop %s.", SES_EXP_PROP_SAS_ADDR); + goto error; + } + + (void) sprintf(sasaddr_str, "%llx", sasaddr); + + /* search matching dev_di_node. */ + for (dnode = topo_list_next(&sdp->sed_devs); dnode != NULL; + dnode = topo_list_next(dnode)) { + if (strstr(dnode->ddn_dpath, sasaddr_str) != NULL) { + found = B_TRUE; + break; + } + } + + if (!found) { + topo_mod_dprintf(mod, + "ses_set_expander_props: Failed to find matching " + "devinfo node for Exapnder SAS address %s", + SES_EXP_PROP_SAS_ADDR); + /* continue on to get storage group props. */ + } else { + /* create/set the devfs-path and devid in the io group */ + if (topo_pgroup_create(tnode, &io_pgroup, &err) != 0) { + topo_mod_dprintf(mod, "ses_set_expander_props: " + "create io error %s\n", topo_strerror(err)); + goto error; + } else { + if (topo_prop_set_string(tnode, TOPO_PGROUP_IO, + TOPO_IO_DEV_PATH, TOPO_PROP_IMMUTABLE, + dnode->ddn_dpath, &err) != 0) { + topo_mod_dprintf(mod, "ses_set_expander_props: " + "set dev error %s\n", topo_strerror(err)); + } + if (topo_prop_set_string(tnode, TOPO_PGROUP_IO, + TOPO_IO_DEVID, TOPO_PROP_IMMUTABLE, + dnode->ddn_devid, &err) != 0) { + topo_mod_dprintf(mod, "ses_set_expander_props: " + "set devid error %s\n", topo_strerror(err)); + } + if (dnode->ddn_ppath_count != 0 && + topo_prop_set_string_array(tnode, TOPO_PGROUP_IO, + TOPO_IO_PHYS_PATH, TOPO_PROP_IMMUTABLE, + (const char **)dnode->ddn_ppath, + dnode->ddn_ppath_count, &err) != 0) { + topo_mod_dprintf(mod, "ses_set_expander_props: " + "set phys-path error %s\n", + topo_strerror(err)); + } + } + } + + /* create the storage group */ + if (topo_pgroup_create(tnode, &storage_pgroup, &err) != 0) { + topo_mod_dprintf(mod, "ses_set_expander_props: " + "create storage error %s\n", topo_strerror(err)); + goto error; + } else { + /* set the SAS address prop of the expander. */ + if (topo_prop_set_string(tnode, TOPO_PGROUP_STORAGE, + TOPO_PROP_SAS_ADDR, TOPO_PROP_IMMUTABLE, sasaddr_str, + &err) != 0) { + topo_mod_dprintf(mod, "ses_set_expander_props: " + "set %S error %s\n", TOPO_PROP_SAS_ADDR, + topo_strerror(err)); + } + + /* Get the phy information for the expander */ + if (nvlist_lookup_nvlist_array(props, SES_SAS_PROP_PHYS, + &phylist, &pcount) != 0) { + topo_mod_dprintf(mod, + "Failed to get prop %s.", SES_SAS_PROP_PHYS); + } else { + /* + * For each phy, get the connector element index and + * stores into connector element index array. + */ + *phycount = pcount; + for (i = 0; i < pcount; i++) { + if (nvlist_lookup_uint64(phylist[i], + SES_PROP_CE_IDX, &connidx) == 0) { + if (connidx != 0xff) { + connlist[i] = connidx; + } else { + connlist[i] = -1; + } + } else { + /* Fail to get the index. set to -1. */ + connlist[i] = -1; + } + } + + /* set the phy count prop of the expander. */ + if (topo_prop_set_uint64(tnode, TOPO_PGROUP_STORAGE, + TOPO_PROP_PHY_COUNT, TOPO_PROP_IMMUTABLE, pcount, + &err) != 0) { + topo_mod_dprintf(mod, "ses_set_expander_props: " + "set %S error %s\n", TOPO_PROP_PHY_COUNT, + topo_strerror(err)); + } + + /* + * set the connector element index of + * the expander phys. + */ + } + + /* populate other misc storage group properties */ + if (found) { + if (dnode->ddn_mfg && (topo_prop_set_string(tnode, + TOPO_PGROUP_STORAGE, TOPO_STORAGE_MANUFACTURER, + TOPO_PROP_IMMUTABLE, dnode->ddn_mfg, &err) != 0)) { + topo_mod_dprintf(mod, "ses_set_expander_props: " + "set mfg error %s\n", topo_strerror(err)); + } + + if (dnode->ddn_model && (topo_prop_set_string(tnode, + TOPO_PGROUP_STORAGE, TOPO_STORAGE_MODEL, + TOPO_PROP_IMMUTABLE, + dnode->ddn_model, &err) != 0)) { + topo_mod_dprintf(mod, "ses_set_expander_props: " + "set model error %s\n", topo_strerror(err)); + } + + if (dnode->ddn_serial && (topo_prop_set_string(tnode, + TOPO_PGROUP_STORAGE, TOPO_STORAGE_SERIAL_NUM, + TOPO_PROP_IMMUTABLE, + dnode->ddn_serial, &err) != 0)) { + topo_mod_dprintf(mod, "ses_set_expander_props: " + "set serial error %s\n", + topo_strerror(err)); + } + + if (dnode->ddn_firm && (topo_prop_set_string(tnode, + TOPO_PGROUP_STORAGE, + TOPO_STORAGE_FIRMWARE_REV, TOPO_PROP_IMMUTABLE, + dnode->ddn_firm, &err) != 0)) { + topo_mod_dprintf(mod, "ses_set_expander_props: " + "set firm error %s\n", topo_strerror(err)); + } + } + } + return (0); error: @@ -814,6 +1091,374 @@ error: } /* + * Create SAS expander specific props. + */ +/*ARGSUSED*/ +static int +ses_set_connector_props(ses_enum_data_t *sdp, ses_enum_node_t *snp, + tnode_t *tnode, int64_t phy_mask) +{ + ses_node_t *np = snp->sen_node; + topo_mod_t *mod = sdp->sed_mod; + nvlist_t *props; + int err, i; + uint64_t conntype; + char phymask_str[17], *conntype_str; + boolean_t found; + + props = ses_node_props(np); + + /* + * convert phy mask to string. + */ + (void) snprintf(phymask_str, 17, "%llx", phy_mask); + + /* create the storage group */ + if (topo_pgroup_create(tnode, &storage_pgroup, &err) != 0) { + topo_mod_dprintf(mod, "ses_set_expander_props: " + "create storage error %s\n", topo_strerror(err)); + return (-1); + } else { + /* set the SAS address prop of the expander. */ + if (topo_prop_set_string(tnode, TOPO_PGROUP_STORAGE, + TOPO_STORAGE_SAS_PHY_MASK, TOPO_PROP_IMMUTABLE, + phymask_str, &err) != 0) { + topo_mod_dprintf(mod, "ses_set_expander_props: " + "set %S error %s\n", TOPO_STORAGE_SAS_PHY_MASK, + topo_strerror(err)); + } + + /* Get the connector type information for the expander */ + if (nvlist_lookup_uint64(props, + SES_SC_PROP_CONNECTOR_TYPE, &conntype) != 0) { + topo_mod_dprintf(mod, "Failed to get prop %s.", + TOPO_STORAGE_SAS_PHY_MASK); + } else { + found = B_FALSE; + for (i = 0; ; i++) { + if (sas_connector_type_list[i].type == + SAS_CONNECTOR_TYPE_CODE_NOT_DEFINED) { + break; + } + if (sas_connector_type_list[i].type == + conntype) { + conntype_str = + sas_connector_type_list[i].name; + found = B_TRUE; + break; + } + } + + if (!found) { + if (conntype < + SAS_CONNECTOR_TYPE_CODE_NOT_DEFINED) { + conntype_str = + SAS_CONNECTOR_TYPE_RESERVED; + } else { + conntype_str = + SAS_CONNECTOR_TYPE_NOT_DEFINED; + } + } + + /* set the phy count prop of the expander. */ + if (topo_prop_set_string(tnode, TOPO_PGROUP_STORAGE, + TOPO_STORAGE_SAS_CONNECTOR_TYPE, + TOPO_PROP_IMMUTABLE, conntype_str, &err) != 0) { + topo_mod_dprintf(mod, "ses_set_expander_props: " + "set %S error %s\n", TOPO_PROP_PHY_COUNT, + topo_strerror(err)); + } + } + } + + return (0); +} + +/* + * Instantiate SAS expander nodes for a given ESC Electronics node(controller) + * nodes. + */ +/*ARGSUSED*/ +static int +ses_create_esc_sasspecific(ses_enum_data_t *sdp, ses_enum_node_t *snp, + tnode_t *pnode, ses_enum_chassis_t *cp, + boolean_t dorange) +{ + topo_mod_t *mod = sdp->sed_mod; + tnode_t *exptn, *contn; + boolean_t found; + sas_connector_phy_data_t connectors[64] = {NULL}; + uint64_t max; + ses_enum_node_t *ctlsnp, *xsnp, *consnp; + ses_node_t *np = snp->sen_node; + nvlist_t *props, *psprops; + uint64_t index, psindex, conindex, psstatus, i, j, count; + int64_t cidxlist[256] = {NULL}; + int phycount; + + props = ses_node_props(np); + + if (nvlist_lookup_uint64(props, SES_PROP_ELEMENT_ONLY_INDEX, + &index) != 0) + return (-1); + + /* + * For SES constroller node, check to see if there are + * associated SAS expanders. + */ + found = B_FALSE; + max = 0; + for (ctlsnp = topo_list_next(&cp->sec_nodes); ctlsnp != NULL; + ctlsnp = topo_list_next(ctlsnp)) { + if (ctlsnp->sen_type == SES_ET_SAS_EXPANDER) { + found = B_TRUE; + if (ctlsnp->sen_instance > max) + max = ctlsnp->sen_instance; + } + } + + /* + * No SAS expander found notthing to process. + */ + if (!found) + return (0); + + topo_mod_dprintf(mod, "%s Controller %d: creating " + "%llu %s nodes", cp->sec_csn, index, max + 1, SASEXPANDER); + + /* + * The max number represent the number of elements + * deducted from the highest SES_PROP_ELEMENT_CLASS_INDEX + * of SET_ET_SAS_EXPANDER type element. + * + * There may be multiple ESC Electronics element(controllers) + * within JBOD(typicall two for redundancy) and SAS expander + * elements are associated with only one of them. We are + * still creating the range based max number here. + * That will cover the case that all expanders are associated + * with one SES controller. + */ + if (dorange && topo_node_range_create(mod, pnode, + SASEXPANDER, 0, max) != 0) { + topo_mod_dprintf(mod, + "topo_node_create_range() failed: %s", + topo_mod_errmsg(mod)); + return (-1); + } + + /* + * Search exapnders with the parent index matching with + * ESC Electronics element index. + * Note the index used here is a global index across + * SES elements. + */ + for (xsnp = topo_list_next(&cp->sec_nodes); xsnp != NULL; + xsnp = topo_list_next(xsnp)) { + if (xsnp->sen_type == SES_ET_SAS_EXPANDER) { + /* + * get the parent ESC controller. + */ + psprops = ses_node_props(xsnp->sen_node); + if (nvlist_lookup_uint64(psprops, + SES_PROP_STATUS_CODE, &psstatus) == 0) { + if (psstatus == SES_ESC_NOT_INSTALLED) { + /* + * Not installed. + * Don't create a ndoe. + */ + continue; + } + } else { + /* + * The element should have status code. + * If not there is no way to find + * out if the expander element exist or + * not. + */ + continue; + } + + /* Get the physical parent index to compare. */ + if (nvlist_lookup_uint64(psprops, + LIBSES_PROP_PHYS_PARENT, &psindex) == 0) { + if (index == psindex) { + /* indentation moved forward */ + /* + * Handle basic node information of SAS expander + * element - binding to parent node and + * allocating FMRI... + */ + if (ses_create_generic(sdp, xsnp, pnode, SASEXPANDER, + "SAS-EXPANDER", &exptn) != 0) + continue; + /* + * Now handle SAS expander unique portion of node creation. + * The max nubmer of the phy count is 256 since SES-2 + * defines as 1 byte field. The cidxlist has the same + * number of elements. + * + * We use size 64 array to store the connectors. + * Typically a connectors associated with 4 phys so that + * matches with the max number of connecters associated + * with an expander. + * The phy count goes up to 38 for Sun supported + * JBOD. + */ + memset(cidxlist, 0, sizeof (int64_t) * 64); + if (ses_set_expander_props(sdp, xsnp, pnode, exptn, &phycount, + cidxlist) != 0) { + /* + * error on getting specific prop failed. + * continue on. Note that the node is + * left bound. + */ + continue; + } + + /* + * count represetns the number of connectors discovered so far. + */ + count = 0; + memset(connectors, 0, sizeof (sas_connector_phy_data_t) * 64); + for (i = 0; i < phycount; i++) { + if (cidxlist[i] != -1) { + /* connector index is valid. */ + for (j = 0; j < count; j++) { + if (connectors[j].index == + cidxlist[i]) { + /* + * Just update phy mask. + * The postion for connector + * index lists(cidxlist index) + * is set. + */ + connectors[j].phy_mask = + connectors[j].phy_mask | + (1ULL << i); + break; + } + } + /* + * If j and count matche a new connector + * index is found. + */ + if (j == count) { + /* add a new index and phy mask. */ + connectors[count].index = cidxlist[i]; + connectors[count].phy_mask = + connectors[count].phy_mask | + (1ULL << i); + count++; + } + } + } + + /* + * create range for the connector nodes. + * The class index of the ses connector element + * is set as the instance nubmer for the node. + * Even though one expander may not have all connectors + * are associated with we are creating the range with + * max possible instance number. + */ + found = B_FALSE; + max = 0; + for (consnp = topo_list_next(&cp->sec_nodes); + consnp != NULL; consnp = topo_list_next(consnp)) { + if (consnp->sen_type == SES_ET_SAS_CONNECTOR) { + psprops = ses_node_props(consnp->sen_node); + found = B_TRUE; + if (consnp->sen_instance > max) + max = consnp->sen_instance; + } + } + + /* + * No SAS connector found nothing to process. + */ + if (!found) + return (0); + + if (dorange && topo_node_range_create(mod, exptn, + RECEPTACLE, 0, max) != 0) { + topo_mod_dprintf(mod, + "topo_node_create_range() failed: %s", + topo_mod_errmsg(mod)); + return (-1); + } + + /* search matching connector element using the index. */ + for (i = 0; i < count; i++) { + found = B_FALSE; + for (consnp = topo_list_next(&cp->sec_nodes); + consnp != NULL; consnp = topo_list_next(consnp)) { + if (consnp->sen_type == SES_ET_SAS_CONNECTOR) { + psprops = ses_node_props( + consnp->sen_node); + /* + * Get the physical parent index to + * compare. + * The connector elements are children + * of ESC Electronics element even + * though we enumerate them under + * an expander in libtopo. + */ + if (nvlist_lookup_uint64(psprops, + SES_PROP_ELEMENT_ONLY_INDEX, + &conindex) == 0) { + if (conindex == + connectors[i].index) { + found = B_TRUE; + break; + } + } + } + } + + /* now create a libtopo node. */ + if (found) { + /* Create generic props. */ + if (ses_create_generic(sdp, consnp, exptn, + RECEPTACLE, "RECEPTACLE", &contn) != + 0) { + continue; + } + /* Create connector specific props. */ + if (ses_set_connector_props(sdp, consnp, + contn, connectors[i].phy_mask) != 0) { + continue; + } + } + } + /* end indentation change */ + } + } + } + } + + return (0); +} + +/* + * Instantiate any protocol specific portion of a node. + */ +/*ARGSUSED*/ +static int +ses_create_protocol_specific(ses_enum_data_t *sdp, ses_enum_node_t *snp, + tnode_t *pnode, uint64_t type, ses_enum_chassis_t *cp, + boolean_t dorange) +{ + + if (type == SES_ET_ESC_ELECTRONICS) { + /* create SAS specific children(expanders and connectors. */ + return (ses_create_esc_sasspecific(sdp, snp, pnode, cp, + dorange)); + } + + return (0); +} + +/* * Instantiate any children of a given type. */ static int @@ -825,6 +1470,7 @@ ses_create_children(ses_enum_data_t *sdp, tnode_t *pnode, uint64_t type, boolean_t found; uint64_t max; ses_enum_node_t *snp; + tnode_t *tn; /* * First go through and count how many matching nodes we have. @@ -864,8 +1510,22 @@ ses_create_children(ses_enum_data_t *sdp, tnode_t *pnode, uint64_t type, snp = topo_list_next(snp)) { if (snp->sen_type == type) { if (ses_create_generic(sdp, snp, pnode, - nodename, defaultlabel) != 0) + nodename, defaultlabel, &tn) != 0) return (-1); + /* + * For some SES element there may be protocol specific + * information to process. Here we are processing + * the association between enclosure controller and + * SAS expanders. + */ + if (type == SES_ET_ESC_ELECTRONICS) { + /* create SAS expander node */ + if (ses_create_protocol_specific(sdp, snp, + tn, type, cp, dorange) != 0) { + return (-1); + } + } + } } @@ -883,7 +1543,6 @@ ses_create_subchassis(ses_enum_data_t *sdp, tnode_t *pnode, tnode_t *tn; nvlist_t *props; nvlist_t *auth = NULL, *fmri = NULL; - char *part = NULL, *revision = NULL; uint64_t instance = scp->sec_instance; char *desc; char label[128]; @@ -905,8 +1564,8 @@ ses_create_subchassis(ses_enum_data_t *sdp, tnode_t *pnode, * piece of code will need to be updated via an RFE. */ if ((fmri = topo_mod_hcfmri(mod, pnode, FM_HC_SCHEME_VERSION, - SUBCHASSIS, (topo_instance_t)instance, NULL, auth, part, revision, - scp->sec_lid)) == NULL) { + SUBCHASSIS, (topo_instance_t)instance, NULL, auth, NULL, NULL, + NULL)) == NULL) { topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s", topo_mod_errmsg(mod)); goto error; @@ -944,11 +1603,25 @@ ses_create_subchassis(ses_enum_data_t *sdp, tnode_t *pnode, if (topo_node_label_set(tn, desc, &err) != 0) goto error; - if (ses_set_standard_props(mod, tn, NULL, + if (ses_set_standard_props(mod, NULL, tn, NULL, ses_node_id(scp->sec_enclosure), scp->sec_target->set_devpath) != 0) goto error; /* + * Set the 'chassis-type' property for this subchassis. This is either + * 'ses-class-description' or 'subchassis'. + */ + if (nvlist_lookup_string(props, SES_PROP_CLASS_DESCRIPTION, &desc) != 0) + desc = "subchassis"; + + if (topo_prop_set_string(tn, TOPO_PGROUP_SES, + TOPO_PROP_CHASSIS_TYPE, TOPO_PROP_IMMUTABLE, desc, &err) != 0) { + topo_mod_dprintf(mod, "failed to create property %s: %s\n", + TOPO_PROP_CHASSIS_TYPE, topo_strerror(err)); + goto error; + } + + /* * For enclosures, we want to include all possible targets (for upgrade * purposes). */ @@ -1115,7 +1788,7 @@ ses_create_chassis(ses_enum_data_t *sdp, tnode_t *pnode, ses_enum_chassis_t *cp) goto error; } - if (ses_set_standard_props(mod, tn, auth, + if (ses_set_standard_props(mod, NULL, tn, auth, ses_node_id(cp->sec_enclosure), cp->sec_target->set_devpath) != 0) goto error; @@ -1145,7 +1818,9 @@ ses_create_chassis(ses_enum_data_t *sdp, tnode_t *pnode, ses_enum_chassis_t *cp) } /* - * Create the nodes for power supplies, fans, and devices. + * Create the nodes for power supplies, fans, controllers and devices. + * Note that SAS exopander nodes and connector nodes are handled + * through protocol specific processing of controllers. */ if (ses_create_children(sdp, tn, SES_ET_POWER_SUPPLY, PSU, "PSU", cp, B_TRUE) != 0 || @@ -1159,9 +1834,9 @@ ses_create_chassis(ses_enum_data_t *sdp, tnode_t *pnode, ses_enum_chassis_t *cp) BAY, "BAY", cp, B_TRUE) != 0) goto error; - if (cp->sec_scinstance > 0 && - topo_node_range_create(mod, tn, SUBCHASSIS, 0, - cp->sec_scinstance - 1) != 0) { + if (cp->sec_maxinstance >= 0 && + (topo_node_range_create(mod, tn, SUBCHASSIS, 0, + cp->sec_maxinstance) != 0)) { topo_mod_dprintf(mod, "topo_node_create_range() failed: %s", topo_mod_errmsg(mod)); goto error; @@ -1174,8 +1849,9 @@ ses_create_chassis(ses_enum_data_t *sdp, tnode_t *pnode, ses_enum_chassis_t *cp) goto error; topo_mod_dprintf(mod, "created Subchassis node with " - "LID (%s)\n and target (%s) under Chassis with CSN (%s)", - scp->sec_lid, scp->sec_target->set_devpath, cp->sec_csn); + "instance %u\nand target (%s) under Chassis with CSN %s", + scp->sec_instance, scp->sec_target->set_devpath, + cp->sec_csn); sc_count++; } @@ -1238,21 +1914,22 @@ ses_create_bays(ses_enum_data_t *sdp, tnode_t *pnode) static int ses_init_chassis(topo_mod_t *mod, ses_enum_data_t *sdp, ses_enum_chassis_t *pcp, ses_enum_chassis_t *cp, ses_node_t *np, nvlist_t *props, - char *lid, ses_chassis_type_e flags) + uint64_t subchassis, ses_chassis_type_e flags) { boolean_t internal, ident; assert((flags & (SES_NEW_CHASSIS | SES_NEW_SUBCHASSIS | SES_DUP_CHASSIS | SES_DUP_SUBCHASSIS)) != 0); - assert((cp != NULL) && (np != NULL) && (props != NULL) && - (lid != NULL)); + assert(cp != NULL); + assert(np != NULL); + assert(props != NULL); if (flags & (SES_NEW_SUBCHASSIS | SES_DUP_SUBCHASSIS)) assert(pcp != NULL); - topo_mod_dprintf(mod, "ses_init_chassis: %s: lid(%s), flags (%d)", - sdp->sed_name, lid, flags); + topo_mod_dprintf(mod, "ses_init_chassis: %s: index %llu, flags (%d)", + sdp->sed_name, subchassis, flags); if (flags & (SES_NEW_CHASSIS | SES_NEW_SUBCHASSIS)) { @@ -1261,15 +1938,22 @@ ses_init_chassis(topo_mod_t *mod, ses_enum_data_t *sdp, ses_enum_chassis_t *pcp, LIBSES_EN_PROP_INTERNAL, &internal) == 0) cp->sec_internal = internal; - cp->sec_lid = lid; cp->sec_enclosure = np; cp->sec_target = sdp->sed_target; if (flags & SES_NEW_CHASSIS) { - cp->sec_instance = sdp->sed_instance++; + if (!cp->sec_internal) + cp->sec_instance = sdp->sed_instance++; topo_list_append(&sdp->sed_chassis, cp); } else { - cp->sec_instance = pcp->sec_scinstance++; + if (subchassis != NO_SUBCHASSIS) + cp->sec_instance = subchassis; + else + cp->sec_instance = pcp->sec_scinstance++; + + if (cp->sec_instance > pcp->sec_maxinstance) + pcp->sec_maxinstance = cp->sec_instance; + topo_list_append(&pcp->sec_subchassis, cp); } @@ -1307,8 +1991,7 @@ ses_enum_gather(ses_node_t *np, void *data) uint64_t instance, type; uint64_t prevstatus, status; boolean_t report; - boolean_t have_subchassis = B_TRUE; - char *lid; + uint64_t subchassis = NO_SUBCHASSIS; if (ses_node_type(np) == SES_NODE_ENCLOSURE) { /* @@ -1328,14 +2011,12 @@ ses_enum_gather(ses_node_t *np, void *data) &csn) != 0) return (SES_WALK_ACTION_TERMINATE); - if (nvlist_lookup_string(props, LIBSES_EN_PROP_SUBCHASSIS_ID, - &lid) != 0) { - have_subchassis = B_FALSE; - lid = ""; - } + (void) nvlist_lookup_uint64(props, LIBSES_EN_PROP_SUBCHASSIS_ID, + &subchassis); topo_mod_dprintf(mod, "ses_enum_gather: Enclosure Node (%s) " - "CSN (%s), LID (%s)", sdp->sed_name, csn, lid); + "CSN (%s), subchassis (%llu)", sdp->sed_name, csn, + subchassis); /* * We need to determine whether this enclosure node @@ -1376,24 +2057,26 @@ ses_enum_gather(ses_node_t *np, void *data) sizeof (ses_enum_chassis_t))) == NULL) goto error; + cp->sec_scinstance = SES_STARTING_SUBCHASSIS; + cp->sec_maxinstance = -1; cp->sec_csn = csn; - if (!have_subchassis || strcmp(csn, lid) == 0) { + if (subchassis == NO_SUBCHASSIS) { /* 1.1 This is a new chassis */ topo_mod_dprintf(mod, "%s: Initialize new " - "chassis with CSN (%s) and LID (%s)", - sdp->sed_name, csn, lid); + "chassis with CSN %s", sdp->sed_name, csn); if (ses_init_chassis(mod, sdp, NULL, cp, - np, props, lid, SES_NEW_CHASSIS) < 0) + np, props, NO_SUBCHASSIS, + SES_NEW_CHASSIS) < 0) goto error; } else { /* 1.2 This is a new subchassis */ topo_mod_dprintf(mod, "%s: Initialize new " - "subchassis with CSN (%s) and LID (%s)", - sdp->sed_name, csn, lid); + "subchassis with CSN %s and index %llu", + sdp->sed_name, csn, subchassis); if ((scp = topo_mod_zalloc(mod, sizeof (ses_enum_chassis_t))) == NULL) @@ -1401,39 +2084,41 @@ ses_enum_gather(ses_node_t *np, void *data) scp->sec_csn = csn; - if (ses_init_chassis(mod, sdp, cp, scp, - np, props, lid, SES_NEW_SUBCHASSIS) < 0) + if (ses_init_chassis(mod, sdp, cp, scp, np, + props, subchassis, SES_NEW_SUBCHASSIS) < 0) goto error; } } else { - /* 2. We have a chassis with this CSN */ - - if (!have_subchassis || strcmp(csn, lid) == 0) { - /* This is a chassis */ - - if (!have_subchassis || - strlen(cp->sec_lid) > 0) { + /* + * We have a chassis or subchassis with this CSN. If + * it's a chassis, we must check to see whether it is + * a placeholder previously created because we found a + * subchassis with this CSN. We will know that because + * the sec_target value will not be set; it is set only + * in ses_init_chassis(). In that case, initialise it + * as a new chassis; otherwise, it's a duplicate and we + * need to append only. + */ + if (subchassis == NO_SUBCHASSIS) { + if (cp->sec_target != NULL) { /* 2.1 This is a duplicate chassis */ topo_mod_dprintf(mod, "%s: Append " - "duplicate chassis with CSN (%s) " - "and LID (%s)", - sdp->sed_name, csn, lid); + "duplicate chassis with CSN (%s)", + sdp->sed_name, csn); if (ses_init_chassis(mod, sdp, NULL, cp, - np, props, lid, + np, props, NO_SUBCHASSIS, SES_DUP_CHASSIS) < 0) goto error; } else { - /* 2.2 Init the placeholder chassis */ - + /* Placeholder chassis - init it up */ topo_mod_dprintf(mod, "%s: Initialize" - "placeholder chassis with CSN (%s) " - "and LID (%s)", - sdp->sed_name, csn, lid); + "placeholder chassis with CSN %s", + sdp->sed_name, csn); - if (ses_init_chassis(mod, sdp, NULL, cp, - np, props, lid, + if (ses_init_chassis(mod, sdp, NULL, + cp, np, props, NO_SUBCHASSIS, SES_NEW_CHASSIS) < 0) goto error; @@ -1443,7 +2128,7 @@ ses_enum_gather(ses_node_t *np, void *data) for (scp = topo_list_next(&cp->sec_subchassis); scp != NULL; scp = topo_list_next(scp)) - if (strcmp(scp->sec_lid, lid) == 0) + if (scp->sec_instance == subchassis) break; if (scp == NULL) { @@ -1452,7 +2137,7 @@ ses_enum_gather(ses_node_t *np, void *data) topo_mod_dprintf(mod, "%s: Initialize " "new subchassis with CSN (%s) " "and LID (%s)", - sdp->sed_name, csn, lid); + sdp->sed_name, csn); if ((scp = topo_mod_zalloc(mod, sizeof (ses_enum_chassis_t))) @@ -1462,7 +2147,7 @@ ses_enum_gather(ses_node_t *np, void *data) scp->sec_csn = csn; if (ses_init_chassis(mod, sdp, cp, scp, - np, props, lid, + np, props, subchassis, SES_NEW_SUBCHASSIS) < 0) goto error; } else { @@ -1470,11 +2155,10 @@ ses_enum_gather(ses_node_t *np, void *data) topo_mod_dprintf(mod, "%s: Append " "duplicate subchassis with " - "CSN (%s) and LID (%s)", - sdp->sed_name, csn, lid); + "CSN (%s)", sdp->sed_name, csn); if (ses_init_chassis(mod, sdp, cp, scp, - np, props, lid, + np, props, subchassis, SES_DUP_SUBCHASSIS) < 0) goto error; } @@ -1498,7 +2182,9 @@ ses_enum_gather(ses_node_t *np, void *data) type != SES_ET_ARRAY_DEVICE && type != SES_ET_COOLING && type != SES_ET_POWER_SUPPLY && - type != SES_ET_ESC_ELECTRONICS) + type != SES_ET_ESC_ELECTRONICS && + type != SES_ET_SAS_EXPANDER && + type != SES_ET_SAS_CONNECTOR) return (SES_WALK_ACTION_CONTINUE); /* @@ -1714,7 +2400,7 @@ ses_enum(topo_mod_t *mod, tnode_t *rnode, const char *name, data->sed_mod = mod; topo_mod_setspecific(mod, data); - if (disk_list_gather(mod, &data->sed_disks) != 0) + if (dev_list_gather(mod, &data->sed_devs) != 0) goto error; /* diff --git a/usr/src/lib/fm/topo/modules/common/ses/ses.h b/usr/src/lib/fm/topo/modules/common/ses/ses.h index 94ae7266ef..ce524ebc0a 100644 --- a/usr/src/lib/fm/topo/modules/common/ses/ses.h +++ b/usr/src/lib/fm/topo/modules/common/ses/ses.h @@ -20,8 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _SES_H @@ -60,8 +59,12 @@ typedef struct ses_enum_target { #define TOPO_PGROUP_SES "ses" #define TOPO_PROP_NODE_ID "node-id" #define TOPO_PROP_TARGET_PATH "target-path" -#define TOPO_PROP_SAS_ADDR "sas-address" #define TOPO_PROP_PATHS "paths" +#define TOPO_PROP_SAS_ADDR "sas-address" +#define TOPO_PROP_PHY_COUNT "phy-count" +#define TOPO_PROP_CHASSIS_TYPE "chassis-type" +#define TOPO_PROP_SAS_PHY_MASK "phy-mask" +#define TOPO_PROP_SAS_CONNECTOR_TYPE "sas-connector-type" #ifndef NDEBUG #define verify(x) assert(x) diff --git a/usr/src/lib/fm/topo/modules/i86pc/pcibus/Makefile b/usr/src/lib/fm/topo/modules/i86pc/pcibus/Makefile index ec904260f1..1b34ed3510 100644 --- a/usr/src/lib/fm/topo/modules/i86pc/pcibus/Makefile +++ b/usr/src/lib/fm/topo/modules/i86pc/pcibus/Makefile @@ -29,7 +29,7 @@ CLASS = arch UTILDIR = ../../common/pcibus HBDIR = ../../common/hostbridge UTILSRCS = did.c did_hash.c did_props.c util.c -PCISRCS = pcibus.c pcibus_labels.c +PCISRCS = pcibus.c pcibus_labels.c pcibus_hba.c MODULESRCS = $(UTILSRCS) $(PCISRCS) pci_i86pc.c diff --git a/usr/src/lib/fm/topo/modules/sun4/pcibus/Makefile.pci b/usr/src/lib/fm/topo/modules/sun4/pcibus/Makefile.pci index 916478491f..277e868277 100644 --- a/usr/src/lib/fm/topo/modules/sun4/pcibus/Makefile.pci +++ b/usr/src/lib/fm/topo/modules/sun4/pcibus/Makefile.pci @@ -29,7 +29,7 @@ SUN4DIR = ../../sun4/$(MODULE) UTILDIR = ../../common/pcibus HBDIR = ../../common/hostbridge UTILSRCS = did.c did_hash.c did_props.c util.c -PCISRCS = pcibus.c pcibus_labels.c pci_sun4.c +PCISRCS = pcibus.c pcibus_labels.c pci_sun4.c pcibus_hba.c MODULESRCS = $(PCISRCS) $(UTILSRCS) pci_$(ARCH).c diff --git a/usr/src/lib/libfru/libfruraw/fruraw.c b/usr/src/lib/libfru/libfruraw/fruraw.c index 872d3c203e..d776a024c6 100644 --- a/usr/src/lib/libfru/libfruraw/fruraw.c +++ b/usr/src/lib/libfru/libfruraw/fruraw.c @@ -20,8 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <stdio.h> @@ -551,8 +550,9 @@ frt_get_segment_name(fru_seghdl_t node, char **name) for (each_seg = 0; each_seg < num_segment; each_seg++) { if (segs[each_seg].handle == node) { segs[each_seg].name[FRU_SEGNAMELEN] = '\0'; - *name = segs[each_seg].name; + *name = strdup(segs[each_seg].name); free(sects); + free(segs); return (FRU_SUCCESS); } } diff --git a/usr/src/lib/libfru/libfruraw/raw_access.c b/usr/src/lib/libfru/libfruraw/raw_access.c index 6fe602d7b2..6649fee8a6 100644 --- a/usr/src/lib/libfru/libfruraw/raw_access.c +++ b/usr/src/lib/libfru/libfruraw/raw_access.c @@ -20,8 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <stdio.h> @@ -1197,12 +1196,10 @@ fru_close_container(container_hdl_t container) } } - free(sec_hash_obj->u.sec_obj); /* free section hash object */ - prev_hash = sec_hash_obj; - sec_hash_obj = sec_hash_obj->u.sec_obj->next; + free(prev_hash->u.sec_obj); /* free section hash object */ free(prev_hash); /* free section hash */ } diff --git a/usr/src/lib/libfru/libnvfru/nvfru.c b/usr/src/lib/libfru/libnvfru/nvfru.c index de3ef47e6b..08aae7d56a 100644 --- a/usr/src/lib/libfru/libnvfru/nvfru.c +++ b/usr/src/lib/libfru/libnvfru/nvfru.c @@ -20,8 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <stdio.h> @@ -188,7 +187,7 @@ convert_element(const uint8_t *data, const fru_regdef_t *def, char *ppath, return; for (i = head, n = 0, data += sizeof (uint32_t); n < num; i = ((i + 1) % def->iterationCount), n++) { - if (nvlist_alloc(&nv_elems[n], 0, 0) != 0) + if (nvlist_alloc(&nv_elems[n], NV_UNIQUE_NAME, 0) != 0) return; (void) snprintf(num_str, sizeof (num_str), "%d", n); convert_element((data + i*iterlen), &newdef, num_str, @@ -201,7 +200,7 @@ convert_element(const uint8_t *data, const fru_regdef_t *def, char *ppath, nvlist_t *nv_record; if (!from_iter) { - if (nvlist_alloc(&nv_record, 0, 0) != 0) { + if (nvlist_alloc(&nv_record, NV_UNIQUE_NAME, 0) != 0) { return; } } else { @@ -323,7 +322,7 @@ convert_packets_in_segment(fru_seghdl_t segment, void *args) } /* create a new nvlist for each segment */ - ret = nvlist_alloc(&nv_segment, 0, 0); + ret = nvlist_alloc(&nv_segment, NV_UNIQUE_NAME, 0); if (ret) { free(name); return (FRU_FAILURE); @@ -361,7 +360,7 @@ convert_fru(fru_nodehdl_t hdl, nvlist_t **nvlist) return (-1); } - err = nvlist_alloc(&nv, 0, 0); + err = nvlist_alloc(&nv, NV_UNIQUE_NAME, 0); if (err) { return (err); } diff --git a/usr/src/lib/scsi/Makefile b/usr/src/lib/scsi/Makefile index 18c7ae7c2c..8597af30bb 100644 --- a/usr/src/lib/scsi/Makefile +++ b/usr/src/lib/scsi/Makefile @@ -20,14 +20,13 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # -# ident "%Z%%M% %I% %E% SMI" SUBDIRS = \ libscsi \ libses \ + libsmp \ plugins .KEEP_STATE: @@ -36,6 +35,6 @@ SUBDIRS = \ libses: libscsi -plugins: libscsi libses +plugins: libscsi libses libsmp include Makefile.subdirs diff --git a/usr/src/lib/scsi/Makefile.rootdirs b/usr/src/lib/scsi/Makefile.rootdirs index c92390410c..797f633609 100644 --- a/usr/src/lib/scsi/Makefile.rootdirs +++ b/usr/src/lib/scsi/Makefile.rootdirs @@ -19,10 +19,8 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. # -# ident "%Z%%M% %I% %E% SMI" # # Define the transitive set of rules to create a common module's install dir @@ -56,6 +54,27 @@ $(ROOTPLUGINLIBDIR)/ses/vendor: $(ROOTPLUGINLIBDIR)/ses $(ROOTPLUGINLIBDIR)/ses/vendor/$(MACH64): $(ROOTPLUGINLIBDIR)/ses/vendor $(INS.dir) +$(ROOTPLUGINLIBDIR)/smp: $(ROOTPLUGINLIBDIR) + $(INS.dir) + +$(ROOTPLUGINLIBDIR)/smp/engine: $(ROOTPLUGINLIBDIR)/smp + $(INS.dir) + +$(ROOTPLUGINLIBDIR)/smp/engine/$(MACH64): $(ROOTPLUGINLIBDIR)/smp/engine + $(INS.dir) + +$(ROOTPLUGINLIBDIR)/smp/framework: $(ROOTPLUGINLIBDIR)/smp + $(INS.dir) + +$(ROOTPLUGINLIBDIR)/smp/framework/$(MACH64): $(ROOTPLUGINLIBDIR)/smp/framework + $(INS.dir) + +$(ROOTPLUGINLIBDIR)/smp/vendor: $(ROOTPLUGINLIBDIR)/smp + $(INS.dir) + +$(ROOTPLUGINLIBDIR)/smp/vendor/$(MACH64): $(ROOTPLUGINLIBDIR)/smp/vendor + $(INS.dir) + $(ROOTPLUGINHDRDIR): $(INS.dir) @@ -67,3 +86,16 @@ $(ROOTPLUGINHDRDIR)/ses/framework: $(ROOTPLUGINHDRDIR)/ses $(ROOTPLUGINHDRDIR)/ses/vendor: $(ROOTPLUGINHDRDIR)/ses $(INS.dir) + +$(ROOTPLUGINHDRDIR)/smp: $(ROOTPLUGINHDRDIR) + $(INS.dir) + +$(ROOTPLUGINHDRDIR)/smp/engine: $(ROOTPLUGINHDRDIR)/smp + $(INS.dir) + +$(ROOTPLUGINHDRDIR)/smp/framework: $(ROOTPLUGINHDRDIR)/smp + $(INS.dir) + +$(ROOTPLUGINHDRDIR)/smp/vendor: $(ROOTPLUGINHDRDIR)/smp + $(INS.dir) + diff --git a/usr/src/lib/scsi/libscsi/common/libscsi.h b/usr/src/lib/scsi/libscsi/common/libscsi.h index 748913ee1e..4d57d1299c 100644 --- a/usr/src/lib/scsi/libscsi/common/libscsi.h +++ b/usr/src/lib/scsi/libscsi/common/libscsi.h @@ -20,15 +20,12 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _LIBSCSI_H #define _LIBSCSI_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -95,9 +92,6 @@ typedef struct libscsi_status { 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 *); diff --git a/usr/src/lib/scsi/libscsi/common/scsi_engine.c b/usr/src/lib/scsi/libscsi/common/scsi_engine.c index df221eea55..3c6d5ecee9 100644 --- a/usr/src/lib/scsi/libscsi/common/scsi_engine.c +++ b/usr/src/lib/scsi/libscsi/common/scsi_engine.c @@ -20,12 +20,9 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <sys/isa_defs.h> #include <sys/systeminfo.h> @@ -73,8 +70,8 @@ get_engine(libscsi_hdl_t *hp, const char *name) isa[0] = '\0'; #endif - for (p = engine_path, q = strchr(p, ':'); p != NULL; p = q) { - if (q != NULL) { + for (p = engine_path; p != NULL; p = q) { + if ((q = strchr(p, ':')) != NULL) { ptrdiff_t len = q - p; (void) strncpy(engine_dir, p, len); engine_dir[len] = '\0'; diff --git a/usr/src/lib/scsi/libscsi/common/scsi_subr.c b/usr/src/lib/scsi/libscsi/common/scsi_subr.c index fb9a4eb650..712a9f88c5 100644 --- a/usr/src/lib/scsi/libscsi/common/scsi_subr.c +++ b/usr/src/lib/scsi/libscsi/common/scsi_subr.c @@ -20,12 +20,9 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <sys/scsi/generic/commands.h> #include <sys/scsi/impl/spc3_types.h> @@ -300,12 +297,13 @@ libscsi_get_inquiry(libscsi_hdl_t *hp, libscsi_target_t *tp) if ((ap = libscsi_action_alloc(hp, SPC3_CMD_INQUIRY, LIBSCSI_AF_READ | LIBSCSI_AF_SILENT | LIBSCSI_AF_DIAGNOSE, &data, - sizeof (data))) == NULL) + offsetof(spc3_inquiry_data_t, id_vs_36[0]))) == NULL) return (-1); cp = (spc3_inquiry_cdb_t *)libscsi_action_get_cdb(ap); - SCSI_WRITE16(&cp->ic_allocation_length, sizeof (data)); + SCSI_WRITE16(&cp->ic_allocation_length, + offsetof(spc3_inquiry_data_t, id_vs_36[0])); if (libscsi_exec(ap, tp) != 0 || libscsi_action_get_status(ap) != 0) { diff --git a/usr/src/lib/scsi/libses/Makefile.defs b/usr/src/lib/scsi/libses/Makefile.defs index 96f5872fba..9e6d61f601 100644 --- a/usr/src/lib/scsi/libses/Makefile.defs +++ b/usr/src/lib/scsi/libses/Makefile.defs @@ -20,10 +20,8 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. # -# ident "%Z%%M% %I% %E% SMI" SRCS = $(OBJECTS:%.o=../common/%.c) C99MODE = $(C99_ENABLE) @@ -43,6 +41,7 @@ LDLIBS64 += -L$(ROOTSCSILIBDIR)/$(MACH64) LDLIBS += \ -lnvpair \ -lscsi \ + -lumem \ -lc LIBS = $(DYNLIB) $(LINTLIB) diff --git a/usr/src/lib/scsi/libses/common/libses_plugin.h b/usr/src/lib/scsi/libses/common/libses_plugin.h index 7156da7bdf..0bae67bb29 100644 --- a/usr/src/lib/scsi/libses/common/libses_plugin.h +++ b/usr/src/lib/scsi/libses/common/libses_plugin.h @@ -20,15 +20,12 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _LIBSES_PLUGIN_H #define _LIBSES_PLUGIN_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -47,6 +44,13 @@ typedef enum { SES_PAGE_CTL } ses_pagetype_t; +typedef enum ses_page_req { + SES_REQ_OPTIONAL, + SES_REQ_MANDATORY_ALL, + SES_REQ_MANDATORY_STANDARD, + SES_REQ_OPTIONAL_STANDARD +} ses_page_req_t; + typedef struct ses_pagedesc { int spd_pagenum; size_t (*spd_ctl_len)(uint_t, int, size_t); @@ -55,6 +59,7 @@ typedef struct ses_pagedesc { void *(*spd_index)(ses_plugin_t *, ses_node_t *, void *, size_t, size_t *); int spd_gcoff; + ses_page_req_t spd_req; } ses_pagedesc_t; typedef struct ses_plugin_config { diff --git a/usr/src/lib/scsi/libses/common/ses_node.c b/usr/src/lib/scsi/libses/common/ses_node.c index d245160b96..dd9347bd53 100644 --- a/usr/src/lib/scsi/libses/common/ses_node.c +++ b/usr/src/lib/scsi/libses/common/ses_node.c @@ -20,12 +20,9 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <scsi/libses.h> #include "ses_impl.h" @@ -145,7 +142,7 @@ ses_build_snap_skel(ses_snap_t *sp) off_t toff; char *tp, *text; int err; - uint64_t idx; + uint64_t idx, eidx; pp = ses_snap_find_page(sp, SES2_DIAGPAGE_CONFIG, B_FALSE); if (pp == NULL) @@ -221,7 +218,7 @@ ses_build_snap_skel(ses_snap_t *sp) tp = (char *)(ftip + n_etds); - for (i = 0, toff = 0, idx = 0; i < n_etds; i++) { + for (i = 0, toff = 0, idx = eidx = 0; i < n_etds; i++) { tip = ftip + i; if (!SES_WITHIN_PAGE_STRUCT(tip, pp->ssp_page, pp->ssp_len)) @@ -231,6 +228,7 @@ ses_build_snap_skel(ses_snap_t *sp) tip->sthi_subenclosure_id); if (pnp == NULL) { idx += tip->sthi_max_elements + 1; + eidx += tip->sthi_max_elements; toff += tip->sthi_text_len; continue; } @@ -243,6 +241,8 @@ ses_build_snap_skel(ses_snap_t *sp) } else { SES_NV_ADD(uint64, err, pnp->sn_props, SES_PROP_ELEMENT_INDEX, idx + 1); + SES_NV_ADD(uint64, err, pnp->sn_props, + SES_PROP_ELEMENT_ONLY_INDEX, eidx); pnp->sn_rootidx = idx + 1; } @@ -261,6 +261,7 @@ ses_build_snap_skel(ses_snap_t *sp) return (-1); idx += tip->sthi_max_elements + 1; + eidx += tip->sthi_max_elements; continue; } @@ -303,10 +304,14 @@ ses_build_snap_skel(ses_snap_t *sp) 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_ONLY_INDEX, eidx + j); + 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); } + + eidx += tip->sthi_max_elements; } np->sn_snapshot->ss_n_elem = idx; diff --git a/usr/src/lib/scsi/libses/common/ses_plugin.c b/usr/src/lib/scsi/libses/common/ses_plugin.c index f744f61d9c..62c00b4ebc 100644 --- a/usr/src/lib/scsi/libses/common/ses_plugin.c +++ b/usr/src/lib/scsi/libses/common/ses_plugin.c @@ -20,12 +20,9 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <scsi/libses.h> #include "ses_impl.h" @@ -358,8 +355,8 @@ ses_plugin_load(ses_target_t *tp) pluginpath = LIBSES_DEFAULT_PLUGINDIR; ses_plugin_dlclose = (getenv("SES_NODLCLOSE") == NULL); - for (p = pluginpath, q = strchr(p, ':'); p != NULL; p = q) { - if (q != NULL) { + for (p = pluginpath; p != NULL; p = q) { + if ((q = strchr(p, ':')) != NULL) { ptrdiff_t len = q - p; (void) strncpy(pluginroot, p, len); pluginroot[len] = '\0'; @@ -376,7 +373,7 @@ ses_plugin_load(ses_target_t *tp) if (pluginroot[0] != '/') continue; - if (ses_plugin_load_dir(tp, pluginpath) != 0) + if (ses_plugin_load_dir(tp, pluginroot) != 0) return (-1); } diff --git a/usr/src/lib/scsi/libses/common/ses_snap.c b/usr/src/lib/scsi/libses/common/ses_snap.c index 78e7927061..94c72ff964 100644 --- a/usr/src/lib/scsi/libses/common/ses_snap.c +++ b/usr/src/lib/scsi/libses/common/ses_snap.c @@ -20,12 +20,9 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <scsi/libses.h> #include "ses_impl.h" @@ -158,7 +155,7 @@ ses_snap_ctl_page(ses_snap_t *sp, ses2_diag_page_t page, size_t dlen, 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) + if (pp->ssp_alloc < len && grow_snap_page(pp, len) != 0) return (NULL); pp->ssp_len = len; bzero(pp->ssp_page, len); @@ -239,7 +236,7 @@ again: ASSERT(buf == pp->ssp_page); ASSERT(alloc == pp->ssp_alloc); - if (pp->ssp_len == pp->ssp_alloc && pp->ssp_alloc < UINT16_MAX) { + if (pp->ssp_alloc - pp->ssp_len < 0x80 && pp->ssp_alloc < UINT16_MAX) { bzero(pp->ssp_page, pp->ssp_len); pp->ssp_len = 0; if (grow_snap_page(pp, 0) != 0) @@ -247,6 +244,13 @@ again: goto again; } + if (pp->ssp_len < offsetof(spc3_diag_page_impl_t, sdpi_data)) { + bzero(pp->ssp_page, pp->ssp_len); + pp->ssp_len = 0; + return (ses_error(ESES_BAD_RESPONSE, "target returned " + "truncated page 0x%x (length %d)", page, pp->ssp_len)); + } + pip = (spc3_diag_page_impl_t *)buf; if (pip->sdpi_page_code == page) @@ -447,6 +451,7 @@ ses_snap_new(ses_target_t *tp) ses_pagedesc_t *dp; size_t pages, pagesize, pagelen; char *scratch; + boolean_t simple; if ((sp = ses_zalloc(sizeof (ses_snap_t))) == NULL) return (NULL); @@ -464,6 +469,16 @@ again: sp->ss_generation = (uint32_t)-1; sp->ss_time = gethrtime(); + /* + * First check for the short enclosure status diagnostic page and + * determine if this is a simple subenclosure or not. + */ + simple = B_FALSE; + for (pp = sp->ss_pages; pp != NULL; pp = pp->ssp_next) { + if (pp->ssp_num == SES2_DIAGPAGE_SHORT_STATUS) + simple = B_TRUE; + } + for (pp = sp->ss_pages; pp != NULL; pp = pp->ssp_next) { /* * We skip all of: @@ -478,8 +493,20 @@ again: SES_PAGE_DIAG)) == NULL) continue; - if (read_status_page(sp, pp->ssp_num) != 0) + if (read_status_page(sp, pp->ssp_num) != 0) { + /* + * If this page is required, and this is not a simple + * subenclosure, then fail the entire snapshot. + */ + if (dp->spd_req == SES_REQ_MANDATORY_ALL || + (dp->spd_req == SES_REQ_MANDATORY_STANDARD && + !simple)) { + ses_snap_free(sp); + return (NULL); + } + continue; + } /* * If the generation code has changed, we don't have a valid diff --git a/usr/src/lib/scsi/libsmp/Makefile b/usr/src/lib/scsi/libsmp/Makefile new file mode 100644 index 0000000000..d530e09093 --- /dev/null +++ b/usr/src/lib/scsi/libsmp/Makefile @@ -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 (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +include ../../Makefile.lib +include ../Makefile.defs + +HDRS = libsmp.h libsmp_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/libsmp/Makefile.com b/usr/src/lib/scsi/libsmp/Makefile.com new file mode 100644 index 0000000000..946ce85129 --- /dev/null +++ b/usr/src/lib/scsi/libsmp/Makefile.com @@ -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 (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +LIBRARY = libsmp.a +VERS = .1 + +OBJECTS = \ + smp_engine.o \ + smp_errno.o \ + smp_plugin.o \ + smp_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/smp_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) + +.KEEP_STATE: + +all : $(LIBS) + +lint : lintcheck + +../common/smp_errno.c: ../common/mkerrno.sh ../common/libsmp.h + sh ../common/mkerrno.sh < ../common/libsmp.h > $@ + +pics/%.o: ../common/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +include ../../../Makefile.targ +include ../../Makefile.rootdirs diff --git a/usr/src/lib/scsi/libsmp/amd64/Makefile b/usr/src/lib/scsi/libsmp/amd64/Makefile new file mode 100644 index 0000000000..e59eb2b811 --- /dev/null +++ b/usr/src/lib/scsi/libsmp/amd64/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 (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +include ../Makefile.com +include ../../../Makefile.lib.64 + +install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64) diff --git a/usr/src/lib/scsi/libsmp/common/libsmp.h b/usr/src/lib/scsi/libsmp/common/libsmp.h new file mode 100644 index 0000000000..e1371166de --- /dev/null +++ b/usr/src/lib/scsi/libsmp/common/libsmp.h @@ -0,0 +1,125 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#ifndef _LIBSMP_H +#define _LIBSMP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> +#include <sys/sysmacros.h> +#include <sys/scsi/impl/usmp.h> +#include <sys/scsi/generic/smp_frames.h> +#include <libnvpair.h> +#include <stdarg.h> + +#define LIBSMP_VERSION 1 + +#define SMP_TARGET_C_LONG_RESP 0x01 /* Long response (SAS-2 10.4.3.4) */ +#define SMP_TARGET_C_ZONING 0x02 /* Zoning supported */ +#define SMP_TARGET_C_ZG_256 0x04 /* 256 zone groups supported */ + +typedef enum smp_errno { + ESMP_NONE, /* no error */ + ESMP_NOMEM, /* no memory */ + ESMP_ZERO_LENGTH, /* zero-length allocation requested */ + ESMP_VERSION, /* library version mismatch */ + ESMP_BADTARGET, /* invalid target specification */ + ESMP_BADFUNC, /* invalid SMP function */ + ESMP_BADENGINE, /* engine library corrupt */ + ESMP_NOENGINE, /* engine library not found */ + ESMP_ENGINE_INIT, /* engine initialization failed */ + ESMP_ENGINE_VER, /* engine version mismatch */ + ESMP_ENGINE_BADPATH, /* engine path contains no usable components */ + ESMP_BADLENGTH, /* buffer length overflow or size error */ + ESMP_NEEDBUF, /* missing required buffer */ + ESMP_PLUGIN, /* no plugins found */ + ESMP_IO, /* I/O operation failed */ + ESMP_SYS, /* system call failed */ + ESMP_PERM, /* insufficient permissions */ + ESMP_RANGE, /* parameter outside valid range */ + ESMP_NOTSUP, /* operation not supported */ + ESMP_UNKNOWN, /* error of unknown type */ + ESMP_REPGEN_FAILED, /* initial report general command failed */ + ESMP_MAX /* maximum libsmp errno value */ +} smp_errno_t; + +typedef struct smp_target_def { + const char *std_engine; + const void *std_def; +} smp_target_def_t; + +struct smp_target; +typedef struct smp_target smp_target_t; + +struct smp_action; +typedef struct smp_action smp_action_t; + +extern int smp_init(int); +extern void smp_fini(void); + +extern smp_target_t *smp_open(const smp_target_def_t *); +extern uint_t smp_target_getcap(const smp_target_t *); +extern uint16_t smp_target_get_change_count(const smp_target_t *); +extern void smp_target_set_change_count(smp_target_t *, uint16_t); +extern const char *smp_target_vendor(const smp_target_t *); +extern const char *smp_target_product(const smp_target_t *); +extern const char *smp_target_revision(const smp_target_t *); +extern const char *smp_target_component_vendor(const smp_target_t *); +extern uint16_t smp_target_component_id(const smp_target_t *); +extern uint8_t smp_target_component_revision(const smp_target_t *); +extern void smp_target_name(const smp_target_t *, char *, size_t); +extern uint64_t smp_target_addr(const smp_target_t *); +extern void smp_close(smp_target_t *); + +extern smp_errno_t smp_errno(void); +extern smp_errno_t smp_errcode(const char *); +extern const char *smp_errmsg(void); +extern const char *smp_strerror(smp_errno_t); +extern const char *smp_errname(smp_errno_t); + +extern char *smp_trim_strdup(const char *, size_t); + +extern smp_action_t *smp_action_alloc(smp_function_t, smp_target_t *, size_t); +extern smp_action_t *smp_action_xalloc(smp_function_t, smp_target_t *, + void *, size_t, void *, size_t); +extern uint32_t smp_action_get_timeout(const smp_action_t *); +extern void smp_action_set_timeout(smp_action_t *, uint32_t); +extern void smp_action_get_request(const smp_action_t *, void **, size_t *); +extern void smp_action_get_response(const smp_action_t *, + smp_result_t *, void **, size_t *); +extern int smp_exec(smp_action_t *, smp_target_t *); +extern void smp_action_free(smp_action_t *); + +extern nvlist_t *smp_discover(const smp_target_def_t **, size_t); +extern nvlist_t *smp_discover_targets(smp_target_t **, size_t); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBSMP_H */ diff --git a/usr/src/lib/scsi/libsmp/common/libsmp_plugin.h b/usr/src/lib/scsi/libsmp/common/libsmp_plugin.h new file mode 100644 index 0000000000..9d5cbf1b5c --- /dev/null +++ b/usr/src/lib/scsi/libsmp/common/libsmp_plugin.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 (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#ifndef _LIBSMP_PLUGIN_H +#define _LIBSMP_PLUGIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/scsi/generic/smp_frames.h> +#include <scsi/libsmp.h> + +#include <stddef.h> + +#define LIBSMP_PLUGIN_VERSION 1 +#define LIBSMP_ENGINE_VERSION 1 + +#ifndef SMP_REQ_MINLEN +#define SMP_REQ_MINLEN \ + (offsetof(smp_request_frame_t, srf_data[0]) + sizeof (smp_crc_t)) +#endif +#ifndef SMP_RESP_MINLEN +#define SMP_RESP_MINLEN \ + (offsetof(smp_response_frame_t, srf_data[0]) + sizeof (smp_crc_t)) +#endif + +#define VERIFY(x) ((void)((x) || smp_assert(#x, __FILE__, __LINE__))) + +#ifdef DEBUG +#define ASSERT(x) VERIFY(x) +#else +#define ASSERT(x) +#endif + +struct smp_engine; +typedef struct smp_engine smp_engine_t; + +struct smp_plugin; +typedef struct smp_plugin smp_plugin_t; + +typedef struct smp_engine_ops { + void *(*seo_open)(const void *); + void (*seo_close)(void *); + int (*seo_exec)(void *, smp_action_t *); + void (*seo_target_name)(void *, char *, size_t); + uint64_t (*seo_target_addr)(void *); +} smp_engine_ops_t; + +typedef struct smp_engine_config { + const char *sec_name; + const smp_engine_ops_t *sec_ops; +} smp_engine_config_t; + +#define SMP_FD_F_NEEDS_CHANGE_COUNT 0x0001 +#define SMP_FD_F_PROVIDES_CHANGE_COUNT 0x0002 +#define SMP_FD_F_READ 0x0004 +#define SMP_FD_F_WRITE 0x0008 + +typedef struct smp_function_def { + smp_function_t sfd_function; + uint_t sfd_capmask; + uint_t sfd_capset; + uint_t sfd_flags; + size_t (*sfd_rq_len)(size_t, smp_target_t *); + off_t (*sfd_rq_dataoff)(smp_action_t *, smp_target_t *); + void (*sfd_rq_setframe)(smp_action_t *, smp_target_t *); + size_t (*sfd_rs_datalen)(smp_action_t *, smp_target_t *); + off_t (*sfd_rs_dataoff)(smp_action_t *, smp_target_t *); + void (*sfd_rs_getparams)(smp_action_t *, smp_target_t *); +} smp_function_def_t; + +typedef struct smp_plugin_config { + const char *spc_name; + smp_function_def_t *spc_functions; +} smp_plugin_config_t; + +extern int smp_assert(const char *, const char *, int); + +extern void *smp_alloc(size_t); +extern void *smp_zalloc(size_t); +extern char *smp_strdup(const char *); +extern void smp_free(void *); + +extern int smp_set_errno(smp_errno_t); +extern int smp_verror(smp_errno_t, const char *, va_list); +extern int smp_error(smp_errno_t, const char *, ...); + +extern void smp_action_get_request_frame(const smp_action_t *, + void **, size_t *); +extern void smp_action_get_response_frame(const smp_action_t *, + void **, size_t *); +extern void smp_action_set_response_len(smp_action_t *, size_t); +extern void smp_action_set_result(smp_action_t *, smp_result_t); +extern const smp_function_def_t *smp_action_get_function_def( + const smp_action_t *); + +extern int smp_engine_register(smp_engine_t *, int, + const smp_engine_config_t *); + +extern int smp_plugin_register(smp_plugin_t *, int, + const smp_plugin_config_t *); +extern void smp_plugin_setspecific(smp_plugin_t *, void *); +extern void *smp_plugin_getspecific(smp_plugin_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBSMP_PLUGIN_H */ diff --git a/usr/src/lib/scsi/libsmp/common/mkerrno.sh b/usr/src/lib/scsi/libsmp/common/mkerrno.sh new file mode 100644 index 0000000000..3351c1d32d --- /dev/null +++ b/usr/src/lib/scsi/libsmp/common/mkerrno.sh @@ -0,0 +1,85 @@ +#!/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 (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +echo "\ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#pragma ident\t\"@(#)mkerrno.sh\t1.2\t08/07/31\tSMI\" + +#include <strings.h> +#include <scsi/libsmp.h> + +static const struct { +\tchar *name;\t\t/* error name */ +\tchar *msg;\t\t/* error message */ +} _smp_errstr[] = {" + +pattern='^ \(ESMP_[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 _smp_nerrno = sizeof (_smp_errstr) /\n\ + sizeof (_smp_errstr[0]);\n\ +\n\ +const char * +smp_strerror(smp_errno_t err) +{ + return (err < 0 || err >= _smp_nerrno ? \"unknown error\" : + _smp_errstr[err].msg); +} + +const char * +smp_errname(smp_errno_t err) +{ + return (err < 0 || err >= _smp_nerrno ? NULL : + _smp_errstr[err].name); +} + +smp_errno_t +smp_errcode(const char *name) +{ + smp_errno_t err; + + for (err = 0; err < _smp_nerrno; err++) { + if (strcmp(name, _smp_errstr[err].name) == 0) + return (err); + } + + return (ESMP_UNKNOWN); +}" + +exit 0 diff --git a/usr/src/lib/scsi/libsmp/common/smp_engine.c b/usr/src/lib/scsi/libsmp/common/smp_engine.c new file mode 100644 index 0000000000..d76fb48cf6 --- /dev/null +++ b/usr/src/lib/scsi/libsmp/common/smp_engine.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 (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#include <sys/types.h> +#include <sys/isa_defs.h> +#include <sys/systeminfo.h> +#include <sys/scsi/generic/smp_frames.h> + +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <string.h> +#include <strings.h> +#include <dlfcn.h> +#include <limits.h> +#include <pthread.h> +#include <synch.h> + +#include <scsi/libsmp.h> +#include "smp_impl.h" + +static pthread_mutex_t _libsmp_lock = PTHREAD_MUTEX_INITIALIZER; +static smp_engine_t *_libsmp_engines; +static int _libsmp_refcnt; + +static boolean_t _libsmp_engine_dlclose; + +static void +smp_engine_free(smp_engine_t *ep) +{ + if (ep == NULL) + return; + + smp_free(ep->se_name); + smp_free(ep); +} + +static void +smp_engine_destroy(smp_engine_t *ep) +{ + smp_engine_t **pp; + + ASSERT(MUTEX_HELD(&_libsmp_lock)); + + if (ep->se_fini != NULL) + ep->se_fini(ep); + + if (_libsmp_engine_dlclose) + (void) dlclose(ep->se_object); + + ASSERT(ep->se_refcnt == 0); + for (pp = &_libsmp_engines; *pp != NULL; pp = &((*pp)->se_next)) + if (*pp == ep) + break; + + if (*pp != NULL) + *pp = (*pp)->se_next; + + smp_engine_free(ep); +} + +void +smp_engine_init(void) +{ + (void) pthread_mutex_lock(&_libsmp_lock); + ++_libsmp_refcnt; + (void) pthread_mutex_unlock(&_libsmp_lock); +} + +void +smp_engine_fini(void) +{ + smp_engine_t *ep; + + (void) pthread_mutex_lock(&_libsmp_lock); + ASSERT(_libsmp_refcnt > 0); + if (--_libsmp_refcnt == 0) { + while (_libsmp_engines != NULL) { + ep = _libsmp_engines; + _libsmp_engines = ep->se_next; + smp_engine_destroy(ep); + } + } + (void) pthread_mutex_unlock(&_libsmp_lock); +} + +static int +smp_engine_loadone(const char *path) +{ + smp_engine_t *ep; + void *obj; + + ASSERT(MUTEX_HELD(&_libsmp_lock)); + + if ((obj = dlopen(path, RTLD_PARENT | RTLD_LOCAL | RTLD_LAZY)) == NULL) + return (smp_set_errno(ESMP_NOENGINE)); + + if ((ep = smp_zalloc(sizeof (smp_engine_t))) == NULL) { + (void) dlclose(obj); + return (-1); + } + + ep->se_object = obj; + ep->se_init = (int (*)())dlsym(obj, "_smp_init"); + ep->se_fini = (void (*)())dlsym(obj, "_smp_fini"); + + if (ep->se_init == NULL) { + smp_engine_free(ep); + return (smp_set_errno(ESMP_BADENGINE)); + } + + if (ep->se_init(ep) != 0) { + smp_engine_free(ep); + return (-1); + } + + return (0); +} + +int +smp_engine_register(smp_engine_t *ep, int version, + const smp_engine_config_t *ecp) +{ + ASSERT(MUTEX_HELD(&_libsmp_lock)); + + if (version != LIBSMP_ENGINE_VERSION) + return (smp_set_errno(ESMP_VERSION)); + + ep->se_ops = ecp->sec_ops; + ep->se_name = smp_strdup(ecp->sec_name); + + if (ep->se_name == NULL) + return (-1); + + ep->se_next = _libsmp_engines; + _libsmp_engines = ep; + + return (0); +} + +static smp_engine_t * +smp_engine_hold_cached(const char *name) +{ + smp_engine_t *ep; + + ASSERT(MUTEX_HELD(&_libsmp_lock)); + + for (ep = _libsmp_engines; ep != NULL; ep = ep->se_next) { + if (strcmp(ep->se_name, name) == 0) { + ++ep->se_refcnt; + return (ep); + } + } + + (void) smp_set_errno(ESMP_NOENGINE); + return (NULL); +} + +static smp_engine_t * +smp_engine_hold(const char *name) +{ + smp_engine_t *ep; + const char *pluginpath, *p, *q; + char pluginroot[PATH_MAX]; + char path[PATH_MAX]; + char isa[257]; + + (void) pthread_mutex_lock(&_libsmp_lock); + ep = smp_engine_hold_cached(name); + if (ep != NULL) { + (void) pthread_mutex_unlock(&_libsmp_lock); + return (ep); + } + +#if defined(_LP64) + if (sysinfo(SI_ARCHITECTURE_64, isa, sizeof (isa)) < 0) + isa[0] = '\0'; +#else + isa[0] = '\0'; +#endif + + if ((pluginpath = getenv("SMP_PLUGINPATH")) == NULL) + pluginpath = LIBSMP_DEFAULT_PLUGINDIR; + + _libsmp_engine_dlclose = (getenv("SMP_NODLCLOSE") == NULL); + + for (p = pluginpath; p != NULL; p = q) { + if ((q = strchr(p, ':')) != 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; + + (void) snprintf(path, PATH_MAX, "%s/%s/%s/%s%s", + pluginroot, LIBSMP_PLUGIN_ENGINE, + isa, name, LIBSMP_PLUGIN_EXT); + + if (smp_engine_loadone(path) == 0) { + ep = smp_engine_hold_cached(name); + (void) pthread_mutex_unlock(&_libsmp_lock); + return (ep); + } + } + + return (NULL); +} + +static void +smp_engine_rele(smp_engine_t *ep) +{ + (void) pthread_mutex_lock(&_libsmp_lock); + ASSERT(ep->se_refcnt > 0); + --ep->se_refcnt; + (void) pthread_mutex_unlock(&_libsmp_lock); +} + +static void +smp_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; + } +} + +smp_target_t * +smp_open(const smp_target_def_t *tdp) +{ + smp_engine_t *ep; + smp_target_t *tp; + void *private; + const char *engine; + + if ((engine = tdp->std_engine) == NULL) { + if ((engine = getenv("LIBSMP_DEFAULT_ENGINE")) == NULL) + engine = LIBSMP_DEFAULT_ENGINE; + } + + if ((ep = smp_engine_hold(engine)) == NULL) + return (NULL); + + if ((tp = smp_zalloc(sizeof (smp_target_t))) == NULL) { + smp_engine_rele(ep); + return (NULL); + } + + if ((private = ep->se_ops->seo_open(tdp->std_def)) == NULL) { + smp_engine_rele(ep); + smp_free(tp); + return (NULL); + } + + smp_parse_mtbf("LIBSMP_MTBF_REQUEST", &tp->st_mtbf_request); + smp_parse_mtbf("LIBSMP_MTBF_RESPONSE", &tp->st_mtbf_response); + + tp->st_engine = ep; + tp->st_priv = private; + + if (smp_plugin_load(tp) != 0) { + smp_close(tp); + return (NULL); + } + + return (tp); +} + +void +smp_target_name(const smp_target_t *tp, char *buf, size_t len) +{ + tp->st_engine->se_ops->seo_target_name(tp->st_priv, buf, len); +} + +uint64_t +smp_target_addr(const smp_target_t *tp) +{ + return (tp->st_engine->se_ops->seo_target_addr(tp->st_priv)); +} + +const char * +smp_target_vendor(const smp_target_t *tp) +{ + return (tp->st_vendor); +} + +const char * +smp_target_product(const smp_target_t *tp) +{ + return (tp->st_product); +} + +const char * +smp_target_revision(const smp_target_t *tp) +{ + return (tp->st_revision); +} + +const char * +smp_target_component_vendor(const smp_target_t *tp) +{ + return (tp->st_component_vendor); +} + +uint16_t +smp_target_component_id(const smp_target_t *tp) +{ + return (tp->st_component_id); +} + +uint8_t +smp_target_component_revision(const smp_target_t *tp) +{ + return (tp->st_component_revision); +} + +uint_t +smp_target_getcap(const smp_target_t *tp) +{ + uint_t cap = 0; + + if (tp->st_repgen.srgr_long_response) + cap |= SMP_TARGET_C_LONG_RESP; + + if (tp->st_repgen.srgr_zoning_supported) + cap |= SMP_TARGET_C_ZONING; + + if (tp->st_repgen.srgr_number_of_zone_grps == SMP_ZONE_GROUPS_256) + cap |= SMP_TARGET_C_ZG_256; + + return (cap); +} + +void +smp_target_set_change_count(smp_target_t *tp, uint16_t cc) +{ + tp->st_change_count = cc; +} + +uint16_t +smp_target_get_change_count(const smp_target_t *tp) +{ + return (tp->st_change_count); +} + +void +smp_close(smp_target_t *tp) +{ + smp_free(tp->st_vendor); + smp_free(tp->st_product); + smp_free(tp->st_revision); + smp_free(tp->st_component_vendor); + + smp_plugin_unload(tp); + + tp->st_engine->se_ops->seo_close(tp->st_priv); + smp_engine_rele(tp->st_engine); + + smp_free(tp); +} + +/* + * 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 +smp_action_set_timeout(smp_action_t *ap, uint32_t timeout) +{ + ap->sa_timeout = timeout; +} + +/* + * Obtain the timeout setting for this action. + */ +uint32_t +smp_action_get_timeout(const smp_action_t *ap) +{ + return (ap->sa_timeout); +} + +const smp_function_def_t * +smp_action_get_function_def(const smp_action_t *ap) +{ + return (ap->sa_def); +} + +/* + * Obtain the user-requested request allocation size. Note that the + * interpretation of this is function-dependent. + */ +size_t +smp_action_get_rqsd(const smp_action_t *ap) +{ + return (ap->sa_request_rqsd); +} + +/* + * Obtains the address and amount of space allocated for the portion of the + * request data that lies between the header (if any) and the CRC. + */ +void +smp_action_get_request(const smp_action_t *ap, void **reqp, size_t *dlenp) +{ + if (reqp != NULL) { + if (ap->sa_request_data_off >= 0) { + *reqp = ap->sa_request + ap->sa_request_data_off; + } else { + *reqp = NULL; + } + } + + if (dlenp != NULL) + *dlenp = ap->sa_request_alloc_len - + (ap->sa_request_data_off + sizeof (smp_crc_t)); +} + +/* + * Obtains the address and amount of valid response data (that part of the + * response frame, if any, that lies between the header and the CRC). The + * result, if any, is also returned in the location pointed to by result. + */ +void +smp_action_get_response(const smp_action_t *ap, smp_result_t *resultp, + void **respp, size_t *dlenp) +{ + if (resultp != NULL) + *resultp = ap->sa_result; + + if (respp != NULL) + *respp = (ap->sa_response_data_len > 0) ? + (ap->sa_response + ap->sa_response_data_off) : NULL; + + if (dlenp != NULL) + *dlenp = ap->sa_response_data_len; +} + +/* + * Obtains the entire request frame and the amount of space allocated for it. + * This is intended only for use by plugins; front-end consumers should use + * smp_action_get_request() instead. + */ +void +smp_action_get_request_frame(const smp_action_t *ap, void **reqp, size_t *alenp) +{ + if (reqp != NULL) + *reqp = ap->sa_request; + + if (alenp != NULL) + *alenp = ap->sa_request_alloc_len; +} + +/* + * Obtains the entire response frame and the amount of space allocated for it. + * This is intended only for use by plugins; front-end consumers should use + * smp_action_get_response() instead. + */ +void +smp_action_get_response_frame(const smp_action_t *ap, + void **respp, size_t *lenp) +{ + if (respp != NULL) + *respp = ap->sa_response; + + if (lenp != NULL) { + if (ap->sa_flags & SMP_ACTION_F_EXEC) + *lenp = ap->sa_response_engine_len; + else + *lenp = ap->sa_response_alloc_len; + } +} + +/* + * Set the total response frame length as determined by the engine. This + * should never be called by consumers or plugins other than engines. + */ +void +smp_action_set_response_len(smp_action_t *ap, size_t elen) +{ + ap->sa_response_engine_len = elen; +} + +void +smp_action_set_result(smp_action_t *ap, smp_result_t result) +{ + ap->sa_result = result; +} + +/* + * Allocate an action object. The object will contain a request buffer + * to hold the frame to be transmitted to the target, a response buffer + * for the frame to be received from it, and auxiliary private information. + * + * For the request, callers may specify: + * + * - An externally-allocated buffer and its size in bytes, or + * - NULL and a function-specific size descriptor, or + * + * Note that for some functions, the size descriptor may be 0, indicating that + * a default buffer length will be used. It is the caller's responsibility + * to correctly interpret function-specific buffer lengths. See appropriate + * plugin documentation for information on buffer sizes and buffer content + * interpretation. + * + * For the response, callers may specify: + * + * - An externally-allocated buffer and its size in bytes, or + * - NULL and 0, to use a guaranteed-sufficient buffer. + * + * If an invalid request size descriptor is provided, or a preallocated + * buffer is provided and it is insufficiently large, this function will + * fail with ESMP_RANGE. + * + * Callers are discouraged from allocating their own buffers and must be + * aware of the consequences of specifying non-default lengths. + */ +smp_action_t * +smp_action_xalloc(smp_function_t fn, smp_target_t *tp, + void *rq, size_t rqsd, void *rs, size_t rslen) +{ + smp_plugin_t *pp; + const smp_function_def_t *dp = NULL; + smp_action_t *ap; + uint_t cap; + size_t rqlen, len; + uint8_t *alloc; + int i; + + cap = smp_target_getcap(tp); + + for (pp = tp->st_plugin_first; pp != NULL; pp = pp->sp_next) { + if (pp->sp_functions == NULL) + continue; + + for (i = 0; pp->sp_functions[i].sfd_rq_len != NULL; i++) { + dp = &pp->sp_functions[i]; + if (dp->sfd_function == fn && + ((cap & dp->sfd_capmask) == dp->sfd_capset)) + break; + } + } + + if (dp == NULL) { + (void) smp_set_errno(ESMP_BADFUNC); + return (NULL); + } + + if (rq == NULL) { + if ((rqlen = dp->sfd_rq_len(rqsd, tp)) == 0) + return (NULL); + } else if (rqlen < SMP_REQ_MINLEN) { + (void) smp_set_errno(ESMP_RANGE); + return (NULL); + } + + if (rs == NULL) { + rslen = 1020 + SMP_RESP_MINLEN; + } else if (rslen < SMP_RESP_MINLEN) { + (void) smp_set_errno(ESMP_RANGE); + return (NULL); + } + + len = offsetof(smp_action_t, sa_buf[0]); + if (rq == NULL) + len += rqlen; + if (rs == NULL) + len += rslen; + + if ((ap = smp_zalloc(len)) == NULL) + return (NULL); + + ap->sa_def = dp; + alloc = ap->sa_buf; + + if (rq == NULL) { + ap->sa_request = alloc; + alloc += rqlen; + } + ap->sa_request_alloc_len = rqlen; + + if (rs == NULL) { + ap->sa_response = alloc; + alloc += rslen; + } + ap->sa_response_alloc_len = rslen; + + ASSERT(alloc - (uint8_t *)ap == len); + + ap->sa_request_data_off = dp->sfd_rq_dataoff(ap, tp); + ap->sa_flags |= SMP_ACTION_F_OFFSET; + + return (ap); +} + +/* + * Simplified action allocator. All buffers are allocated for the + * caller. The request buffer size will be based on the function-specific + * interpretation of the rqsize parameter. The response buffer size will be + * a function-specific value sufficiently large to capture any response. + */ +smp_action_t * +smp_action_alloc(smp_function_t fn, smp_target_t *tp, size_t rqsd) +{ + return (smp_action_xalloc(fn, tp, NULL, rqsd, NULL, 0)); +} + +void +smp_action_free(smp_action_t *ap) +{ + if (ap == NULL) + return; + + smp_free(ap); +} + +/* + * 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 +smp_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 +smp_exec(smp_action_t *ap, smp_target_t *tp) +{ + const smp_function_def_t *dp; + int ret; + + dp = ap->sa_def; + dp->sfd_rq_setframe(ap, tp); + + if (tp->st_mtbf_request != 0) { + smp_inject_errors(ap->sa_request, ap->sa_request_alloc_len, + tp->st_mtbf_request); + } + + ret = tp->st_engine->se_ops->seo_exec(tp->st_priv, ap); + + if (ret == 0 && tp->st_mtbf_response != 0) { + smp_inject_errors(ap->sa_response, ap->sa_response_engine_len, + tp->st_mtbf_response); + } + + if (ret != 0) + return (ret); + + ap->sa_flags |= SMP_ACTION_F_EXEC; + + /* + * Obtain the data length and offset from the underlying plugins. + * Then offer the plugins the opportunity to set any parameters in the + * target to reflect state observed in the response. + */ + ap->sa_response_data_len = dp->sfd_rs_datalen(ap, tp); + ap->sa_response_data_off = dp->sfd_rs_dataoff(ap, tp); + dp->sfd_rs_getparams(ap, tp); + + ap->sa_flags |= SMP_ACTION_F_DECODE; + + return (0); +} diff --git a/usr/src/lib/scsi/libsmp/common/smp_impl.h b/usr/src/lib/scsi/libsmp/common/smp_impl.h new file mode 100644 index 0000000000..14b069a16f --- /dev/null +++ b/usr/src/lib/scsi/libsmp/common/smp_impl.h @@ -0,0 +1,123 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#ifndef _SMP_IMPL_H +#define _SMP_IMPL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/scsi/generic/smp_frames.h> + +#include <scsi/libsmp.h> +#include <scsi/libsmp_plugin.h> + +#include <pthread.h> + +#define LIBSMP_ERRMSGLEN 512 + +#define LIBSMP_DEFAULT_PLUGINDIR "/usr/lib/scsi/plugins/smp" +#define LIBSMP_PLUGIN_ENGINE "engine" +#define LIBSMP_PLUGIN_FRAMEWORK "framework" +#define LIBSMP_PLUGIN_VENDOR "vendor" + +#define LIBSMP_PLUGIN_EXT ".so" + +#define LIBSMP_DEFAULT_ENGINE "usmp" + +struct smp_engine { + char *se_name; + const smp_engine_ops_t *se_ops; + void *se_object; + int (*se_init)(struct smp_engine *); + void (*se_fini)(struct smp_engine *); + uint_t se_refcnt; + struct smp_engine *se_next; +}; + +struct smp_plugin { + struct smp_plugin *sp_next; + struct smp_plugin *sp_prev; + smp_target_t *sp_target; + uint64_t sp_priority; + void *sp_object; + void *sp_data; + boolean_t sp_initialized; + const smp_function_def_t *sp_functions; + int (*sp_init)(smp_plugin_t *); + void (*sp_fini)(smp_plugin_t *); +}; + +#define SMP_ACTION_F_OFFSET 0x01 +#define SMP_ACTION_F_EXEC 0x02 +#define SMP_ACTION_F_DECODE 0x04 + +struct smp_action { + uint32_t sa_timeout; + const smp_function_def_t *sa_def; + uint8_t *sa_request; + size_t sa_request_rqsd; + size_t sa_request_alloc_len; + off_t sa_request_data_off; + uint8_t *sa_response; + size_t sa_response_alloc_len; + size_t sa_response_engine_len; + size_t sa_response_data_len; + off_t sa_response_data_off; + smp_result_t sa_result; + uint_t sa_flags; + uint_t sa_cap; + uint8_t sa_buf[1]; +}; + +struct smp_target { + smp_engine_t *st_engine; + void *st_priv; + uint_t st_mtbf_request; + uint_t st_mtbf_response; + uint16_t st_change_count; + smp_plugin_t *st_plugin_first; + smp_plugin_t *st_plugin_last; + char *st_vendor; + char *st_product; + char *st_revision; + char *st_component_vendor; + uint16_t st_component_id; + uint8_t st_component_revision; + smp_report_general_resp_t st_repgen; +}; + +extern void smp_engine_init(void); +extern void smp_engine_fini(void); + +extern int smp_plugin_load(smp_target_t *); +extern void smp_plugin_unload(smp_target_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _SMP_IMPL_H */ diff --git a/usr/src/lib/scsi/libsmp/common/smp_plugin.c b/usr/src/lib/scsi/libsmp/common/smp_plugin.c new file mode 100644 index 0000000000..3df5e6e649 --- /dev/null +++ b/usr/src/lib/scsi/libsmp/common/smp_plugin.c @@ -0,0 +1,428 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#include <sys/types.h> +#include <sys/systeminfo.h> +#include <sys/scsi/generic/commands.h> +#include <sys/scsi/impl/commands.h> + +#include <scsi/libsmp.h> +#include <scsi/libsmp_plugin.h> + +#include <alloca.h> +#include <dlfcn.h> +#include <link.h> +#include <dirent.h> +#include <string.h> +#include <strings.h> +#include <limits.h> + +#include "smp_impl.h" + +static boolean_t _libsmp_plugin_dlclose; + +/* + * As part of basic initialization, we always retrieve the REPORT GENERAL + * data so that we will know whether this target supports the long response + * format. + */ +static int +smp_report_general(smp_target_t *tp) +{ + smp_action_t *ap; + smp_report_general_resp_t *rp; + smp_result_t result; + size_t len; + + if ((ap = smp_action_alloc(SMP_FUNC_REPORT_GENERAL, tp, 0)) == NULL) + return (-1); + + if (smp_exec(ap, tp) != 0) { + smp_action_free(ap); + return (smp_set_errno(ESMP_REPGEN_FAILED)); + } + + smp_action_get_response(ap, &result, (void **)&rp, &len); + + if (result != SMP_RES_FUNCTION_ACCEPTED || len < 24) { + smp_action_free(ap); + return (smp_set_errno(ESMP_REPGEN_FAILED)); + } + + bcopy(rp, &tp->st_repgen, sizeof (tp->st_repgen)); + + smp_action_free(ap); + + return (0); +} + +static int +smp_report_manufacturer_information(smp_target_t *tp) +{ + smp_action_t *ap; + smp_report_manufacturer_info_resp_t *rp; + smp_result_t result; + size_t len; + + ap = smp_action_alloc(SMP_FUNC_REPORT_MANUFACTURER_INFO, tp, 0); + if (ap == NULL) + return (-1); + + if (smp_exec(ap, tp) != 0) { + smp_action_free(ap); + return (smp_set_errno(ESMP_REPGEN_FAILED)); + } + + smp_action_get_response(ap, &result, (void **)&rp, &len); + + if (result != SMP_RES_FUNCTION_ACCEPTED || + len != sizeof (smp_report_manufacturer_info_resp_t)) { + smp_action_free(ap); + return (0); /* Not supported */ + } + + tp->st_vendor = smp_trim_strdup(rp->srmir_vendor_identification, + sizeof (rp->srmir_vendor_identification)); + tp->st_product = smp_trim_strdup(rp->srmir_product_identification, + sizeof (rp->srmir_product_identification)); + tp->st_revision = smp_trim_strdup(rp->srmir_product_revision_level, + sizeof (rp->srmir_product_revision_level)); + + if (rp->srmir_sas_1_1_format) { + tp->st_component_vendor = + smp_trim_strdup(rp->srmir_component_vendor_identification, + sizeof (rp->srmir_component_vendor_identification)); + + tp->st_component_id = SCSI_READ16(&rp->srmir_component_id); + tp->st_component_revision = rp->srmir_component_revision_level; + } + + if (tp->st_vendor == NULL || tp->st_product == NULL || + tp->st_revision == NULL || + (rp->srmir_sas_1_1_format && tp->st_component_vendor == NULL)) { + smp_action_free(ap); + return (smp_set_errno(ESMP_NOMEM)); + } + + smp_action_free(ap); + + return (0); +} + +static int +smp_target_fill(smp_target_t *tp) +{ + if (smp_report_general(tp) != 0 || + smp_report_manufacturer_information(tp) != 0) + return (-1); + + return (0); +} + +const smp_function_def_t * +smp_get_funcdef(smp_target_t *tp, int fn) +{ + smp_plugin_t *pp; + const smp_function_def_t *dp; + + for (pp = tp->st_plugin_first; pp != NULL; pp = pp->sp_next) { + if (pp->sp_functions == NULL) + continue; + + for (dp = &pp->sp_functions[0]; dp->sfd_rq_len != NULL; dp++) { + if (dp->sfd_function == fn) + return (dp); + } + } + + (void) smp_error(ESMP_BADFUNC, "failed to find function 0x%x", fn); + return (NULL); +} + +int +smp_plugin_register(smp_plugin_t *pp, int version, + const smp_plugin_config_t *pcp) +{ + if (version != LIBSMP_PLUGIN_VERSION) + return (smp_set_errno(ESMP_VERSION)); + + pp->sp_functions = pcp->spc_functions; + + return (0); +} + +void +smp_plugin_setspecific(smp_plugin_t *pp, void *data) +{ + pp->sp_data = data; +} + +void * +smp_plugin_getspecific(smp_plugin_t *pp) +{ + return (pp->sp_data); +} + +static void +smp_plugin_cleanstr(char *s) +{ + while (*s != '\0') { + if (*s == ' ' || *s == '/') + *s = '-'; + s++; + } +} + +static void +smp_plugin_destroy(smp_plugin_t *pp) +{ + if (pp->sp_initialized && pp->sp_fini != NULL) + pp->sp_fini(pp); + + if (_libsmp_plugin_dlclose) + (void) dlclose(pp->sp_object); + + smp_free(pp); +} + +static int +smp_plugin_loadone(smp_target_t *tp, const char *path, uint32_t pass) +{ + smp_plugin_t *pp, **loc; + void *obj; + int (*smp_priority)(void); + + if ((obj = dlopen(path, RTLD_PARENT | RTLD_LOCAL | RTLD_LAZY)) == NULL) + return (0); + + if ((pp = smp_zalloc(sizeof (smp_plugin_t))) == NULL) { + (void) dlclose(obj); + return (-1); + } + + pp->sp_object = obj; + pp->sp_init = (int (*)())dlsym(obj, "_smp_init"); + pp->sp_fini = (void (*)())dlsym(obj, "_smp_fini"); + pp->sp_target = tp; + + if (pp->sp_init == NULL) { + smp_plugin_destroy(pp); + return (0); + } + + /* + * Framework modules can establish an explicit prioritying by declaring + * the '_smp_priority' symbol, which returns an integer used to create + * an explicit ordering between plugins. + */ + if ((smp_priority = (int (*)())dlsym(obj, "_smp_priority")) != NULL) + pp->sp_priority = smp_priority(); + + pp->sp_priority |= (uint64_t)pass << 32; + + for (loc = &tp->st_plugin_first; *loc != NULL; loc = &(*loc)->sp_next) { + if ((*loc)->sp_priority > pp->sp_priority) + break; + } + + if (*loc != NULL) + (*loc)->sp_prev = pp; + else + tp->st_plugin_last = pp; + + pp->sp_next = *loc; + *loc = pp; + + if (pp->sp_init(pp) != 0) + return (-1); + pp->sp_initialized = B_TRUE; + + return (0); +} + +static int +smp_plugin_load_dir(smp_target_t *tp, const char *pluginroot) +{ + char path[PATH_MAX]; + DIR *dirp; + struct dirent64 *dp; + char *c_vendor, *vendor, *product, *revision; + char isa[257]; + + (void) snprintf(path, sizeof (path), "%s/%s", + pluginroot, LIBSMP_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, LIBSMP_PLUGIN_FRAMEWORK, + isa, dp->d_name); + + if (smp_plugin_loadone(tp, path, 0) != 0) { + (void) closedir(dirp); + return (-1); + } + } + + (void) closedir(dirp); + } + + /* + * Now attempt to load platform-specific plugins. The framework + * plugins had better give us the ability to perform basic SMP + * functions like REPORT GENERAL and REPORT MANUFACTURER INFORMATION; + * if not, we're toast anyway. If the latter is not supported, we + * will not be able to use any vendor-specific plugins. Note that + * there are actually two possible specifications for vendor plugins: + * those matching the vendor/product/revision fields, and those + * matching the component vendor/id/revision fields. The component is + * less specific, so we try to load those first. + */ + + if (smp_target_fill(tp) != 0) + return (-1); + + if (tp->st_vendor == NULL) + return (0); + + if (tp->st_component_vendor != NULL) { + c_vendor = alloca(strlen(tp->st_component_vendor) + 1); + (void) strcpy(c_vendor, tp->st_component_vendor); + smp_plugin_cleanstr(c_vendor); + } + + vendor = alloca(strlen(tp->st_vendor) + 1); + product = alloca(strlen(tp->st_product) + 1); + revision = alloca(strlen(tp->st_revision) + 1); + + (void) strcpy(vendor, tp->st_vendor); + (void) strcpy(product, tp->st_product); + (void) strcpy(revision, tp->st_revision); + + smp_plugin_cleanstr(vendor); + smp_plugin_cleanstr(product); + smp_plugin_cleanstr(revision); + + if (tp->st_component_vendor != NULL) { + (void) snprintf(path, sizeof (path), "%s/%s/%s/component_%s%s", + pluginroot, LIBSMP_PLUGIN_VENDOR, isa, c_vendor, + LIBSMP_PLUGIN_EXT); + if (smp_plugin_loadone(tp, path, 1) != 0) + return (-1); + + (void) snprintf(path, sizeof (path), + "%s/%s/%s/component_%s-%04x%s", + pluginroot, LIBSMP_PLUGIN_VENDOR, isa, c_vendor, + tp->st_component_id, LIBSMP_PLUGIN_EXT); + if (smp_plugin_loadone(tp, path, 2) != 0) + return (-1); + + (void) snprintf(path, sizeof (path), + "%s/%s/%s/component_%s-%04x-%02x%s", + pluginroot, LIBSMP_PLUGIN_VENDOR, isa, c_vendor, + tp->st_component_id, tp->st_component_revision, + LIBSMP_PLUGIN_EXT); + if (smp_plugin_loadone(tp, path, 3) != 0) + return (-1); + } + + (void) snprintf(path, sizeof (path), "%s/%s/%s/%s%s", pluginroot, + LIBSMP_PLUGIN_VENDOR, isa, vendor, LIBSMP_PLUGIN_EXT); + if (smp_plugin_loadone(tp, path, 4) != 0) + return (-1); + + (void) snprintf(path, sizeof (path), "%s/%s/%s/%s-%s%s", pluginroot, + LIBSMP_PLUGIN_VENDOR, isa, vendor, product, LIBSMP_PLUGIN_EXT); + if (smp_plugin_loadone(tp, path, 5) != 0) + return (-1); + + (void) snprintf(path, sizeof (path), "%s/%s/%s/%s-%s-%s%s", pluginroot, + LIBSMP_PLUGIN_VENDOR, isa, vendor, product, + revision, LIBSMP_PLUGIN_EXT); + if (smp_plugin_loadone(tp, path, 6) != 0) + return (-1); + + return (0); +} + +int +smp_plugin_load(smp_target_t *tp) +{ + char pluginroot[PATH_MAX]; + const char *pluginpath, *p, *q; + + if ((pluginpath = getenv("SMP_PLUGINPATH")) == NULL) + pluginpath = LIBSMP_DEFAULT_PLUGINDIR; + _libsmp_plugin_dlclose = (getenv("SMP_NODLCLOSE") == NULL); + + for (p = pluginpath; p != NULL; p = q) { + if ((q = strchr(p, ':')) != 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 (smp_plugin_load_dir(tp, pluginroot) != 0) + return (-1); + } + + if (tp->st_plugin_first == NULL) + return (smp_error(ESMP_PLUGIN, "no plugins found")); + + return (0); +} + +void +smp_plugin_unload(smp_target_t *tp) +{ + smp_plugin_t *pp; + + while ((pp = tp->st_plugin_first) != NULL) { + tp->st_plugin_first = pp->sp_next; + smp_plugin_destroy(pp); + } +} diff --git a/usr/src/lib/scsi/libsmp/common/smp_subr.c b/usr/src/lib/scsi/libsmp/common/smp_subr.c new file mode 100644 index 0000000000..f332c3c7bf --- /dev/null +++ b/usr/src/lib/scsi/libsmp/common/smp_subr.c @@ -0,0 +1,244 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#include <sys/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 <thread.h> +#include <pthread.h> +#include <ctype.h> + +#include <scsi/libsmp.h> +#include <scsi/libsmp_plugin.h> +#include "smp_impl.h" + +__thread smp_errno_t _smp_errno; +__thread char _smp_errmsg[LIBSMP_ERRMSGLEN]; + +int +smp_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 +smp_set_errno(smp_errno_t err) +{ + _smp_errno = err; + _smp_errmsg[0] = '\0'; + + return (-1); +} + +/* + * Internal routine for setting both _smp_errno and _smp_errmsg. We save + * and restore the UNIX errno across this routing so the caller can use either + * smp_set_errno(), smp_error(), or smp_verror() without this value changing. + */ +int +smp_verror(smp_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 smp_set_errno() is destructive to + * lsh_errmsg, we do this after we print into our temporary buffer + * (in case _smp_errmsg is part of the error message) and before we + * copy the temporary buffer on to _smp_errmsg (to prevent our new + * message from being nuked by the call to smp_set_errno()). + */ + errmsg = alloca(sizeof (_smp_errmsg)); + (void) vsnprintf(errmsg, sizeof (_smp_errmsg), fmt, ap); + (void) smp_set_errno(err); + + n = strlen(errmsg); + + if (n != 0 && errmsg[n - 1] == '\n') + errmsg[n - 1] = '\0'; + + bcopy(errmsg, _smp_errmsg, n + 1); + + return (-1); +} + +int +smp_error(smp_errno_t err, const char *fmt, ...) +{ + va_list ap; + + if (fmt == NULL) + return (smp_set_errno(err)); + + va_start(ap, fmt); + err = smp_verror(err, fmt, ap); + va_end(ap); + + return (err); +} + +smp_errno_t +smp_errno(void) +{ + return (_smp_errno); +} + +const char * +smp_errmsg(void) +{ + if (_smp_errmsg[0] == '\0') + (void) strlcpy(_smp_errmsg, smp_strerror(_smp_errno), + sizeof (_smp_errmsg)); + + return (_smp_errmsg); +} + +/*ARGSUSED*/ +void * +smp_alloc(size_t size) +{ + void *mem; + + if (size == 0) { + (void) smp_set_errno(ESMP_ZERO_LENGTH); + return (NULL); + } + + if ((mem = malloc(size)) == NULL) + (void) smp_set_errno(ESMP_NOMEM); + + return (mem); +} + +void * +smp_zalloc(size_t size) +{ + void *mem; + + if ((mem = smp_alloc(size)) == NULL) + return (NULL); + + bzero(mem, size); + + return (mem); +} + +char * +smp_strdup(const char *str) +{ + size_t len = strlen(str); + char *dup = smp_alloc(len + 1); + + if (dup == NULL) + return (NULL); + + return (strcpy(dup, str)); +} + +void +smp_free(void *ptr) +{ + free(ptr); +} + +/* + * Trim any leading and/or trailing spaces from the fixed-length string + * argument and return a newly-allocated copy of it. + */ +char * +smp_trim_strdup(const char *str, size_t len) +{ + const char *p; + char *r; + + for (p = str; p - str < len && isspace(*p); p++) + ; + + len -= (p - str); + + if (len == 0) + return (NULL); + + for (str = p + len - 1; str > p && isspace(*str); str--, len--) + ; + + if (len == 0) + return (NULL); + + r = smp_alloc(len + 1); + if (r == NULL) + return (NULL); + + bcopy(p, r, len); + r[len] = '\0'; + + return (r); +} + +int +smp_init(int version) +{ + if (version != LIBSMP_VERSION) + return (smp_error(ESMP_VERSION, + "library version %d does not match requested version %d", + LIBSMP_VERSION, version)); + + smp_engine_init(); + + return (0); +} + +void +smp_fini(void) +{ + smp_engine_fini(); +} diff --git a/usr/src/lib/scsi/libsmp/i386/Makefile b/usr/src/lib/scsi/libsmp/i386/Makefile new file mode 100644 index 0000000000..c6e75c4787 --- /dev/null +++ b/usr/src/lib/scsi/libsmp/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 (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) diff --git a/usr/src/lib/scsi/libsmp/libsmp_api.map b/usr/src/lib/scsi/libsmp/libsmp_api.map new file mode 100644 index 0000000000..1abe720d13 --- /dev/null +++ b/usr/src/lib/scsi/libsmp/libsmp_api.map @@ -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 (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +{ + smp_strerror = FUNCTION extern; + smp_errname = FUNCTION extern; + smp_errcode = FUNCTION extern; + smp_alloc = FUNCTION extern; + smp_zalloc = FUNCTION extern; + smp_strdup = FUNCTION extern; + smp_free = FUNCTION extern; + smp_set_errno = FUNCTION extern; + smp_verror = FUNCTION extern; + smp_error = FUNCTION extern; + smp_action_get_timeout = FUNCTION extern; + smp_action_get_request = FUNCTION extern; + smp_action_get_response = FUNCTION extern; + smp_action_get_request_frame = FUNCTION extern; + smp_action_get_response_frame = FUNCTION extern; + smp_action_get_function_def = FUNCTION extern; + smp_action_set_response_len = FUNCTION extern; + smp_action_set_result = FUNCTION extern; + smp_target_getcap = FUNCTION extern; + smp_target_set_change_count = FUNCTION extern; + smp_target_get_change_count = FUNCTION extern; + smp_assert = FUNCTION extern; + smp_engine_register = FUNCTION extern; + smp_plugin_register = FUNCTION extern; +}; diff --git a/usr/src/lib/scsi/libsmp/llib-lsmp b/usr/src/lib/scsi/libsmp/llib-lsmp new file mode 100644 index 0000000000..3beb22f496 --- /dev/null +++ b/usr/src/lib/scsi/libsmp/llib-lsmp @@ -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 (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + + +/*LINTLIBRARY*/ +/*PROTOLIB1*/ + +#include <scsi/libsmp.h> +#include <scsi/libsmp_plugin.h> diff --git a/usr/src/lib/scsi/libsmp/mapfile-vers b/usr/src/lib/scsi/libsmp/mapfile-vers new file mode 100644 index 0000000000..aabf0f23c3 --- /dev/null +++ b/usr/src/lib/scsi/libsmp/mapfile-vers @@ -0,0 +1,90 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +# +# MAPFILE HEADER START +# +# WARNING: STOP NOW. DO NOT MODIFY THIS FILE. +# Object versioning must comply with the rules detailed in +# +# usr/src/lib/README.mapfiles +# +# You should not be making modifications here until you've read the most current +# copy of that file. If you need help, contact a gatekeeper for guidance. +# +# MAPFILE HEADER END +# + +SUNWprivate_1.1 { + global: + smp_init; + smp_fini; + smp_open; + smp_target_getcap; + smp_target_set_change_count; + smp_target_get_change_count; + smp_target_vendor; + smp_target_product; + smp_target_revision; + smp_target_component_vendor; + smp_target_component_id; + smp_target_component_revision; + smp_target_name; + smp_target_addr; + smp_close; + smp_action_alloc; + smp_action_get_timeout; + smp_action_set_timeout; + smp_action_get_request; + smp_action_get_response; + smp_action_get_request_frame; + smp_action_get_response_frame; + smp_action_get_function_def; + smp_action_set_response_len; + smp_action_set_result; + smp_action_free; + smp_exec; + smp_errno; + smp_errmsg; + smp_strerror; + smp_errname; + smp_errcode; + smp_assert; + smp_engine_register; + smp_plugin_register; + smp_plugin_setspecific; + smp_plugin_getspecific; + + smp_alloc; + smp_zalloc; + smp_strdup; + smp_free; + smp_set_errno; + smp_verror; + smp_error; + + local: + *; +}; diff --git a/usr/src/lib/scsi/libsmp/sparc/Makefile b/usr/src/lib/scsi/libsmp/sparc/Makefile new file mode 100644 index 0000000000..c6e75c4787 --- /dev/null +++ b/usr/src/lib/scsi/libsmp/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 (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) diff --git a/usr/src/lib/scsi/libsmp/sparcv9/Makefile b/usr/src/lib/scsi/libsmp/sparcv9/Makefile new file mode 100644 index 0000000000..e59eb2b811 --- /dev/null +++ b/usr/src/lib/scsi/libsmp/sparcv9/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 (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +include ../Makefile.com +include ../../../Makefile.lib.64 + +install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64) diff --git a/usr/src/lib/scsi/plugins/Makefile b/usr/src/lib/scsi/plugins/Makefile index 3541ca3744..adca0d6bc9 100644 --- a/usr/src/lib/scsi/plugins/Makefile +++ b/usr/src/lib/scsi/plugins/Makefile @@ -20,14 +20,13 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. # -#ident "%Z%%M% %I% %E% SMI" SUBDIRS = \ scsi \ - ses + ses \ + smp .KEEP_STATE: diff --git a/usr/src/lib/scsi/plugins/ses/LSILOGIC-SASX28-A.0/Makefile.com b/usr/src/lib/scsi/plugins/ses/LSILOGIC-SASX28-A.0/Makefile.com index 12b1a6a086..b9ddfada51 100644 --- a/usr/src/lib/scsi/plugins/ses/LSILOGIC-SASX28-A.0/Makefile.com +++ b/usr/src/lib/scsi/plugins/ses/LSILOGIC-SASX28-A.0/Makefile.com @@ -20,16 +20,13 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. # -#ident "%Z%%M% %I% %E% SMI" - MODULE = LSILOGIC-SASX28-A.0 SRCS = lsilogic.c SRCDIR = ../common PLUGINTYPE = vendor -ALIASES = +ALIASES = LSILOGIC-SASX28-A.1 include ../../Makefile.lib diff --git a/usr/src/lib/scsi/plugins/ses/SUN/Makefile b/usr/src/lib/scsi/plugins/ses/SUN/Makefile index 76abb8e31f..2a0b08ec73 100644 --- a/usr/src/lib/scsi/plugins/ses/SUN/Makefile +++ b/usr/src/lib/scsi/plugins/ses/SUN/Makefile @@ -20,11 +20,10 @@ # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # -HDRS = +HDRS = sun.h sun_impl.h HDRDIR = common PLUGINTYPE = vendor diff --git a/usr/src/lib/scsi/plugins/ses/SUN/Makefile.com b/usr/src/lib/scsi/plugins/ses/SUN/Makefile.com index ca7636d0d1..af2b60f558 100644 --- a/usr/src/lib/scsi/plugins/ses/SUN/Makefile.com +++ b/usr/src/lib/scsi/plugins/ses/SUN/Makefile.com @@ -20,13 +20,19 @@ # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # MODULE = SUN -SRCS = sun_spms.c +SRCS = sun.c \ + sun_element.c \ + sun_enclosure.c \ + sun_pages.c + SRCDIR = ../common PLUGINTYPE = vendor include ../../Makefile.lib + +$(PROG) := LDLIBS += -lnvfru + diff --git a/usr/src/lib/scsi/plugins/ses/SUN/common/sun.c b/usr/src/lib/scsi/plugins/ses/SUN/common/sun.c new file mode 100644 index 0000000000..32753a2eee --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/SUN/common/sun.c @@ -0,0 +1,79 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#include <stddef.h> +#include <string.h> +#include <strings.h> +#include <alloca.h> +#include <libnvpair.h> + +#include <scsi/libses.h> +#include <scsi/libses_plugin.h> +#include <scsi/plugins/ses/framework/libses.h> +#include <scsi/plugins/ses/vendor/sun.h> +#include <scsi/plugins/ses/vendor/sun_impl.h> + +#include "../../../../../../lib/libfru/libnvfru/nvfru.h" + +int +sun_fruid_parse_common(sun_fru_descr_impl_t *sfdip, nvlist_t *nvl) +{ + int nverr; + + SES_NV_ADD(boolean_value, nverr, nvl, + LIBSES_PROP_FRU, sfdip-> sfdi_fru); + SES_NV_ADD(uint64, nverr, nvl, + LIBSES_PROP_PHYS_PARENT, sfdip->sfdi_parent_element_index); + + return (0); +} + +static int +sun_node_parse(ses_plugin_t *sp, ses_node_t *np) +{ + switch (ses_node_type(np)) { + case SES_NODE_ENCLOSURE: + return (sun_fill_enclosure_node(sp, np)); + + case SES_NODE_AGGREGATE: + case SES_NODE_ELEMENT: + return (sun_fill_element_node(sp, np)); + + default: + return (0); + } +} + +int +_ses_init(ses_plugin_t *sp) +{ + ses_plugin_config_t config = { + .spc_pages = sun_pages, + .spc_node_parse = sun_node_parse + }; + + return (ses_plugin_register(sp, LIBSES_PLUGIN_VERSION, + &config) != 0); +} diff --git a/usr/src/lib/scsi/plugins/ses/SUN/common/sun.h b/usr/src/lib/scsi/plugins/ses/SUN/common/sun.h new file mode 100644 index 0000000000..cf519a8568 --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/SUN/common/sun.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 (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#ifndef _VENDOR_SUN_H +#define _VENDOR_SUN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Node properties + */ +#define SUN_DIAGPAGE_FRUID SES2_DIAGPAGE_VENDOR_0 + +#ifdef __cplusplus +} +#endif + +#endif /* _VENDOR_SUN_H */ diff --git a/usr/src/lib/scsi/plugins/ses/SUN/common/sun_element.c b/usr/src/lib/scsi/plugins/ses/SUN/common/sun_element.c new file mode 100644 index 0000000000..433342fae7 --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/SUN/common/sun_element.c @@ -0,0 +1,53 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#include <sys/types.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> +#include <libnvpair.h> + +#include <scsi/libses.h> +#include <scsi/libses_plugin.h> +#include <scsi/plugins/ses/vendor/sun.h> +#include <scsi/plugins/ses/vendor/sun_impl.h> + +int +sun_fill_element_node(ses_plugin_t *sp, ses_node_t *np) +{ + ses_snap_t *snap = ses_node_snapshot(np); + nvlist_t *props = ses_node_props(np); + sun_fru_descr_impl_t *sfdip; + size_t len; + int err; + + if ((sfdip = ses_plugin_page_lookup(sp, snap, + SUN_DIAGPAGE_FRUID, np, &len)) != NULL) { + if ((err = sun_fruid_parse_common(sfdip, props)) != 0) + return (err); + } + + return (0); +} diff --git a/usr/src/lib/scsi/plugins/ses/SUN/common/sun_enclosure.c b/usr/src/lib/scsi/plugins/ses/SUN/common/sun_enclosure.c new file mode 100644 index 0000000000..f825b00ff3 --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/SUN/common/sun_enclosure.c @@ -0,0 +1,142 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#include <sys/scsi/impl/spc3_types.h> + +#include <stddef.h> +#include <string.h> +#include <strings.h> +#include <libnvpair.h> + +#include <scsi/libses.h> +#include <scsi/libses_plugin.h> +#include <scsi/plugins/ses/framework/ses2.h> +#include <scsi/plugins/ses/framework/ses2_impl.h> +#include <scsi/plugins/ses/framework/libses.h> +#include <scsi/plugins/ses/vendor/sun.h> +#include <scsi/plugins/ses/vendor/sun_impl.h> + +/*ARGSUSED*/ +static int +enc_parse_feature_block(ses_plugin_t *sp, ses_node_t *np) +{ + sun_feature_block_impl_t *sfbip; + nvlist_t *encprops; + uint8_t *vsp; + uint_t vsp_len; + uint_t cid_off, cid_len; + uint16_t revision; + uint64_t chunk; + int nverr; + + encprops = ses_node_props(np); + if (nvlist_lookup_byte_array(encprops, SES_EN_PROP_VS, + &vsp, &vsp_len) != 0 || + vsp_len < offsetof(sun_feature_block_impl_t, _reserved2)) + return (0); + + sfbip = (sun_feature_block_impl_t *)vsp; + + if (strncmp((char *)sfbip->sfbi_spms_header, "SPMS", 4) != 0 || + sfbip->sfbi_spms_major_ver != 1) + return (0); + + revision = SCSI_READ16(&sfbip->sfbi_spms_revision); + + /* + * The offset read from the Sun Feature Block needs to be adjusted + * so that the difference in the sizes of the Enclosure + * Descriptor and the INQUIRY data format is accounted for. + */ + cid_len = sfbip->sfbi_chassis_id_len; + + if (sfbip->sfbi_chassis_id_off >= 96 && cid_len >= 4) { + cid_off = sfbip->sfbi_chassis_id_off - + (sizeof (ses2_ed_impl_t) - 1); + cid_off += offsetof(ses2_ed_impl_t, st_priv[0]) - + offsetof(spc3_inquiry_data_t, id_vs_36[0]); + + if (cid_off + cid_len <= vsp_len) { + SES_NV_ADD(fixed_string, nverr, encprops, + LIBSES_EN_PROP_CSN, (char *)(vsp + cid_off), + cid_len); + } + } + + if (revision >= 104) { + SES_NV_ADD(boolean_value, nverr, encprops, + LIBSES_EN_PROP_INTERNAL, sfbip->sfbi_int); + } + + if (revision >= 105) { + if (sfbip->sfbi_fw_upload_max_chunk_sz == 0) + chunk = 512; + else if (sfbip->sfbi_fw_upload_max_chunk_sz == 0x7f) + chunk = 65536; + else + chunk = 512 * sfbip->sfbi_fw_upload_max_chunk_sz; + + SES_NV_ADD(uint64, nverr, encprops, + LIBSES_EN_PROP_FIRMWARE_CHUNK_SIZE, chunk); + } + + /* + * If this is a subchassis, it will have a subchassis index field + * with a value other than 0. See SPMS-1r111 4.1.3.1. If not, we + * will see 0 and will not create the subchassis member at all; note + * that this is backward-compatible with pre-111 implementations that + * treated this as a reserved field. No such implementation contains + * a subchassis. + */ + if (sfbip->sfbi_spms_revision >= 111 && + sfbip->sfbi_subchassis_index != 0) { + SES_NV_ADD(uint64, nverr, encprops, + LIBSES_EN_PROP_SUBCHASSIS_ID, + sfbip->sfbi_subchassis_index - 1); + } + + return (0); +} + +int +sun_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); + sun_fru_descr_impl_t *sfdi; + int err; + size_t len; + + if ((err = enc_parse_feature_block(sp, np)) != 0) + return (err); + + if ((sfdi = ses_plugin_page_lookup(sp, snap, + SUN_DIAGPAGE_FRUID, np, &len)) != NULL) { + if ((err = sun_fruid_parse_common(sfdi, props)) != 0) + return (err); + } + + return (0); +} diff --git a/usr/src/lib/scsi/plugins/ses/SUN/common/sun_impl.h b/usr/src/lib/scsi/plugins/ses/SUN/common/sun_impl.h new file mode 100644 index 0000000000..3429f8fd7b --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/SUN/common/sun_impl.h @@ -0,0 +1,101 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#ifndef _PLUGIN_SUN_IMPL_H +#define _PLUGIN_SUN_IMPL_H + +#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) + +/* + * SPMS-1 r111, section 4.2.4 - Configuration + * SPMS-1 r111, section 4.1.3.1, Table 8 - Sun Feature Definition + */ +typedef struct sun_feature_block_impl { + uint8_t sfbi_spms_header[4]; + uint8_t sfbi_spms_major_ver; + uint8_t _reserved1; + uint16_t sfbi_spms_revision; + uint8_t sfbi_chassis_id_off; + uint8_t sfbi_chassis_id_len; + DECL_BITFIELD2( + sfbi_fw_upload_max_chunk_sz :7, + sfbi_int :1); + uint8_t sfbi_subchassis_index; + uint8_t _reserved2[48]; + uint8_t sfbi_ps[1]; /* Flexible platform specific content */ +} sun_feature_block_impl_t; + +/* + * SPMS-1 SUNW,FRUID FRU descriptor (Table 23, 4.2.18) + */ +typedef struct sun_fru_descr_impl { + DECL_BITFIELD2( + sfdi_fru :1, + _reserved1 :7); + uint8_t sfdi_parent_element_index; + uint16_t sfdi_fru_data_length; + uint8_t sfdi_fru_data[1]; /* FRUPROM contents */ +} sun_fru_descr_impl_t; + +/* + * SPMS-1 SUNW,FRUID diagnostic page (Table 22, 4.2.18) + */ +typedef struct sun_fruid_page_impl { + uint8_t sfpi_page_code; + uint8_t _reserved1; + uint16_t sfpi_page_length; + uint32_t sfpi_generation_code; + uint16_t sfpi_descr_addrs[1]; +} sun_fruid_page_impl_t; + +#pragma pack() + +extern ses_pagedesc_t sun_pages[]; + +extern int sun_fill_element_node(ses_plugin_t *, ses_node_t *); +extern int sun_fill_enclosure_node(ses_plugin_t *, ses_node_t *); +extern int sun_fruid_parse_common(sun_fru_descr_impl_t *, nvlist_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _PLUGIN_SUN_IMPL_H */ diff --git a/usr/src/lib/scsi/plugins/ses/SUN/common/sun_pages.c b/usr/src/lib/scsi/plugins/ses/SUN/common/sun_pages.c new file mode 100644 index 0000000000..d8796418e6 --- /dev/null +++ b/usr/src/lib/scsi/plugins/ses/SUN/common/sun_pages.c @@ -0,0 +1,79 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#include <stddef.h> +#include <strings.h> + +#include <scsi/libses.h> +#include <scsi/libses_plugin.h> +#include <scsi/plugins/ses/vendor/sun.h> +#include <scsi/plugins/ses/vendor/sun_impl.h> + +/*ARGSUSED*/ +static void * +sun_fruid_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); + sun_fruid_page_impl_t *sfpip = data; + sun_fru_descr_impl_t *sfdip; + uint16_t *addr; + + if (ses_node_type(np) != SES_NODE_ELEMENT && + ses_node_type(np) != SES_NODE_ENCLOSURE) + return (NULL); + + if (nvlist_lookup_uint64(props, SES_PROP_ELEMENT_ONLY_INDEX, + &index) != 0) + return (NULL); + + addr = &sfpip->sfpi_descr_addrs[index]; + if (!SES_WITHIN_PAGE_STRUCT(addr, data, pagelen)) + return (NULL); + + sfdip = (sun_fru_descr_impl_t *)((uint8_t *)sfpip + SCSI_READ16(addr)); + if (!SES_WITHIN_PAGE_STRUCT(sfdip, data, pagelen)) + return (NULL); + + *len = MIN(((uint8_t *)sfpip - (uint8_t *)sfdip) + pagelen, + SCSI_READ16(&sfdip->sfdi_fru_data_length) + + offsetof(sun_fru_descr_impl_t, sfdi_fru_data)); + + return (sfdip); +} + +ses_pagedesc_t sun_pages[] = { +{ + .spd_pagenum = SUN_DIAGPAGE_FRUID, + .spd_index = sun_fruid_index, + .spd_req = SES_REQ_OPTIONAL_STANDARD, + .spd_gcoff = offsetof(sun_fruid_page_impl_t, sfpi_generation_code) +}, +{ + .spd_pagenum = -1, + .spd_gcoff = -1 +} +}; diff --git a/usr/src/lib/scsi/plugins/ses/SUN/common/sun_spms.c b/usr/src/lib/scsi/plugins/ses/SUN/common/sun_spms.c deleted file mode 100644 index 995a71c47e..0000000000 --- a/usr/src/lib/scsi/plugins/ses/SUN/common/sun_spms.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ - -/* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#include <stddef.h> -#include <string.h> -#include <strings.h> -#include <alloca.h> - -#include <scsi/libses.h> -#include <scsi/libses_plugin.h> -#include <sys/scsi/impl/spc3_types.h> -#include <scsi/plugins/ses/framework/ses2_impl.h> - -/* - * Sun SPMS-1 r106, section 4.2.4 - Configuration - * Sun SPMS r106, section 4.1.3.1, Table 8 - Sun Feature Definition - * SES-2 r20, section 6.1.2.2, Table 7 - Enclosure Descriptor - * SPC-4 r14, section 6.4.2, Table 121 - Std. INQUIRY data format - * - * Vendor Specific Enclosure Information: - * (The below offsets are relative to the SES2 Enclosure Descriptor.) - * Sun Feature Block, starts at offset 0x28, size 20 bytes - * Platform specific content, starts at offset 0x64, variable size - * - */ -#pragma pack(1) - -typedef struct ses_sun_spms_vs { - char ssvs_spms_header[4]; - uint8_t ssvs_spms_major_ver; - uint8_t __reserved1; - uint16_t ssvs_spms_revision; - uint8_t ssvs_chassis_id_off; - uint8_t ssvs_chassis_id_len; - DECL_BITFIELD2( - ssvs_fw_upload_max_chunk_sz :7, - ssvs_int :1); - uint8_t __reserved2[49]; - uint8_t ssvs_ps[1]; /* Flexible platform specific content */ -} ses_sun_spms_vs_t; - -#pragma pack() - -/*ARGSUSED*/ -static int -sun_parse_node(ses_plugin_t *sp, ses_node_t *np) -{ - ses_sun_spms_vs_t *sfbp; - nvlist_t *encprops, *lid_nv; - uint8_t *vsp; - uint_t vsp_len; - uint_t cid_off, cid_len; - uint64_t wwn; - char lid[17]; - int nverr; - - if (ses_node_type(np) != SES_NODE_ENCLOSURE) - return (0); - - encprops = ses_node_props(np); - if (nvlist_lookup_byte_array(encprops, SES_EN_PROP_VS, - &vsp, &vsp_len) != 0 || - vsp_len < offsetof(ses_sun_spms_vs_t, __reserved2)) - return (0); - - sfbp = (ses_sun_spms_vs_t *)vsp; - - if (strncmp(sfbp->ssvs_spms_header, "SPMS", 4) != 0) - return (0); - - - /* - * NOTE - The following is a temporary mechanism to identify - * subchassis until SPMS defines a formal method to do so. - */ - if (nvlist_lookup_nvlist(encprops, SES_EN_PROP_LID, &lid_nv) != 0 || - nvlist_lookup_uint64(lid_nv, SPC3_NAA_INT, &wwn) != 0) - return (0); - - (void) snprintf(lid, sizeof (lid), "%llx", wwn); - - SES_NV_ADD(fixed_string, nverr, encprops, LIBSES_EN_PROP_SUBCHASSIS_ID, - lid, 16); - - if (sfbp->ssvs_chassis_id_off < 96) - return (0); - - cid_len = sfbp->ssvs_chassis_id_len; - if (cid_len < 4) - return (0); - - /* - * The offset read from the Sun Feature Block needs to be adjusted - * so that the difference in the sizes of the Enclosure - * Descriptor and the INQUIRY data format is accounted for. - */ - cid_off = sfbp->ssvs_chassis_id_off - (sizeof (ses2_ed_impl_t) - 1); - cid_off += offsetof(ses2_ed_impl_t, st_priv[0]) - - offsetof(spc3_inquiry_data_t, id_vs_36[0]); - - if (cid_off + cid_len > vsp_len) - return (0); - - SES_NV_ADD(fixed_string, nverr, encprops, LIBSES_EN_PROP_CSN, - (char *)(vsp + cid_off), cid_len); - - return (0); -} - -int -_ses_init(ses_plugin_t *sp) -{ - ses_plugin_config_t config = { - .spc_node_parse = sun_parse_node - }; - - return (ses_plugin_register(sp, LIBSES_PLUGIN_VERSION, - &config) != 0); -} diff --git a/usr/src/lib/scsi/plugins/ses/libses/Makefile.com b/usr/src/lib/scsi/plugins/ses/libses/Makefile.com index 104909fce5..f610715c62 100644 --- a/usr/src/lib/scsi/plugins/ses/libses/Makefile.com +++ b/usr/src/lib/scsi/plugins/ses/libses/Makefile.com @@ -20,10 +20,8 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. # -#ident "%Z%%M% %I% %E% SMI" MODULE = libses SRCS = libses.c \ @@ -35,5 +33,7 @@ include ../../Makefile.lib SES2HDR = $(ROOTPLUGINHDRDIR)/ses/framework/ses2.h +CLEANFILES += ../common/libses_elemtype.c + ../common/libses_elemtype.c: ../common/mkelemtype.sh $(SES2HDR) sh ../common/mkelemtype.sh < $(SES2HDR) > $@ diff --git a/usr/src/lib/scsi/plugins/ses/libses/common/libses.h b/usr/src/lib/scsi/plugins/ses/libses/common/libses.h index 90984ea8b1..50d27c4edb 100644 --- a/usr/src/lib/scsi/plugins/ses/libses/common/libses.h +++ b/usr/src/lib/scsi/plugins/ses/libses/common/libses.h @@ -20,8 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _FRAMEWORK_LIBSES_H @@ -52,6 +51,8 @@ extern "C" { */ #define LIBSES_PROP_PART "libses-part-number" #define LIBSES_PROP_SERIAL "libses-serial-number" +#define LIBSES_PROP_FRU "libses-is-fru" +#define LIBSES_PROP_PHYS_PARENT "libses-physical-parent-element-index" /* * The chassis serial number is a pseudo property that doesn't exist in SES @@ -76,6 +77,12 @@ extern "C" { */ #define LIBSES_EN_PROP_SUBCHASSIS_ID "libses-subchassis-id" +/* + * Maximum allowed firmware upload chunk size. Obtained in a vendor- or + * platform-specific manner but generic in nature. + */ +#define LIBSES_EN_PROP_FIRMWARE_CHUNK_SIZE "libses-firmware-chunksize" + #ifdef __cplusplus } #endif diff --git a/usr/src/lib/scsi/plugins/ses/ses2/common/ses2.h b/usr/src/lib/scsi/plugins/ses/ses2/common/ses2.h index 8c8f431697..f37e4e19d6 100644 --- a/usr/src/lib/scsi/plugins/ses/ses2/common/ses2.h +++ b/usr/src/lib/scsi/plugins/ses/ses2/common/ses2.h @@ -20,14 +20,11 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ -#ifndef _FRAMEWORK_SES_H -#define _FRAMEWORK_SES_H - -#pragma ident "%Z%%M% %I% %E% SMI" +#ifndef _FRAMEWORK_SES2_H +#define _FRAMEWORK_SES2_H #ifdef __cplusplus extern "C" { @@ -81,6 +78,7 @@ typedef enum ses_element_status_code { #define SES_PROP_ELEMENT_CLASS_INDEX "ses-element-class-index" /* U64 */ #define SES_PROP_ELEMENT_INDEX "ses-element-index" /* U64 */ +#define SES_PROP_ELEMENT_ONLY_INDEX "ses-element-only-index" /* U64 */ #define SES_PROP_BAY_NUMBER "ses-bay-number" /* U64 */ #define SES_PROP_PRDFAIL "ses-failure-predicted" #define SES_PROP_SWAP "ses-swapped" @@ -515,9 +513,10 @@ typedef enum ses2_diag_page { #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" +#define SES_CTL_PROP_UCODE_DATA_LEN "ses-ctl-ucode-data-length" /* U64 */ #ifdef __cplusplus } #endif -#endif /* _FRAMEWORK_SES_H */ +#endif /* _FRAMEWORK_SES2_H */ 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 index f6bcf8b46d..337656dab2 100644 --- a/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_enclosure.c +++ b/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_enclosure.c @@ -20,12 +20,9 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <stddef.h> #include <string.h> #include <strings.h> @@ -77,7 +74,7 @@ enc_parse_help(ses_plugin_t *sp, ses_node_t *np) ses2_subhelp_text_impl_t *tip; nvlist_t *nvl = ses_node_props(np); uint64_t eid; - size_t len; + size_t len, textlen; off_t pos; int nverr; @@ -97,14 +94,15 @@ enc_parse_help(ses_plugin_t *sp, ses_node_t *np) if (tip->ssti_subenclosure_identifier != eid) continue; + textlen = SCSI_READ16( + &tip->ssti_subenclosure_help_text_length); + if (!SES_WITHIN_PAGE(tip->ssti_subenclosure_help_text, - tip->ssti_subenclosure_help_text_length, shpip, - len)) + textlen, 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); + tip->ssti_subenclosure_help_text, textlen); return (0); } } @@ -155,13 +153,15 @@ enc_parse_string_in(ses_plugin_t *sp, ses_node_t *np) if (dip->ssidi_subenclosure_identifier != eid) continue; - if (!SES_WITHIN_PAGE(dip->ssidi_data, - dip->ssidi_substring_data_length, ssip, len)) + textlen = + SCSI_READ16(&dip->ssidi_substring_data_length); + + if (!SES_WITHIN_PAGE(dip->ssidi_data, textlen, + ssip, len)) break; SES_NV_ADD(fixed_string, nverr, nvl, SES_EN_PROP_STRING, - (char *)dip->ssidi_data, - dip->ssidi_substring_data_length); + (char *)dip->ssidi_data, textlen); 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 index c690f5f13b..fc7dca6991 100644 --- 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 @@ -18,18 +18,11 @@ * * 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. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <stddef.h> #include <stdio.h> @@ -40,7 +33,7 @@ #include <scsi/libses.h> #include "ses2_impl.h" -#define SES_UCODE_CHUNK_SIZE (32 * 1024) +#define SES_UCODE_DEF_CHUNK (32 * 1024) /*ARGSUSED*/ static int @@ -53,6 +46,7 @@ enc_do_ucode(ses_plugin_t *sp, ses_node_t *np, nvlist_t *nvl) size_t offset, len, pagelen; uint_t datalen; uint64_t mode; + uint64_t chunksz = SES_UCODE_DEF_CHUNK; /* * Get the data and check the length. @@ -83,10 +77,15 @@ enc_do_ucode(ses_plugin_t *sp, ses_node_t *np, nvlist_t *nvl) bufid = 0; (void) nvlist_lookup_uint64(nvl, SES_CTL_PROP_UCODE_BUFID, &bufid); + (void) nvlist_lookup_uint64(nvl, SES_CTL_PROP_UCODE_DATA_LEN, &chunksz); + + if (chunksz & 3) + return (ses_error(ESES_RANGE, + "upload chunk size %llu is not divisible by 4", chunksz)); - for (offset = 0; offset < datalen; offset += SES_UCODE_CHUNK_SIZE) { + for (offset = 0; offset < datalen; offset += chunksz) { - len = MIN(datalen - offset, SES_UCODE_CHUNK_SIZE); + len = MIN(datalen - offset, chunksz); if (len & 0x3) pagelen = (len + 4) & ~0x3; else @@ -114,6 +113,7 @@ enc_do_ucode(ses_plugin_t *sp, ses_node_t *np, nvlist_t *nvl) (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); + (void) nvlist_remove_all(nvl, SES_CTL_PROP_UCODE_DATA_LEN); 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 index 11f6d5739a..43c287975c 100644 --- a/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_impl.h +++ b/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_impl.h @@ -20,15 +20,12 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _PLUGIN_SES_IMPL_H #define _PLUGIN_SES_IMPL_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -1348,7 +1345,7 @@ typedef struct ses2_subhelp_text_impl { } ses2_subhelp_text_impl_t; #define SES2_SUBHELP_LEN(stip) \ - ((stip)->ssti_subenclosure_help_text_length + \ + (SCSI_READ16(&(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). @@ -1383,7 +1380,7 @@ typedef struct ses2_substring_in_data_impl { } ses2_substring_in_data_impl_t; #define SES2_SUBSTR_LEN(sdip) \ - ((sdip)->ssidi_substring_data_length + \ + (SCSI_READ16(&(sdip)->ssidi_substring_data_length) + \ offsetof(ses2_substring_in_data_impl_t, ssidi_data[0])) /* 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 index 7c6d7726ba..8a2562d463 100644 --- a/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_pages.c +++ b/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_pages.c @@ -20,12 +20,9 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <stddef.h> #include <strings.h> @@ -359,61 +356,74 @@ ses2_subnickout_len(uint_t nelem, int page, size_t datalen) ses_pagedesc_t ses2_pages[] = { { .spd_pagenum = SES2_DIAGPAGE_SUPPORTED_PAGES, + .spd_req = SES_REQ_MANDATORY_ALL, .spd_gcoff = -1 }, { .spd_pagenum = SES2_DIAGPAGE_CONFIG, + .spd_req = SES_REQ_MANDATORY_STANDARD, .spd_gcoff = offsetof(ses2_config_page_impl_t, scpi_generation_code) }, { .spd_pagenum = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, + .spd_req = SES_REQ_MANDATORY_STANDARD, .spd_index = ses2_status_index, .spd_gcoff = offsetof(ses2_status_page_impl_t, sspi_generation_code) }, { .spd_pagenum = SES2_DIAGPAGE_HELP_TEXT, + .spd_req = SES_REQ_OPTIONAL_STANDARD, .spd_gcoff = -1 }, { .spd_pagenum = SES2_DIAGPAGE_STRING_IO, + .spd_req = SES_REQ_OPTIONAL_STANDARD, .spd_gcoff = -1 }, { .spd_pagenum = SES2_DIAGPAGE_THRESHOLD_IO, .spd_index = ses2_threshold_index, + .spd_req = SES_REQ_OPTIONAL_STANDARD, .spd_gcoff = offsetof(ses2_threshold_in_page_impl_t, stipi_generation_code) }, { .spd_pagenum = SES2_DIAGPAGE_ELEMENT_DESC, .spd_index = ses2_element_index, + .spd_req = SES_REQ_OPTIONAL_STANDARD, .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_req = SES_REQ_OPTIONAL_STANDARD, .spd_gcoff = offsetof(ses2_aes_page_impl_t, sapi_generation_code) }, { .spd_pagenum = SES2_DIAGPAGE_SUBENCLOSURE_HELP_TEXT, + .spd_req = SES_REQ_OPTIONAL_STANDARD, .spd_gcoff = offsetof(ses2_subhelp_page_impl_t, sspi_generation_code) }, { .spd_pagenum = SES2_DIAGPAGE_SUBENCLOSURE_STRING_IO, + .spd_req = SES_REQ_OPTIONAL_STANDARD, .spd_gcoff = offsetof(ses2_substring_in_page_impl_t, ssipi_generation_code) }, { .spd_pagenum = SES2_DIAGPAGE_SUPPORTED_SES_PAGES, + .spd_req = SES_REQ_OPTIONAL_STANDARD, .spd_gcoff = -1 }, { .spd_pagenum = SES2_DIAGPAGE_DL_MICROCODE_CTL_STATUS, + .spd_req = SES_REQ_OPTIONAL_STANDARD, .spd_gcoff = offsetof(ses2_ucode_status_page_impl_t, suspi_generation_code) }, { .spd_pagenum = SES2_DIAGPAGE_SUBENCLOSURE_NICKNAME_CTL_STATUS, + .spd_req = SES_REQ_OPTIONAL_STANDARD, .spd_gcoff = offsetof(ses2_subnick_status_page_impl_t, sspci_generation_code) }, @@ -422,23 +432,27 @@ ses_pagedesc_t ses2_pages[] = { .spd_pagenum = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, .spd_ctl_len = ses2_ctl_len, .spd_ctl_fill = ses2_ctl_fill, + .spd_req = SES_REQ_MANDATORY_STANDARD, .spd_gcoff = offsetof(ses2_control_page_impl_t, scpi_generation_code) }, { .spd_pagenum = SES2_DIAGPAGE_STRING_IO, .spd_ctl_len = ses2_stringout_len, + .spd_req = SES_REQ_OPTIONAL_STANDARD, .spd_gcoff = -1 }, { .spd_pagenum = SES2_DIAGPAGE_THRESHOLD_IO, .spd_ctl_len = ses2_threshout_len, .spd_ctl_fill = ses2_threshout_ctl_fill, + .spd_req = SES_REQ_OPTIONAL_STANDARD, .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_req = SES_REQ_OPTIONAL_STANDARD, .spd_gcoff = offsetof(ses2_substring_out_page_impl_t, ssopi_generation_code) }, @@ -446,12 +460,14 @@ ses_pagedesc_t ses2_pages[] = { .spd_pagenum = SES2_DIAGPAGE_DL_MICROCODE_CTL_STATUS, .spd_ctl_len = ses2_ucodeout_len, .spd_ctl_fill = ses2_ucodeout_ctl_fill, + .spd_req = SES_REQ_OPTIONAL_STANDARD, .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_req = SES_REQ_OPTIONAL_STANDARD, .spd_gcoff = offsetof(ses2_subnick_ctl_page_impl_t, sspci_generation_code) }, diff --git a/usr/src/lib/scsi/plugins/smp/Makefile b/usr/src/lib/scsi/plugins/smp/Makefile new file mode 100644 index 0000000000..ee46918af4 --- /dev/null +++ b/usr/src/lib/scsi/plugins/smp/Makefile @@ -0,0 +1,34 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +SUBDIRS = \ + sas2 \ + usmp + +.KEEP_STATE: + +.PARALLEL: + +include ../../Makefile.subdirs diff --git a/usr/src/lib/scsi/plugins/smp/Makefile.lib b/usr/src/lib/scsi/plugins/smp/Makefile.lib new file mode 100644 index 0000000000..1b44f8e4a6 --- /dev/null +++ b/usr/src/lib/scsi/plugins/smp/Makefile.lib @@ -0,0 +1,83 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +.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) + +ROOTPLUGINDIR = $(ROOTPLUGINLIBDIR)/smp/$(PLUGINTYPE) +ROOTPLUGINDIR64 = $(ROOTPLUGINLIBDIR)/smp/$(PLUGINTYPE)/$(MACH64) + +ROOTPROG = $(ROOTPLUGINDIR)/$(PROG) +ROOTPROG64 = $(ROOTPLUGINDIR64)/$(PROG) + +# +# A module can set ALIASES as a list of additional names to correspond to the +# same library. +# +ROOTALIASES = $(ALIASES:%=$(ROOTPLUGINDIR)/%.so) +ROOTALIASES64 = $(ALIASES:%=$(ROOTPLUGINDIR64)/%.so) + +LINTFLAGS += -mu +LINTFILES = $(SRCS:%.c=%.ln) + +DMODLINTTGT = $(DMOD:%=lint_dmod) +DMODLINTFILES = $(DMOD_SRCS:%.c=%.ln) + +APIMAP = ../../../../libsmp/libsmp_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 + +$(DMODPROG) := LDFLAGS += $(ZNODEFS) diff --git a/usr/src/lib/scsi/plugins/smp/Makefile.plugin b/usr/src/lib/scsi/plugins/smp/Makefile.plugin new file mode 100644 index 0000000000..add83a92c4 --- /dev/null +++ b/usr/src/lib/scsi/plugins/smp/Makefile.plugin @@ -0,0 +1,57 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +include $(SRC)/Makefile.master + +SUBDIRS = $(MACH) +$(BUILD64)SUBDIRS += $(MACH64) + +include ../../../Makefile.defs + +ROOTHDRDIR = $(ROOTPLUGINHDRDIR)/smp/$(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/smp/Makefile.targ b/usr/src/lib/scsi/plugins/smp/Makefile.targ new file mode 100644 index 0000000000..5aee626e08 --- /dev/null +++ b/usr/src/lib/scsi/plugins/smp/Makefile.targ @@ -0,0 +1,86 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +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: + +$(ROOTPLUGINDIR)/%: $(PROG) + $(RM) $@; $(LN) -s $< $@ + +$(ROOTPLUGINDIR64)/%: $(PROG) + $(RM) $@; $(LN) -s $< $@ + +$(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/smp/sas2/Makefile b/usr/src/lib/scsi/plugins/smp/sas2/Makefile new file mode 100644 index 0000000000..8ababf2063 --- /dev/null +++ b/usr/src/lib/scsi/plugins/smp/sas2/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 (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +HDRS = +HDRDIR = common +PLUGINTYPE = framework + +include ../Makefile.plugin diff --git a/usr/src/lib/scsi/plugins/smp/sas2/Makefile.com b/usr/src/lib/scsi/plugins/smp/sas2/Makefile.com new file mode 100644 index 0000000000..6c6f48fba0 --- /dev/null +++ b/usr/src/lib/scsi/plugins/smp/sas2/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 (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +MODULE = sas2 +SRCS = sas2.c \ + sas2_functions.c + +SRCDIR = ../common +PLUGINTYPE = framework + +include ../../Makefile.lib diff --git a/usr/src/lib/scsi/plugins/smp/sas2/amd64/Makefile b/usr/src/lib/scsi/plugins/smp/sas2/amd64/Makefile new file mode 100644 index 0000000000..0a34065b01 --- /dev/null +++ b/usr/src/lib/scsi/plugins/smp/sas2/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 (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +include ../Makefile.com +include $(SRC)/Makefile.master.64 + +install: all $(ROOTPROG64) + +include ../../Makefile.targ diff --git a/usr/src/lib/scsi/plugins/smp/sas2/common/sas2.c b/usr/src/lib/scsi/plugins/smp/sas2/common/sas2.c new file mode 100644 index 0000000000..0874cacac5 --- /dev/null +++ b/usr/src/lib/scsi/plugins/smp/sas2/common/sas2.c @@ -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 (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#include <scsi/libsmp.h> +#include <scsi/libsmp_plugin.h> +#include "sas2.h" + +int +_smp_init(smp_plugin_t *pp) +{ + smp_plugin_config_t config = { + .spc_name = "SAS-2", + .spc_functions = sas2_functions + }; + + return (smp_plugin_register(pp, LIBSMP_PLUGIN_VERSION, &config)); +} diff --git a/usr/src/lib/scsi/plugins/smp/sas2/common/sas2.h b/usr/src/lib/scsi/plugins/smp/sas2/common/sas2.h new file mode 100644 index 0000000000..4000725f6b --- /dev/null +++ b/usr/src/lib/scsi/plugins/smp/sas2/common/sas2.h @@ -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 (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#ifndef _SAS2_H +#define _SAS2_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern smp_function_def_t sas2_functions[]; + +#ifdef __cplusplus +} +#endif + +#endif /* _SAS2_H */ diff --git a/usr/src/lib/scsi/plugins/smp/sas2/common/sas2_functions.c b/usr/src/lib/scsi/plugins/smp/sas2/common/sas2_functions.c new file mode 100644 index 0000000000..1e515746c3 --- /dev/null +++ b/usr/src/lib/scsi/plugins/smp/sas2/common/sas2_functions.c @@ -0,0 +1,1066 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#include <sys/types.h> +#include <sys/scsi/generic/commands.h> +#include <sys/scsi/impl/commands.h> +#include <sys/scsi/generic/smp_frames.h> + +#include <scsi/libsmp.h> +#include <scsi/libsmp_plugin.h> +#include "sas2.h" + +/*ARGSUSED*/ +static size_t +sas2_rq_len(size_t user, smp_target_t *tp) +{ + if (user != 0) { + (void) smp_set_errno(ESMP_RANGE); + return (0); + } + + return (SMP_REQ_MINLEN); +} + +/*ARGSUSED*/ +static off_t +sas2_rq_dataoff(smp_action_t *ap, smp_target_t *tp) +{ + size_t len; + + smp_action_get_request_frame(ap, NULL, &len); + + if (len > SMP_REQ_MINLEN) + return (offsetof(smp_request_frame_t, srf_data[0])); + + return (-1); +} + +static void +sas2_rq_setframe(smp_action_t *ap, smp_target_t *tp) +{ + const smp_function_def_t *dp = smp_action_get_function_def(ap); + smp_request_frame_t *fp; + uint_t cap; + uint16_t change_count; + uint16_t *rqcc; + size_t rqlen, rslen; + + smp_action_get_request_frame(ap, (void *)&fp, &rqlen); + smp_action_get_response_frame(ap, NULL, &rslen); + cap = smp_target_getcap(tp); + + fp->srf_frame_type = SMP_FRAME_TYPE_REQUEST; + fp->srf_function = dp->sfd_function; + + if (cap & SMP_TARGET_C_LONG_RESP) { + fp->srf_allocated_response_len = (rslen - SMP_RESP_MINLEN) / 4; + fp->srf_request_len = (rqlen - SMP_REQ_MINLEN) / 4; + } else { + fp->srf_allocated_response_len = 0; + fp->srf_request_len = 0; + } + + /* + * If this command requires that the expected expander change count + * be set (as many do), we will attempt to set it based on the + * most recently executed command. However, if the user has set it + * already, we will not overwrite that setting. It is the consumer's + * responsibility to keep track of expander changes each time it + * receives a new change count in a response. + */ + if (dp->sfd_flags & SMP_FD_F_NEEDS_CHANGE_COUNT) { + ASSERT(rqlen >= SMP_REQ_MINLEN + sizeof (uint16_t)); + /* LINTED - alignment */ + rqcc = (uint16_t *)(&fp->srf_data[0]); + if (SCSI_READ16(rqcc) == 0) { + change_count = smp_target_get_change_count(tp); + SCSI_WRITE16(rqcc, change_count); + } + } +} + +/*ARGSUSED*/ +static size_t +sas2_rs_datalen(smp_action_t *ap, smp_target_t *tp) +{ + smp_response_frame_t *fp; + size_t len; + + smp_action_get_response_frame(ap, (void **)&fp, &len); + + if (len >= SMP_RESP_MINLEN) + len -= SMP_RESP_MINLEN; + else + return (0); + + len &= ~3; + + if (fp->srf_response_len == 0) + return (0); + + return (MIN(len, 4 * (fp->srf_response_len))); +} + +/*ARGSUSED*/ +static off_t +sas2_rs_dataoff(smp_action_t *ap, smp_target_t *tp) +{ + size_t len; + + smp_action_get_response_frame(ap, NULL, &len); + + if (len > SMP_RESP_MINLEN) + return (offsetof(smp_request_frame_t, srf_data[0])); + + return (-1); +} + +static void +sas2_rs_getparams(smp_action_t *ap, smp_target_t *tp) +{ + const smp_function_def_t *dp; + smp_response_frame_t *fp; + size_t len; + uint16_t change_count; + + dp = smp_action_get_function_def(ap); + + smp_action_get_response_frame(ap, (void **)&fp, &len); + + smp_action_set_result(ap, fp->srf_result); + + if (!(dp->sfd_flags & SMP_FD_F_PROVIDES_CHANGE_COUNT)) + return; + + if (len <= SMP_RESP_MINLEN + sizeof (uint16_t)) + return; + + change_count = SCSI_READ16(&fp->srf_data[0]); + smp_target_set_change_count(tp, change_count); +} + +/*ARGSUSED*/ +static size_t +sas2_report_general_rs_datalen(smp_action_t *ap, smp_target_t *tp) +{ + const smp_function_def_t *dp = smp_action_get_function_def(ap); + smp_response_frame_t *fp; + size_t len; + + ASSERT(dp->sfd_function == SMP_FUNC_REPORT_GENERAL); + smp_action_get_response_frame(ap, (void **)&fp, &len); + + if (len >= SMP_RESP_MINLEN) + len -= SMP_RESP_MINLEN; + else + return (0); + + len &= ~3; + + if (fp->srf_response_len == 0) + return (MIN(len, 24)); + + return (MIN(len, 4 * (fp->srf_response_len))); +} + +/*ARGSUSED*/ +static size_t +sas2_report_manufacturer_info_rs_datalen(smp_action_t *ap, smp_target_t *tp) +{ + const smp_function_def_t *dp = smp_action_get_function_def(ap); + smp_response_frame_t *fp; + size_t len; + + ASSERT(dp->sfd_function == SMP_FUNC_REPORT_MANUFACTURER_INFO); + smp_action_get_response_frame(ap, (void **)&fp, &len); + + if (len >= SMP_RESP_MINLEN) + len -= SMP_RESP_MINLEN; + else + return (0); + + len &= ~3; + + if (fp->srf_response_len == 0) + return (MIN(len, 56)); + + return (MIN(len, 4 * (fp->srf_response_len))); +} + +/*ARGSUSED*/ +static size_t +sas2_report_self_config_status_rq_len(size_t user, smp_target_t *tp) +{ + if (user != 0) { + (void) smp_set_errno(ESMP_RANGE); + return (0); + } + + return (SMP_REQ_MINLEN + sizeof (smp_report_self_config_status_req_t)); +} + +/*ARGSUSED*/ +static size_t +sas2_report_zone_perm_table_rq_len(size_t user, smp_target_t *tp) +{ + if (user != 0) { + (void) smp_set_errno(ESMP_RANGE); + return (0); + } + + return (SMP_REQ_MINLEN + sizeof (smp_report_zone_perm_table_req_t)); +} + +/*ARGSUSED*/ +static size_t +sas2_report_broadcast_rq_len(size_t user, smp_target_t *tp) +{ + if (user != 0) { + (void) smp_set_errno(ESMP_RANGE); + return (0); + } + + return (SMP_REQ_MINLEN + sizeof (smp_report_broadcast_req_t)); +} + +/*ARGSUSED*/ +static size_t +sas2_discover_rq_len(size_t user, smp_target_t *tp) +{ + if (user != 0) { + (void) smp_set_errno(ESMP_RANGE); + return (0); + } + + return (SMP_REQ_MINLEN + sizeof (smp_discover_req_t)); +} + +/*ARGSUSED*/ +static size_t +sas2_discover_rs_datalen(smp_action_t *ap, smp_target_t *tp) +{ + const smp_function_def_t *dp = smp_action_get_function_def(ap); + smp_response_frame_t *fp; + size_t len; + + ASSERT(dp->sfd_function == SMP_FUNC_DISCOVER); + smp_action_get_response_frame(ap, (void **)&fp, &len); + + if (len >= SMP_RESP_MINLEN) + len -= SMP_RESP_MINLEN; + else + return (0); + + len &= ~3; + + if (fp->srf_response_len == 0) + return (MIN(len, 48)); + + return (MIN(len, 4 * (fp->srf_response_len))); +} + +/*ARGSUSED*/ +static size_t +sas2_report_phy_error_log_rq_len(size_t user, smp_target_t *tp) +{ + if (user != 0) { + (void) smp_set_errno(ESMP_RANGE); + return (0); + } + + return (SMP_REQ_MINLEN + sizeof (smp_report_phy_error_log_req_t)); +} + +/*ARGSUSED*/ +static size_t +sas2_report_phy_error_log_rs_datalen(smp_action_t *ap, smp_target_t *tp) +{ + const smp_function_def_t *dp = smp_action_get_function_def(ap); + smp_response_frame_t *fp; + size_t len; + + ASSERT(dp->sfd_function == SMP_FUNC_REPORT_PHY_ERROR_LOG); + smp_action_get_response_frame(ap, (void **)&fp, &len); + + if (len >= SMP_RESP_MINLEN) + len -= SMP_RESP_MINLEN; + else + return (0); + + len &= ~3; + + if (fp->srf_response_len == 0) + return (MIN(len, sizeof (smp_report_phy_error_log_resp_t))); + + return (MIN(len, 4 * (fp->srf_response_len))); +} + +/*ARGSUSED*/ +static size_t +sas2_report_phy_sata_rq_len(size_t user, smp_target_t *tp) +{ + if (user != 0) { + (void) smp_set_errno(ESMP_RANGE); + return (0); + } + + return (SMP_REQ_MINLEN + sizeof (smp_report_phy_sata_req_t)); +} + +/*ARGSUSED*/ +static size_t +sas2_report_phy_sata_rs_datalen(smp_action_t *ap, smp_target_t *tp) +{ + const smp_function_def_t *dp = smp_action_get_function_def(ap); + smp_response_frame_t *fp; + size_t len; + + ASSERT(dp->sfd_function == SMP_FUNC_REPORT_PHY_SATA); + smp_action_get_response_frame(ap, (void **)&fp, &len); + + if (len >= SMP_RESP_MINLEN) + len -= SMP_RESP_MINLEN; + else + return (0); + + len &= ~3; + + if (fp->srf_response_len == 0) + return (MIN(len, 52)); + + return (MIN(len, 4 * (fp->srf_response_len))); +} + +/*ARGSUSED*/ +static size_t +sas2_report_route_info_rq_len(size_t user, smp_target_t *tp) +{ + if (user != 0) { + (void) smp_set_errno(ESMP_RANGE); + return (0); + } + + return (SMP_REQ_MINLEN + sizeof (smp_report_route_info_req_t)); +} + +/*ARGSUSED*/ +static size_t +sas2_report_route_info_rs_datalen(smp_action_t *ap, smp_target_t *tp) +{ + const smp_function_def_t *dp = smp_action_get_function_def(ap); + smp_response_frame_t *fp; + size_t len; + + ASSERT(dp->sfd_function == SMP_FUNC_REPORT_ROUTE_INFO); + smp_action_get_response_frame(ap, (void **)&fp, &len); + + if (len >= SMP_RESP_MINLEN) + len -= SMP_RESP_MINLEN; + else + return (0); + + len &= ~3; + + if (fp->srf_response_len == 0) + return (MIN(len, sizeof (smp_report_route_info_resp_t))); + + return (MIN(len, 4 * (fp->srf_response_len))); +} + +/*ARGSUSED*/ +static size_t +sas2_report_phy_event_rq_len(size_t user, smp_target_t *tp) +{ + if (user != 0) { + (void) smp_set_errno(ESMP_RANGE); + return (0); + } + + return (SMP_REQ_MINLEN + sizeof (smp_report_phy_event_req_t)); +} + +/*ARGSUSED*/ +static size_t +sas2_discover_list_rq_len(size_t user, smp_target_t *tp) +{ + if (user != 0) { + (void) smp_set_errno(ESMP_RANGE); + return (0); + } + + return (SMP_REQ_MINLEN + sizeof (smp_discover_list_req_t)); +} + +/*ARGSUSED*/ +static size_t +sas2_report_phy_event_list_rq_len(size_t user, smp_target_t *tp) +{ + if (user != 0) { + (void) smp_set_errno(ESMP_RANGE); + return (0); + } + + return (SMP_REQ_MINLEN + sizeof (smp_report_phy_event_list_req_t)); +} + +/*ARGSUSED*/ +static size_t +sas2_report_exp_route_table_list_rq_len(size_t user, smp_target_t *tp) +{ + if (user != 0) { + (void) smp_set_errno(ESMP_RANGE); + return (0); + } + + return (SMP_REQ_MINLEN + + sizeof (smp_report_exp_route_table_list_req_t)); +} + +/*ARGSUSED*/ +static size_t +sas2_config_general_rq_len(size_t user, smp_target_t *tp) +{ + if (user != 0) { + (void) smp_set_errno(ESMP_RANGE); + return (0); + } + + return (SMP_REQ_MINLEN + sizeof (smp_config_general_req_t)); +} + +/*ARGSUSED*/ +static size_t +sas2_enable_disable_zoning_rq_len(size_t user, smp_target_t *tp) +{ + if (user != 0) { + (void) smp_set_errno(ESMP_RANGE); + return (0); + } + + return (SMP_REQ_MINLEN + sizeof (smp_enable_disable_zoning_req_t)); +} + +/*ARGSUSED*/ +static size_t +sas2_zoned_broadcast_rq_len(size_t user, smp_target_t *tp) +{ + size_t descrsz; + + if (user == 0 || user > 1008) { + (void) smp_set_errno(ESMP_RANGE); + return (0); + } + + descrsz = P2ROUNDUP((user - 1), 4); + + return (SMP_REQ_MINLEN + descrsz + sizeof (smp_zoned_broadcast_req_t)); +} + +/*ARGSUSED*/ +static size_t +sas2_zone_lock_rq_len(size_t user, smp_target_t *tp) +{ + if (user != 0) { + (void) smp_set_errno(ESMP_RANGE); + return (0); + } + + return (SMP_REQ_MINLEN + sizeof (smp_zone_lock_req_t)); +} + +/*ARGSUSED*/ +static size_t +sas2_zone_activate_rq_len(size_t user, smp_target_t *tp) +{ + if (user != 0) { + (void) smp_set_errno(ESMP_RANGE); + return (0); + } + + return (SMP_REQ_MINLEN + sizeof (smp_zone_activate_req_t)); +} + +/*ARGSUSED*/ +static size_t +sas2_zone_unlock_rq_len(size_t user, smp_target_t *tp) +{ + if (user != 0) { + (void) smp_set_errno(ESMP_RANGE); + return (0); + } + + return (SMP_REQ_MINLEN + sizeof (smp_zone_unlock_req_t)); +} + +/*ARGSUSED*/ +static size_t +sas2_config_zone_manager_password_rq_len(size_t user, smp_target_t *tp) +{ + if (user != 0) { + (void) smp_set_errno(ESMP_RANGE); + return (0); + } + + return (SMP_REQ_MINLEN + + sizeof (smp_config_zone_manager_password_req_t)); +} + +/*ARGSUSED*/ +static size_t +sas2_config_zone_phy_info_rq_len(size_t user, smp_target_t *tp) +{ + if (user == 0 || user > 252) { + (void) smp_set_errno(ESMP_RANGE); + return (0); + } + + return (SMP_REQ_MINLEN + sizeof (smp_config_zone_phy_info_req_t) + + (user - 1) * sizeof (smp_zone_phy_config_descr_t)); +} + +static size_t +sas2_config_zone_perm_table_rq_len(size_t user, smp_target_t *tp) +{ + uint_t cap = smp_target_getcap(tp); + size_t maxdescr, descrsz; + + if (cap & SMP_TARGET_C_ZG_256) + descrsz = sizeof (smp_zone_perm_descr256_t); + else + descrsz = sizeof (smp_zone_perm_descr128_t); + + maxdescr = (1020 - sizeof (smp_config_zone_perm_table_req_t)) / descrsz; + + if (user == 0 || user > maxdescr) { + (void) smp_set_errno(ESMP_RANGE); + return (0); + } + + return (SMP_REQ_MINLEN + sizeof (smp_config_zone_perm_table_req_t) - 1 + + user * descrsz); +} + +/*ARGSUSED*/ +static size_t +sas2_config_route_info_rq_len(size_t user, smp_target_t *tp) +{ + if (user != 0) { + (void) smp_set_errno(ESMP_RANGE); + return (0); + } + + return (SMP_REQ_MINLEN + sizeof (smp_config_route_info_req_t)); +} + +/*ARGSUSED*/ +static size_t +sas2_phy_control_rq_len(size_t user, smp_target_t *tp) +{ + if (user != 0) { + (void) smp_set_errno(ESMP_RANGE); + return (0); + } + + return (SMP_REQ_MINLEN + sizeof (smp_phy_control_req_t)); +} + +/*ARGSUSED*/ +static size_t +sas2_phy_test_function_rq_len(size_t user, smp_target_t *tp) +{ + if (user != 0) { + (void) smp_set_errno(ESMP_RANGE); + return (0); + } + + return (SMP_REQ_MINLEN + sizeof (smp_phy_test_function_req_t)); +} + +/*ARGSUSED*/ +static size_t +sas2_config_phy_event_rq_len(size_t user, smp_target_t *tp) +{ + if (user == 0 || user > 126) { + (void) smp_set_errno(ESMP_RANGE); + return (0); + } + + return (SMP_REQ_MINLEN + sizeof (smp_config_phy_event_req_t) + + (user - 1) * sizeof (smp_phy_event_config_descr_t)); +} + +smp_function_def_t sas2_functions[] = { +{ + .sfd_function = SMP_FUNC_REPORT_GENERAL, + .sfd_flags = SMP_FD_F_READ | SMP_FD_F_PROVIDES_CHANGE_COUNT, + .sfd_rq_len = sas2_rq_len, + .sfd_rq_dataoff = sas2_rq_dataoff, + .sfd_rq_setframe = sas2_rq_setframe, + .sfd_rs_datalen = sas2_report_general_rs_datalen, + .sfd_rs_dataoff = sas2_rs_dataoff, + .sfd_rs_getparams = sas2_rs_getparams +}, +{ + .sfd_function = SMP_FUNC_REPORT_MANUFACTURER_INFO, + .sfd_flags = SMP_FD_F_READ | SMP_FD_F_PROVIDES_CHANGE_COUNT, + .sfd_rq_len = sas2_rq_len, + .sfd_rq_dataoff = sas2_rq_dataoff, + .sfd_rq_setframe = sas2_rq_setframe, + .sfd_rs_datalen = sas2_report_manufacturer_info_rs_datalen, + .sfd_rs_dataoff = sas2_rs_dataoff, + .sfd_rs_getparams = sas2_rs_getparams +}, +{ + .sfd_function = SMP_FUNC_REPORT_SELF_CONFIG_STATUS, + .sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE | + SMP_FD_F_PROVIDES_CHANGE_COUNT, + .sfd_rq_len = sas2_report_self_config_status_rq_len, + .sfd_rq_dataoff = sas2_rq_dataoff, + .sfd_rq_setframe = sas2_rq_setframe, + .sfd_rs_datalen = sas2_rs_datalen, + .sfd_rs_dataoff = sas2_rs_dataoff, + .sfd_rs_getparams = sas2_rs_getparams +}, +{ + .sfd_function = SMP_FUNC_REPORT_ZONE_PERM_TABLE, + .sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE | + SMP_FD_F_PROVIDES_CHANGE_COUNT, + .sfd_rq_len = sas2_report_zone_perm_table_rq_len, + .sfd_rq_dataoff = sas2_rq_dataoff, + .sfd_rq_setframe = sas2_rq_setframe, + .sfd_rs_datalen = sas2_rs_datalen, + .sfd_rs_dataoff = sas2_rs_dataoff, + .sfd_rs_getparams = sas2_rs_getparams +}, +{ + .sfd_function = SMP_FUNC_REPORT_ZONE_MANAGER_PASSWORD, + .sfd_flags = SMP_FD_F_READ | SMP_FD_F_PROVIDES_CHANGE_COUNT, + .sfd_rq_len = sas2_rq_len, + .sfd_rq_dataoff = sas2_rq_dataoff, + .sfd_rq_setframe = sas2_rq_setframe, + .sfd_rs_datalen = sas2_rs_datalen, + .sfd_rs_dataoff = sas2_rs_dataoff, + .sfd_rs_getparams = sas2_rs_getparams +}, +{ + .sfd_function = SMP_FUNC_REPORT_BROADCAST, + .sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE | + SMP_FD_F_PROVIDES_CHANGE_COUNT, + .sfd_rq_len = sas2_report_broadcast_rq_len, + .sfd_rq_dataoff = sas2_rq_dataoff, + .sfd_rq_setframe = sas2_rq_setframe, + .sfd_rs_datalen = sas2_rs_datalen, + .sfd_rs_dataoff = sas2_rs_dataoff, + .sfd_rs_getparams = sas2_rs_getparams +}, +{ + .sfd_function = SMP_FUNC_DISCOVER, + .sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE | + SMP_FD_F_PROVIDES_CHANGE_COUNT, + .sfd_rq_len = sas2_discover_rq_len, + .sfd_rq_dataoff = sas2_rq_dataoff, + .sfd_rq_setframe = sas2_rq_setframe, + .sfd_rs_datalen = sas2_discover_rs_datalen, + .sfd_rs_dataoff = sas2_rs_dataoff, + .sfd_rs_getparams = sas2_rs_getparams +}, +{ + .sfd_function = SMP_FUNC_REPORT_PHY_ERROR_LOG, + .sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE | + SMP_FD_F_PROVIDES_CHANGE_COUNT, + .sfd_rq_len = sas2_report_phy_error_log_rq_len, + .sfd_rq_dataoff = sas2_rq_dataoff, + .sfd_rq_setframe = sas2_rq_setframe, + .sfd_rs_datalen = sas2_report_phy_error_log_rs_datalen, + .sfd_rs_dataoff = sas2_rs_dataoff, + .sfd_rs_getparams = sas2_rs_getparams +}, +{ + .sfd_function = SMP_FUNC_REPORT_PHY_SATA, + .sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE | + SMP_FD_F_PROVIDES_CHANGE_COUNT, + .sfd_rq_len = sas2_report_phy_sata_rq_len, + .sfd_rq_dataoff = sas2_rq_dataoff, + .sfd_rq_setframe = sas2_rq_setframe, + .sfd_rs_datalen = sas2_report_phy_sata_rs_datalen, + .sfd_rs_dataoff = sas2_rs_dataoff, + .sfd_rs_getparams = sas2_rs_getparams +}, +{ + .sfd_function = SMP_FUNC_REPORT_ROUTE_INFO, + .sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE | + SMP_FD_F_PROVIDES_CHANGE_COUNT, + .sfd_rq_len = sas2_report_route_info_rq_len, + .sfd_rq_dataoff = sas2_rq_dataoff, + .sfd_rq_setframe = sas2_rq_setframe, + .sfd_rs_datalen = sas2_report_route_info_rs_datalen, + .sfd_rs_dataoff = sas2_rs_dataoff, + .sfd_rs_getparams = sas2_rs_getparams +}, +{ + .sfd_function = SMP_FUNC_REPORT_PHY_EVENT, + .sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE | + SMP_FD_F_PROVIDES_CHANGE_COUNT, + .sfd_rq_len = sas2_report_phy_event_rq_len, + .sfd_rq_dataoff = sas2_rq_dataoff, + .sfd_rq_setframe = sas2_rq_setframe, + .sfd_rs_datalen = sas2_rs_datalen, + .sfd_rs_dataoff = sas2_rs_dataoff, + .sfd_rs_getparams = sas2_rs_getparams +}, +{ + .sfd_function = SMP_FUNC_DISCOVER_LIST, + .sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE | + SMP_FD_F_PROVIDES_CHANGE_COUNT, + .sfd_rq_len = sas2_discover_list_rq_len, + .sfd_rq_dataoff = sas2_rq_dataoff, + .sfd_rq_setframe = sas2_rq_setframe, + .sfd_rs_datalen = sas2_rs_datalen, + .sfd_rs_dataoff = sas2_rs_dataoff, + .sfd_rs_getparams = sas2_rs_getparams +}, +{ + .sfd_function = SMP_FUNC_REPORT_PHY_EVENT_LIST, + .sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE | + SMP_FD_F_PROVIDES_CHANGE_COUNT, + .sfd_rq_len = sas2_report_phy_event_list_rq_len, + .sfd_rq_dataoff = sas2_rq_dataoff, + .sfd_rq_setframe = sas2_rq_setframe, + .sfd_rs_datalen = sas2_rs_datalen, + .sfd_rs_dataoff = sas2_rs_dataoff, + .sfd_rs_getparams = sas2_rs_getparams +}, +{ + .sfd_function = SMP_FUNC_REPORT_EXP_ROUTE_TABLE_LIST, + .sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE | + SMP_FD_F_PROVIDES_CHANGE_COUNT, + .sfd_rq_len = sas2_report_exp_route_table_list_rq_len, + .sfd_rq_dataoff = sas2_rq_dataoff, + .sfd_rq_setframe = sas2_rq_setframe, + .sfd_rs_datalen = sas2_rs_datalen, + .sfd_rs_dataoff = sas2_rs_dataoff, + .sfd_rs_getparams = sas2_rs_getparams +}, +{ + .sfd_function = SMP_FUNC_CONFIG_GENERAL, + .sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT, + .sfd_rq_len = sas2_config_general_rq_len, + .sfd_rq_dataoff = sas2_rq_dataoff, + .sfd_rq_setframe = sas2_rq_setframe, + .sfd_rs_datalen = sas2_rs_datalen, + .sfd_rs_dataoff = sas2_rs_dataoff, + .sfd_rs_getparams = sas2_rs_getparams +}, +{ + .sfd_function = SMP_FUNC_ENABLE_DISABLE_ZONING, + .sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT, + .sfd_rq_len = sas2_enable_disable_zoning_rq_len, + .sfd_rq_dataoff = sas2_rq_dataoff, + .sfd_rq_setframe = sas2_rq_setframe, + .sfd_rs_datalen = sas2_rs_datalen, + .sfd_rs_dataoff = sas2_rs_dataoff, + .sfd_rs_getparams = sas2_rs_getparams +}, +{ + .sfd_function = SMP_FUNC_ZONED_BROADCAST, + .sfd_flags = SMP_FD_F_WRITE, + .sfd_rq_len = sas2_zoned_broadcast_rq_len, + .sfd_rq_dataoff = sas2_rq_dataoff, + .sfd_rq_setframe = sas2_rq_setframe, + .sfd_rs_datalen = sas2_rs_datalen, + .sfd_rs_dataoff = sas2_rs_dataoff, + .sfd_rs_getparams = sas2_rs_getparams +}, +{ + .sfd_function = SMP_FUNC_ZONE_LOCK, + .sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE | + SMP_FD_F_NEEDS_CHANGE_COUNT, + .sfd_rq_len = sas2_zone_lock_rq_len, + .sfd_rq_dataoff = sas2_rq_dataoff, + .sfd_rq_setframe = sas2_rq_setframe, + .sfd_rs_datalen = sas2_rs_datalen, + .sfd_rs_dataoff = sas2_rs_dataoff, + .sfd_rs_getparams = sas2_rs_getparams +}, +{ + .sfd_function = SMP_FUNC_ZONE_ACTIVATE, + .sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT, + .sfd_rq_len = sas2_zone_activate_rq_len, + .sfd_rq_dataoff = sas2_rq_dataoff, + .sfd_rq_setframe = sas2_rq_setframe, + .sfd_rs_datalen = sas2_rs_datalen, + .sfd_rs_dataoff = sas2_rs_dataoff, + .sfd_rs_getparams = sas2_rs_getparams +}, +{ + .sfd_function = SMP_FUNC_ZONE_UNLOCK, + .sfd_flags = SMP_FD_F_WRITE, + .sfd_rq_len = sas2_zone_unlock_rq_len, + .sfd_rq_dataoff = sas2_rq_dataoff, + .sfd_rq_setframe = sas2_rq_setframe, + .sfd_rs_datalen = sas2_rs_datalen, + .sfd_rs_dataoff = sas2_rs_dataoff, + .sfd_rs_getparams = sas2_rs_getparams +}, +{ + .sfd_function = SMP_FUNC_CONFIG_ZONE_MANAGER_PASSWORD, + .sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT, + .sfd_rq_len = sas2_config_zone_manager_password_rq_len, + .sfd_rq_dataoff = sas2_rq_dataoff, + .sfd_rq_setframe = sas2_rq_setframe, + .sfd_rs_datalen = sas2_rs_datalen, + .sfd_rs_dataoff = sas2_rs_dataoff, + .sfd_rs_getparams = sas2_rs_getparams +}, +{ + .sfd_function = SMP_FUNC_CONFIG_ZONE_PHY_INFO, + .sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT, + .sfd_rq_len = sas2_config_zone_phy_info_rq_len, + .sfd_rq_dataoff = sas2_rq_dataoff, + .sfd_rq_setframe = sas2_rq_setframe, + .sfd_rs_datalen = sas2_rs_datalen, + .sfd_rs_dataoff = sas2_rs_dataoff, + .sfd_rs_getparams = sas2_rs_getparams +}, +{ + .sfd_function = SMP_FUNC_CONFIG_ZONE_PERM_TABLE, + .sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT, + .sfd_rq_len = sas2_config_zone_perm_table_rq_len, + .sfd_rq_dataoff = sas2_rq_dataoff, + .sfd_rq_setframe = sas2_rq_setframe, + .sfd_rs_datalen = sas2_rs_datalen, + .sfd_rs_dataoff = sas2_rs_dataoff, + .sfd_rs_getparams = sas2_rs_getparams +}, +{ + .sfd_function = SMP_FUNC_CONFIG_ROUTE_INFO, + .sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT, + .sfd_rq_len = sas2_config_route_info_rq_len, + .sfd_rq_dataoff = sas2_rq_dataoff, + .sfd_rq_setframe = sas2_rq_setframe, + .sfd_rs_datalen = sas2_rs_datalen, + .sfd_rs_dataoff = sas2_rs_dataoff, + .sfd_rs_getparams = sas2_rs_getparams +}, +{ + .sfd_function = SMP_FUNC_PHY_CONTROL, + .sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT, + .sfd_rq_len = sas2_phy_control_rq_len, + .sfd_rq_dataoff = sas2_rq_dataoff, + .sfd_rq_setframe = sas2_rq_setframe, + .sfd_rs_datalen = sas2_rs_datalen, + .sfd_rs_dataoff = sas2_rs_dataoff, + .sfd_rs_getparams = sas2_rs_getparams +}, +{ + .sfd_function = SMP_FUNC_PHY_TEST_FUNCTION, + .sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT, + .sfd_rq_len = sas2_phy_test_function_rq_len, + .sfd_rq_dataoff = sas2_rq_dataoff, + .sfd_rq_setframe = sas2_rq_setframe, + .sfd_rs_datalen = sas2_rs_datalen, + .sfd_rs_dataoff = sas2_rs_dataoff, + .sfd_rs_getparams = sas2_rs_getparams +}, +{ + .sfd_function = SMP_FUNC_CONFIG_PHY_EVENT, + .sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT, + .sfd_rq_len = sas2_config_phy_event_rq_len, + .sfd_rq_dataoff = sas2_rq_dataoff, + .sfd_rq_setframe = sas2_rq_setframe, + .sfd_rs_datalen = sas2_rs_datalen, + .sfd_rs_dataoff = sas2_rs_dataoff, + .sfd_rs_getparams = sas2_rs_getparams +}, +{ + .sfd_function = -1 +} +}; + +/* + * Returns the number of bytes in the request frame, including the header + * and footer, for the given function and capabilities. Presently the only + * relevant capability is long-request, which in some cases increases the + * size of the request from the SAS-1 spec to that found in SAS-2. + * + * Variably-sized request frames have no default size; we return 0 in that + * case, which will often be interpreted by the caller as an error although + * in general it is not. + */ +size_t +smp_default_request_len(uint_t cap, smp_function_t fn) +{ + switch (fn) { + case SMP_FUNC_REPORT_GENERAL: + case SMP_FUNC_REPORT_MANUFACTURER_INFO: + case SMP_FUNC_REPORT_ZONE_MANAGER_PASSWORD: + return (SMP_REQ_MINLEN); + + case SMP_FUNC_REPORT_SELF_CONFIG_STATUS: + if (cap & SMP_TARGET_C_LONG_RESP) + return (SMP_REQ_MINLEN + + sizeof (smp_report_self_config_status_req_t)); + return (SMP_REQ_MINLEN); + case SMP_FUNC_REPORT_ZONE_PERM_TABLE: + if (cap & SMP_TARGET_C_LONG_RESP) + return (SMP_REQ_MINLEN + + sizeof (smp_report_zone_perm_table_req_t)); + return (SMP_REQ_MINLEN); + case SMP_FUNC_REPORT_BROADCAST: + if (cap & SMP_TARGET_C_LONG_RESP) + return (SMP_REQ_MINLEN + + sizeof (smp_report_broadcast_req_t)); + return (SMP_REQ_MINLEN); + case SMP_FUNC_DISCOVER: + return (SMP_REQ_MINLEN + sizeof (smp_discover_req_t)); + case SMP_FUNC_REPORT_PHY_ERROR_LOG: + return (SMP_REQ_MINLEN + + sizeof (smp_report_phy_error_log_req_t)); + case SMP_FUNC_REPORT_PHY_SATA: + return (SMP_REQ_MINLEN + sizeof (smp_report_phy_sata_req_t)); + case SMP_FUNC_REPORT_ROUTE_INFO: + return (SMP_REQ_MINLEN + sizeof (smp_report_route_info_req_t)); + case SMP_FUNC_REPORT_PHY_EVENT: + if (cap & SMP_TARGET_C_LONG_RESP) + return (SMP_REQ_MINLEN + + sizeof (smp_report_phy_event_req_t)); + return (SMP_REQ_MINLEN); + case SMP_FUNC_DISCOVER_LIST: + if (cap & SMP_TARGET_C_LONG_RESP) + return (SMP_REQ_MINLEN + + sizeof (smp_discover_list_req_t)); + return (SMP_REQ_MINLEN); + case SMP_FUNC_REPORT_PHY_EVENT_LIST: + if (cap & SMP_TARGET_C_LONG_RESP) + return (SMP_REQ_MINLEN + + sizeof (smp_report_phy_event_list_req_t)); + return (SMP_REQ_MINLEN); + case SMP_FUNC_REPORT_EXP_ROUTE_TABLE_LIST: + if (cap & SMP_TARGET_C_LONG_RESP) + return (SMP_REQ_MINLEN + + sizeof (smp_report_exp_route_table_list_req_t)); + return (SMP_REQ_MINLEN); + case SMP_FUNC_CONFIG_GENERAL: + if (cap & SMP_TARGET_C_LONG_RESP) + return (SMP_REQ_MINLEN + + sizeof (smp_config_general_req_t)); + return (SMP_REQ_MINLEN); + case SMP_FUNC_ENABLE_DISABLE_ZONING: + if (cap & SMP_TARGET_C_LONG_RESP) + return (SMP_REQ_MINLEN + + sizeof (smp_enable_disable_zoning_req_t)); + return (SMP_REQ_MINLEN); + case SMP_FUNC_ZONE_LOCK: + if (cap & SMP_TARGET_C_LONG_RESP) + return (SMP_REQ_MINLEN + + sizeof (smp_zone_lock_req_t)); + return (SMP_REQ_MINLEN); + case SMP_FUNC_ZONE_ACTIVATE: + if (cap & SMP_TARGET_C_LONG_RESP) + return (SMP_REQ_MINLEN + + sizeof (smp_zone_activate_req_t)); + return (SMP_REQ_MINLEN); + case SMP_FUNC_ZONE_UNLOCK: + if (cap & SMP_TARGET_C_LONG_RESP) + return (SMP_REQ_MINLEN + + sizeof (smp_zone_unlock_req_t)); + return (SMP_REQ_MINLEN); + case SMP_FUNC_CONFIG_ZONE_MANAGER_PASSWORD: + if (cap & SMP_TARGET_C_LONG_RESP) + return (SMP_REQ_MINLEN + + sizeof (smp_config_zone_manager_password_req_t)); + return (SMP_REQ_MINLEN); + case SMP_FUNC_CONFIG_ROUTE_INFO: + return (SMP_REQ_MINLEN + sizeof (smp_config_route_info_req_t)); + case SMP_FUNC_PHY_CONTROL: + return (SMP_REQ_MINLEN + sizeof (smp_phy_control_req_t)); + case SMP_FUNC_PHY_TEST_FUNCTION: + return (SMP_REQ_MINLEN + sizeof (smp_phy_test_function_req_t)); + + case SMP_FUNC_ZONED_BROADCAST: + case SMP_FUNC_CONFIG_ZONE_PHY_INFO: + case SMP_FUNC_CONFIG_ZONE_PERM_TABLE: + case SMP_FUNC_CONFIG_PHY_EVENT: + default: + return (0); + } +} + +/* + * This is slightly different - return the length in bytes, including the + * header and footer, to be assumed for the response frame type if the + * length field is zero. Since the length field will not be zero unless the + * long response bit is clear or the target is buggy, we always assume that + * the caller wants the size of the v1 frame. + */ +/*ARGSUSED*/ +size_t +smp_default_response_len(uint_t cap, smp_function_t fn) +{ + switch (fn) { + case SMP_FUNC_REPORT_SELF_CONFIG_STATUS: + case SMP_FUNC_REPORT_ZONE_PERM_TABLE: + case SMP_FUNC_REPORT_ZONE_MANAGER_PASSWORD: + case SMP_FUNC_REPORT_BROADCAST: + case SMP_FUNC_REPORT_PHY_EVENT: + case SMP_FUNC_DISCOVER_LIST: + case SMP_FUNC_REPORT_PHY_EVENT_LIST: + case SMP_FUNC_REPORT_EXP_ROUTE_TABLE_LIST: + case SMP_FUNC_CONFIG_GENERAL: + case SMP_FUNC_ENABLE_DISABLE_ZONING: + case SMP_FUNC_ZONED_BROADCAST: + case SMP_FUNC_ZONE_LOCK: + case SMP_FUNC_ZONE_ACTIVATE: + case SMP_FUNC_ZONE_UNLOCK: + case SMP_FUNC_CONFIG_ZONE_MANAGER_PASSWORD: + case SMP_FUNC_CONFIG_ZONE_PHY_INFO: + case SMP_FUNC_CONFIG_ZONE_PERM_TABLE: + case SMP_FUNC_CONFIG_ROUTE_INFO: + case SMP_FUNC_PHY_CONTROL: + case SMP_FUNC_PHY_TEST_FUNCTION: + case SMP_FUNC_CONFIG_PHY_EVENT: + return (SMP_RESP_MINLEN); + + case SMP_FUNC_REPORT_GENERAL: + return (SMP_RESP_MINLEN + 24); + case SMP_FUNC_REPORT_MANUFACTURER_INFO: + return (SMP_RESP_MINLEN + + sizeof (smp_report_manufacturer_info_resp_t)); + case SMP_FUNC_DISCOVER: + return (SMP_RESP_MINLEN + 48); + case SMP_FUNC_REPORT_PHY_ERROR_LOG: + return (SMP_RESP_MINLEN + + sizeof (smp_report_phy_error_log_resp_t)); + case SMP_FUNC_REPORT_PHY_SATA: + return (SMP_RESP_MINLEN + 52); + case SMP_FUNC_REPORT_ROUTE_INFO: + return (SMP_RESP_MINLEN + + sizeof (smp_report_route_info_resp_t)); + + default: + return (0); + } +} diff --git a/usr/src/lib/scsi/plugins/smp/sas2/i386/Makefile b/usr/src/lib/scsi/plugins/smp/sas2/i386/Makefile new file mode 100644 index 0000000000..6a01a5dce1 --- /dev/null +++ b/usr/src/lib/scsi/plugins/smp/sas2/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 (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +include ../Makefile.com + +install: all $(ROOTPROG) + +include ../../Makefile.targ diff --git a/usr/src/lib/scsi/plugins/smp/sas2/sparc/Makefile b/usr/src/lib/scsi/plugins/smp/sas2/sparc/Makefile new file mode 100644 index 0000000000..6a01a5dce1 --- /dev/null +++ b/usr/src/lib/scsi/plugins/smp/sas2/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 (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +include ../Makefile.com + +install: all $(ROOTPROG) + +include ../../Makefile.targ diff --git a/usr/src/lib/scsi/plugins/smp/sas2/sparcv9/Makefile b/usr/src/lib/scsi/plugins/smp/sas2/sparcv9/Makefile new file mode 100644 index 0000000000..0a34065b01 --- /dev/null +++ b/usr/src/lib/scsi/plugins/smp/sas2/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 (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +include ../Makefile.com +include $(SRC)/Makefile.master.64 + +install: all $(ROOTPROG64) + +include ../../Makefile.targ diff --git a/usr/src/lib/scsi/plugins/smp/usmp/Makefile b/usr/src/lib/scsi/plugins/smp/usmp/Makefile new file mode 100644 index 0000000000..d0d0a64787 --- /dev/null +++ b/usr/src/lib/scsi/plugins/smp/usmp/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 (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +HDRS = +HDRDIR = common +PLUGINTYPE = engine + +include ../Makefile.plugin diff --git a/usr/src/lib/scsi/plugins/smp/usmp/Makefile.com b/usr/src/lib/scsi/plugins/smp/usmp/Makefile.com new file mode 100644 index 0000000000..2c19fd0446 --- /dev/null +++ b/usr/src/lib/scsi/plugins/smp/usmp/Makefile.com @@ -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 (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +MODULE = usmp +SRCS = usmp.c + +SRCDIR = ../common +PLUGINTYPE = engine + +include ../../Makefile.lib + +LDLIBS += -ldevinfo \ + -ldevid diff --git a/usr/src/lib/scsi/plugins/smp/usmp/amd64/Makefile b/usr/src/lib/scsi/plugins/smp/usmp/amd64/Makefile new file mode 100644 index 0000000000..0a34065b01 --- /dev/null +++ b/usr/src/lib/scsi/plugins/smp/usmp/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 (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +include ../Makefile.com +include $(SRC)/Makefile.master.64 + +install: all $(ROOTPROG64) + +include ../../Makefile.targ diff --git a/usr/src/lib/scsi/plugins/smp/usmp/common/usmp.c b/usr/src/lib/scsi/plugins/smp/usmp/common/usmp.c new file mode 100644 index 0000000000..fa3ea08921 --- /dev/null +++ b/usr/src/lib/scsi/plugins/smp/usmp/common/usmp.c @@ -0,0 +1,231 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/scsi/scsi_address.h> +#include <sys/scsi/impl/usmp.h> +#include <sys/libdevid.h> + +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include <strings.h> +#include <stdio.h> +#include <limits.h> + +#include <scsi/libsmp.h> +#include <scsi/libsmp_plugin.h> + +#include <libdevinfo.h> + +struct usmp_dev { + int ud_fd; + char *ud_dev; + uint64_t ud_addr; +}; + +struct di_walk_arg { + dev_t dev; + uint64_t addr; +}; + +static int +di_walk(di_node_t node, di_minor_t minor, void *arg) +{ + struct di_walk_arg *wp = arg; + char *wwn; + + if (di_minor_spectype(minor) != S_IFCHR) + return (DI_WALK_CONTINUE); + + if (di_minor_devt(minor) == wp->dev) { + if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, + SCSI_ADDR_PROP_TARGET_PORT, &wwn) != 1 && + di_prop_lookup_strings(DDI_DEV_T_ANY, node, + "smp-wwn", &wwn) != 1) + return (DI_WALK_CONTINUE); + + if (scsi_wwnstr_to_wwn(wwn, &wp->addr) != DDI_SUCCESS) + return (DI_WALK_CONTINUE); + + return (DI_WALK_TERMINATE); + } + + return (DI_WALK_CONTINUE); +} + +static void * +usmp_open(const void *target) +{ + struct usmp_dev *dp; + const char *target_name = (const char *)target; + + struct stat64 st; + di_node_t root, smp; + struct di_walk_arg walk; + + if ((dp = smp_zalloc(sizeof (struct usmp_dev))) == NULL) + return (NULL); + + if ((dp->ud_dev = smp_strdup(target_name)) == NULL) { + smp_free(dp); + return (NULL); + } + + if ((dp->ud_fd = open(target_name, O_RDONLY)) < 0) { + (void) smp_error(ESMP_BADTARGET, + "failed to open %s for reading: %s", + target_name, strerror(errno)); + smp_free(dp->ud_dev); + smp_free(dp); + return (NULL); + } + + if (fstat64(dp->ud_fd, &st) != 0) { + (void) smp_error(ESMP_BADTARGET, + "failed to stat %s: %s", target_name, strerror(errno)); + (void) close(dp->ud_fd); + smp_free(dp->ud_dev); + smp_free(dp); + return (NULL); + } + + if ((root = di_init("/", DINFOCACHE)) != DI_NODE_NIL) { + for (smp = di_drv_first_node("smp", root); smp != DI_NODE_NIL; + smp = di_drv_next_node(smp)) { + bzero(&walk, sizeof (walk)); + walk.dev = st.st_rdev; + (void) di_walk_minor(smp, NULL, 0, &walk, di_walk); + if (walk.addr != 0) { + dp->ud_addr = walk.addr; + break; + } + } + di_fini(root); + } + + return (dp); +} + +static void +usmp_close(void *private) +{ + struct usmp_dev *dp = (struct usmp_dev *)private; + + if (dp == NULL) + return; + + if (dp->ud_fd > 0) + (void) close(dp->ud_fd); + + smp_free(dp->ud_dev); + smp_free(dp); +} + +static int +usmp_exec(void *private, smp_action_t *ap) +{ + struct usmp_dev *dp = (struct usmp_dev *)private; + struct usmp_cmd cmd; + void *req, *resp; + size_t reqlen, resplen; + + bzero(&cmd, sizeof (cmd)); + + smp_action_get_request_frame(ap, &req, &reqlen); + smp_action_get_response_frame(ap, &resp, &resplen); + + ASSERT(req != NULL); + ASSERT(resp != NULL); + ASSERT(reqlen != 0); + ASSERT(resplen != 0); + + cmd.usmp_req = req; + cmd.usmp_reqsize = reqlen; + cmd.usmp_rsp = resp; + cmd.usmp_rspsize = resplen; + cmd.usmp_timeout = (int)smp_action_get_timeout(ap); + + if (ioctl(dp->ud_fd, USMPFUNC, &cmd) < 0) { + ASSERT(errno != EFAULT); + switch (errno) { + case EINVAL: + return (smp_error(ESMP_BADFUNC, "internal usmp error")); + case EPERM: + return (smp_error(ESMP_PERM, + "insufficient privileges")); + case EIO: + return (smp_error(ESMP_IO, "I/O error")); + default: + return (smp_error(ESMP_SYS, "usmp ioctl failed: %s", + strerror(errno))); + } + } + + /* + * There is no way to determine the amount of data actually transferred + * so we will just place the upper bound at the allocated size. + */ + smp_action_set_response_len(ap, resplen); + + return (0); +} + +static void +usmp_target_name(void *private, char *buf, size_t len) +{ + struct usmp_dev *dp = (struct usmp_dev *)private; + + (void) strlcpy(buf, dp->ud_dev, len); +} + +static uint64_t +usmp_target_addr(void *private) +{ + struct usmp_dev *dp = (struct usmp_dev *)private; + + return (dp->ud_addr); +} + +static const smp_engine_ops_t usmp_ops = { + .seo_open = usmp_open, + .seo_close = usmp_close, + .seo_exec = usmp_exec, + .seo_target_name = usmp_target_name, + .seo_target_addr = usmp_target_addr +}; + +int +_smp_init(smp_engine_t *ep) +{ + smp_engine_config_t config = { + .sec_name = "usmp", + .sec_ops = &usmp_ops + }; + + return (smp_engine_register(ep, LIBSMP_ENGINE_VERSION, &config)); +} diff --git a/usr/src/lib/scsi/plugins/smp/usmp/i386/Makefile b/usr/src/lib/scsi/plugins/smp/usmp/i386/Makefile new file mode 100644 index 0000000000..6a01a5dce1 --- /dev/null +++ b/usr/src/lib/scsi/plugins/smp/usmp/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 (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +include ../Makefile.com + +install: all $(ROOTPROG) + +include ../../Makefile.targ diff --git a/usr/src/lib/scsi/plugins/smp/usmp/sparc/Makefile b/usr/src/lib/scsi/plugins/smp/usmp/sparc/Makefile new file mode 100644 index 0000000000..6a01a5dce1 --- /dev/null +++ b/usr/src/lib/scsi/plugins/smp/usmp/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 (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +include ../Makefile.com + +install: all $(ROOTPROG) + +include ../../Makefile.targ diff --git a/usr/src/lib/scsi/plugins/smp/usmp/sparcv9/Makefile b/usr/src/lib/scsi/plugins/smp/usmp/sparcv9/Makefile new file mode 100644 index 0000000000..0a34065b01 --- /dev/null +++ b/usr/src/lib/scsi/plugins/smp/usmp/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 (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +include ../Makefile.com +include $(SRC)/Makefile.master.64 + +install: all $(ROOTPROG64) + +include ../../Makefile.targ diff --git a/usr/src/pkg/manifests/developer-library-lint.mf b/usr/src/pkg/manifests/developer-library-lint.mf index aaa2aa2228..fb273a3175 100644 --- a/usr/src/pkg/manifests/developer-library-lint.mf +++ b/usr/src/pkg/manifests/developer-library-lint.mf @@ -20,8 +20,7 @@ # # -# Copyright 2010 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. # set name=pkg.fmri value=pkg:/developer/library/lint@$(PKGVERS) @@ -336,10 +335,13 @@ file path=usr/lib/llib-lzoneinfo file path=usr/lib/llib-lzoneinfo.ln file path=usr/lib/scsi/$(ARCH64)/llib-lscsi.ln file path=usr/lib/scsi/$(ARCH64)/llib-lses.ln +file path=usr/lib/scsi/$(ARCH64)/llib-lsmp.ln file path=usr/lib/scsi/llib-lscsi file path=usr/lib/scsi/llib-lscsi.ln file path=usr/lib/scsi/llib-lses file path=usr/lib/scsi/llib-lses.ln +file path=usr/lib/scsi/llib-lsmp +file path=usr/lib/scsi/llib-lsmp.ln file path=usr/lib/values-Xa.o file path=usr/lib/values-Xc.o file path=usr/lib/values-Xs.o diff --git a/usr/src/pkg/manifests/system-header.mf b/usr/src/pkg/manifests/system-header.mf index 9c4a81ef50..4ec067162c 100644 --- a/usr/src/pkg/manifests/system-header.mf +++ b/usr/src/pkg/manifests/system-header.mf @@ -63,6 +63,9 @@ dir path=usr/include/scsi/plugins dir path=usr/include/scsi/plugins/ses dir path=usr/include/scsi/plugins/ses/framework dir path=usr/include/scsi/plugins/ses/vendor +dir path=usr/include/scsi/plugins/smp +dir path=usr/include/scsi/plugins/smp/engine +dir path=usr/include/scsi/plugins/smp/framework dir path=usr/include/security dir path=usr/include/sharefs dir path=usr/include/sys @@ -727,9 +730,12 @@ file path=usr/include/schedctl.h file path=usr/include/scsi/libscsi.h file path=usr/include/scsi/libses.h file path=usr/include/scsi/libses_plugin.h +file path=usr/include/scsi/libsmp.h +file path=usr/include/scsi/libsmp_plugin.h file path=usr/include/scsi/plugins/ses/framework/libses.h file path=usr/include/scsi/plugins/ses/framework/ses2.h file path=usr/include/scsi/plugins/ses/framework/ses2_impl.h +file path=usr/include/scsi/plugins/ses/vendor/sun.h file path=usr/include/sdp.h file path=usr/include/search.h file path=usr/include/secdb.h @@ -1353,6 +1359,7 @@ file path=usr/include/sys/scsi/generic/message.h file path=usr/include/sys/scsi/generic/mode.h file path=usr/include/sys/scsi/generic/persist.h file path=usr/include/sys/scsi/generic/sense.h +file path=usr/include/sys/scsi/generic/sff_frames.h file path=usr/include/sys/scsi/generic/smp_frames.h file path=usr/include/sys/scsi/generic/status.h file path=usr/include/sys/scsi/impl/commands.h diff --git a/usr/src/pkg/manifests/system-io-tests.mf b/usr/src/pkg/manifests/system-io-tests.mf index c790788b6f..3c273ffc4d 100644 --- a/usr/src/pkg/manifests/system-io-tests.mf +++ b/usr/src/pkg/manifests/system-io-tests.mf @@ -20,8 +20,7 @@ # # -# Copyright 2010 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. # set name=pkg.fmri value=pkg:/system/io/tests@$(PKGVERS) @@ -59,6 +58,7 @@ $(i386_ONLY)file path=usr/kernel/drv/tclient group=sys $(i386_ONLY)file path=usr/kernel/drv/tphci group=sys $(i386_ONLY)file path=usr/kernel/drv/tvhci group=sys file path=usr/lib/scsi/sestopo mode=0555 +file path=usr/lib/scsi/smp mode=0555 file path=usr/sbin/devctl mode=0555 file path=usr/sbin/emul64ioctl mode=0555 legacy pkg=SUNWioth arch=$(ARCH) category=system desc="I/O Test Header Files" \ diff --git a/usr/src/pkg/manifests/system-library-storage-scsi-plugins.mf b/usr/src/pkg/manifests/system-library-storage-scsi-plugins.mf index a2493b3d56..a30665c401 100644 --- a/usr/src/pkg/manifests/system-library-storage-scsi-plugins.mf +++ b/usr/src/pkg/manifests/system-library-storage-scsi-plugins.mf @@ -20,8 +20,7 @@ # # -# Copyright 2010 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. # set name=pkg.fmri value=pkg:/system/library/storage/scsi-plugins@$(PKGVERS) @@ -57,3 +56,7 @@ link path=usr/lib/scsi/plugins/ses/vendor/$(ARCH64)/SUN-Storage-J4200.so \ target=SUN-Storage-J4400.so link path=usr/lib/scsi/plugins/ses/vendor/SUN-Storage-J4200.so \ target=SUN-Storage-J4400.so +link path=usr/lib/scsi/plugins/ses/vendor/$(ARCH64)/LSILOGIC-SASX28-A.1.so \ + target=LSILOGIC-SASX28-A.0.so +link path=usr/lib/scsi/plugins/ses/vendor/LSILOGIC-SASX28-A.1.so \ + target=LSILOGIC-SASX28-A.0.so diff --git a/usr/src/pkg/manifests/system-library.mf b/usr/src/pkg/manifests/system-library.mf index 4bf5e75395..85ff43d292 100644 --- a/usr/src/pkg/manifests/system-library.mf +++ b/usr/src/pkg/manifests/system-library.mf @@ -20,8 +20,7 @@ # # -# Copyright 2010 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. # set name=pkg.fmri value=pkg:/system/library@$(PKGVERS) @@ -74,6 +73,11 @@ dir path=usr/lib/scsi/plugins/ses/framework dir path=usr/lib/scsi/plugins/ses/framework/$(ARCH64) dir path=usr/lib/scsi/plugins/ses/vendor $(sparc_ONLY)dir path=usr/lib/scsi/plugins/ses/vendor/$(ARCH64) +dir path=usr/lib/scsi/plugins/smp +dir path=usr/lib/scsi/plugins/smp/framework +dir path=usr/lib/scsi/plugins/smp/framework/$(ARCH64) +dir path=usr/lib/scsi/plugins/smp/engine +dir path=usr/lib/scsi/plugins/smp/engine/$(ARCH64) dir path=usr/lib/security dir path=usr/lib/security/$(ARCH64) dir path=usr/xpg4 @@ -375,14 +379,20 @@ file path=usr/lib/raidcfg/$(ARCH64)/mpt.so.1 file path=usr/lib/raidcfg/mpt.so.1 file path=usr/lib/scsi/$(ARCH64)/libscsi.so.1 file path=usr/lib/scsi/$(ARCH64)/libses.so.1 +file path=usr/lib/scsi/$(ARCH64)/libsmp.so.1 file path=usr/lib/scsi/libscsi.so.1 file path=usr/lib/scsi/libses.so.1 +file path=usr/lib/scsi/libsmp.so.1 file path=usr/lib/scsi/plugins/scsi/engines/$(ARCH64)/uscsi.so file path=usr/lib/scsi/plugins/scsi/engines/uscsi.so +file path=usr/lib/scsi/plugins/smp/engine/$(ARCH64)/usmp.so +file path=usr/lib/scsi/plugins/smp/engine/usmp.so file path=usr/lib/scsi/plugins/ses/framework/$(ARCH64)/libses.so file path=usr/lib/scsi/plugins/ses/framework/$(ARCH64)/ses2.so file path=usr/lib/scsi/plugins/ses/framework/libses.so file path=usr/lib/scsi/plugins/ses/framework/ses2.so +file path=usr/lib/scsi/plugins/smp/framework/$(ARCH64)/sas2.so +file path=usr/lib/scsi/plugins/smp/framework/sas2.so file path=usr/lib/security/$(ARCH64)/crypt_bsdbf.so.1 file path=usr/lib/security/$(ARCH64)/crypt_bsdmd5.so.1 file path=usr/lib/security/$(ARCH64)/crypt_sha256.so.1 @@ -1095,8 +1105,10 @@ link path=usr/lib/nss_nis.so.1 target=../../lib/nss_nis.so.1 link path=usr/lib/nss_user.so.1 target=../../lib/nss_user.so.1 link path=usr/lib/scsi/$(ARCH64)/libscsi.so target=./libscsi.so.1 link path=usr/lib/scsi/$(ARCH64)/libses.so target=./libses.so.1 +link path=usr/lib/scsi/$(ARCH64)/libsmp.so target=./libsmp.so.1 link path=usr/lib/scsi/libscsi.so target=./libscsi.so.1 link path=usr/lib/scsi/libses.so target=./libses.so.1 +link path=usr/lib/scsi/libsmp.so target=./libsmp.so.1 link path=usr/lib/security/$(ARCH64)/crypt_bsdbf.so target=./crypt_bsdbf.so.1 link path=usr/lib/security/$(ARCH64)/crypt_bsdmd5.so target=./crypt_bsdmd5.so.1 link path=usr/lib/security/$(ARCH64)/crypt_sha256.so target=./crypt_sha256.so.1 diff --git a/usr/src/uts/common/sys/Makefile b/usr/src/uts/common/sys/Makefile index 830b344630..afec1faf4c 100644 --- a/usr/src/uts/common/sys/Makefile +++ b/usr/src/uts/common/sys/Makefile @@ -904,6 +904,7 @@ SCSIGENHDRS= \ mode.h \ persist.h \ sense.h \ + sff_frames.h \ smp_frames.h \ status.h @@ -1179,6 +1180,7 @@ CHECKHDRS= \ $(SCSICONFHDRS:%.h=scsi/conf/%.check) \ $(SCSIIMPLHDRS:%.h=scsi/impl/%.check) \ $(SCSIISCSIHDRS:%.h=scsi/adapters/%.check) \ + $(SCSIGENHDRS:%.h=scsi/generic/%.check) \ $(SCSITARGETSHDRS:%.h=scsi/targets/%.check) \ $(SCSIVHCIHDRS:%.h=scsi/adapters/%.check) \ $(SATAGENHDRS:%.h=sata/%.check) \ diff --git a/usr/src/uts/common/sys/scsi/generic/sff_frames.h b/usr/src/uts/common/sys/scsi/generic/sff_frames.h new file mode 100644 index 0000000000..b59b88bf5e --- /dev/null +++ b/usr/src/uts/common/sys/scsi/generic/sff_frames.h @@ -0,0 +1,261 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#ifndef _SYS_SCSI_GENERIC_SFF_FRAMES_H +#define _SYS_SCSI_GENERIC_SFF_FRAMES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/sysmacros.h> + +/* + * The definitions of SMP frame formats defined by SFF-8485. + * These are NOT compatible with the generic SAS-1 and/or SAS-2 SMP frame + * formats, but the function numbers and result codes are defined by SAS-2. + */ + +#pragma pack(1) + +typedef struct sff_request_frame { + uint8_t srf_frame_type; + uint8_t srf_function; + uint8_t srf_data[1]; +} sff_request_frame_t; + +typedef struct sff_response_frame { + uint8_t srf_frame_type; + uint8_t srf_function; + uint8_t srf_result; + uint8_t _reserved1; + uint8_t srf_data[1]; +} sff_response_frame_t; + +/* + * SFF-8485 8.4.1 GPIO register overview + */ +typedef enum sff_gpio_reg_type { + SFF_GPIO_CFG = 0x00, + SFF_GPIO_RX = 0x01, + SFF_GPIO_RX_GP = 0x02, + SFF_GPIO_TX = 0x03, + SFF_GPIO_TX_GP = 0x04 +} sff_gpio_reg_type_t; + +/* + * SFF-8485 8.4.2.1 GPIO configuration registers overview + */ +typedef enum sff_gpio_cfg_reg_index { + SFF_GPIO_CFG_0 = 0x00, + SFF_GPIO_CFG_1 = 0x01 +} sff_gpio_cfg_reg_index_t; + +/* + * SFF-8485 8.4.2.2 GPIO_CFG[0] register + */ +typedef struct sff_gpio_cfg_reg_0 { + uint8_t _reserved1; + DECL_BITFIELD2( + sgcr0_version :4, + _reserved2 :4); + DECL_BITFIELD3( + sgcr0_gp_register_count :4, + sgcr0_cfg_register_count :3, + sgcr0_gpio_enable :1); + uint8_t sgcr0_supported_drive_count; +} sff_gpio_cfg_reg_0_t; + +/* + * SFF-8485 8.4.2.3 GPIO_CFG[1] register + */ +typedef struct sff_gpio_cfg_reg_1 { + uint8_t _reserved1; + DECL_BITFIELD2( + sgcr1_blink_gen_rate_a :4, + sgcr1_blink_gen_rate_b :4); + DECL_BITFIELD2( + sgcr1_max_activity_on :4, + sgcr1_force_activity_off :4); + DECL_BITFIELD2( + sgcr1_stretch_activity_on :4, + sgcr1_stretch_activity_off :4); +} sff_gpio_cfg_reg_1_t; + +/* + * SFF-8485 8.4.3 GPIO receive registers + */ +typedef struct sff_gpio_rx_reg { + DECL_BITFIELD2( + sgrr_drive_3_gpio_input :3, + _reserved1 :5); + DECL_BITFIELD2( + sgrr_drive_2_gpio_input :3, + _reserved1 :5); + DECL_BITFIELD2( + sgrr_drive_1_gpio_input :3, + _reserved1 :5); + DECL_BITFIELD2( + sgrr_drive_0_gpio_input :3, + _reserved1 :5); +} sff_gpio_rx_reg_t; + +/* + * SFF-8485 8.4.4 GPIO transmit registers + */ +typedef enum sff_drive_error { + SFF_DRIVE_ERR_DISABLE = 0x0, + SFF_DRIVE_ERR_ENABLE = 0x1, + SFF_DRIVE_ERR_BLINK_A_1_0 = 0x2, + SFF_DRIVE_ERR_BLINK_A_0_1 = 0x3, + SFF_DRIVE_ERR_ENABLE_4 = 0x4, + SFF_DRIVE_ERR_ENABLE_5 = 0x5, + SFF_DRIVE_ERR_BLINK_B_1_0 = 0x6, + SFF_DRIVE_ERR_BLINK_B_0_1 = 0x7 +} sff_drive_error_t; + +typedef enum sff_drive_locate { + SFF_DRIVE_LOC_DISABLE = 0x0, + SFF_DRIVE_LOC_ENABLE = 0x1, + SFF_DRIVE_BLINK_A_1_0 = 0x2, + SFF_DRIVE_BLINK_A_0_1 = 0x3 +} sff_drive_locate_t; + +typedef enum sff_drive_activity { + SFF_DRIVE_ACT_DISABLE = 0x0, + SFF_DRIVE_ACT_ENABLE = 0x1, + SFF_DRIVE_ACT_BLINK_A_1_0 = 0x2, + SFF_DRIVE_ACT_BLINK_A_0_1 = 0x3, + SFF_DRIVE_ACT_ENABLE_END = 0x4, + SFF_DRIVE_ACT_ENABLE_START = 0x5, + SFF_DRIVE_ACT_BLINK_B_1_0 = 0x6, + SFF_DRIVE_ACT_BLINK_B_0_1 = 0x7 +} sff_drive_activity_t; + +typedef struct sff_gpio_tx_reg { + DECL_BITFIELD3( + sgtr_drive_3_error :3, /* sff_drive_error_t */ + sgtr_drive_3_locate :2, /* sff_drive_locate_t */ + sgtr_drive_3_activity :3); /* sff_drive_activity_t */ + DECL_BITFIELD3( + sgtr_drive_2_error :3, /* sff_drive_error_t */ + sgtr_drive_2_locate :2, /* sff_drive_locate_t */ + sgtr_drive_2_activity :3); /* sff_drive_activity_t */ + DECL_BITFIELD3( + sgtr_drive_1_error :3, /* sff_drive_error_t */ + sgtr_drive_1_locate :2, /* sff_drive_locate_t */ + sgtr_drive_1_activity :3); /* sff_drive_activity_t */ + DECL_BITFIELD3( + sgtr_drive_0_error :3, /* sff_drive_error_t */ + sgtr_drive_0_locate :2, /* sff_drive_locate_t */ + sgtr_drive_0_activity :3); /* sff_drive_activity_t */ +} sff_gpio_tx_reg_t; + +/* + * SFF-8485 8.4.5.1 GPIO general purpose receive registers overview + */ +typedef enum sff_gpio_rx_gp_reg_index { + SFF_GPIO_REG_RX_GP_CFG = 0x00, + SFF_GPIO_REG_RX_GP_1 = 0x01 /* ... */ +} sff_gpio_rx_gp_reg_index_t; + +/* + * SFF-8485 8.4.5.2 GPIO_RX_GP_CFG register + */ +typedef struct sff_gpio_rx_gp_cfg_reg { + uint8_t _reserved1[2]; + uint8_t sgrgcr_count; + uint8_t _reserved2; +} sff_gpio_rx_gp_cfg_reg_t; + +/* + * SFF-8485 8.4.5.3 GPIO_RX_GP[1..n] register + */ +typedef uint8_t sff_gpio_rx_gp_reg_t[4]; /* little-endian */ + +/* + * SFF-8485 8.4.6.1 GPIO general purpose transmit registers overview + */ +typedef enum sff_gpio_tx_gp_reg_index { + SFF_GPIO_REG_TX_GP_CFG = 0x00, + SFF_GPIO_REG_TX_GP_1 = 0x01 /* ... */ +} sff_gpio_tx_gp_reg_index_t; + +/* + * SFF-8485 8.4.6.2 GPIO_TX_GP_CFG register + */ +typedef struct sff_gpio_tx_cfg_reg { + uint8_t _reserved1[2]; + uint8_t sgtcr_count; + DECL_BITFIELD5( + sgtcr_sload_0 :1, + sgtcr_sload_1 :1, + sgtcr_sload_2 :1, + sgtcr_sload_3 :1, + _reserved2 :4); +} sff_gpio_tx_cfg_reg_t; + +/* + * SFF-8485 8.4.6.3 GPIO_TX_GP[1..n] registers + */ +typedef uint8_t sff_gpio_tx_gp_reg_t[4]; /* little-endian */ + +/* + * SFF-8485 8.2.2 READ GPIO REGISTER request + */ +typedef struct sff_read_gpio_req { + uint8_t srgr_register_type; + uint8_t srgr_register_index; + uint8_t srgr_register_count; + uint8_t _reserved1[3]; +} sff_read_gpio_req_t; + +typedef uint8_t sff_gpio_reg_t[4]; + +/* + * SFF-8485 8.2.2 READ GPIO REGISTER response + */ +typedef struct sff_read_gpio_resp { + sff_gpio_reg_t srgr_regs[1]; +} smp_response_frame_t; + +/* + * SFF-8485 8.2.3 WRITE GPIO REGISTER request (no additional response) + */ +typedef struct sff_write_gpio_req { + uint8_t swgr_register_type; + uint8_t swgr_register_index; + uint8_t swgr_register_count; + uint8_t _reserved1[3]; + sff_gpio_reg_t swgr_regs[1]; +} sff_write_gpio_req_t; + +#pragma pack() + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_SCSI_GENERIC_SFF_FRAMES_H */ |
