/**
 * get_dlpar_nodes
 *
 * @param list_type
 * @returns pointer to node list on success, NULL otherwise
 */
struct dr_node *
get_dlpar_nodes(uint32_t node_types)
{
	struct dr_connector *drc_list = NULL;
	struct dr_node *node_list = NULL;
	struct dirent *de;
	DIR *d;
	char path[1024];

	say(DEBUG, "Getting node types 0x%08x\n", node_types);

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

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

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

		if ((! strcmp(de->d_name, "vdevice"))
		    && (node_types & VIO_NODES))
			add_pci_vio_node(path, VIO_DEV, &node_list);
		else if (! strncmp(de->d_name, "pci@", 4)) {
			if (node_types & PCI_NODES)
				add_pci_vio_node(path, PCI_DLPAR_DEV,
						 &node_list);
			else if (node_types & PHB_NODES) {
				if (drc_list == NULL)
					drc_list = get_drc_info(OFDT_BASE);
				add_phb_node(path, drc_list, &node_list);
			}
		} else if ((! strncmp(de->d_name, "lhea@", 5))
			 && (node_types & HEA_NODES)) {
			if (drc_list == NULL)
				drc_list = get_drc_info(OFDT_BASE);

			add_hea_node(path, drc_list, &node_list);
		}
	}

	closedir(d);

	if (node_list != NULL) {
		add_linux_devices(NULL, node_list);

		if (node_types & PHB_NODES)
			update_phb_ic_info(node_list);
	}

	return node_list;
}
/**
 * acquire_hp_children
 *
 * @param slot_of_path
 * @param n_acquired
 * @returns 0 on success, !0 otherwise
 */
int acquire_hp_children(char *slot_of_path, int *n_acquired)
{
	struct dr_connector *drc_list, *drc;
	int rc;
	int failure = 0, count = 0;

	drc_list = get_drc_info(slot_of_path);
	if (drc_list == NULL) {
		/* No hotplug-capable children */
		return 0;
	}

	for (drc = drc_list; drc != NULL; drc = drc->next) {
		if (is_hp_type(drc->type)) {
			rc = acquire_hp_resource(drc, slot_of_path);
			if (rc) {
				say(ERROR, "failed to acquire %s\n", drc->name);
				failure = 1;
			}
			count++;
		}
	}

	*n_acquired = count;
	return failure;
}
/**
 * add_pci_vio_node
 * @bried Add a PCI or virtual device node
 *
 * @param path ofdt path to this node
 * @param dev_type type of device
 * @param node_list pointer to list to add node to
 * @returns 0 on success, !0 otherwise
 */
static int
add_pci_vio_node(const char *path, int dev_type, struct dr_node **node_list)
{
	struct dr_connector *drc_list;
	struct dr_connector *drc;
	struct dr_node *node;
	int child_dev_type = 0;
	int rc = -1;

	drc_list = get_drc_info(path);
	if (drc_list == NULL)
		return -1;

	for (drc = drc_list; drc != NULL; drc = drc->next) {
		switch (dev_type) {
			case PCI_HP_DEV:
				if (! is_hp_type(drc->type))
					continue;
				child_dev_type = dev_type;
				break;

			case PCI_DLPAR_DEV:
			case VIO_DEV:
				if (! is_logical_type(drc->type))
					continue;
				child_dev_type = dev_type;
				break;
			case PHB_DEV:
				if (is_logical_type(drc->type))
					child_dev_type = PCI_DLPAR_DEV;
				else
					child_dev_type = PCI_HP_DEV;
				break;
		}

		node = alloc_dr_node(drc, child_dev_type, path);
		if (node == NULL) {
			say(ERROR, "Could not allocate pci/vio node\n");
			return -1;
		}

		if (child_dev_type == PCI_HP_DEV)
			node->is_owned = 1;

		rc = init_node(node);
		if (rc) {
			free(node);
			return rc;
		}

		node->next = *node_list;
		*node_list = node;
	}

	return rc;
}
Beispiel #4
0
/**
 * get_drc_by_name
 * @brief Retrieve a dr_connector with the specified drc_name
 *
 * This routine searches the drc lists for a dr_connector with the
 * specified name starting at the specified directory.  If a dr_connector
 * is found the root_dir that the dr_connector was found in is also
 * filled out.
 *
 * @param drc_name name of the dr_connector to search for
 * @param drc pointer to a drc to point to the found dr_connector
 * @param root_dir pointer to buf to fill in with root directory
 * @param start_dir, directory to start searching
 * @returns 0 on success (drc and root_dir filled in), !0 on failure
 */
