示例#1
0
/*
 * 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);
}
示例#2
0
/*
 * 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);
	}
}
示例#3
0
/*
 * 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);
}
示例#4
0
/* 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);
}
示例#5
0
/*
 * 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);
}
示例#6
0
/*
 * 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);
}
示例#7
0
/*
 * 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);
}
示例#8
0
文件: piclsbl.c 项目: andreiw/polaris
/*
 * 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);
}
示例#9
0
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);
		}
	}
}
示例#10
0
/*
 * 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);
}
示例#11
0
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);
}
示例#12
0
/* 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);
}
示例#13
0
/* 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);
}
示例#14
0
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);
	}
}
示例#15
0
/*
 * 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);
}
示例#16
0
文件: piclsbl.c 项目: andreiw/polaris
/*
 * 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);
}
示例#17
0
/*
 * 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);
}
示例#18
0
/*
 * 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);
}
示例#19
0
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);
}