/* * Get a list of nodes of the specified classname under nodeh * Once a node of the specified class is found, it's children are not * searched. */ static node_list_t * get_node_list_by_class(picl_nodehdl_t nodeh, const char *classname, node_list_t *listp) { int err; char clname[PICL_CLASSNAMELEN_MAX+1]; picl_nodehdl_t chdh; /* * go through the children */ err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, &chdh, sizeof (picl_nodehdl_t)); while (err == PICL_SUCCESS) { err = ptree_get_propval_by_name(chdh, PICL_PROP_CLASSNAME, clname, strlen(classname) + 1); if ((err == PICL_SUCCESS) && (strcmp(clname, classname) == 0)) listp = add_node_to_list(chdh, listp); else listp = get_node_list_by_class(chdh, classname, listp); err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh, sizeof (picl_nodehdl_t)); } return (listp); }
/* * checks if a fru is present under location using pdev-path and busaddr */ boolean_t is_fru_present_under_location(frutree_locnode_t *locp) { di_node_t rnode; frutree_devinfo_t *devinfo = NULL; char probe_path[PICL_PROPNAMELEN_MAX]; if (locp == NULL) { return (B_FALSE); } if (ptree_get_propval_by_name(locp->locnodeh, PICL_PROP_PROBE_PATH, probe_path, sizeof (probe_path)) != PICL_SUCCESS) { if (ptree_get_propval_by_name(locp->locnodeh, PICL_PROP_DEVFS_PATH, probe_path, sizeof (probe_path)) != PICL_SUCCESS) { return (B_FALSE); } } rnode = di_init(probe_path, DINFOSUBTREE); if (rnode == DI_NODE_NIL) { di_fini(rnode); return (B_FALSE); } devinfo = (frutree_devinfo_t *)malloc(sizeof (frutree_devinfo_t)); if (devinfo == NULL) { di_fini(rnode); return (B_FALSE); } devinfo->rnode = rnode; devinfo->arg = (frutree_locnode_t **)&locp; devinfo->retval = PICL_FAILURE; if (di_walk_node(rnode, DI_WALK_SIBFIRST, &devinfo, find_fru_node) != 0) { di_fini(rnode); free(devinfo); return (B_FALSE); } di_fini(rnode); if (devinfo->retval == PICL_SUCCESS) { free(devinfo); return (B_TRUE); } else { free(devinfo); return (B_FALSE); } }
/* * Compare the /platform tree to the /frutree to determine if a * device has been removed */ static int is_removed_device(char *plat, char *fru) { int err; picl_nodehdl_t plath, frusloth, frumodh; /* Check for node in /platform tree */ err = ptree_get_node_by_path(plat, &plath); if (err == PICL_SUCCESS) return (PICL_FAILURE); /* * The node is not in /platform, so find the corresponding slot in * the frutree */ err = ptree_get_node_by_path(fru, &frusloth); if (err != PICL_SUCCESS) return (err); /* * If the slot in the frutree does not have a child, then return * PICL_FAILURE. This means that the /platform tree and * the frutree are consistent and no action is necessary. * Otherwise return PICL_SUCCESS to indicate that the needs * to be removed from the frutree */ err = ptree_get_propval_by_name(frusloth, PICL_PROP_CHILD, &frumodh, sizeof (picl_nodehdl_t)); if (err != PICL_SUCCESS) return (err); return (PICL_SUCCESS); }
/* Hotplug routine used to remove an existing power supply */ static int remove_power_supply(int slotnum) { picl_nodehdl_t powersloth; picl_nodehdl_t powermodh; int err; /* Find the node for the given power supply slot */ if (ptree_get_node_by_path(frutree_power_supply[slotnum], &powersloth) == PICL_SUCCESS) { /* Make sure it's got a child, then delete it */ err = ptree_get_propval_by_name(powersloth, PICL_PROP_CHILD, &powermodh, sizeof (picl_nodehdl_t)); if (err != PICL_SUCCESS) { return (err); } err = ptree_delete_node(powermodh); if (err != PICL_SUCCESS) { return (err); } else { (void) ptree_destroy_node(powermodh); } /* Post picl-fru-removed event */ post_frudr_event(PICL_FRU_REMOVED, NULL, powermodh); } return (PICL_SUCCESS); }
/* * Callback to the ptree walk function during add_cpus. * As a part of the args receives a cpu di_node, compares * each picl cpu node's cpuid to the device tree node's cpuid. * Sets arg struct's result to 1 on a match. */ static int cpu_exists(picl_nodehdl_t nodeh, void *c_args) { di_node_t di_node; cpu_lookup_t *cpu_arg; int err; int dcpuid, pcpuid; int reg_prop[4]; if (c_args == NULL) return (PICL_INVALIDARG); cpu_arg = c_args; di_node = cpu_arg->di_node; dcpuid = get_cpuid(di_node); err = ptree_get_propval_by_name(nodeh, OBP_REG, reg_prop, sizeof (reg_prop)); if (err != PICL_SUCCESS) return (PICL_WALK_CONTINUE); pcpuid = CFGHDL_TO_CPUID(reg_prop[0]); if (dcpuid == pcpuid) { cpu_arg->result = 1; return (PICL_WALK_TERMINATE); } cpu_arg->result = 0; return (PICL_WALK_CONTINUE); }
/* * Callback to the ptree walk function during remove_cpus. * As a part of the args receives a picl nodeh, searches * the device tree for a cpu whose cpuid matches the picl cpu node. * Sets arg struct's result to 1 if it failed to match and terminates * the walk. */ static int remove_cpu_candidate(picl_nodehdl_t nodeh, void *c_args) { di_node_t di_node; cpu_lookup_t *cpu_arg; int err; int pcpuid; int reg_prop[SUN4V_CPU_REGSIZE]; if (c_args == NULL) return (PICL_INVALIDARG); cpu_arg = c_args; di_node = cpu_arg->di_node; err = ptree_get_propval_by_name(nodeh, OBP_REG, reg_prop, sizeof (reg_prop)); if (err != PICL_SUCCESS) { return (PICL_WALK_CONTINUE); } pcpuid = CFGHDL_TO_CPUID(reg_prop[0]); if (!find_cpu(di_node, pcpuid)) { cpu_arg->result = 1; cpu_arg->nodeh = nodeh; return (PICL_WALK_TERMINATE); } cpu_arg->result = 0; return (PICL_WALK_CONTINUE); }
/* * add OBP_REG property to picl cpu node if it's not already there. */ static void add_reg_prop(picl_nodehdl_t pn, di_node_t dn) { int reg_prop[SUN4V_CPU_REGSIZE]; int status; int dlen; int *pdata; ptree_propinfo_t propinfo; status = ptree_get_propval_by_name(pn, OBP_REG, reg_prop, sizeof (reg_prop)); if (status == PICL_SUCCESS) { return; } dlen = di_prom_prop_lookup_ints(ph, dn, OBP_REG, &pdata); if (dlen < 0) { return; } status = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, PICL_PTYPE_BYTEARRAY, PICL_READ, dlen * sizeof (int), OBP_REG, NULL, NULL); if (status != PICL_SUCCESS) { return; } (void) ptree_create_and_add_prop(pn, &propinfo, pdata, NULL); }
/* * callback routine for ptree_walk_tree_by_class() */ static int cb_find_disk(picl_nodehdl_t node, void *args) { disk_lookup_t *lookup = (disk_lookup_t *)args; int status = -1; char *n; char path[PICL_PROPNAMELEN_MAX]; status = ptree_get_propval_by_name(node, "Path", (void *)&path, PICL_PROPNAMELEN_MAX); if (status != PICL_SUCCESS) { return (PICL_WALK_CONTINUE); } if (strcmp(path, lookup->path) == 0) { lookup->disk = node; lookup->result = DISK_FOUND; /* store the HBA's device path for use in check_raid() */ n = strstr(path, "/sd"); strncpy(n, "\0", 1); (void) snprintf(hba_devctl, MAXPATHLEN, "/devices%s:devctl", path); return (PICL_WALK_TERMINATE); } return (PICL_WALK_CONTINUE); }
static int find_fru_node(di_node_t node, void *arg) { frutree_locnode_t *locp = NULL; char *char_di_bus_addr = NULL; int busaddr = 0; int di_busaddr = 0; char bus_addr[PICL_PROPNAMELEN_MAX]; frutree_devinfo_t *devinfo = NULL; devinfo = *(frutree_devinfo_t **)arg; locp = *(frutree_locnode_t **)devinfo->arg; if (devinfo->rnode == node) { return (DI_WALK_CONTINUE); } char_di_bus_addr = di_bus_addr(node); if (char_di_bus_addr == NULL) { return (DI_WALK_PRUNECHILD); } if (ptree_get_propval_by_name(locp->locnodeh, PICL_PROP_BUS_ADDR, bus_addr, sizeof (bus_addr)) != PICL_SUCCESS) { return (DI_WALK_PRUNECHILD); } if (strstr(bus_addr, ",") != NULL) { /* bus addr is of type 1,0 */ if (strcmp(bus_addr, char_di_bus_addr) == 0) { devinfo->retval = PICL_SUCCESS; return (DI_WALK_TERMINATE); } else { return (DI_WALK_PRUNECHILD); } } else { /* bus addr is of type 0x */ /* check if the values are same */ errno = 0; busaddr = strtol(bus_addr, (char **)NULL, 16); if (errno != 0) { return (DI_WALK_PRUNECHILD); } errno = 0; di_busaddr = strtol(char_di_bus_addr, (char **)NULL, 16); if (errno != 0) { return (DI_WALK_PRUNECHILD); } if (di_busaddr == busaddr) { devinfo->retval = PICL_SUCCESS; return (DI_WALK_TERMINATE); } else { return (DI_WALK_PRUNECHILD); } } }
/* * Look up the container_hdl in the PICL tree. */ container_hdl_t fru_open_container(picl_nodehdl_t fruh) { int err; container_hdl_t container_hdl; if (fru_open_dev() == -1) { return (NULL); } err = ptree_get_propval_by_name(fruh, PICL_PROP_DATA_AVAIL, NULL, NULL); if (err != PICL_SUCCESS) { syslog(LOG_ERR, GETPV, PICL_PROP_DATA_AVAIL, err); return (NULL); } err = ptree_get_propval_by_name(fruh, PICL_PROP_SC_HANDLE, &container_hdl, sizeof (container_hdl_t)); if (err != PICL_SUCCESS) { syslog(LOG_ERR, GETPV, PICL_PROP_SC_HANDLE, err); return (NULL); } return (container_hdl); }
int find_disk(picl_nodehdl_t node, void *args) { disk_lookup_t *lookup = (disk_lookup_t *)args; int status; char path[PICL_PROPNAMELEN_MAX]; status = ptree_get_propval_by_name(node, "Path", (void *)&path, PICL_PROPNAMELEN_MAX); if (status != PICL_SUCCESS) { return (PICL_WALK_CONTINUE); } if (strcmp(path, lookup->path) == 0) { lookup->disk = node; lookup->result = DISK_FOUND; return (PICL_WALK_TERMINATE); } return (PICL_WALK_CONTINUE); }
/* Deletes and destroys all PICL nodes for which rooth is a ancestor */ static int remove_all_nodes(picl_nodehdl_t rooth) { picl_nodehdl_t chdh; int err, done = 0; while (!done) { err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &chdh, sizeof (picl_nodehdl_t)); if (err != PICL_PROPNOTFOUND) { (void) remove_all_nodes(chdh); } else { err = ptree_delete_node(rooth); if (err != PICL_SUCCESS) { return (err); } else { (void) ptree_destroy_node(rooth); } done = 1; } } return (PICL_SUCCESS); }
/* Hotplug routine used to remove an existing CPU Mem Module */ static int remove_cpu_module(int slotnum) { picl_nodehdl_t cpumemsloth; picl_nodehdl_t cpumemmodh; int err; /* Find the node for the given CPU Memory module slot */ if (ptree_get_node_by_path(frutree_cpu_module[slotnum], &cpumemsloth) == PICL_SUCCESS) { /* Make sure it's got a child, then delete it */ err = ptree_get_propval_by_name(cpumemsloth, PICL_PROP_CHILD, &cpumemmodh, sizeof (picl_nodehdl_t)); if (err != PICL_SUCCESS) { return (err); } err = remove_all_nodes(cpumemmodh); if (err != PICL_SUCCESS) { return (err); } } return (PICL_SUCCESS); }
picl_errno_t get_fru_path(char *parent_path, frutree_frunode_t *frup) { picl_errno_t rc = 0; picl_nodehdl_t loch; di_node_t rnode; frutree_devinfo_t *devinfo = NULL; char slot_type[PICL_PROPNAMELEN_MAX]; char probe_path[PICL_PROPNAMELEN_MAX]; char bus_addr[PICL_PROPNAMELEN_MAX]; if ((rc = ptree_get_propval_by_name(frup->frunodeh, PICL_PROP_PARENT, &loch, sizeof (loch))) != PICL_SUCCESS) { return (rc); } if ((rc = ptree_get_propval_by_name(loch, PICL_PROP_SLOT_TYPE, slot_type, sizeof (slot_type))) != PICL_SUCCESS) { return (rc); } if (strcmp(slot_type, SANIBEL_SCSI_SLOT) == 0 || strcmp(slot_type, SANIBEL_IDE_SLOT) == 0) { if (ptree_get_propval_by_name(loch, PICL_PROP_PROBE_PATH, probe_path, sizeof (probe_path)) != PICL_SUCCESS) { return (rc); } (void) strncpy(frup->fru_path, probe_path, sizeof (frup->fru_path)); return (PICL_SUCCESS); } prom_handle = di_prom_init(); rnode = di_init(parent_path, DINFOSUBTREE|DINFOMINOR); if (rnode == DI_NODE_NIL) { di_prom_fini(prom_handle); return (PICL_FAILURE); } devinfo = (frutree_devinfo_t *)malloc(sizeof (frutree_devinfo_t)); if (devinfo == NULL) { di_fini(rnode); di_prom_fini(prom_handle); return (PICL_NOSPACE); } if (ptree_get_propval_by_name(loch, PICL_PROP_BUS_ADDR, bus_addr, sizeof (bus_addr)) != PICL_SUCCESS) { free(devinfo); di_fini(rnode); di_prom_fini(prom_handle); return (rc); } devinfo->rnode = rnode; (void) strncpy(devinfo->bus_addr, bus_addr, sizeof (devinfo->bus_addr)); devinfo->path[0] = '\0'; devinfo->arg = frup; if (di_walk_node(rnode, DI_WALK_SIBFIRST, &devinfo, walk_tree) != 0) { di_fini(rnode); di_prom_fini(prom_handle); free(devinfo); return (PICL_FAILURE); } di_fini(rnode); di_prom_fini(prom_handle); if (devinfo->path[0]) { (void) strncpy(frup->fru_path, devinfo->path, sizeof (frup->fru_path)); free(devinfo); return (PICL_SUCCESS); } else { free(devinfo); return (PICL_NODENOTFOUND); } }
/* * update_picl * Called when disk goes off-line or goes to ready status. * In the case of disk ready, locate platform tree node for the disk * and add a target property (if missing). * (The target address is fixed for a given disk slot and is used to * tie the frutree disk-unit to the correct ssd node). * Returns EAGAIN for a retriable failure, otherwise 0. */ static int update_picl(led_dtls_t *dtls, int disk) { static char trailer[] = ",0"; picl_nodehdl_t slotndh; picl_nodehdl_t diskndh; ptree_propinfo_t propinfo; int r; if (dtls->disk_detected[disk] != 0) { picl_nodehdl_t fpndh; picl_nodehdl_t ssdndh; picl_prophdl_t tbl_h; picl_prophdl_t tbl_prop_h; picl_prophdl_t row_props_h[FCAL_DEVTABLE_NCOLS]; char valbuf[80]; char addr[MAXPATHLEN]; char *ptrd; const uchar_t *ptrs; int len; int addr_len; for (;;) { r = ptree_get_node_by_path(dtls->fcal_disk_parent, &fpndh); if (r != PICL_SUCCESS) { return (0); } r = ptree_get_propval_by_name(fpndh, PICL_PROP_CLASSNAME, (void *)valbuf, sizeof (valbuf)); if (r != PICL_SUCCESS) { return (0); } else if (strcmp(valbuf, "fp") == 0) { /* * The node with class fp (if present) is a * holding node representing no actual hardware. * Its presence results in two nodes with the * same effective address. (The fp class node is * UnitAddress 0,0 and the other fp node [class * devctl] has bus-addr 0,0). Locating the * required fp node for dynamic reconfiguration * then goes wrong. So, just remove it. */ SYSLOG(LOG_WARNING, EM_SPURIOUS_FP); r = ptree_delete_node(fpndh); if (r == PICL_SUCCESS) { (void) ptree_destroy_node(fpndh); continue; } return (0); } else { break; } } /* * Got a good parent node. Look at its children for a node * with this new port name. * * generate expected bus-addr property from the port-wwn * Note: dtls->disk_port[disk] points to an array of uchar_t, * the first character contains the length of the residue. * The bus-addr property is formatted as follows: * wabcdef0123456789,0 * where the 16 hex-digits represent 8 bytes from disk_port[]; */ ptrs = dtls->disk_port[disk]; if (ptrs == NULL) return (0); len = *ptrs++; ptrd = addr; *ptrd++ = 'w'; for (r = 0; r < len; r++, ptrd += 2) { (void) snprintf(ptrd, MAXPATHLEN - (ptrd - addr), "%.2x", *ptrs++); } addr_len = 1 + strlcat(addr, trailer, MAXPATHLEN); if (addr_len > MAXPATHLEN) return (0); r = ptree_find_node(fpndh, FCAL_PICL_PROP_BUS_ADDR, PICL_PTYPE_CHARSTRING, addr, addr_len, &ssdndh); /* * If the disk node corresponding to the newly inserted disk * cannot be found in the platform tree, we have probably * got in too early - probably before it's up to speed. In * this case, the WWN gleaned from devinfo may also be wrong. * This case is worth retrying in later polls when it may * succeed, so return EAGAIN. All other failures are probably * terminal, so log a failure and quit. */ if (r == PICL_NODENOTFOUND) return (EAGAIN); if (r != PICL_SUCCESS) { SYSLOG(LOG_ERR, EM_NO_FP_NODE, disk); return (0); } /* * Found platform entry for disk, add target prop */ r = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, PICL_PTYPE_INT, PICL_READ, sizeof (int), FCAL_PICL_PROP_TARGET, NULL, NULL); if (r != PICL_SUCCESS) return (0); (void) ptree_create_and_add_prop(ssdndh, &propinfo, &disk, NULL); /* * Remove pre-existing disk-unit node and its * properties - maybe its reference property is * out-of-date. */ delete_disk_unit(dtls, disk); /* * Add a disk-unit node in frutree */ r = find_disk_slot(dtls, disk, &slotndh); if (r != PICL_SUCCESS) return (0); r = ptree_create_and_add_node(slotndh, fcal_disk_unit, PICL_CLASS_FRU, &diskndh); if (r != PICL_SUCCESS) return (0); r = create_Device_table(&tbl_h, &tbl_prop_h); if (r != PICL_SUCCESS) return (0); r = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, PICL_PTYPE_CHARSTRING, PICL_READ, sizeof (PICL_CLASS_BLOCK), PICL_PROP_CLASS, NULL, NULL); if (r != PICL_SUCCESS) return (0); r = ptree_create_prop(&propinfo, PICL_CLASS_BLOCK, &row_props_h[0]); if (r != PICL_SUCCESS) return (0); r = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, PICL_PTYPE_REFERENCE, PICL_READ, sizeof (picl_prophdl_t), FCAL_PICL_BLOCK_REF, NULL, NULL); if (r != PICL_SUCCESS) return (0); r = ptree_create_prop(&propinfo, &ssdndh, &row_props_h[1]); if (r != PICL_SUCCESS) return (0); r = ptree_add_row_to_table(tbl_h, FCAL_DEVTABLE_NCOLS, row_props_h); if (r != PICL_SUCCESS) return (0); (void) ptree_add_prop(diskndh, tbl_prop_h); } else { /* * disk gone, remove disk_unit fru from frutree */ delete_disk_unit(dtls, disk); } return (0); }
/* * Ontario SBL event handler, subscribed to: * PICLEVENT_SYSEVENT_DEVICE_ADDED * PICLEVENT_SYSEVENT_DEVICE_REMOVED */ static void piclsbl_handler(const char *ename, const void *earg, size_t size, void *cookie) { char *devfs_path; char hdd_location[PICL_PROPNAMELEN_MAX]; nvlist_t *nvlp = NULL; pcp_msg_t send_msg; pcp_msg_t recv_msg; pcp_sbl_req_t *req_ptr = NULL; pcp_sbl_resp_t *resp_ptr = NULL; int status = -1; int target; disk_lookup_t lookup; int channel_fd; /* * setup the request data to attach to the libpcp msg */ if ((req_ptr = (pcp_sbl_req_t *)umem_zalloc(sizeof (pcp_sbl_req_t), UMEM_DEFAULT)) == NULL) goto sbl_return; /* * This plugin serves to enable or disable the blue RAS * 'ok-to-remove' LED that is on each of the 4 disks on the * Ontario. We catch the event via the picl handler, and * if the event is DEVICE_ADDED for one of our onboard disks, * then we'll be turning off the LED. Otherwise, if the event * is DEVICE_REMOVED, then we turn it on. */ if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_ADDED) == 0) req_ptr->sbl_action = PCP_SBL_DISABLE; else if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_REMOVED) == 0) req_ptr->sbl_action = PCP_SBL_ENABLE; else goto sbl_return; /* * retrieve the device's physical path from the event payload */ if (nvlist_unpack((char *)earg, size, &nvlp, NULL)) goto sbl_return; if (nvlist_lookup_string(nvlp, "devfs-path", &devfs_path)) goto sbl_return; /* * look for this disk in the picl tree, and if it's * location indicates that it's one of our internal * disks, then set sbl_id to incdicate which one. * otherwise, return as it is not one of our disks. */ lookup.path = strdup(devfs_path); lookup.disk = NULL; lookup.result = DISK_NOT_FOUND; /* first, find the disk */ status = ptree_walk_tree_by_class(root_node, "disk", (void *)&lookup, cb_find_disk); if (status != PICL_SUCCESS) goto sbl_return; if (lookup.result == DISK_FOUND) { /* now, lookup it's location in the node */ status = ptree_get_propval_by_name(lookup.disk, "Location", (void *)&hdd_location, PICL_PROPNAMELEN_MAX); if (status != PICL_SUCCESS) { syslog(LOG_ERR, "piclsbl: failed hdd discovery"); goto sbl_return; } } if (strcmp(hdd_location, HDD0) == 0) { req_ptr->sbl_id = PCP_SBL_HDD0; target = 0; } else if (strcmp(hdd_location, HDD1) == 0) { req_ptr->sbl_id = PCP_SBL_HDD1; target = 1; } else if (strcmp(hdd_location, HDD2) == 0) { req_ptr->sbl_id = PCP_SBL_HDD2; target = 2; } else if (strcmp(hdd_location, HDD3) == 0) { req_ptr->sbl_id = PCP_SBL_HDD3; target = 3; } else { /* this is not one of the onboard disks */ goto sbl_return; } /* * check the onboard RAID configuration for this disk. if it is * a member of a RAID and is not the RAID itself, ignore the event */ if (check_raid(target)) goto sbl_return; /* * we have the information we need, init the platform channel. * the platform channel driver will only allow one connection * at a time on this socket. on the offchance that more than * one event comes in, we'll retry to initialize this connection * up to 3 times */ if ((channel_fd = (*pcp_init_ptr)(LED_CHANNEL)) < 0) { /* failed to init; wait and retry up to 3 times */ int s = PCPINIT_TIMEOUT; int retries = 0; while (++retries) { (void) sleep(s); if ((channel_fd = (*pcp_init_ptr)(LED_CHANNEL)) >= 0) break; else if (retries == 3) { syslog(LOG_ERR, "piclsbl: ", "SC channel initialization failed"); goto sbl_return; } /* continue */ } } /* * populate the message for libpcp */ send_msg.msg_type = PCP_SBL_CONTROL; send_msg.sub_type = NULL; send_msg.msg_len = sizeof (pcp_sbl_req_t); send_msg.msg_data = (uint8_t *)req_ptr; /* * send the request, receive the response */ if ((*pcp_send_recv_ptr)(channel_fd, &send_msg, &recv_msg, PCPCOMM_TIMEOUT) < 0) { /* we either timed out or erred; either way try again */ int s = PCPCOMM_TIMEOUT; (void) sleep(s); if ((*pcp_send_recv_ptr)(channel_fd, &send_msg, &recv_msg, PCPCOMM_TIMEOUT) < 0) { syslog(LOG_ERR, "piclsbl: communication failure"); goto sbl_return; } } /* * validate that this data was meant for us */ if (recv_msg.msg_type != PCP_SBL_CONTROL_R) { syslog(LOG_ERR, "piclsbl: unbound packet received"); goto sbl_return; } /* * verify that the LED action has taken place */ resp_ptr = (pcp_sbl_resp_t *)recv_msg.msg_data; if (resp_ptr->status == PCP_SBL_ERROR) { syslog(LOG_ERR, "piclsbl: OK2RM LED action error"); goto sbl_return; } /* * ensure the LED action taken is the one requested */ if ((req_ptr->sbl_action == PCP_SBL_DISABLE) && (resp_ptr->sbl_state != SBL_STATE_OFF)) syslog(LOG_ERR, "piclsbl: OK2RM LED not OFF after disk " "configuration"); else if ((req_ptr->sbl_action == PCP_SBL_ENABLE) && (resp_ptr->sbl_state != SBL_STATE_ON)) syslog(LOG_ERR, "piclsbl: OK2RM LED not ON after disk " "unconfiguration"); else if (resp_ptr->sbl_state == SBL_STATE_UNKNOWN) syslog(LOG_ERR, "piclsbl: OK2RM LED set to unknown state"); sbl_return: (*pcp_close_ptr)(channel_fd); if (req_ptr != NULL) umem_free(req_ptr, sizeof (pcp_sbl_req_t)); if (resp_ptr != NULL) free(resp_ptr); if (nvlp != NULL) nvlist_free(nvlp); }
/* * routine to handle all the picl state and condition change events */ void env_handle_event(const char *ename, const void *earg, size_t size) { picl_nodehdl_t nodeh = 0; nvlist_t *nvlp; char *value; boolean_t state_event; char result[PICL_PROPNAMELEN_MAX]; if (!ename) { return; } if (strcmp(ename, PICLEVENT_STATE_CHANGE) == 0) { state_event = B_TRUE; } else if (strcmp(ename, PICLEVENT_CONDITION_CHANGE) == 0) { state_event = B_FALSE; } else { return; } /* unpack the nvlist and get the information */ if (nvlist_unpack((char *)earg, size, &nvlp, NULL)) { return; } if (nvlist_lookup_uint64(nvlp, PICLEVENTARG_NODEHANDLE, &nodeh) == -1) { nvlist_free(nvlp); return; } if (nvlist_lookup_string(nvlp, (state_event) ? PICLEVENTARG_STATE : PICLEVENTARG_CONDITION, &value) != 0) { nvlist_free(nvlp); return; } if (env_debug & PICLEVENTS) { if (ptree_get_propval_by_name(nodeh, PICL_PROP_NAME, result, sizeof (result)) != PICL_SUCCESS) { syslog(LOG_ERR, " SUNW_envmond: error in getting" " %s", PICL_PROP_NAME); nvlist_free(nvlp); return; } syslog(LOG_INFO, "SUNW_envmond: %s (%s) on %s", ename, value, result); } if (chassis_nodehdl == 0 && state_event) { if (ptree_get_propval_by_name(nodeh, PICL_PROP_NAME, result, sizeof (result)) != PICL_SUCCESS) { nvlist_free(nvlp); return; } if (strcmp(result, PICL_NODE_CHASSIS) == 0) { chassis_nodehdl = nodeh; } } if (nodeh == chassis_nodehdl && state_event) { (void) env_handle_chassis_configuring_event(value); } /* do any platform specific handling that is reqd */ env_platmod_handle_event(ename, earg, size); nvlist_free(nvlp); }
/* * initializes the port driver and instance fields based on libdevinfo */ picl_errno_t get_port_info(frutree_portnode_t *portp) { picl_errno_t rc; di_node_t rnode, curr, peer; char devfs_path[PICL_PROPNAMELEN_MAX]; char bus_addr[PICL_PROPNAMELEN_MAX]; char *di_busaddr = NULL, *di_drv = NULL; int di_int_busaddr, int_busaddr; if ((rc = ptree_get_propval_by_name(portp->portnodeh, PICL_PROP_DEVFS_PATH, devfs_path, sizeof (devfs_path))) != PICL_SUCCESS) { return (rc); } if (ptree_get_propval_by_name(portp->portnodeh, PICL_PROP_BUS_ADDR, bus_addr, sizeof (bus_addr)) != PICL_SUCCESS) { return (rc); } rnode = di_init(devfs_path, DINFOCPYALL); if (rnode == DI_NODE_NIL) { return (PICL_FAILURE); } peer = di_child_node(rnode); while (peer != DI_NODE_NIL) { curr = peer; peer = di_sibling_node(curr); di_busaddr = di_bus_addr(curr); if (di_busaddr == NULL) { continue; } /* compare the bus_addr */ if (strstr(bus_addr, ",") != NULL) { /* bus addr is of type 1,0 */ if (strcmp(bus_addr, di_busaddr) != 0) { continue; } } else { /* bus addr is of type 0x */ errno = 0; int_busaddr = strtol(bus_addr, (char **)NULL, 16); if (errno != 0) { continue; } errno = 0; di_int_busaddr = strtol(di_busaddr, (char **)NULL, 16); if (errno != 0) { continue; } if (di_int_busaddr != int_busaddr) { continue; } } di_drv = di_driver_name(curr); if (di_drv == NULL) { di_fini(rnode); return (PICL_FAILURE); } /* initialize the driver name and instance number */ (void) strncpy(portp->driver, di_drv, sizeof (portp->driver)); portp->instance = di_instance(curr); di_fini(rnode); return (PICL_SUCCESS); } di_fini(rnode); return (PICL_NODENOTFOUND); }
int add_cpu_prop(picl_nodehdl_t node, void *args) { mde_cookie_t *cpulistp; mde_cookie_t *cachelistp; mde_cookie_t *tlblistp; int x, num_nodes; int ncpus, ncaches, ntlbs; int status; int reg_prop[SUN4V_CPU_REGSIZE], cpuid; uint64_t int_value; status = ptree_get_propval_by_name(node, OBP_REG, reg_prop, sizeof (reg_prop)); if (status != PICL_SUCCESS) { return (PICL_WALK_TERMINATE); } cpuid = CFGHDL_TO_CPUID(reg_prop[0]); /* * Allocate space for our searches. */ num_nodes = md_node_count(mdp); cpulistp = (mde_cookie_t *) alloca(sizeof (mde_cookie_t) *num_nodes); if (cpulistp == NULL) { return (PICL_WALK_TERMINATE); } cachelistp = (mde_cookie_t *) alloca(sizeof (mde_cookie_t) *num_nodes); if (cachelistp == NULL) { return (PICL_WALK_TERMINATE); } tlblistp = (mde_cookie_t *) alloca(sizeof (mde_cookie_t) *num_nodes); if (tlblistp == NULL) { return (PICL_WALK_TERMINATE); } /* * Starting at the root node, scan the "fwd" dag for * all the cpus in this description. */ ncpus = md_scan_dag(mdp, rootnode, md_find_name(mdp, "cpu"), md_find_name(mdp, "fwd"), cpulistp); if (ncpus < 0) { return (PICL_WALK_TERMINATE); } /* * Create PD cpus with a few select properties */ for (x = 0; x < ncpus; x++) { if (md_get_prop_val(mdp, cpulistp[x], "id", &int_value)) { continue; } if (int_value != cpuid) continue; add_md_prop(node, sizeof (int_value), "cpuid", &int_value, PICL_PTYPE_INT); add_md_prop(node, sizeof (int_value), "portid", &int_value, PICL_PTYPE_INT); /* get caches for CPU */ ncaches = md_scan_dag(mdp, cpulistp[x], md_find_name(mdp, "cache"), md_find_name(mdp, "fwd"), cachelistp); add_cache_props(node, cachelistp, ncaches); /* get tlbs for CPU */ ntlbs = md_scan_dag(mdp, cpulistp[x], md_find_name(mdp, "tlb"), md_find_name(mdp, "fwd"), tlblistp); add_tlb_props(node, tlblistp, ntlbs); } return (PICL_WALK_CONTINUE); }