mirror of
https://github.com/torvalds/linux.git
synced 2026-09-12 12:34:02 +02:00
s390/qeth: allow bridgeport queries despite OS_MISMATCH
When HiperSockets interfaces on the same VCHID span different OS
families, reads of the sysfs attributes bridge_role and bridge_state
fail with -EPERM if bridge port ownership belongs to another OS family.
As a result, userspace tools such as 'lszdev -ii' cannot retrieve
bridge_role and bridge_state, even though firmware returns valid bridge
port data for QUERY_BRIDGE_PORTS requests.
The firmware reports IPA_RC_SBP_IQD_OS_MISMATCH (0x0010) to indicate
that bridge port ownership belongs to a different OS family. For
QUERY_BRIDGE_PORTS operations, firmware still returns valid bridge port
data (role=none, state=inactive) together with a primary return code of
0x0000 (success).
Allow QUERY_BRIDGE_PORTS requests to return the bridge port data
provided by the firmware despite OS_MISMATCH. To make the OS family
mismatch visible to userspace, represent the firmware-reported role
"none" as "none (OS family mismatch)" while preserving the reported
bridge_state.
The behavior for non-QUERY bridge port commands is unchanged; SET
operations continue to return -EPERM when another OS family owns the
bridge port.
This restores readability of bridge_role and bridge_state.
Fixes: 1b05cf6285 ("qeth: Include error message for "OS Mismatch"")
Cc: stable@vger.kernel.org
Suggested-by: Halil Pasic <pasic@linux.ibm.com>
Reviewed-by: Alexandra Winter <wintera@linux.ibm.com>
Signed-off-by: Nagamani PV <nagamani@linux.ibm.com>
Link: https://patch.msgid.link/20260901155344.3561483-1-nagamani@linux.ibm.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
38b6be1010
commit
74f27fc864
|
|
@ -13,7 +13,8 @@ extern const struct attribute_group *qeth_l2_attr_groups[];
|
|||
|
||||
int qeth_bridgeport_query_ports(struct qeth_card *card,
|
||||
enum qeth_sbp_roles *role,
|
||||
enum qeth_sbp_states *state);
|
||||
enum qeth_sbp_states *state,
|
||||
bool *os_mismatch);
|
||||
int qeth_bridgeport_setrole(struct qeth_card *card, enum qeth_sbp_roles role);
|
||||
int qeth_bridgeport_an_set(struct qeth_card *card, int enable);
|
||||
|
||||
|
|
|
|||
|
|
@ -1158,7 +1158,7 @@ static void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card)
|
|||
qeth_bridgeport_setrole(card, card->options.sbp.role);
|
||||
/* Let the callback function refresh the stored role value. */
|
||||
qeth_bridgeport_query_ports(card, &card->options.sbp.role,
|
||||
NULL);
|
||||
NULL, NULL);
|
||||
}
|
||||
if (card->options.sbp.hostnotification) {
|
||||
if (qeth_bridgeport_an_set(card, 1))
|
||||
|
|
@ -1545,6 +1545,7 @@ struct _qeth_sbp_cbctl {
|
|||
struct {
|
||||
enum qeth_sbp_roles *role;
|
||||
enum qeth_sbp_states *state;
|
||||
bool *os_mismatch;
|
||||
} qports;
|
||||
} data;
|
||||
};
|
||||
|
|
@ -1721,10 +1722,19 @@ static int qeth_bridgeport_query_ports_cb(struct qeth_card *card,
|
|||
struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
|
||||
struct _qeth_sbp_cbctl *cbctl = (struct _qeth_sbp_cbctl *)reply->param;
|
||||
struct qeth_sbp_port_data *qports;
|
||||
u16 sbp_rc;
|
||||
int rc;
|
||||
|
||||
QETH_CARD_TEXT(card, 2, "brqprtcb");
|
||||
rc = qeth_bridgeport_makerc(card, cmd);
|
||||
sbp_rc = cmd->data.sbp.hdr.return_code;
|
||||
|
||||
/* on OS family mismatch, query still returns valid port data;
|
||||
* treat as success
|
||||
*/
|
||||
if (sbp_rc == IPA_RC_SBP_IQD_OS_MISMATCH && !cmd->hdr.return_code)
|
||||
rc = 0;
|
||||
else
|
||||
rc = qeth_bridgeport_makerc(card, cmd);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
@ -1740,6 +1750,9 @@ static int qeth_bridgeport_query_ports_cb(struct qeth_card *card,
|
|||
if (cbctl->data.qports.state)
|
||||
*cbctl->data.qports.state = qports->entry[0].state;
|
||||
}
|
||||
if (cbctl->data.qports.os_mismatch)
|
||||
*cbctl->data.qports.os_mismatch =
|
||||
(sbp_rc == IPA_RC_SBP_IQD_OS_MISMATCH);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1748,13 +1761,17 @@ static int qeth_bridgeport_query_ports_cb(struct qeth_card *card,
|
|||
* @card: qeth_card structure pointer.
|
||||
* @role: Role of the port: 0-none, 1-primary, 2-secondary.
|
||||
* @state: State of the port: 0-inactive, 1-standby, 2-active.
|
||||
* @os_mismatch: if non-NULL, set to true when firmware reports
|
||||
* OS family mismatch.
|
||||
*
|
||||
* Returns negative errno-compatible error indication or 0 on success.
|
||||
*
|
||||
* 'role' and 'state' are not updated in case of hardware operation failure.
|
||||
* 'role', 'state' and 'os_mismatch' are not updated in case of
|
||||
* hardware operation failure.
|
||||
*/
|
||||
int qeth_bridgeport_query_ports(struct qeth_card *card,
|
||||
enum qeth_sbp_roles *role, enum qeth_sbp_states *state)
|
||||
enum qeth_sbp_roles *role, enum qeth_sbp_states *state,
|
||||
bool *os_mismatch)
|
||||
{
|
||||
struct qeth_cmd_buffer *iob;
|
||||
struct _qeth_sbp_cbctl cbctl = {
|
||||
|
|
@ -1762,6 +1779,7 @@ int qeth_bridgeport_query_ports(struct qeth_card *card,
|
|||
.qports = {
|
||||
.role = role,
|
||||
.state = state,
|
||||
.os_mismatch = os_mismatch,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ static ssize_t qeth_bridge_port_role_state_show(struct device *dev,
|
|||
{
|
||||
struct qeth_card *card = dev_get_drvdata(dev);
|
||||
enum qeth_sbp_states state = QETH_SBP_STATE_INACTIVE;
|
||||
bool os_mismatch = false;
|
||||
int rc = 0;
|
||||
char *word;
|
||||
|
||||
|
|
@ -25,7 +26,7 @@ static ssize_t qeth_bridge_port_role_state_show(struct device *dev,
|
|||
if (qeth_card_hw_is_reachable(card) &&
|
||||
card->options.sbp.supported_funcs)
|
||||
rc = qeth_bridgeport_query_ports(card,
|
||||
&card->options.sbp.role, &state);
|
||||
&card->options.sbp.role, &state, &os_mismatch);
|
||||
if (!rc) {
|
||||
if (show_state)
|
||||
switch (state) {
|
||||
|
|
@ -52,6 +53,10 @@ static ssize_t qeth_bridge_port_role_state_show(struct device *dev,
|
|||
if (rc)
|
||||
QETH_CARD_TEXT_(card, 2, "SBP%02x:%02x",
|
||||
card->options.sbp.role, state);
|
||||
else if (!show_state &&
|
||||
card->options.sbp.role == QETH_SBP_ROLE_NONE &&
|
||||
os_mismatch)
|
||||
rc = sysfs_emit(buf, "%s (OS family mismatch)\n", word);
|
||||
else
|
||||
rc = sysfs_emit(buf, "%s\n", word);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user