Fixes issues with DLPAR on some p7 platforms.
Signed-off-by: Brian King <br...@li...>
---
src/drmgr/drslot_chrp_phb.c | 164 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 164 insertions(+)
diff -puN src/drmgr/drslot_chrp_phb.c~dlpar_hp src/drmgr/drslot_chrp_phb.c
--- powerpc-utils/src/drmgr/drslot_chrp_phb.c~dlpar_hp 2010-08-10 16:00:35.000000000 -0500
+++ powerpc-utils-bjking1/src/drmgr/drslot_chrp_phb.c 2010-08-10 17:55:22.000000000 -0500
@@ -8,6 +8,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <dirent.h>
#include <librtas.h>
#include <errno.h>
#include "dr.h"
@@ -87,6 +88,156 @@ release_phb(struct dr_node *phb)
return rc;
}
+struct hpdev {
+ struct hpdev *next;
+ char path[256];
+ char devspec[256];
+};
+
+#define SYSFS_PCI_DEV_PATH "/sys/bus/pci/devices"
+
+static void free_hpdev_list(struct hpdev *hpdev_list)
+{
+ struct hpdev *hpdev;
+
+ while (hpdev_list) {
+ hpdev = hpdev_list;
+ hpdev_list = hpdev_list->next;
+ free(hpdev);
+ }
+}
+
+static int get_os_hp_devices(struct hpdev **hpdev_list)
+{
+ struct hpdev *hp_list = NULL;
+ struct hpdev *hpdev;
+ DIR *d;
+ struct dirent *de;
+ int rc = 0;
+
+ d = opendir(SYSFS_PCI_DEV_PATH);
+ if (!d) {
+ err_msg("Failed to open %s\n", SYSFS_PCI_DEV_PATH);
+ return -1;
+ }
+
+ while ((de = readdir(d)) != NULL) {
+ if (is_dot_dir(de->d_name))
+ continue;
+
+ hpdev = zalloc(sizeof(*hpdev));
+ if (!hpdev) {
+ rc = -1;
+ break;
+ }
+
+ rc = sprintf(hpdev->path, "%s/%s", SYSFS_PCI_DEV_PATH,
+ de->d_name);
+ if (rc < 0)
+ break;
+
+ rc = get_str_attribute(hpdev->path, "devspec", hpdev->devspec,
+ 256);
+ if (rc)
+ break;
+
+ dbg("HPDEV: %s\n %s\n", hpdev->path, hpdev->devspec);
+ hpdev->next = hp_list;
+ hp_list = hpdev;
+ }
+
+ closedir(d);
+
+ if (rc) {
+ free_hpdev_list(hp_list);
+ hp_list = NULL;
+ }
+
+ *hpdev_list = hp_list;
+ return rc;
+}
+
+static int hp_remove_os_device(struct hpdev *hpdev)
+{
+ FILE *file;
+ char path[256];
+ int rc;
+
+ sprintf(path, "%s/%s", hpdev->path, "remove");
+
+ file = fopen(path, "w");
+ if (!file)
+ return -1;
+
+ dbg("Removing %s\n", hpdev->path);
+ rc = fwrite("1", 1, 1, file);
+ if (rc == 1)
+ rc = 0;
+
+ fclose(file);
+ sleep(5);
+ return rc;
+}
+
+static int disable_os_hp_children_recurse(struct dr_node *phb,
+ struct hpdev *hpdev_list, char *ofpath)
+{
+ struct hpdev *hpdev;
+ DIR *d;
+ struct dirent *de;
+ int rc = 0;
+
+ d = opendir(ofpath);
+ if (!d)
+ return -1;
+
+ while ((de = readdir(d)) != NULL) {
+ char devspec[256];
+
+ if (is_dot_dir(de->d_name))
+ continue;
+
+ if (de->d_type == DT_DIR) {
+ char lpath[4096];
+ sprintf(lpath, "%s/%s", ofpath, de->d_name);
+ rc = disable_os_hp_children_recurse(phb, hpdev_list, lpath);
+ }
+
+ memset(devspec, 0, 256);
+ sprintf(devspec, "%s/%s", ofpath + strlen(OFDT_BASE),
+ de->d_name);
+
+ for (hpdev = hpdev_list; hpdev; hpdev = hpdev->next) {
+ if (!strcmp(hpdev->devspec, devspec)) {
+ rc = hp_remove_os_device(hpdev);
+ break;
+ }
+ }
+
+ if (rc) {
+ err_msg("Failed to hotplug remove %s\n", hpdev->path);
+ break;
+ }
+ }
+
+ closedir(d);
+ return rc;
+}
+
+static int disable_os_hp_children(struct dr_node *phb)
+{
+ struct hpdev *hpdev_list;
+ int rc = 0;
+
+ rc = get_os_hp_devices(&hpdev_list);
+ if (rc)
+ return -1;
+
+ rc = disable_os_hp_children_recurse(phb, hpdev_list, phb->ofdt_path);
+ free_hpdev_list(hpdev_list);
+ return rc;
+}
+
/**
* remove_phb
*
@@ -127,6 +278,19 @@ remove_phb(struct options *opts)
}
}
+ /* If there are any directories under the phb left at this point,
+ * they are OS hotplug devies. Note: this is different from DR
+ * hotplug devices. This really occurs on systems that do not
+ * support DR hotplug devices. The device tree does not get populated
+ * with drc information for these devices and such they do not appear
+ * on the list generated by the calls to get_node_*
+ *
+ * For these devices we simply hotplug remove them from the OS.
+ */
+ rc = disable_os_hp_children(phb);
+ if (rc)
+ goto phb_remove_error;
+
rc = dlpar_io_kernel_op(dlpar_remove_slot, phb->drc_name);
if (rc) {
err_msg("kernel remove failed for %s, rc = %d\n",
_
|