1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  *
  26  * Copyright 2019 Peter Tribble.
  27  */
  28 
  29 /*
  30  * The MDESC picl plugin serves 2 different functionalities.
  31  * --The first is to look up certain CPU properties in the MDESC an to add
  32  * these properties in the already created CPU PICL nodes in the /platform
  33  * section of the tree.
  34  * --The second functionality is to create a /disk_discovery section of the
  35  * PICL tree which will have a disk node created for each disk node in the
  36  * machine description.
  37  */
  38 
  39 #include "mdescplugin.h"
  40 #include <libnvpair.h>
  41 
  42 #pragma init(mdescplugin_register)      /* place in .init section */
  43 
  44 picl_nodehdl_t  root_node;
  45 md_t            *mdp;
  46 mde_cookie_t    rootnode;
  47 
  48 void mdescplugin_init(void);
  49 void mdescplugin_fini(void);
  50 static void signal_devtree(void);
  51 
  52 extern int add_cpu_prop(picl_nodehdl_t node, void *args);
  53 extern int disk_discovery(void);
  54 extern md_t *mdesc_devinit(void);
  55 extern void mdesc_devfini(md_t *mdp);
  56 extern int update_devices(char *dev, int op);
  57 
  58 picld_plugin_reg_t mdescplugin_reg = {
  59         PICLD_PLUGIN_VERSION_1,
  60         PICLD_PLUGIN_CRITICAL,
  61         "mdesc_plugin",
  62         mdescplugin_init,
  63         mdescplugin_fini
  64 };
  65 
  66 #define DISK_FOUND 0x00
  67 #define DISK_NOT_FOUND 0x01
  68 
  69 typedef struct disk_lookup {
  70         char *path;
  71         picl_nodehdl_t disk;
  72         int result;
  73 } disk_lookup_t;
  74 
  75 int
  76 find_disk(picl_nodehdl_t node, void *args)
  77 {
  78         disk_lookup_t *lookup  = (disk_lookup_t *)args;
  79         int status;
  80         char path[PICL_PROPNAMELEN_MAX];
  81 
  82         status = ptree_get_propval_by_name(node, "Path", (void *)&path,
  83             PICL_PROPNAMELEN_MAX);
  84         if (status != PICL_SUCCESS) {
  85                 return (PICL_WALK_CONTINUE);
  86         }
  87 
  88         if (strcmp(path, lookup->path) == 0) {
  89                 lookup->disk = node;
  90                 lookup->result = DISK_FOUND;
  91                 return (PICL_WALK_TERMINATE);
  92         }
  93 
  94         return (PICL_WALK_CONTINUE);
  95 }
  96 
  97 /*
  98  * DR event handler
  99  * respond to the picl events:
 100  *      PICLEVENT_DR_AP_STATE_CHANGE
 101  */
 102 static void
 103 dr_handler(const char *ename, const void *earg, size_t size, void *cookie)
 104 {
 105         nvlist_t        *nvlp = NULL;
 106         char            *dtype;
 107         char            *ap_id;
 108         char            *hint;
 109 
 110 
 111         if (strcmp(ename, PICLEVENT_DR_AP_STATE_CHANGE) != 0) {
 112                 return;
 113         }
 114 
 115         if (nvlist_unpack((char *)earg, size, &nvlp, NULL)) {
 116                 return;
 117         }
 118 
 119         if (nvlist_lookup_string(nvlp, PICLEVENTARG_DATA_TYPE, &dtype)) {
 120                 nvlist_free(nvlp);
 121                 return;
 122         }
 123 
 124         if (strcmp(dtype, PICLEVENTARG_PICLEVENT_DATA) != 0) {
 125                 nvlist_free(nvlp);
 126                 return;
 127         }
 128 
 129         if (nvlist_lookup_string(nvlp, PICLEVENTARG_AP_ID, &ap_id)) {
 130                 nvlist_free(nvlp);
 131                 return;
 132         }
 133 
 134         if (nvlist_lookup_string(nvlp, PICLEVENTARG_HINT, &hint)) {
 135                 nvlist_free(nvlp);
 136                 return;
 137         }
 138 
 139         mdp = mdesc_devinit();
 140         if (mdp == NULL) {
 141                 nvlist_free(nvlp);
 142                 return;
 143         }
 144 
 145         rootnode = md_root_node(mdp);
 146 
 147         if (strcmp(hint, DR_HINT_INSERT) == 0)
 148                 (void) update_devices(ap_id, DEV_ADD);
 149         else if (strcmp(hint, DR_HINT_REMOVE) == 0)
 150                 (void) update_devices(ap_id, DEV_REMOVE);
 151 
 152         mdesc_devfini(mdp);
 153         nvlist_free(nvlp);
 154 
 155         /*
 156          * Signal the devtree plugin to add more cpu properties.
 157          */
 158         signal_devtree();
 159 }
 160 
 161 /*
 162  * Discovery event handler
 163  * respond to the picl events:
 164  *      PICLEVENT_SYSEVENT_DEVICE_ADDED
 165  *      PICLEVENT_SYSEVENT_DEVICE_REMOVED
 166  */
 167 static void
 168 dsc_handler(const char *ename, const void *earg, size_t size, void *cookie)
 169 {
 170         nvlist_t        *nvlp = NULL;
 171         char            *path;
 172         disk_lookup_t   lookup;
 173         int             status;
 174 
 175         /*
 176          * retrieve the device's physical path from the event arg
 177          * and determine which disk (if any) we are working with
 178          */
 179         if (nvlist_unpack((char *)earg, size, &nvlp, NULL))
 180                 return;
 181         if (nvlist_lookup_string(nvlp, "devfs-path", &path))
 182                 return;
 183 
 184         lookup.path = strdup(path);
 185         lookup.disk = NULL;
 186         lookup.result = DISK_NOT_FOUND;
 187 
 188         status = ptree_walk_tree_by_class(root_node, "disk", (void *)&lookup,
 189             find_disk);
 190         if (status != PICL_SUCCESS) {
 191                 return;
 192         }
 193 
 194         if (lookup.result == DISK_FOUND) {
 195                 if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_ADDED) == 0)
 196                         ptree_update_propval_by_name(lookup.disk, "State",
 197                             (void *)strdup(CONFIGURED), PICL_PROPNAMELEN_MAX);
 198                 else if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_REMOVED) == 0)
 199                         ptree_update_propval_by_name(lookup.disk, "State",
 200                             (void *)strdup(UNCONFIGURED), PICL_PROPNAMELEN_MAX);
 201         }
 202 
 203         nvlist_free(nvlp);
 204 }
 205 
 206 /*ARGSUSED*/
 207 static void
 208 mdesc_ev_completion_handler(char *ename, void *earg, size_t size)
 209 {
 210         free(earg);
 211 }
 212 
 213 static void
 214 signal_devtree(void)
 215 {
 216         nvlist_t *nvl;
 217         char *packed_nvl;
 218         size_t nvl_size;
 219         int status;
 220 
 221         if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, NULL) != 0)
 222                 return;
 223 
 224         /*
 225          * This event is consumed by the devtree
 226          * plug-in.  The event signals the plug-in to re-run its
 227          * cpu initialization function, which will cause it to add
 228          * additional information to the cpu devtree nodes (particularly,
 229          * the administrative state of the cpus.)
 230          */
 231         if (nvlist_add_string(nvl, PICLEVENTARG_EVENT_NAME,
 232             PICLEVENT_CPU_STATE_CHANGE) != 0) {
 233                 free(nvl);
 234                 return;
 235         }
 236 
 237         /*
 238          * The devtree plug-in needs to see a devfs path argument for
 239          * any event it considers.  We supply one here which is essentially
 240          * a dummy since it is not processed by the devtree plug-in for
 241          * this event.
 242          */
 243         if (nvlist_add_string(nvl, PICLEVENTARG_DEVFS_PATH, "/cpu") != 0) {
 244                 free(nvl);
 245                 return;
 246         }
 247         packed_nvl = NULL;
 248         if (nvlist_pack(nvl, &packed_nvl, &nvl_size, NV_ENCODE_NATIVE,
 249             0) != 0) {
 250                 free(nvl);
 251                 return;
 252         }
 253         if ((status = ptree_post_event(PICLEVENT_CPU_STATE_CHANGE,
 254             packed_nvl, nvl_size, mdesc_ev_completion_handler)) !=
 255             PICL_SUCCESS) {
 256                 free(nvl);
 257                 syslog(LOG_WARNING,
 258                     "signal_devtree: can't post cpu event: %d\n", status);
 259         }
 260 }
 261 
 262 void
 263 mdescplugin_init(void)
 264 {
 265         int             status;
 266 
 267         status = ptree_get_root(&root_node);
 268         if (status != PICL_SUCCESS) {
 269                 return;
 270         }
 271 
 272         mdp = mdesc_devinit();
 273         if (mdp == NULL)
 274                 return;
 275 
 276         /*
 277          * update the cpu configuration in case the snapshot cache used by the
 278          * devtree plugin is out of date.
 279          */
 280         (void) update_devices(OBP_CPU, DEV_ADD);
 281         (void) update_devices(OBP_CPU, DEV_REMOVE);
 282 
 283         rootnode = md_root_node(mdp);
 284 
 285         /*
 286          * This is the start of the CPU property augmentation code.
 287          * add_cpu_prop and the rest of the CPU code lives in cpu_prop_update.c
 288          */
 289         status = ptree_walk_tree_by_class(root_node, "cpu", NULL, add_cpu_prop);
 290         if (status != PICL_SUCCESS) {
 291                 return;
 292         }
 293 
 294         signal_devtree();
 295 
 296         (void) disk_discovery();
 297 
 298         /*
 299          * register dsc_handler for both "sysevent-device-added" and
 300          * and for "sysevent-device-removed" PICL events
 301          */
 302         (void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED,
 303             dsc_handler, NULL);
 304         (void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED,
 305             dsc_handler, NULL);
 306         (void) ptree_register_handler(PICLEVENT_DR_AP_STATE_CHANGE,
 307             dr_handler, NULL);
 308 
 309         mdesc_devfini(mdp);
 310 }
 311 
 312 void
 313 mdescplugin_fini(void)
 314 {
 315         /* unregister the event handler */
 316         (void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED,
 317             dsc_handler, NULL);
 318         (void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED,
 319             dsc_handler, NULL);
 320         (void) ptree_unregister_handler(PICLEVENT_DR_AP_STATE_CHANGE,
 321             dr_handler, NULL);
 322 }
 323 
 324 void
 325 mdescplugin_register(void)
 326 {
 327         picld_plugin_register(&mdescplugin_reg);
 328 }