1940d71d2Seschrock /*
2940d71d2Seschrock  * CDDL HEADER START
3940d71d2Seschrock  *
4940d71d2Seschrock  * The contents of this file are subject to the terms of the
5940d71d2Seschrock  * Common Development and Distribution License (the "License").
6940d71d2Seschrock  * You may not use this file except in compliance with the License.
7940d71d2Seschrock  *
8940d71d2Seschrock  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9940d71d2Seschrock  * or http://www.opensolaris.org/os/licensing.
10940d71d2Seschrock  * See the License for the specific language governing permissions
11940d71d2Seschrock  * and limitations under the License.
12940d71d2Seschrock  *
13940d71d2Seschrock  * When distributing Covered Code, include this CDDL HEADER in each
14940d71d2Seschrock  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15940d71d2Seschrock  * If applicable, add the following below this CDDL HEADER, with the
16940d71d2Seschrock  * fields enclosed by brackets "[]" replaced with your own identifying
17940d71d2Seschrock  * information: Portions Copyright [yyyy] [name of copyright owner]
18940d71d2Seschrock  *
19940d71d2Seschrock  * CDDL HEADER END
20940d71d2Seschrock  */
22940d71d2Seschrock /*
2344ed9dbbSStephen Hanson  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24edb433b6SMilan Jurik  * Copyright 2012 Milan Jurik. All rights reserved.
25057c620aSHans Rosenfeld  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
263c6ffbabSRob Johnston  * Copyright 2020 Joyent, Inc.
27940d71d2Seschrock  */
296efb64caSEric Schrock #include <alloca.h>
30940d71d2Seschrock #include <dirent.h>
31940d71d2Seschrock #include <devid.h>
32940d71d2Seschrock #include <fm/libdiskstatus.h>
33940d71d2Seschrock #include <inttypes.h>
34940d71d2Seschrock #include <pthread.h>
35940d71d2Seschrock #include <strings.h>
36ac88567aSHyon Kim #include <string.h>
37940d71d2Seschrock #include <unistd.h>
38940d71d2Seschrock #include <sys/dkio.h>
39940d71d2Seschrock #include <sys/fm/protocol.h>
4044ed9dbbSStephen Hanson #include <sys/libdevid.h>
41940d71d2Seschrock #include <sys/scsi/scsi_types.h>
42ac88567aSHyon Kim #include <sys/byteorder.h>
43f76de749SStephen Hanson #include <pthread.h>
44f76de749SStephen Hanson #include <signal.h>
45f76de749SStephen Hanson #include <fcntl.h>
46f76de749SStephen Hanson #include <sys/ctfs.h>
47f76de749SStephen Hanson #include <libcontract.h>
48f76de749SStephen Hanson #include <poll.h>
49f76de749SStephen Hanson #include <sys/contract/device.h>
50f76de749SStephen Hanson #include <libsysevent.h>
51f76de749SStephen Hanson #include <sys/sysevent/eventdefs.h>
52ded93414SHyon Kim #include <scsi/plugins/ses/vendor/sun.h>
54940d71d2Seschrock #include "disk.h"
55d91236feSeschrock #include "ses.h"
57940d71d2Seschrock #define	SES_VERSION	1
59ac88567aSHyon Kim #define	SES_STARTING_SUBCHASSIS 256	/* valid subchassis IDs are uint8_t */
60ac88567aSHyon Kim #define	NO_SUBCHASSIS	((uint64_t)-1)
61ac88567aSHyon Kim 
62525b85dbSEric Schrock static int ses_snap_freq = 250;		/* in milliseconds */
64d91236feSeschrock #define	SES_STATUS_UNAVAIL(s)	\
650b32bb8bSEric Schrock 	((s) == SES_ESC_UNSUPPORTED || (s) >= SES_ESC_NOT_INSTALLED)
67ded93414SHyon Kim #define	HR_SECOND   1000000000
68ded93414SHyon Kim 
69*c5591576SRob Johnston #define	SES_INST_NOTSET		UINT64_MAX
70*c5591576SRob Johnston 
71940d71d2Seschrock /*
72940d71d2Seschrock  * Because multiple SES targets can be part of a single chassis, we construct
73940d71d2Seschrock  * our own hierarchy that takes this into account.  These SES targets may refer
74940d71d2Seschrock  * to the same devices (multiple paths) or to different devices (managing
75940d71d2Seschrock  * different portions of the space).  We arrange things into a
76940d71d2Seschrock  * ses_enum_enclosure_t, which contains a set of ses targets, and a list of all
77940d71d2Seschrock  * nodes found so far.
78940d71d2Seschrock  */
790b32bb8bSEric Schrock typedef struct ses_alt_node {
800b32bb8bSEric Schrock 	topo_list_t		san_link;
810b32bb8bSEric Schrock 	ses_node_t		*san_node;
820b32bb8bSEric Schrock } ses_alt_node_t;
84940d71d2Seschrock typedef struct ses_enum_node {
85940d71d2Seschrock 	topo_list_t		sen_link;
86940d71d2Seschrock 	ses_node_t		*sen_node;
870b32bb8bSEric Schrock 	topo_list_t		sen_alt_nodes;
88940d71d2Seschrock 	uint64_t		sen_type;
89940d71d2Seschrock 	uint64_t		sen_instance;
90940d71d2Seschrock 	ses_enum_target_t	*sen_target;
91940d71d2Seschrock } ses_enum_node_t;
93940d71d2Seschrock typedef struct ses_enum_chassis {
94940d71d2Seschrock 	topo_list_t		sec_link;
9553dbcc59SSundeep Panicker 	topo_list_t		sec_subchassis;
96940d71d2Seschrock 	topo_list_t		sec_nodes;
97940d71d2Seschrock 	topo_list_t		sec_targets;
98940d71d2Seschrock 	const char		*sec_csn;
99940d71d2Seschrock 	ses_node_t		*sec_enclosure;
100940d71d2Seschrock 	ses_enum_target_t	*sec_target;
101940d71d2Seschrock 	topo_instance_t		sec_instance;
10253dbcc59SSundeep Panicker 	topo_instance_t		sec_scinstance;
103ac88567aSHyon Kim 	topo_instance_t		sec_maxinstance;
104940d71d2Seschrock 	boolean_t		sec_hasdev;
105d91236feSeschrock 	boolean_t		sec_internal;
106940d71d2Seschrock } ses_enum_chassis_t;
108940d71d2Seschrock typedef struct ses_enum_data {
109ac88567aSHyon Kim 	topo_list_t		sed_devs;
110940d71d2Seschrock 	topo_list_t		sed_chassis;
111940d71d2Seschrock 	ses_enum_chassis_t	*sed_current;
112940d71d2Seschrock 	ses_enum_target_t	*sed_target;
113940d71d2Seschrock 	int			sed_errno;
114940d71d2Seschrock 	char			*sed_name;
115940d71d2Seschrock 	topo_mod_t		*sed_mod;
116940d71d2Seschrock 	topo_instance_t		sed_instance;
117940d71d2Seschrock } ses_enum_data_t;
119ac88567aSHyon Kim typedef struct sas_connector_phy_data {
120ded93414SHyon Kim 	uint64_t    scpd_index;
121ded93414SHyon Kim 	uint64_t    scpd_pm;
122ac88567aSHyon Kim } sas_connector_phy_data_t;
123ac88567aSHyon Kim 
124ac88567aSHyon Kim typedef struct sas_connector_type {
125ded93414SHyon Kim 	uint64_t    sct_type;
126ded93414SHyon Kim 	char	    *sct_name;
127ac88567aSHyon Kim } sas_connector_type_t;
128ac88567aSHyon Kim 
129ac88567aSHyon Kim static const sas_connector_type_t sas_connector_type_list[] = {
130ac88567aSHyon Kim 	{   0x0, "Information unknown"  },
131ac88567aSHyon Kim 	{   0x1, "External SAS 4x receptacle (see SAS-2 and SFF-8470)"	},
132ac88567aSHyon Kim 	{   0x2, "Exteranl Mini SAS 4x receptacle (see SAS-2 and SFF-8088)" },
13347d6cd81SRobert Mustacchi 	{   0x3, "QSFP+ receptacle (see SAS-2.1 and SFF-8436)" },
13447d6cd81SRobert Mustacchi 	{   0x4, "Mini SAS 4x active receptacle (see SAS-2.1 and SFF-8088)" },
13547d6cd81SRobert Mustacchi 	{   0x5, "Mini SAS HD 4x receptacle (see SAS-2.1 and SFF-8644)" },
13647d6cd81SRobert Mustacchi 	{   0x6, "Mini SAS HD 8x receptacle (see SAS-2.1 and SFF-8644)" },
13747d6cd81SRobert Mustacchi 	{   0x7, "Mini SAS HD 16x receptacle (see SAS-2.1 and SFF-8644)" },
138ac88567aSHyon Kim 	{   0xF, "Vendor-specific external connector"	},
139ac88567aSHyon Kim 	{   0x10, "Internal wide SAS 4i plug (see SAS-2 and SFF-8484)"	},
140ac88567aSHyon Kim 	{   0x11,
141ac88567aSHyon Kim 	"Internal wide Mini SAS 4i receptacle (see SAS-2 and SFF-8087)"	},
14247d6cd81SRobert Mustacchi 	{   0x12, "Mini SAS HD 4i receptacle (see SAS-2.1 and SFF-8643)" },
14347d6cd81SRobert Mustacchi 	{   0x20, "Internal SAS Drive receptacle (see SAS-2 and SFF-8482)" },
14447d6cd81SRobert Mustacchi 	{   0x21, "Internal SATA host plug (see SAS-2 and SATA-2)"	},
145ac88567aSHyon Kim 	{   0x22, "Internal SAS Drive plug (see SAS-2 and SFF-8482)"	},
146ac88567aSHyon Kim 	{   0x23, "Internal SATA device plug (see SAS-2 and SATA-2)"	},
14747d6cd81SRobert Mustacchi 	{   0x24, "Micro SAS receptacle (see SAS-2.14)"	},
14847d6cd81SRobert Mustacchi 	{   0x25, "Micro SATA device plug (see SAS-2.1 and SATA)"	},
14947d6cd81SRobert Mustacchi 	{   0x26, "Micro SAS plug (see SAS-2.1 and SFF-8486)"	},
15047d6cd81SRobert Mustacchi 	{   0x27, "Micro SAS/SATA plug (see SAS-2.1 and SFF-8486)"	},
15147d6cd81SRobert Mustacchi 	{   0x28,
15247d6cd81SRobert Mustacchi 	"12 Gb/s SAS Drive backplane receptacle (see SAS-34 and SFF-8680)" },
15347d6cd81SRobert Mustacchi 	{   0x29, "12Gb/s SAS Drive Plug (see SAS-3 and SFF-8680)"	},
15447d6cd81SRobert Mustacchi 	{   0x2A, "Multifunction 12 Gb/s 6x Unshielded receptacle connector "
15547d6cd81SRobert Mustacchi 		"receptacle (see SAS-3 and SFF-8639)"	},
15647d6cd81SRobert Mustacchi 	{   0x2B, "Multifunction 12 Gb/s 6x Unshielded receptable connector "
15747d6cd81SRobert Mustacchi 		"plug (see SAS-3 and SFF-8639)"	},
158ac88567aSHyon Kim 	{   0x2F, "Internal SAS virtual connector"  },
159ac88567aSHyon Kim 	{   0x3F, "Vendor-specific internal connector"	},
160ac88567aSHyon Kim 	{   0x70, "Other Vendor-specific connector"	},
161ac88567aSHyon Kim 	{   0x71, "Other Vendor-specific connector"	},
162ac88567aSHyon Kim 	{   0x72, "Other Vendor-specific connector"	},
163ac88567aSHyon Kim 	{   0x73, "Other Vendor-specific connector"	},
164ac88567aSHyon Kim 	{   0x74, "Other Vendor-specific connector"	},
165ac88567aSHyon Kim 	{   0x75, "Other Vendor-specific connector"	},
166ac88567aSHyon Kim 	{   0x76, "Other Vendor-specific connector"	},
167ac88567aSHyon Kim 	{   0x77, "Other Vendor-specific connector"	},
168ac88567aSHyon Kim 	{   0x78, "Other Vendor-specific connector"	},
169ac88567aSHyon Kim 	{   0x79, "Other Vendor-specific connector"	},
170ac88567aSHyon Kim 	{   0x7A, "Other Vendor-specific connector"	},
171ac88567aSHyon Kim 	{   0x7B, "Other Vendor-specific connector"	},
172ac88567aSHyon Kim 	{   0x7C, "Other Vendor-specific connector"	},
173ac88567aSHyon Kim 	{   0x7D, "Other Vendor-specific connector"	},
174ac88567aSHyon Kim 	{   0x7E, "Other Vendor-specific connector"	},
175ac88567aSHyon Kim 	{   0x7F, "Other Vendor-specific connector"	},
176ac88567aSHyon Kim 	{   0x80, "Not Defined"	}
177ac88567aSHyon Kim };
178ac88567aSHyon Kim 
179ac88567aSHyon Kim #define	SAS_CONNECTOR_TYPE_CODE_NOT_DEFINED  0x80
180ac88567aSHyon Kim #define	SAS_CONNECTOR_TYPE_NOT_DEFINED \
18147d6cd81SRobert Mustacchi 	"Connector type not defined by SES-2 standard"
182ac88567aSHyon Kim #define	SAS_CONNECTOR_TYPE_RESERVED \
183ac88567aSHyon Kim 	"Connector type reserved by SES-2 standard"
184ac88567aSHyon Kim 
185ded93414SHyon Kim typedef struct phys_enum_type {
186ded93414SHyon Kim 	uint64_t    pet_type;
187ded93414SHyon Kim 	char	    *pet_nodename;
188ded93414SHyon Kim 	char	    *pet_defaultlabel;
189ded93414SHyon Kim 	boolean_t   pet_dorange;
190ded93414SHyon Kim } phys_enum_type_t;
191ded93414SHyon Kim 
192ded93414SHyon Kim static const phys_enum_type_t phys_enum_type_list[] = {
193ded93414SHyon Kim 	{   SES_ET_ARRAY_DEVICE, BAY, "BAY", B_TRUE  },
194ded93414SHyon Kim 	{   SES_ET_COOLING, FAN, "FAN", B_TRUE  },
195ded93414SHyon Kim 	{   SES_ET_DEVICE, BAY, "BAY", B_TRUE  },
197ded93414SHyon Kim 	{   SES_ET_POWER_SUPPLY, PSU, "PSU", B_TRUE  },
202ded93414SHyon Kim };
203ded93414SHyon Kim 
204ded93414SHyon Kim #define	N_PHYS_ENUM_TYPES (sizeof (phys_enum_type_list) / \
205ded93414SHyon Kim 	sizeof (phys_enum_type_list[0]))
206ded93414SHyon Kim 
207ded93414SHyon Kim /*
208ded93414SHyon Kim  * Structure for the hierarchical tree for element nodes.
209ded93414SHyon Kim  */
210ded93414SHyon Kim typedef struct ses_phys_tree {
211ded93414SHyon Kim     ses_node_t	*spt_snode;
212ded93414SHyon Kim     ses_enum_node_t	*spt_senumnode;
213ded93414SHyon Kim     boolean_t	spt_isfru;
214ded93414SHyon Kim     uint64_t	spt_eonlyindex;
215ded93414SHyon Kim     uint64_t	spt_cindex;
216ded93414SHyon Kim     uint64_t	spt_pindex;
217ded93414SHyon Kim     uint64_t	spt_maxinst;
218ded93414SHyon Kim     struct ses_phys_tree    *spt_parent;
219ded93414SHyon Kim     struct ses_phys_tree    *spt_child;
220ded93414SHyon Kim     struct ses_phys_tree    *spt_sibling;
221ded93414SHyon Kim     tnode_t	*spt_tnode;
222ded93414SHyon Kim } ses_phys_tree_t;
223ded93414SHyon Kim 
22453dbcc59SSundeep Panicker typedef enum {
22553dbcc59SSundeep Panicker 	SES_NEW_CHASSIS		= 0x1,
22653dbcc59SSundeep Panicker 	SES_NEW_SUBCHASSIS	= 0x2,
22753dbcc59SSundeep Panicker 	SES_DUP_CHASSIS		= 0x4,
22853dbcc59SSundeep Panicker 	SES_DUP_SUBCHASSIS	= 0x8
22953dbcc59SSundeep Panicker } ses_chassis_type_e;
23053dbcc59SSundeep Panicker 
231b4879163SHyon Kim static const topo_pgroup_info_t smp_pgroup = {
232b4879163SHyon Kim 	TOPO_PGROUP_SMP,
235ac88567aSHyon Kim 	1
236ac88567aSHyon Kim };
237ac88567aSHyon Kim 
238a961ec00SHyon Kim static const topo_pgroup_info_t ses_pgroup = {
239a961ec00SHyon Kim 	TOPO_PGROUP_SES,
242a961ec00SHyon Kim 	1
243a961ec00SHyon Kim };
244a961ec00SHyon Kim 
245940d71d2Seschrock static int ses_present(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
246940d71d2Seschrock     nvlist_t **);
247940d71d2Seschrock static int ses_contains(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
248940d71d2Seschrock     nvlist_t **);
250940d71d2Seschrock static const topo_method_t ses_component_methods[] = {
252940d71d2Seschrock 	    TOPO_METH_PRESENT_VERSION0, TOPO_STABILITY_INTERNAL, ses_present },
253d91236feSeschrock 	{ TOPO_METH_FAC_ENUM, TOPO_METH_FAC_ENUM_DESC, 0,
254d91236feSeschrock 	    TOPO_STABILITY_INTERNAL, ses_node_enum_facility },
25788045cffSRobert Johnston 	    topo_method_sensor_failure },
258d91236feSeschrock 	{ NULL }
259d91236feSeschrock };
261317c37f3SRob Johnston #define	TOPO_METH_SMCI_4U36_LABEL		"smci_4u36_bay_label"
262317c37f3SRob Johnston #define	TOPO_METH_SMCI_4U36_LABEL_DESC	\
263317c37f3SRob Johnston 	"compute bay labels on SMCI 4U36 storage platform variants"
264317c37f3SRob Johnston #define	TOPO_METH_SMCI_4U36_LABEL_VERSION	0
265317c37f3SRob Johnston static int smci_4u36_bay_label(topo_mod_t *, tnode_t *, topo_version_t,
266317c37f3SRob Johnston     nvlist_t *, nvlist_t **);
267317c37f3SRob Johnston 
268d91236feSeschrock static const topo_method_t ses_bay_methods[] = {
269d91236feSeschrock 	{ TOPO_METH_FAC_ENUM, TOPO_METH_FAC_ENUM_DESC, 0,
270d91236feSeschrock 	    TOPO_STABILITY_INTERNAL, ses_node_enum_facility },
2738abca89fSRob Johnston 	    topo_mod_hc_occupied },
274317c37f3SRob Johnston 	{ TOPO_METH_SMCI_4U36_LABEL, TOPO_METH_SMCI_4U36_LABEL_DESC,
276317c37f3SRob Johnston 	    smci_4u36_bay_label },
2778abca89fSRob Johnston 	{ NULL }
2788abca89fSRob Johnston };
2798abca89fSRob Johnston 
2808abca89fSRob Johnston static const topo_method_t ses_recep_methods[] = {
2838abca89fSRob Johnston 	    topo_mod_hc_occupied },
284940d71d2Seschrock 	{ NULL }
285940d71d2Seschrock };
287940d71d2Seschrock static const topo_method_t ses_enclosure_methods[] = {
289940d71d2Seschrock 	    TOPO_METH_CONTAINS_VERSION, TOPO_STABILITY_INTERNAL, ses_contains },
290d91236feSeschrock 	{ TOPO_METH_FAC_ENUM, TOPO_METH_FAC_ENUM_DESC, 0,
291d91236feSeschrock 	    TOPO_STABILITY_INTERNAL, ses_enc_enum_facility },
292940d71d2Seschrock 	{ NULL }
293940d71d2Seschrock };
295317c37f3SRob Johnston /*
296317c37f3SRob Johnston  * The bay_label_overrides table can be used to map a server product ID to a
297317c37f3SRob Johnston  * topo method that will be invoked to override the value of the label property
298317c37f3SRob Johnston  * for all bay nodes.  By default the property value is static, derived from
299317c37f3SRob Johnston  * the corresponding SES array device element's descriptor string.
300317c37f3SRob Johnston  */
301317c37f3SRob Johnston typedef struct ses_label_overrides {
302317c37f3SRob Johnston 	const char *slbl_product;
303317c37f3SRob Johnston 	const char *slbl_mname;
304317c37f3SRob Johnston } ses_label_overrides_t;
305317c37f3SRob Johnston 
306317c37f3SRob Johnston /*
307317c37f3SRob Johnston  * This table covers three generations of SMCI's 4U 36-bay storage server
308317c37f3SRob Johnston  * (and the Joyent-branded versions).  There was also an Ivy Bridge variant
309317c37f3SRob Johnston  * which has been omitted due to an inability to find one to test on.
310317c37f3SRob Johnston  */
311317c37f3SRob Johnston static const ses_label_overrides_t bay_label_overrides[] = {
312317c37f3SRob Johnston 	/* Sandy Bridge variant */
313317c37f3SRob Johnston 	{ "SSG-6047R-E1R36L", TOPO_METH_SMCI_4U36_LABEL },
314317c37f3SRob Johnston 	{ "Joyent-Storage-Platform-5001", TOPO_METH_SMCI_4U36_LABEL },
315317c37f3SRob Johnston 
316317c37f3SRob Johnston 	/* Broadwell variant */
317317c37f3SRob Johnston 	{ "SSG-6048R-E1CR36L", TOPO_METH_SMCI_4U36_LABEL },
318317c37f3SRob Johnston 	{ "Joyent-Storage-Platform-7001", TOPO_METH_SMCI_4U36_LABEL },
319317c37f3SRob Johnston 
320317c37f3SRob Johnston 	/* Skylake variant */
321317c37f3SRob Johnston 	{ "SSG-6049P-E1CR36L", TOPO_METH_SMCI_4U36_LABEL },
322317c37f3SRob Johnston 	{ "Joyent-S10G5", TOPO_METH_SMCI_4U36_LABEL }
323317c37f3SRob Johnston };
324317c37f3SRob Johnston 
325317c37f3SRob Johnston #define	N_BAY_LBL_OVERRIDES (sizeof (bay_label_overrides) / \
326317c37f3SRob Johnston 	sizeof (bay_label_overrides[0]))
327317c37f3SRob Johnston 
328f76de749SStephen Hanson /*
329f76de749SStephen Hanson  * Functions for tracking ses devices which we were unable to open. We retry
330f76de749SStephen Hanson  * these at regular intervals using ses_recheck_dir() and if we find that we
331f76de749SStephen Hanson  * can now open any of them then we send a sysevent to indicate that a new topo
332f76de749SStephen Hanson  * snapshot should be taken.
333f76de749SStephen Hanson  */
334f76de749SStephen Hanson typedef struct ses_open_fail_list {
335f76de749SStephen Hanson 	struct ses_open_fail_list	*sof_next;
336f76de749SStephen Hanson 	char				*sof_path;
337f76de749SStephen Hanson } ses_open_fail_list_t;
338f76de749SStephen Hanson 
339f76de749SStephen Hanson static ses_open_fail_list_t *ses_sofh;
340f76de749SStephen Hanson static pthread_mutex_t ses_sofmt;
34105b58617SStephen Hanson static void ses_ct_print(char *ptr);
342f76de749SStephen Hanson 
343f76de749SStephen Hanson static void
ses_recheck_dir()34405b58617SStephen Hanson ses_recheck_dir()
345f76de749SStephen Hanson {
346f76de749SStephen Hanson 	ses_target_t *target;
347f76de749SStephen Hanson 	sysevent_id_t eid;
34805b58617SStephen Hanson 	char buf[80];
349f76de749SStephen Hanson 	ses_open_fail_list_t *sof;
350f76de749SStephen Hanson 
351f76de749SStephen Hanson 	/*
352f76de749SStephen Hanson 	 * check list of "unable to open" devices
353f76de749SStephen Hanson 	 */
354f76de749SStephen Hanson 	(void) pthread_mutex_lock(&ses_sofmt);
355f76de749SStephen Hanson 	for (sof = ses_sofh; sof != NULL; sof = sof->sof_next) {
356f76de749SStephen Hanson 		/*
357f76de749SStephen Hanson 		 * see if we can open it now
358f76de749SStephen Hanson 		 */
359f76de749SStephen Hanson 		if ((target = ses_open(LIBSES_VERSION,
360f76de749SStephen Hanson 		    sof->sof_path)) == NULL) {
36105b58617SStephen Hanson 			(void) snprintf(buf, sizeof (buf),
362f76de749SStephen Hanson 			    "recheck_dir - still can't open %s", sof->sof_path);
36305b58617SStephen Hanson 			ses_ct_print(buf);
364f76de749SStephen Hanson 			continue;
365f76de749SStephen Hanson 		}
366f76de749SStephen Hanson 
367f76de749SStephen Hanson 		/*
368f76de749SStephen Hanson 		 * ok - better force a new snapshot
369f76de749SStephen Hanson 		 */
37005b58617SStephen Hanson 		(void) snprintf(buf, sizeof (buf),
371f76de749SStephen Hanson 		    "recheck_dir - can now open %s", sof->sof_path);
37205b58617SStephen Hanson 		ses_ct_print(buf);
373f76de749SStephen Hanson 		(void) sysevent_post_event(EC_PLATFORM, ESC_PLATFORM_SP_RESET,
374f76de749SStephen Hanson 		    SUNW_VENDOR, "fmd", NULL, &eid);
375f76de749SStephen Hanson 		ses_close(target);
376f76de749SStephen Hanson 		break;
377f76de749SStephen Hanson 	}
378f76de749SStephen Hanson 	(void) pthread_mutex_unlock(&ses_sofmt);
379f76de749SStephen Hanson }
380f76de749SStephen Hanson 
381f76de749SStephen Hanson static void
ses_sof_alloc(topo_mod_t * mod,char * path)382f76de749SStephen Hanson ses_sof_alloc(topo_mod_t *mod, char *path)
383f76de749SStephen Hanson {
384f76de749SStephen Hanson 	ses_open_fail_list_t *sof;
385f76de749SStephen Hanson 
386f76de749SStephen Hanson 	(void) pthread_mutex_lock(&ses_sofmt);
387f76de749SStephen Hanson 	sof = topo_mod_zalloc(mod, sizeof (*sof));
388f76de749SStephen Hanson 	topo_mod_dprintf(mod, "sof_alloc %s", path);
389f76de749SStephen Hanson 	sof->sof_path = path;
390f76de749SStephen Hanson 	sof->sof_next = ses_sofh;
391f76de749SStephen Hanson 	ses_sofh = sof;
392f76de749SStephen Hanson 	(void) pthread_mutex_unlock(&ses_sofmt);
393f76de749SStephen Hanson }
394f76de749SStephen Hanson 
395f76de749SStephen Hanson static void
ses_sof_freeall(topo_mod_t * mod)396f76de749SStephen Hanson ses_sof_freeall(topo_mod_t *mod)
397f76de749SStephen Hanson {
398f76de749SStephen Hanson 	ses_open_fail_list_t *sof, *next_sof;
399f76de749SStephen Hanson 
400f76de749SStephen Hanson 	(void) pthread_mutex_lock(&ses_sofmt);
401f76de749SStephen Hanson 	for (sof = ses_sofh; sof != NULL; sof = next_sof) {
402f76de749SStephen Hanson 		next_sof = sof->sof_next;
403f76de749SStephen Hanson 		topo_mod_dprintf(mod, "sof_freeall %s", sof->sof_path);
404f76de749SStephen Hanson 		topo_mod_strfree(mod, sof->sof_path);
405f76de749SStephen Hanson 		topo_mod_free(mod, sof, sizeof (*sof));
406f76de749SStephen Hanson 	}
407f76de749SStephen Hanson 	ses_sofh = NULL;
408f76de749SStephen Hanson 	(void) pthread_mutex_unlock(&ses_sofmt);
409f76de749SStephen Hanson }
410f76de749SStephen Hanson 
411f76de749SStephen Hanson /*
412f76de749SStephen Hanson  * functions for verifying that the ses_enum_target_t held in a device
413f76de749SStephen Hanson  * contract's cookie field is still valid (it may have been freed by
414f76de749SStephen Hanson  * ses_release()).
415f76de749SStephen Hanson  */
416f76de749SStephen Hanson typedef struct ses_stp_list {
417f76de749SStephen Hanson 	struct ses_stp_list	*ssl_next;
418f76de749SStephen Hanson 	ses_enum_target_t	*ssl_tgt;
419f76de749SStephen Hanson } ses_stp_list_t;
420f76de749SStephen Hanson 
421f76de749SStephen Hanson static ses_stp_list_t *ses_sslh;
422f76de749SStephen Hanson static pthread_mutex_t ses_sslmt;
423f76de749SStephen Hanson 
424f76de749SStephen Hanson static void
ses_ssl_alloc(topo_mod_t * mod,ses_enum_target_t * stp)425f76de749SStephen Hanson ses_ssl_alloc(topo_mod_t *mod, ses_enum_target_t *stp)
426f76de749SStephen Hanson {
427f76de749SStephen Hanson 	ses_stp_list_t *ssl;
428f76de749SStephen Hanson 
429f76de749SStephen Hanson 	(void) pthread_mutex_lock(&ses_sslmt);
430f76de749SStephen Hanson 	ssl = topo_mod_zalloc(mod, sizeof (*ssl));
431f76de749SStephen Hanson 	topo_mod_dprintf(mod, "ssl_alloc %p", stp);
432f76de749SStephen Hanson 	ssl->ssl_tgt = stp;
433f76de749SStephen Hanson 	ssl->ssl_next = ses_sslh;
434f76de749SStephen Hanson 	ses_sslh = ssl;
435f76de749SStephen Hanson 	(void) pthread_mutex_unlock(&ses_sslmt);
436f76de749SStephen Hanson }
437f76de749SStephen Hanson 
438f76de749SStephen Hanson static void
ses_ssl_free(topo_mod_t * mod,ses_enum_target_t * stp)439f76de749SStephen Hanson ses_ssl_free(topo_mod_t *mod, ses_enum_target_t *stp)
440f76de749SStephen Hanson {
441f76de749SStephen Hanson 	ses_stp_list_t *ssl, *prev_ssl;
442f76de749SStephen Hanson 
443f76de749SStephen Hanson 	(void) pthread_mutex_lock(&ses_sslmt);
444f76de749SStephen Hanson 	prev_ssl = NULL;
445f76de749SStephen Hanson 	for (ssl = ses_sslh; ssl != NULL; ssl = ssl->ssl_next) {
446f76de749SStephen Hanson 		if (ssl->ssl_tgt == stp) {
447f76de749SStephen Hanson 			topo_mod_dprintf(mod, "ssl_free %p", ssl->ssl_tgt);
448f76de749SStephen Hanson 			if (prev_ssl == NULL)
449f76de749SStephen Hanson 				ses_sslh = ssl->ssl_next;
450f76de749SStephen Hanson 			else
451f76de749SStephen Hanson 				prev_ssl->ssl_next = ssl->ssl_next;
452f76de749SStephen Hanson 			topo_mod_free(mod, ssl, sizeof (*ssl));
453f76de749SStephen Hanson 			break;
454f76de749SStephen Hanson 		}
455f76de749SStephen Hanson 		prev_ssl = ssl;
456f76de749SStephen Hanson 	}
457f76de749SStephen Hanson 	(void) pthread_mutex_unlock(&ses_sslmt);
458f76de749SStephen Hanson }
459f76de749SStephen Hanson 
460f76de749SStephen Hanson static int
ses_ssl_valid(ses_enum_target_t * stp)461f76de749SStephen Hanson ses_ssl_valid(ses_enum_target_t *stp)
462f76de749SStephen Hanson {
463f76de749SStephen Hanson 	ses_stp_list_t *ssl;
464f76de749SStephen Hanson 
465f76de749SStephen Hanson 	for (ssl = ses_sslh; ssl != NULL; ssl = ssl->ssl_next)
466f76de749SStephen Hanson 		if (ssl->ssl_tgt == stp)
467f76de749SStephen Hanson 			return (1);
468f76de749SStephen Hanson 	return (0);
469f76de749SStephen Hanson }
470f76de749SStephen Hanson 
471f76de749SStephen Hanson /*
472f76de749SStephen Hanson  * Functions for creating and destroying a background thread
473f76de749SStephen Hanson  * (ses_contract_thread) used for detecting when ses devices have been
474f76de749SStephen Hanson  * retired/unretired.
475f76de749SStephen Hanson  */
476f76de749SStephen Hanson static struct ses_thread_s {
477f76de749SStephen Hanson 	pthread_mutex_t mt;
478f76de749SStephen Hanson 	pthread_t tid;
479f76de749SStephen Hanson 	int thr_sig;
480f76de749SStephen Hanson 	int doexit;
481f76de749SStephen Hanson 	int count;
482f76de749SStephen Hanson } sesthread = {
483f76de749SStephen Hanson 	PTHREAD_MUTEX_INITIALIZER,
484f76de749SStephen Hanson 	0,
485f76de749SStephen Hanson 	SIGTERM,
486f76de749SStephen Hanson 	0,
487f76de749SStephen Hanson 	0
488f76de749SStephen Hanson };
489f76de749SStephen Hanson 
49005b58617SStephen Hanson typedef struct ses_mod_list {
49105b58617SStephen Hanson 	struct ses_mod_list	*smod_next;
49205b58617SStephen Hanson 	topo_mod_t		*smod_mod;
49305b58617SStephen Hanson } ses_mod_list_t;
49405b58617SStephen Hanson 
49505b58617SStephen Hanson static ses_mod_list_t *ses_smod;
49605b58617SStephen Hanson 
49705b58617SStephen Hanson static void
ses_ct_print(char * ptr)49805b58617SStephen Hanson ses_ct_print(char *ptr)
49905b58617SStephen Hanson {
50005b58617SStephen Hanson 	(void) pthread_mutex_lock(&sesthread.mt);
5012eb07f5eSStephen Hanson 	if (ses_smod != NULL && ses_smod->smod_mod != NULL)
50205b58617SStephen Hanson 		topo_mod_dprintf(ses_smod->smod_mod, ptr);
50305b58617SStephen Hanson 	(void) pthread_mutex_unlock(&sesthread.mt);
50405b58617SStephen Hanson }
50505b58617SStephen Hanson 
50605b58617SStephen Hanson /*ARGSUSED*/
507f76de749SStephen Hanson static void *
ses_contract_thread(void * arg)508f76de749SStephen Hanson ses_contract_thread(void *arg)
509f76de749SStephen Hanson {
510f76de749SStephen Hanson 	int efd, ctlfd, statfd;
511f76de749SStephen Hanson 	ct_evthdl_t ev;
512f76de749SStephen Hanson 	ctevid_t evid;
513f76de749SStephen Hanson 	uint_t event;
514f76de749SStephen Hanson 	char path[PATH_MAX];
51505b58617SStephen Hanson 	char buf[80];
516f76de749SStephen Hanson 	ses_enum_target_t *stp;
517f76de749SStephen Hanson 	ct_stathdl_t stathdl;
518f76de749SStephen Hanson 	ctid_t ctid;
519f76de749SStephen Hanson 	struct pollfd fds;
520f76de749SStephen Hanson 	int pollret;
521057c620aSHans Rosenfeld 	sigset_t sigset;
522f76de749SStephen Hanson 
52305b58617SStephen Hanson 	ses_ct_print("start contract event thread");
524f76de749SStephen Hanson 	efd = open64(CTFS_ROOT "/device/pbundle", O_RDONLY);
525f76de749SStephen Hanson 	fds.fd = efd;
526f76de749SStephen Hanson 	fds.events = POLLIN;
527f76de749SStephen Hanson 	fds.revents = 0;
5288e4148b0SJohn Levon 	(void) sigaddset(&sigset, sesthread.thr_sig);
5298e4148b0SJohn Levon 	(void) pthread_sigmask(SIG_UNBLOCK, &sigset, NULL);
530f76de749SStephen Hanson 	for (;;) {
531f76de749SStephen Hanson 		/* check if we've been asked to exit */
532f76de749SStephen Hanson 		(void) pthread_mutex_lock(&sesthread.mt);
533f76de749SStephen Hanson 		if (sesthread.doexit) {
534f76de749SStephen Hanson 			(void) pthread_mutex_unlock(&sesthread.mt);
535f76de749SStephen Hanson 			break;
536f76de749SStephen Hanson 		}
537f76de749SStephen Hanson 		(void) pthread_mutex_unlock(&sesthread.mt);
538f76de749SStephen Hanson 
539f76de749SStephen Hanson 		/* poll until an event arrives */
540f76de749SStephen Hanson 		if ((pollret = poll(&fds, 1, 10000)) <= 0) {
541f76de749SStephen Hanson 			if (pollret == 0)
54205b58617SStephen Hanson 				ses_recheck_dir();
543f76de749SStephen Hanson 			continue;
544f76de749SStephen Hanson 		}
545f76de749SStephen Hanson 
546f76de749SStephen Hanson 		/* read the event */
547f76de749SStephen Hanson 		(void) pthread_mutex_lock(&ses_sslmt);
54805b58617SStephen Hanson 		ses_ct_print("read contract event");
549f76de749SStephen Hanson 		if (ct_event_read(efd, &ev) != 0) {
550f76de749SStephen Hanson 			(void) pthread_mutex_unlock(&ses_sslmt);
551f76de749SStephen Hanson 			continue;
552f76de749SStephen Hanson 		}
553f76de749SStephen Hanson 
554f76de749SStephen Hanson 		/* see if it is an event we are expecting */
555f76de749SStephen Hanson 		ctid = ct_event_get_ctid(ev);
55605b58617SStephen Hanson 		(void) snprintf(buf, sizeof (buf),
55705b58617SStephen Hanson 		    "got contract event ctid=%d", ctid);
55805b58617SStephen Hanson 		ses_ct_print(buf);
559f76de749SStephen Hanson 		event = ct_event_get_type(ev);
560f76de749SStephen Hanson 		if (event != CT_DEV_EV_OFFLINE && event != CT_EV_NEGEND) {
561edb433b6SMilan Jurik 			(void) snprintf(buf, sizeof (buf),
56205b58617SStephen Hanson 			    "bad contract event %x", event);
56305b58617SStephen Hanson 			ses_ct_print(buf);
564f76de749SStephen Hanson 			ct_event_free(ev);
565f76de749SStephen Hanson 			(void) pthread_mutex_unlock(&ses_sslmt);
566f76de749SStephen Hanson 			continue;
567f76de749SStephen Hanson 		}
568f76de749SStephen Hanson 
569f76de749SStephen Hanson 		/* find target pointer saved in cookie */
570f76de749SStephen Hanson 		evid = ct_event_get_evid(ev);
571f76de749SStephen Hanson 		(void) snprintf(path, PATH_MAX, CTFS_ROOT "/device/%ld/status",
572f76de749SStephen Hanson 		    ctid);
573f76de749SStephen Hanson 		statfd = open64(path, O_RDONLY);
574edb433b6SMilan Jurik 		(void) ct_status_read(statfd, CTD_COMMON, &stathdl);
575f76de749SStephen Hanson 		stp = (ses_enum_target_t *)(uintptr_t)
576f76de749SStephen Hanson 		    ct_status_get_cookie(stathdl);
577f76de749SStephen Hanson 		ct_status_free(stathdl);
578edb433b6SMilan Jurik 		(void) close(statfd);
579f76de749SStephen Hanson 
580f76de749SStephen Hanson 		/* check if target pointer is still valid */
581f76de749SStephen Hanson 		if (ses_ssl_valid(stp) == 0) {
582edb433b6SMilan Jurik 			(void) snprintf(buf, sizeof (buf),
58305b58617SStephen Hanson 			    "contract already abandoned %x", event);
58405b58617SStephen Hanson 			ses_ct_print(buf);
585f76de749SStephen Hanson 			(void) snprintf(path, PATH_MAX,
586f76de749SStephen Hanson 			    CTFS_ROOT "/device/%ld/ctl", ctid);
587f76de749SStephen Hanson 			ctlfd = open64(path, O_WRONLY);
588f76de749SStephen Hanson 			if (event != CT_EV_NEGEND)
589edb433b6SMilan Jurik 				(void) ct_ctl_ack(ctlfd, evid);
590f76de749SStephen Hanson 			else
591edb433b6SMilan Jurik 				(void) ct_ctl_abandon(ctlfd);
592edb433b6SMilan Jurik 			(void) close(ctlfd);
593f76de749SStephen Hanson 			ct_event_free(ev);
594f76de749SStephen Hanson 			(void) pthread_mutex_unlock(&ses_sslmt);
595f76de749SStephen Hanson 			continue;
596f76de749SStephen Hanson 		}
597f76de749SStephen Hanson 
598f76de749SStephen Hanson 		/* find control device for ack/abandon */
599f76de749SStephen Hanson 		(void) pthread_mutex_lock(&stp->set_lock);
600f76de749SStephen Hanson 		(void) snprintf(path, PATH_MAX, CTFS_ROOT "/device/%ld/ctl",
601f76de749SStephen Hanson 		    ctid);
602f76de749SStephen Hanson 		ctlfd = open64(path, O_WRONLY);
603f76de749SStephen Hanson 		if (event != CT_EV_NEGEND) {
604f76de749SStephen Hanson 			/* if this is an offline event, do the offline */
60505b58617SStephen Hanson 			ses_ct_print("got contract offline event");
606f76de749SStephen Hanson 			if (stp->set_target) {
60705b58617SStephen Hanson 				ses_ct_print("contract thread rele");
608f76de749SStephen Hanson 				ses_snap_rele(stp->set_snap);
609f76de749SStephen Hanson 				ses_close(stp->set_target);
610f76de749SStephen Hanson 				stp->set_target = NULL;
611f76de749SStephen Hanson 			}
612edb433b6SMilan Jurik 			(void) ct_ctl_ack(ctlfd, evid);
613f76de749SStephen Hanson 		} else {
614f76de749SStephen Hanson 			/* if this is the negend, then abandon the contract */
61505b58617SStephen Hanson 			ses_ct_print("got contract negend");
616f76de749SStephen Hanson 			if (stp->set_ctid) {
617ad8ef92aSMilan Jurik 				(void) snprintf(buf, sizeof (buf),
61805b58617SStephen Hanson 				    "abandon old contract %d", stp->set_ctid);
61905b58617SStephen Hanson 				ses_ct_print(buf);
6205cc5d5ceSToomas Soome 				stp->set_ctid = 0;
621f76de749SStephen Hanson 			}
622edb433b6SMilan Jurik 			(void) ct_ctl_abandon(ctlfd);
623f76de749SStephen Hanson 		}
624ad8ef92aSMilan Jurik 		(void) close(ctlfd);
625f76de749SStephen Hanson 		(void) pthread_mutex_unlock(&stp->set_lock);
626f76de749SStephen Hanson 		ct_event_free(ev);
627f76de749SStephen Hanson 		(void) pthread_mutex_unlock(&ses_sslmt);
628f76de749SStephen Hanson 	}
629ad8ef92aSMilan Jurik 	(void) close(efd);
630f76de749SStephen Hanson 	return (NULL);
631f76de749SStephen Hanson }
632f76de749SStephen Hanson 
633f76de749SStephen Hanson int
find_thr_sig(void)634f76de749SStephen Hanson find_thr_sig(void)
635f76de749SStephen Hanson {
636f76de749SStephen Hanson 	int i;
637f76de749SStephen Hanson 	sigset_t oset, rset;
638f76de749SStephen Hanson 	int sig[] = {SIGTERM, SIGUSR1, SIGUSR2};
639f76de749SStephen Hanson 	int sig_sz = sizeof (sig) / sizeof (int);
640f76de749SStephen Hanson 	int rc = SIGTERM;
641f76de749SStephen Hanson 
642f76de749SStephen Hanson 	/* prefered set of signals that are likely used to terminate threads */
643f76de749SStephen Hanson 	(void) sigemptyset(&oset);
644f76de749SStephen Hanson 	(void) pthread_sigmask(SIG_SETMASK, NULL, &oset);
645f76de749SStephen Hanson 	for (i = 0; i < sig_sz; i++) {
646f76de749SStephen Hanson 		if (sigismember(&oset, sig[i]) == 0) {
647f76de749SStephen Hanson 			return (sig[i]);
648f76de749SStephen Hanson 		}
649f76de749SStephen Hanson 	}
650f76de749SStephen Hanson 
651f76de749SStephen Hanson 	/* reserved set of signals that are not allowed to terminate thread */
652f76de749SStephen Hanson 	(void) sigemptyset(&rset);
653f76de749SStephen Hanson 	(void) sigaddset(&rset, SIGABRT);
654f76de749SStephen Hanson 	(void) sigaddset(&rset, SIGKILL);
655f76de749SStephen Hanson 	(void) sigaddset(&rset, SIGSTOP);
656f76de749SStephen Hanson 	(void) sigaddset(&rset, SIGCANCEL);
657f76de749SStephen Hanson 
658f76de749SStephen Hanson 	/* Find signal that is not masked and not in the reserved list. */