Skip to content

Commit

Permalink
drmgr/pci: Add multipath partner device support for hotplug add
Browse files Browse the repository at this point in the history
If the PCI device has multipath partner device, the firmware
provides partner DRC index in "ibm,multipath-partner-drc"
property and this property is available in the PCI device node.
So when the PCI device add is initiated, both paths will be
added if the partner path is also configured and enabled with
the following steps:

- Identify slot and notify user to add the device
- Add the path and enable for the specified device
- Find the partner path DRC index from "ibm,multipath-partner-drc"
  property for the specified device
- Add the partner path if it is also configured
- Notify user about adding partner path

Since both paths will be using the same slot, LED indicators and
the slot identification will be done only for the primary device.

Signed-off-by: Haren Myneni <[email protected]>
Signed-off-by: Tyrel Datwyler <[email protected]>
  • Loading branch information
hmyneni authored and tyreld committed Jul 26, 2024
1 parent 1f8b5ef commit 4e6670d
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 60 deletions.
2 changes: 1 addition & 1 deletion src/drmgr/common_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ add_child_node(struct dr_node *parent, char *child_path)
* @param node
* @returns 0 on success, !0 otherwise
*/
static int
int
init_node(struct dr_node *node)
{
DIR *d;
Expand Down
162 changes: 103 additions & 59 deletions src/drmgr/drslot_chrp_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "rtas_calls.h"
#include "dr.h"
#include "drpci.h"
#include "ofdt.h"

static char *sw_error = "Internal software error. Contact your service "
"representative.\n";
Expand Down Expand Up @@ -367,27 +368,38 @@ static int do_identify(struct dr_node *all_nodes)
* off, isolated, and the LED is turned off.
*
* @param slot
* @param partner path or not
* @returns 0 on success, !0 on failure
*/
static int add_work(struct dr_node *node)
static int add_work(struct dr_node *node, bool partner_device)
{
int pow_state; /* Tells us if power was turned on when */
int iso_state; /* Tells us isolation state after */
int pow_state = POWER_OFF; /* Tells us if power was turned */
/* on when */
int iso_state = ISOLATE; /* Tells us isolation state after */
int rc;
struct of_node *new_nodes;/* nodes returned from configure_connector */

/* if we're continuing, set LED_ON and see if a card is really there. */
if (process_led(node, LED_ON))
return -1;
/*
* Already checked the card presence for the original device
* and both multipaths use the same card. So do not need to
* check the card presence again for the partner device.
*/
if (!partner_device) {
/* if we're continuing, set LED_ON and see if a card */
/* is really there. */
if (process_led(node, LED_ON))
return -1;

say(DEBUG, "is calling card_present\n");
rc = card_present(node, &pow_state, &iso_state);
if (!rc) {
say(ERROR, "No PCI card was detected in the specified "
"PCI slot.\n");
rtas_set_indicator(ISOLATION_STATE, node->drc_index, ISOLATE);
set_power(node->drc_power, POWER_OFF);
return -1;
say(DEBUG, "is calling card_present\n");
rc = card_present(node, &pow_state, &iso_state);
if (!rc) {
say(ERROR, "No PCI card was detected in the specified "
"PCI slot.\n");
rtas_set_indicator(ISOLATION_STATE, node->drc_index,
ISOLATE);
set_power(node->drc_power, POWER_OFF);
return -1;
}
}

if (!pow_state) {
Expand Down Expand Up @@ -461,7 +473,7 @@ static int add_work(struct dr_node *node)
* power to a slot off. The prompts the user to insert the new card
* into the slot.
*/
static int do_insert_card_work(struct dr_node *node)
static int do_insert_card_work(struct dr_node *node, bool partner_device)
{
int rc;

Expand Down Expand Up @@ -495,18 +507,18 @@ static int do_insert_card_work(struct dr_node *node)
return -1;
}

if (usr_prompt) {
if (usr_prompt && !partner_device) {
/* Prompt user to put in card and to press
* Enter to continue or other key to exit.
*/
if (process_led(node, LED_ACTION))
return -1;

printf("The visual indicator for the specified PCI slot has\n"
"been set to the action state. Insert the PCI card\n"
"into the identified slot, connect any devices to be\n"
"configured and press Enter to continue. Enter x to "
"exit.\n");
printf("The visual indicator for the PCI slot <%s>\n"
"has been set to the action state. Insert the PCI\n"
"card into the identified slot, connect any devices\n"
"to be configured and press Enter to continue.\n"
"Enter x to exit.\n", node->drc_name);

if (!(getchar() == '\n')) {
process_led(node, LED_OFF);
Expand Down Expand Up @@ -543,6 +555,58 @@ find_partner_node(struct dr_node *node, struct dr_node *all_nodes)
return partner_node;
}

static int insert_add_work(struct dr_node *node, bool partner_device)
{
int usr_key = USER_CONT;
int rc;

if (!partner_device) {
/* Prompt user only if in interactive mode. */
if (usr_prompt) {
if (usr_slot_identification)
usr_key = identify_slot(node);

if (usr_key == USER_QUIT) {
if (node->children == NULL)
process_led(node, LED_OFF);
else
process_led(node, LED_ON);
return 0;
}
}

if (node->children != NULL) {
/* If there's already something here, turn the
* LED on and exit with user error.
*/
process_led(node, LED_ON);
say(ERROR, "The specified PCI slot is already occupied.\n");
return -1;
}
}

if (!pci_hotplug_only) {
rc = do_insert_card_work(node, partner_device);
if (rc)
return rc;
}

/* Call the routine which determines
* what the user wants and does it.
*/
rc = add_work(node, partner_device);
if (rc)
return rc;

/*
* Need to populate w/ children to retrieve partner device
*/
if (init_node(node))
return -1;

return 1;
}

/**
* do_add
*
Expand All @@ -560,8 +624,7 @@ find_partner_node(struct dr_node *node, struct dr_node *all_nodes)
*/
static int do_add(struct dr_node *all_nodes)
{
struct dr_node *node;
int usr_key = USER_CONT;
struct dr_node *node, *partner_node = NULL;
int rc;

node = find_slot(usr_drc_name, 0, all_nodes, 0);
Expand All @@ -573,51 +636,32 @@ static int do_add(struct dr_node *all_nodes)
return -1;
}

/* Prompt user only if in interactive mode. */
if (usr_prompt) {
if (usr_slot_identification)
usr_key = identify_slot(node);

if (usr_key == USER_QUIT) {
if (node->children == NULL)
process_led(node, LED_OFF);
else
process_led(node, LED_ON);
return 0;
}
}

if (node->children != NULL) {
/* If there's already something here, turn the
* LED on and exit with user error.
*/
process_led(node, LED_ON);
say(ERROR, "The specified PCI slot is already occupied.\n");
return -1;
}
rc = insert_add_work(node, false);
if (rc <= 0)
return rc;

if (!pci_hotplug_only) {
rc = do_insert_card_work(node);
if (rc)
partner_node = find_partner_node(node, all_nodes);
if (partner_node) {
printf("<%s> and <%s> are\nmultipath partner devices. "
"So <%s> is\nalso added.\n", node->drc_name,
partner_node->drc_name, partner_node->drc_name);
rc = insert_add_work(partner_node, true);
if (rc <= 0)
return rc;
}

/* Call the routine which determines
* what the user wants and does it.
*/
rc = add_work(node);
if (rc)
return rc;

say(DEBUG, "is calling enable_slot to config adapter\n");

/* Try to config the adapter. The rpaphp module doesn't play well with
* qemu pci slots so we let the generic kernel pci code probe the device
* by rescanning the bus in the qemu virtio case.
*/
if (!pci_virtio)
if (!pci_virtio) {
set_hp_adapter_status(PHP_CONFIG_ADAPTER, node->drc_name);
else
if (partner_node)
set_hp_adapter_status(PHP_CONFIG_ADAPTER,
partner_node->drc_name);
} else
pci_rescan_bus();

return 0;
Expand Down Expand Up @@ -896,7 +940,7 @@ static int do_replace(struct dr_node *all_nodes)
}
}

rc = add_work(repl_node);
rc = add_work(repl_node, false);
if (rc)
return rc;

Expand All @@ -917,7 +961,7 @@ static int do_replace(struct dr_node *all_nodes)
if (remove_work(repl_node, false))
return -1;

rc = add_work(repl_node);
rc = add_work(repl_node, false);
if (!rc)
set_hp_adapter_status(PHP_CONFIG_ADAPTER,
repl_node->drc_name);
Expand Down
1 change: 1 addition & 0 deletions src/drmgr/ofdt.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ int get_min_common_depth(void);
int get_assoc_arrays(const char *dir, struct assoc_arrays *aa,
int min_common_depth);
int of_associativity_to_node(const char *dir, int min_common_depth);
int init_node(struct dr_node *);

static inline int aa_index_to_node(struct assoc_arrays *aa, uint32_t aa_index)
{
Expand Down

0 comments on commit 4e6670d

Please sign in to comment.