Exemple #1
0
/**
 * init_node
 *
 * @param node
 * @returns 0 on success, !0 otherwise
 */
static int
init_node(struct dr_node *node)
{
	DIR *d;
	struct dirent *de;
	char child_path[DR_PATH_MAX];
	uint32_t my_drc_index;
	int rc;

	if (node->is_owned)
		find_ofdt_dname(node, node->ofdt_path);

	d = opendir(node->ofdt_path);
	if (!d)
		return -1;

	rc = 0;
	while ((de = readdir(d)) != NULL) {
		if ((de->d_type != DT_DIR) || is_dot_dir(de->d_name))
			continue;

		sprintf(child_path, "%s/%s", node->ofdt_path, de->d_name);

		if (get_my_drc_index(child_path, &my_drc_index))
			continue;

		if (node->dev_type == PCI_HP_DEV) {
			if (node->drc_index == my_drc_index) {
				/* Add hotplug children */
				add_child_node(node, child_path);
			}
		} else {
			if (!node->is_owned) {
				if (node->drc_index == my_drc_index) {
					/* Update node path */
					snprintf(node->ofdt_path, DR_PATH_MAX,
						 "%s", child_path);
					node->is_owned = 1;

					/* Populate w/ children */
					rc = init_node(node);
					if (rc)
						break;
				}
			} else {
				/* Add all DR-capable children */
				add_child_node(node, child_path);
			}
		}
	}

	closedir(d);
	return rc;
}
static int
cpu_index_to_path(struct dr_node *cpu)
{
	DIR *d;
	struct dirent *de;
	int found = 0;
	int rc;
	char path[DR_PATH_MAX];

	d = opendir(CPU_OFDT_BASE);
	if (d == NULL) {
		say(ERROR, "Could not open %s: %s\n", CPU_OFDT_BASE,
		    strerror(errno));
		return -1;
	}

	while ((de = readdir(d)) != NULL) {
		uint32_t my_drc_index;

		if ((de->d_type != DT_DIR) || is_dot_dir(de->d_name))
			continue;

		if (strncmp(de->d_name, "PowerPC", 7))
			continue;

		sprintf(path, "%s/%s", CPU_OFDT_BASE, de->d_name);

		rc = get_my_drc_index(path, &my_drc_index);
		if (rc) {
			/* This is an error, but continue searching since
			 * this may not be the drc index we are looking for
			 */
			say(DEBUG, "Could not retrieve drc_index for %s\n",
			    path);
			continue;
		}

		if (my_drc_index == cpu->drc_index) {
			found = 1;
			break;
		}
	}

	closedir(d);

	if (found)
		snprintf(cpu->ofdt_path, DR_PATH_MAX, "%s", path);

	return rc;
}
/**
 * update_phb_ic_info
 * @brief Add interrupt controller information to PHB nodes
 *
 * We need to have the interrupt-controller ofdt paths for all PHB
 * nodes to do DLPAR.  This routine adds that information for PHB nodes
 * that we found.
 *
 * @param node_list list of PHB nodes
 * @returns 0 on success, !0 otherwise
 */
static int
update_phb_ic_info(struct dr_node *node_list)
{
	char *ic_dir = "interrupt-controller";
	struct dr_node *node;
	struct dirent *de;
	DIR *d;
	int rc = 0;

	d = opendir(OFDT_BASE);
	if (d == NULL) {
		say(ERROR, "failed to open %s\n%s\n", OFDT_BASE,
		    strerror(errno));
		return -1;
	}

	while ((de = readdir(d)) != NULL) {
		uint my_drc_index;
		char ofdt_path[DR_PATH_MAX];

		if ((de->d_type != DT_DIR) || is_dot_dir(de->d_name))
			continue;

		if (strncmp(de->d_name, ic_dir, strlen(ic_dir)))
			continue;

		sprintf(ofdt_path, "%s/%s", OFDT_BASE, de->d_name);
		rc = get_my_drc_index(ofdt_path, &my_drc_index);
		if (rc)
			/* This is expected to fail sometimes, as there can be
			 * more ICs than PHBs on a system.  In this case, some
			 * ICs won't have my-drc-index. */
			continue;

		for (node = node_list; node; node = node->next) {
			if ((node->dev_type == PHB_DEV)
			    && (node->drc_index == my_drc_index)) {
				snprintf(node->phb_ic_ofdt_path, DR_PATH_MAX,
					 "%s", ofdt_path);
				break;
			}
		}
	}

	closedir(d);
	return 0;
}
/**
 * add_hea_node
 * @brief Add a node for an HEA adapter
 *
 * @param path ofdt_path to this node
 * @param drc_list list of drc's at OFDT_BASE
 * @param pointer to the node list to add new nodes to
 * @return 0 on success, !0 otherwise
 */
