staging/rdma/hfi1: HFI reports wrong offline disabled reason when cable removed

Removing QSFP cable should report 'No Local Media' instead of
'Transient' as reported by 'opaportinfo'.
Workaround is to change the state to
OPA_LINKDOWN_REASON_LOCAL_MEDIA_NOT_INSTALLED in cable handler.

With cable still removed, 'opaportinfo bounce' should not cause a
state change to Polling, as reported by 'opaportinfo'.
Resolution is to prevent physical state change from Offline->Polling.

Use a macro to mask lower nibble of OPA_LINKDOWN_REASON* as needed
for offline_disabled_reason.

Reviewed-by: Mike Marciniszyn <mike.marciniszyn@intel.com>
Reviewed-by: Easwar Hariharan <easwar.hariharan@intel.com>
Reviewed-by: Dean Luick <dean.luick@intel.com>
Reported-by: Todd Rimmer <todd.rimmer@intel.com>
Signed-off-by: Bryan Morgan <bryan.c.morgan@intel.com>
Signed-off-by: Jubin John <jubin.john@intel.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
This commit is contained in:
Bryan Morgan 2016-02-03 14:30:49 -08:00 committed by Doug Ledford
parent 9cd70e1bbf
commit a9c05e350c
4 changed files with 34 additions and 13 deletions

View File

@ -5857,6 +5857,16 @@ static void handle_qsfp_int(struct hfi1_devdata *dd, u32 src_ctx, u64 reg)
ASIC_QSFP2_INVERT :
ASIC_QSFP1_INVERT,
qsfp_int_mgmt);
if ((ppd->offline_disabled_reason >
HFI1_ODR_MASK(
OPA_LINKDOWN_REASONLOCAL_MEDIA_NOT_INSTALLED)) ||
(ppd->offline_disabled_reason ==
HFI1_ODR_MASK(OPA_LINKDOWN_REASON_NONE)))
ppd->offline_disabled_reason =
HFI1_ODR_MASK(
OPA_LINKDOWN_REASONLOCAL_MEDIA_NOT_INSTALLED);
if (ppd->host_link_state == HLS_DN_POLL) {
/*
* The link is still in POLL. This means
@ -9615,9 +9625,10 @@ static int goto_offline(struct hfi1_pportdata *ppd, u8 rem_reason)
ret);
return -EINVAL;
}
if (ppd->offline_disabled_reason == OPA_LINKDOWN_REASON_NONE)
if (ppd->offline_disabled_reason ==
HFI1_ODR_MASK(OPA_LINKDOWN_REASON_NONE))
ppd->offline_disabled_reason =
OPA_LINKDOWN_REASON_TRANSIENT;
HFI1_ODR_MASK(OPA_LINKDOWN_REASON_TRANSIENT);
}
if (do_wait) {
@ -9972,7 +9983,8 @@ int set_link_state(struct hfi1_pportdata *ppd, u32 state)
ret = -EINVAL;
}
}
ppd->offline_disabled_reason = OPA_LINKDOWN_REASON_NONE;
ppd->offline_disabled_reason =
HFI1_ODR_MASK(OPA_LINKDOWN_REASON_NONE);
/*
* If an error occurred above, go back to offline. The
* caller may reschedule another attempt.

View File

@ -99,6 +99,8 @@ extern unsigned long hfi1_cap_mask;
#define HFI1_CAP_IS_USET(cap) (!!HFI1_CAP_UGET(cap))
#define HFI1_MISC_GET() ((hfi1_cap_mask >> HFI1_CAP_MISC_SHIFT) & \
HFI1_CAP_MISC_MASK)
/* Offline Disabled Reason is 4-bits */
#define HFI1_ODR_MASK(rsn) ((rsn) & OPA_PI_MASK_OFFLINE_REASON)
/*
* Control context is always 0 and handles the error packets.

View File

@ -152,7 +152,8 @@ void handle_linkup_change(struct hfi1_devdata *dd, u32 linkup)
/* physical link went up */
ppd->linkup = 1;
ppd->offline_disabled_reason = OPA_LINKDOWN_REASON_NONE;
ppd->offline_disabled_reason =
HFI1_ODR_MASK(OPA_LINKDOWN_REASON_NONE);
/* link widths are not available until the link is fully up */
get_linkup_link_widths(ppd);

View File

@ -590,12 +590,11 @@ static int __subn_get_opa_portinfo(struct opa_smp *smp, u32 am, u8 *data,
pi->port_states.ledenable_offlinereason |=
ppd->is_sm_config_started << 5;
pi->port_states.ledenable_offlinereason |=
ppd->offline_disabled_reason & OPA_PI_MASK_OFFLINE_REASON;
ppd->offline_disabled_reason;
#else
pi->port_states.offline_reason = ppd->neighbor_normal << 4;
pi->port_states.offline_reason |= ppd->is_sm_config_started << 5;
pi->port_states.offline_reason |= ppd->offline_disabled_reason &
OPA_PI_MASK_OFFLINE_REASON;
pi->port_states.offline_reason |= ppd->offline_disabled_reason;
#endif /* PI_LED_ENABLE_SUP */
pi->port_states.portphysstate_portstate =
@ -929,6 +928,14 @@ static int port_states_transition_allowed(struct hfi1_pportdata *ppd,
physical_allowed == HFI_TRANSITION_IGNORED)
return HFI_TRANSITION_IGNORED;
/*
* A change request of Physical Port State from
* 'Offline' to 'Polling' should be ignored.
*/
if ((physical_old == OPA_PORTPHYSSTATE_OFFLINE) &&
(physical_new == IB_PORTPHYSSTATE_POLLING))
return HFI_TRANSITION_IGNORED;
/*
* Either physical_allowed or logical_allowed is
* HFI_TRANSITION_ALLOWED.
@ -993,11 +1000,11 @@ static int set_port_states(struct hfi1_pportdata *ppd, struct opa_smp *smp,
set_link_state(ppd, link_state);
if (link_state == HLS_DN_DISABLE &&
(ppd->offline_disabled_reason >
OPA_LINKDOWN_REASON_SMA_DISABLED ||
HFI1_ODR_MASK(OPA_LINKDOWN_REASON_SMA_DISABLED) ||
ppd->offline_disabled_reason ==
OPA_LINKDOWN_REASON_NONE))
HFI1_ODR_MASK(OPA_LINKDOWN_REASON_NONE)))
ppd->offline_disabled_reason =
OPA_LINKDOWN_REASON_SMA_DISABLED;
HFI1_ODR_MASK(OPA_LINKDOWN_REASON_SMA_DISABLED);
/*
* Don't send a reply if the response would be sent
* through the disabled port.
@ -1710,12 +1717,11 @@ static int __subn_get_opa_psi(struct opa_smp *smp, u32 am, u8 *data,
psi->port_states.ledenable_offlinereason |=
ppd->is_sm_config_started << 5;
psi->port_states.ledenable_offlinereason |=
ppd->offline_disabled_reason & OPA_PI_MASK_OFFLINE_REASON;
ppd->offline_disabled_reason;
#else
psi->port_states.offline_reason = ppd->neighbor_normal << 4;
psi->port_states.offline_reason |= ppd->is_sm_config_started << 5;
psi->port_states.offline_reason |= ppd->offline_disabled_reason &
OPA_PI_MASK_OFFLINE_REASON;
psi->port_states.offline_reason |= ppd->offline_disabled_reason;
#endif /* PI_LED_ENABLE_SUP */
psi->port_states.portphysstate_portstate =