int
get_drc_by_name(char *drc_name, struct dr_connector *drc, char *root_dir,
		char *start_dir)
{
        struct dr_connector *drc_list = NULL;
        struct dr_connector *drc_entry;
	struct dirent *de;
	DIR *d;
        int rc = -1;

	memset(drc, 0, sizeof(*drc));

	/* Try to get the drc in this directory */
        drc_list = get_drc_info(start_dir);
        if (drc_list == NULL)
		return -1;

	drc_entry = search_drc_list(drc_list, NULL, DRC_NAME, drc_name);
	if (drc_entry != NULL) {
		memcpy(drc, drc_entry, sizeof(*drc));
		sprintf(root_dir, "%s", start_dir);
                return 0;
        }

	/* If we didn't find it here, check the subdirs */
	d = opendir(start_dir);
	if (d == NULL)
		return -1;

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

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

		sprintf(dir_path, "%s/%s", start_dir, de->d_name);
		rc = get_drc_by_name(drc_name, drc, root_dir, dir_path);
		if (rc == 0)
			break;
	}
	closedir(d);

	return rc;
}
int
drslot_chrp_phb(struct options *opts)
{
    int rc = -1;

    if (! phb_dlpar_capable()) {
        say(ERROR, "DLPAR PHB operations are not supported on"
            "this kernel.");
        return rc;
    }

    if (!opts->usr_drc_name) {
        struct dr_connector *drc_list = get_drc_info(OFDT_BASE);
        opts->usr_drc_name = drc_index_to_name(opts->usr_drc_index,
                                               drc_list);
        if (!opts->usr_drc_name) {
            say(ERROR,
                "Could not locate DRC name for DRC index: 0x%x",
                opts->usr_drc_index);
            return -1;
        }
    }

    switch(opts->action) {
    case ADD:
        rc = add_phb(opts);
        break;
    case REMOVE:
        rc = remove_phb(opts);
        break;
    case QUERY:
        rc = query_phb(opts);
        break;
    }

    return rc;
}
/**
 * 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;
}
Beispiel #8
0
/**
 * get_lmbs
 * @brief Build a list of all possible lmbs for the system
 *
 * @param sort LMB_NORMAL_SORT or LMB_REVERSE_SORT to control sort order
 *
 * @return list of lmbs, NULL on failure
 */
struct lmb_list_head *
get_lmbs(unsigned int sort)
{
	struct lmb_list_head *lmb_list = NULL;
	struct dr_node *lmb = NULL;
	struct stat sbuf;
	char buf[DR_STR_MAX];
	int rc = 0;

	lmb_list = zalloc(sizeof(*lmb_list));
	if (lmb_list == NULL) {
		say(DEBUG, "Could not allocate LMB list head\n");
		return NULL;
	}

	lmb_list->sort = sort;

	rc = get_str_attribute("/sys/devices/system/memory",
			       "/block_size_bytes", &buf, DR_STR_MAX);
	if (rc) {
		say(DEBUG,
		    "Could not determine block size bytes for memory.\n");
		free_lmbs(lmb_list);
		return NULL;
	}

	block_sz_bytes = strtoul(buf, NULL, 16);

	/* We also need to know which lmbs are already allocated to
	 * the system and their corresponding memory sections as defined
	 * by sysfs.  Walk the device tree and update the appropriate
	 * lmb entries (and their memory sections) as we find their device
	 * tree entries.
	 */
	if (stat(DYNAMIC_RECONFIG_MEM, &sbuf)) {
		struct dr_connector *drc_list, *drc;

		drc_list = get_drc_info(OFDT_BASE);
		if (drc_list == NULL) {
			report_unknown_error(__FILE__, __LINE__);
			rc = -1;
		} else {
			/* For memory dlpar, we need a list of all
			 * posiible memory nodes for the system, initalize
			 * those here.
			 */
			for (drc = drc_list; drc; drc = drc->next) {
				if (strncmp(drc->name, "LMB", 3))
					continue;

				lmb = lmb_list_add(drc->index, lmb_list);
				if (!lmb) {
					say(ERROR, "Failed to add LMB (%x)\n",
					    drc->index);
					rc = -1;
					break;
				}

				lmb_list->lmbs_found++;
			}
		}

		say(INFO, "Maximum of %d LMBs\n", lmb_list->lmbs_found);
		rc = get_mem_node_lmbs(lmb_list);
	} else {
		/* A small hack to here to allow memory add to work in
		 * certain kernels.  Due to a bug in the kernel (see comment
		 * in acquire_lmb()) we need to get lmb info from both places.
		 * For a good kernel, the get_mem_node_lmbs routine will not
		 * update the lmb_list.
		 */
		rc = get_dynamic_reconfig_lmbs(lmb_list);
		if (! rc)
			rc = get_mem_node_lmbs(lmb_list);
	}

	if (rc) {
		free_lmbs(lmb_list);
		lmb_list = NULL;
	} else if (sort == LMB_RANDOM_SORT) {
		shuffle_lmbs(lmb_list);
	}

	return lmb_list;
}