static int
add_hea_node(char *path, struct dr_connector *drc_list,
	     struct dr_node **node_list)
{
	struct dr_connector *drc;
	struct dr_node *hea_node;
	uint my_drc_index;
	int rc;

	if (drc_list == NULL)
		return -1;

	if (get_my_drc_index(path, &my_drc_index))
		return -1;

	for (drc = drc_list; drc != NULL; drc = drc->next) {
		if (drc->index == my_drc_index)
			break;
	}

	if (drc == NULL) {
		say(ERROR, "Could not find drc index 0x%x to add to hea list\n",
		    my_drc_index);
		return -1;
	}

	hea_node = alloc_dr_node(drc, HEA_DEV, path);
	if (hea_node == NULL) {
		say(ERROR, "Could not allocate hea node for drc index 0x%x\n",
		    my_drc_index);
		return -1;
	}

	hea_node->is_owned = 1;
	rc = init_node(hea_node);
	if (rc) {
		free(hea_node);
		return -1;
	}

	hea_node->next = *node_list;
	*node_list = hea_node;
	return 0;
}
/**
 * examine_children
 *
 * @param node
 * @param child_path
 * @returns 0 on success, !0 otherwise
 */
static int
examine_child(struct dr_node *node, char *child_path)
{
	uint32_t my_drc_index;
	int used = 0;
	int rc = 0;

	if (get_my_drc_index(child_path, &my_drc_index))
		goto done;

	if (node->dev_type == PCI_HP_DEV) {
		if (node->drc_index == my_drc_index) {
			/* Add hotplug children */
			add_child_node(node, child_path);
			used = 1;
		}
	} else {
		if (! node->is_owned) {
			if (node->drc_index == my_drc_index) {
				/* Update node path */
				snprintf(node->ofdt_path, DR_PATH_MAX, "%s",
					 child_path);
				node->is_owned = 1;
				used = 1;

				/* Populate w/ children */
				rc = init_node(node);
			}
		} else {
			/* Add all DR-capable children */
			add_child_node(node, child_path);
			used = 1;
		}
	}
done:
	if (! used)
		free(child_path);

	return rc;
}
/**
 * add_phb_node
 * @brief Add a PHB node to the node list
 *
 * @param ofdt_poath, ofdt path to this node
 * @param drc_list list of drc's at OFDT_BASE
 * @param node_list list of nodes to add node to
 * @returns 0 on success, !0 otherwise
 */
static int
add_phb_node(char *ofdt_path, struct dr_connector *drc_list,
	     struct dr_node **node_list)
{
	struct dr_node *phb_node;
	struct dr_connector *drc;
	uint my_drc_index;

	if (get_my_drc_index(ofdt_path, &my_drc_index))
		return -1;

	for (drc = drc_list; drc; drc = drc->next) {
		if (drc->index == my_drc_index)
			break;
	}

	if (drc == NULL) {
		say(ERROR, "Could not find drc index 0x%x to add to phb list\n",
		    my_drc_index);
		return -1;
	}

	phb_node = alloc_dr_node(drc, PHB_DEV, ofdt_path);
	if (phb_node == NULL) {
		say(ERROR, "Could not allocate PHB node for drc index 0x%x\n",
		    my_drc_index);
		return -1;
	}

	phb_node->is_owned = 1;

	add_pci_vio_node(ofdt_path, PHB_DEV, &phb_node->children);

	phb_node->next = *node_list;
	*node_list = phb_node;
	return 0;
}
/**
 * add_child_node
 *
 * Create information about the Open Firmware node and
 * add that information to the appropriate per-node list of
 * Open Firmware nodes. Also create the corresponding information
 * for any PCI device.
 *
 * NOTES:
 *	1) does not need to be concerned about one or more Open
 *	   Firmware nodes having the used-by-rtas property present.
 *	   One of the RTAS services used during removing a PCI adapter
 *	   must take the appropriate action (most likely eliminate RTAS
 *	   usage) in this case.
 *	2) Open Firmware node RPA physical location code:
 *
 *	  [Un.m-]Pn[-Pm]-In[[/Zn]-An]
 *
 *	  where
 *		Un.m is for the enclosure for multi-enclosue systems
 *		Pn is for the planar
 *		In is for the slot
 *		/Zn is for the connector on the adapter card
 *		An is for the device connected to the adapter
 *
 *	  note
 *		There may be multiple levels of planars [Pm].
 *
 * RECOVERY OPERATION:
 *	1) This function does not add the Open Firmware node if the user
 *	   mode process has exceeded all available malloc space. This
 *	   should not happen based on the rather small total amount of
 *	   memory allocation required. The node is marked as skip.
 *	2) This function does not add the device information if there
 *	   is a problem initializing device. The node is marked as skip.
 *
 * @param parent
 * @param child_path
 */
