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 */ 21940d71d2Seschrock 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 */ 28940d71d2Seschrock 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> 53d91236feSeschrock 54940d71d2Seschrock #include "disk.h" 55d91236feSeschrock #include "ses.h" 56940d71d2Seschrock 57940d71d2Seschrock #define SES_VERSION 1 58940d71d2Seschrock 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 */ 63940d71d2Seschrock 64d91236feSeschrock #define SES_STATUS_UNAVAIL(s) \ 650b32bb8bSEric Schrock ((s) == SES_ESC_UNSUPPORTED || (s) >= SES_ESC_NOT_INSTALLED) 66940d71d2Seschrock 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; 83940d71d2Seschrock 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; 92940d71d2Seschrock 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; 107940d71d2Seschrock 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; 118940d71d2Seschrock 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 }, 196ded93414SHyon Kim { SES_ET_ESC_ELECTRONICS, CONTROLLER, "CONTROLLER", B_TRUE }, 197ded93414SHyon Kim { SES_ET_POWER_SUPPLY, PSU, "PSU", B_TRUE }, 198ded93414SHyon Kim { SES_ET_SUNW_FANBOARD, FANBOARD, "FANBOARD", B_TRUE }, 199ded93414SHyon Kim { SES_ET_SUNW_FANMODULE, FANMODULE, "FANMODULE", B_TRUE }, 200ded93414SHyon Kim { SES_ET_SUNW_POWERBOARD, POWERBOARD, "POWERBOARD", B_TRUE }, 201ded93414SHyon Kim { SES_ET_SUNW_POWERMODULE, POWERMODULE, "POWERMODULE", 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, 233ac88567aSHyon Kim TOPO_STABILITY_PRIVATE, 234ac88567aSHyon Kim TOPO_STABILITY_PRIVATE, 235ac88567aSHyon Kim 1 236ac88567aSHyon Kim }; 237ac88567aSHyon Kim 238a961ec00SHyon Kim static const topo_pgroup_info_t ses_pgroup = { 239a961ec00SHyon Kim TOPO_PGROUP_SES, 240a961ec00SHyon Kim TOPO_STABILITY_PRIVATE, 241a961ec00SHyon Kim TOPO_STABILITY_PRIVATE, 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 **); 249940d71d2Seschrock 250940d71d2Seschrock static const topo_method_t ses_component_methods[] = { 251940d71d2Seschrock { TOPO_METH_PRESENT, TOPO_METH_PRESENT_DESC, 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 }, 25588045cffSRobert Johnston { TOPO_METH_SENSOR_FAILURE, TOPO_METH_SENSOR_FAILURE_DESC, 25688045cffSRobert Johnston TOPO_METH_SENSOR_FAILURE_VERSION, TOPO_STABILITY_INTERNAL, 25788045cffSRobert Johnston topo_method_sensor_failure }, 258d91236feSeschrock { NULL } 259d91236feSeschrock }; 260d91236feSeschrock 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 }, 2718abca89fSRob Johnston { TOPO_METH_OCCUPIED, TOPO_METH_OCCUPIED_DESC, 2728abca89fSRob Johnston TOPO_METH_OCCUPIED_VERSION, TOPO_STABILITY_INTERNAL, 2738abca89fSRob Johnston topo_mod_hc_occupied }, 274317c37f3SRob Johnston { TOPO_METH_SMCI_4U36_LABEL, TOPO_METH_SMCI_4U36_LABEL_DESC, 275317c37f3SRob Johnston TOPO_METH_SMCI_4U36_LABEL_VERSION, TOPO_STABILITY_INTERNAL, 276317c37f3SRob Johnston smci_4u36_bay_label }, 2778abca89fSRob Johnston { NULL } 2788abca89fSRob Johnston }; 2798abca89fSRob Johnston 2808abca89fSRob Johnston static const topo_method_t ses_recep_methods[] = { 2818abca89fSRob Johnston { TOPO_METH_OCCUPIED, TOPO_METH_OCCUPIED_DESC, 2828abca89fSRob Johnston TOPO_METH_OCCUPIED_VERSION, TOPO_STABILITY_INTERNAL, 2838abca89fSRob Johnston topo_mod_hc_occupied }, 284940d71d2Seschrock { NULL } 285940d71d2Seschrock }; 286940d71d2Seschrock 287940d71d2Seschrock static const topo_method_t ses_enclosure_methods[] = { 288940d71d2Seschrock { TOPO_METH_CONTAINS, TOPO_METH_CONTAINS_DESC, 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 }; 294940d71d2Seschrock 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 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 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 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 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 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 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 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 * 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 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. */ 659f76de749SStephen Hanson for (i = 1; i < MAXSIG; i++) { 660f76de749SStephen Hanson if (sigismember(&rset, i) == 1) { 661