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