static void
add_child_node(struct dr_node *parent, char *child_path)
{
	struct dr_connector *drc_list, *drc;
	char loc_code[DR_BUF_SZ];
	char *slash;
	struct dr_node *child;
	uint my_drc_index;
	int rc;

	assert(parent != NULL);
	assert(strlen(child_path) != 0);

	/* Make sure that the Open Firmware node is not added twice
	 * in case the ibm,my-drc-index property is put in all nodes
	 * for the adapter instead of just the ones at the connector.
	 */
	if (parent->children != NULL) {
		struct dr_node *tmp;
		for (tmp = parent->children; tmp; tmp = tmp->next) {
			if (! strcmp(tmp->ofdt_path, child_path))
				return;
		}
	}

	/* Create the Open Firmware node's information and insert that
	 * information into the node's list based on the node's RPA
	 * physical location code.  Ignore the OF node if the node
	 * does not have an RPA physical location code because that is
	 * a firmware error.
	 */
	rc = get_property(child_path, "ibm,loc-code", &loc_code, DR_BUF_SZ);
	if (rc)
		return;

	/* Skip the Open Firmware node if it is a device node. Determine that
	 * the node is for a device by looking for a hyphen after the last
	 * slash (...-In/Z1-An).
	 */
	slash = strrchr(loc_code, '/');
	if (slash != NULL) {
		char *hyphen;
		hyphen = strchr(slash, '-');
		if (hyphen != NULL)
			return;

		*slash = '\0';
	}

	if (parent->dev_type == PCI_HP_DEV) { 	/* hotplug */
		/* Squadrons don't have "/" in devices' (scsi,
		 * ethernet, tokenring ...) loc-code strings.
		 *
		 * Skip the Open Firmware node if the node's RPA
		 * physical location code does not match the node's
		 * location code.  Ignore the connector information,
		 * i.e. information after last slash if no hyphen
		 * follows.
		 */
		if ((strcmp(parent->drc_name, loc_code) != 0)
		    && (slash != NULL)) {
			parent->skip = 1;
			return;
		}
	}

	/* Restore the slash because the full RPA location code
	 * is saved for each OF node so that the connector
	 * information can be used to sort the OF node list for
	 * each node.
	 */
	if (slash != NULL)
		*slash = '/';

	if (get_my_drc_index(child_path, &my_drc_index))
		return;

	/* need the drc-info in the dir above */
	slash = strrchr(child_path, '/');
	*slash = '\0';
	drc_list = get_drc_info(child_path);
	*slash = '/';

	for (drc = drc_list; drc != NULL; drc = drc->next) {
		if (drc->index == my_drc_index)
			break;
	}

	/* Allocate space for the Open Firmware node information.  */
	child = alloc_dr_node(drc, parent->dev_type, child_path);
	if (child == NULL) {
		parent->skip = 1;
		return;
	}

	if ((! strcmp(parent->drc_type, "SLOT"))
	    && (parent->dev_type == PCI_DLPAR_DEV))
		snprintf(child->ofdt_dname, DR_STR_MAX, "%s",
			 parent->ofdt_dname);
	else
		get_property(child_path, "name", child->ofdt_dname,
			     sizeof(child->ofdt_dname));

	switch (parent->dev_type) {
	    case PCI_HP_DEV:
	    case PCI_DLPAR_DEV:
	    {
		get_ofdt_uint_property(child_path, "vendor-id",
				       &child->pci_vendor_id);
		get_ofdt_uint_property(child_path, "device-id",
				       &child->pci_device_id);
		get_ofdt_uint_property(child_path, "class_code",
				       &child->pci_class_code);
		break;
	    }

	    case HEA_DEV:
	    {
		child->dev_type = HEA_PORT_DEV;

		get_ofdt_uint_property(child_path, "ibm,hea-port-no",
				       &child->hea_port_no);
		get_ofdt_uint_property(child_path, "ibm,hea-port-tenure",
				       &child->hea_port_tenure);
		break;
	    }
	}

	child->next = parent->children;
	parent->children = child;
}
/**
 * init_cpu_info
 * @brief Initialize cpu information
 *
 * @returns pointer to cpu_info on success, NULL otherwise
 */
