static ssize_t remove_slot_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t nbytes) { char drc_name[MAX_DRC_NAME_LEN]; int rc; char *end; if (nbytes >= MAX_DRC_NAME_LEN) return 0; memcpy(drc_name, buf, nbytes); end = strchr(drc_name, '\n'); if (!end) end = &drc_name[nbytes]; *end = '\0'; rc = dlpar_remove_slot(drc_name); if (rc) return rc; return nbytes; }
/** * add_phb * * @param op * @returns 0 on success, !0 otherwise */ static int add_phb(struct options *opts) { struct dr_node *phb = NULL; int rc, n_children = 0; phb = get_node_by_name(opts->usr_drc_name, PHB_NODES); if (phb) { say(ERROR, "PHB is already owned by this partition\n"); rc = RC_ALREADY_OWN; goto phb_add_error; } rc = acquire_phb(opts->usr_drc_name, &phb); if (rc) return rc; rc = acquire_hp_children(phb->ofdt_path, &n_children); if (rc) { if (release_phb(phb)) { say(ERROR, "Unknown failure. Data may be out of sync " "and\nthe system may require a reboot.\n"); } goto phb_add_error; } rc = dlpar_add_slot(phb->drc_name); if (rc) { if (n_children) { if (release_hp_children(phb->drc_name)) { say(ERROR, "Unknown failure. Data may be out " "of sync and\nthe system may require " "a reboot.\n"); } } if (release_phb(phb)) { say(ERROR, "Unknown failure. Data may be out of sync " "and\nthe system may require a reboot.\n"); } goto phb_add_error; } if (n_children) { rc = enable_hp_children(phb->drc_name); if (rc) { say(ERROR, "Adapter configuration failed.\n"); if (release_hp_children(phb->drc_name)) { say(ERROR, "Unknown failure. Data may be out " "of sync and \nthe system may require " "a reboot.\n"); } if (dlpar_remove_slot(phb->drc_name)) { say(DEBUG, "remove %s from hotplug subsystem " "failed\n", phb->drc_name); say(ERROR, "Unknown failure. Data may be out " "of sync and \nthe system may require " "a reboot.\n"); } if (release_phb(phb)) { say(ERROR, "Unknown failure. Data may be out " "of sync and \nthe system may require " "a reboot.\n"); } } } phb_add_error: if (phb) free_node(phb); return rc; }
/** * remove_phb * * @param op * @returns 0 on success, !0 otherwise */ static int remove_phb(struct options *opts) { struct dr_node *phb; struct dr_node *child; struct dr_node *hp_list; int rc = 0; phb = get_node_by_name(opts->usr_drc_name, PHB_NODES); if (phb == NULL) { say(ERROR, "Could not find PHB %s\n", opts->usr_drc_name); return RC_NONEXISTENT; } /* If this PHB still owns children that are not hotplug, fail. */ for (child = phb->children; child; child = child->next) { if ((child->is_owned) && (child->dev_type != PCI_HP_DEV)) { rc = -1; goto phb_remove_error; } } /* Now, disable any hotplug children */ hp_list = get_hp_nodes(); for (child = phb->children; child; child = child->next) { struct dr_node *slot; if (child->dev_type == PCI_HP_DEV) { rc = disable_hp_children(child->drc_name); if (rc) say(ERROR, "failed to disable hotplug children\n"); /* find dr_node corresponding to child slot's drc_name */ for (slot = hp_list; slot; slot = slot->next) if (!strcmp(child->drc_name, slot->drc_name)) break; /* release any hp children from the slot */ rc = release_hp_children_from_node(slot); if (rc && rc != -EINVAL) { say(ERROR, "failed to release hotplug children\n"); goto phb_remove_error; } } } /* 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_remove_slot(phb->drc_name); if (rc) { say(ERROR, "kernel remove failed for %s, rc = %d\n", phb->drc_name, rc); goto phb_remove_error; } rc = release_phb(phb); phb_remove_error: if (phb) free_node(phb); return rc; }