static int
init_cpu_info(struct dr_info *dr_info)
{
	struct dr_connector *drc_list, *drc;
	struct dr_node *cpu, *cpu_list = NULL;
	DIR *d;
	struct dirent *de;
	int rc = 0;

	drc_list = get_drc_info(CPU_OFDT_BASE);
	if (drc_list == NULL) {
		say(ERROR, "Could not get drc information for %s\n",
		    CPU_OFDT_BASE);
		return -1;
	}

	/* For cpu dlpar, we need a list of all possible cpus on the system */
	for (drc = drc_list; drc; drc = drc->next) {
		cpu = alloc_dr_node(drc, CPU_DEV, NULL);
		if (cpu == NULL) {
			say(ERROR, "Could not allocate CPU node structure: "
			    "%s\n", strerror(errno));
			free_node(cpu_list);
			return -1;
		}

		cpu->next = cpu_list;
		cpu_list = cpu;
	}

	d = opendir(CPU_OFDT_BASE);
	if (d == NULL) {
		say(ERROR, "Could not open %s: %s\n", CPU_OFDT_BASE,
		    strerror(errno));
		free_node(cpu_list);
		return -1;
	}

	while ((de = readdir(d)) != NULL) {
		char path[DR_PATH_MAX];

		if ((de->d_type != DT_DIR) || is_dot_dir(de->d_name))
			continue;

		if (! strncmp(de->d_name, "PowerPC", 7)) {
			uint32_t my_drc_index;

			memset(path, 0, 1024);
			sprintf(path, "%s/%s", CPU_OFDT_BASE, de->d_name);

			rc = get_my_drc_index(path, &my_drc_index);
			if (rc) {
				say(ERROR, "Could not retrieve drc index for "
				    "%s\n", path);
				break;
			}

			for (cpu = cpu_list; cpu; cpu = cpu->next) {
				if (cpu->drc_index == my_drc_index)
					break;
			}

			if (cpu == NULL) {
				say(ERROR, "Could not find cpu with drc index "
				    "%x\n", my_drc_index);
				rc = -1;
				break;
			}

			rc = update_cpu_node(cpu, path, dr_info);
			if (rc)
				break;

			say(DEBUG, "Found cpu %s\n", cpu->name);
		}
	}

	closedir(d);

	if (rc)
		free_node(cpu_list);
	else
		dr_info->all_cpus = cpu_list;

	return rc;
}
Exemple #9
0
/**
 * get_mem_node_lmbs
 * @brief Retrieve lmbs from the OF device tree represented as memory@XXX nodes
 *
 * @param lmb_list pointer to lmb list head to populate
 * @returns 0 on success, !0 on failure
 */
int
get_mem_node_lmbs(struct lmb_list_head *lmb_list)
{
	struct dr_node *lmb;
	struct dirent *de;
	DIR *d;
	int rc = 0;

	d = opendir(OFDT_BASE);
	if (d == NULL) {
		report_unknown_error(__FILE__, __LINE__);
		say(DEBUG, "Could not open %s\n", OFDT_BASE);
		return -1;
	}

	while ((de = readdir(d)) != NULL) {
		char path[1024];
		uint32_t my_drc_index;
		char *tmp;

		if (de->d_type != DT_DIR)
			continue;

		if (strncmp(de->d_name, "memory@", 7))
			continue;

		memset(path, 0, 1024);
		sprintf(path, "%s/%s", OFDT_BASE, de->d_name);

		if (get_my_drc_index(path, &my_drc_index))
			continue;

		for (lmb = lmb_list->lmbs; lmb; lmb = lmb->next) {
			if (lmb->drc_index == my_drc_index)
				break;
		}

		if (lmb == NULL) {
			say(DEBUG, "Could not find LMB with drc-index of %x\n",
			    my_drc_index);
			rc = -1;
			break;
		}

		snprintf(lmb->ofdt_path, DR_PATH_MAX, "%s", path);
		lmb->is_owned = 1;

		/* Find the lmb size for this lmb */
		/* XXX Do nothing with size and break if it can't be found
		 * but don't change rc to indicate failure?
		 * Why not continue? If we break, set rc=-1? */
		if (get_lmb_size(lmb))
			break;

		/* Find the physical address for this lmb */
		tmp = strrchr(lmb->ofdt_path, '@');
		if (tmp == NULL) {
			say(DEBUG, "Could not determine physical address for "
			    "%s\n", lmb->ofdt_path);
			/* XXX No rc change? */
			break;
		}

		lmb->lmb_address = strtoull(tmp + 1, NULL, 16);

		/* find the associated sysfs memory blocks */
		rc = get_mem_scns(lmb);
		if (rc)
			break;
	}

	closedir(d);
	return rc;
}