diff options
author | Ursula Braun <ubraun@linux.vnet.ibm.com> | 2018-01-26 03:28:46 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-01-26 10:41:56 -0500 |
commit | da05bf2981f1035fc37d4253ccf0692faf19b8c0 (patch) | |
tree | 27ff80d935e5e41b46b8c3f67ec9cddab9a1fee7 | |
parent | a81e4affe1789a3d1010f219ad53382a760aa2ea (diff) |
net/smc: handle device, port, and QP error events
RoCE device changes cause an IB event, processed in the global event
handler for the ROCE device. Problems for a certain Queue Pair cause a QP
event, processed in the QP event handler for this QP.
Among those events are port errors and other fatal device errors. All
link groups using such a port or device must be terminated in those cases.
Signed-off-by: Ursula Braun <ubraun@linux.vnet.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/smc/smc_ib.c | 38 |
1 files changed, 25 insertions, 13 deletions
diff --git a/net/smc/smc_ib.c b/net/smc/smc_ib.c index 90f1a7f9085c..2a8957bd6d38 100644 --- a/net/smc/smc_ib.c +++ b/net/smc/smc_ib.c | |||
@@ -141,6 +141,17 @@ out: | |||
141 | return rc; | 141 | return rc; |
142 | } | 142 | } |
143 | 143 | ||
144 | static void smc_ib_port_terminate(struct smc_ib_device *smcibdev, u8 ibport) | ||
145 | { | ||
146 | struct smc_link_group *lgr, *l; | ||
147 | |||
148 | list_for_each_entry_safe(lgr, l, &smc_lgr_list.list, list) { | ||
149 | if (lgr->lnk[SMC_SINGLE_LINK].smcibdev == smcibdev && | ||
150 | lgr->lnk[SMC_SINGLE_LINK].ibport == ibport) | ||
151 | smc_lgr_terminate(lgr); | ||
152 | } | ||
153 | } | ||
154 | |||
144 | /* process context wrapper for might_sleep smc_ib_remember_port_attr */ | 155 | /* process context wrapper for might_sleep smc_ib_remember_port_attr */ |
145 | static void smc_ib_port_event_work(struct work_struct *work) | 156 | static void smc_ib_port_event_work(struct work_struct *work) |
146 | { | 157 | { |
@@ -151,6 +162,8 @@ static void smc_ib_port_event_work(struct work_struct *work) | |||
151 | for_each_set_bit(port_idx, &smcibdev->port_event_mask, SMC_MAX_PORTS) { | 162 | for_each_set_bit(port_idx, &smcibdev->port_event_mask, SMC_MAX_PORTS) { |
152 | smc_ib_remember_port_attr(smcibdev, port_idx + 1); | 163 | smc_ib_remember_port_attr(smcibdev, port_idx + 1); |
153 | clear_bit(port_idx, &smcibdev->port_event_mask); | 164 | clear_bit(port_idx, &smcibdev->port_event_mask); |
165 | if (!smc_ib_port_active(smcibdev, port_idx + 1)) | ||
166 | smc_ib_port_terminate(smcibdev, port_idx + 1); | ||
154 | } | 167 | } |
155 | } | 168 | } |
156 | 169 | ||
@@ -165,15 +178,7 @@ static void smc_ib_global_event_handler(struct ib_event_handler *handler, | |||
165 | 178 | ||
166 | switch (ibevent->event) { | 179 | switch (ibevent->event) { |
167 | case IB_EVENT_PORT_ERR: | 180 | case IB_EVENT_PORT_ERR: |
168 | port_idx = ibevent->element.port_num - 1; | ||
169 | set_bit(port_idx, &smcibdev->port_event_mask); | ||
170 | schedule_work(&smcibdev->port_event_work); | ||
171 | /* fall through */ | ||
172 | case IB_EVENT_DEVICE_FATAL: | 181 | case IB_EVENT_DEVICE_FATAL: |
173 | /* tbd in follow-on patch: | ||
174 | * abnormal close of corresponding connections | ||
175 | */ | ||
176 | break; | ||
177 | case IB_EVENT_PORT_ACTIVE: | 182 | case IB_EVENT_PORT_ACTIVE: |
178 | port_idx = ibevent->element.port_num - 1; | 183 | port_idx = ibevent->element.port_num - 1; |
179 | set_bit(port_idx, &smcibdev->port_event_mask); | 184 | set_bit(port_idx, &smcibdev->port_event_mask); |
@@ -186,7 +191,8 @@ static void smc_ib_global_event_handler(struct ib_event_handler *handler, | |||
186 | 191 | ||
187 | void smc_ib_dealloc_protection_domain(struct smc_link *lnk) | 192 | void smc_ib_dealloc_protection_domain(struct smc_link *lnk) |
188 | { | 193 | { |
189 | ib_dealloc_pd(lnk->roce_pd); | 194 | if (lnk->roce_pd) |
195 | ib_dealloc_pd(lnk->roce_pd); | ||
190 | lnk->roce_pd = NULL; | 196 | lnk->roce_pd = NULL; |
191 | } | 197 | } |
192 | 198 | ||
@@ -203,14 +209,18 @@ int smc_ib_create_protection_domain(struct smc_link *lnk) | |||
203 | 209 | ||
204 | static void smc_ib_qp_event_handler(struct ib_event *ibevent, void *priv) | 210 | static void smc_ib_qp_event_handler(struct ib_event *ibevent, void *priv) |
205 | { | 211 | { |
212 | struct smc_ib_device *smcibdev = | ||
213 | (struct smc_ib_device *)ibevent->device; | ||
214 | u8 port_idx; | ||
215 | |||
206 | switch (ibevent->event) { | 216 | switch (ibevent->event) { |
207 | case IB_EVENT_DEVICE_FATAL: | 217 | case IB_EVENT_DEVICE_FATAL: |
208 | case IB_EVENT_GID_CHANGE: | 218 | case IB_EVENT_GID_CHANGE: |
209 | case IB_EVENT_PORT_ERR: | 219 | case IB_EVENT_PORT_ERR: |
210 | case IB_EVENT_QP_ACCESS_ERR: | 220 | case IB_EVENT_QP_ACCESS_ERR: |
211 | /* tbd in follow-on patch: | 221 | port_idx = ibevent->element.port_num - 1; |
212 | * abnormal close of corresponding connections | 222 | set_bit(port_idx, &smcibdev->port_event_mask); |
213 | */ | 223 | schedule_work(&smcibdev->port_event_work); |
214 | break; | 224 | break; |
215 | default: | 225 | default: |
216 | break; | 226 | break; |
@@ -219,7 +229,8 @@ static void smc_ib_qp_event_handler(struct ib_event *ibevent, void *priv) | |||
219 | 229 | ||
220 | void smc_ib_destroy_queue_pair(struct smc_link *lnk) | 230 | void smc_ib_destroy_queue_pair(struct smc_link *lnk) |
221 | { | 231 | { |
222 | ib_destroy_qp(lnk->roce_qp); | 232 | if (lnk->roce_qp) |
233 | ib_destroy_qp(lnk->roce_qp); | ||
223 | lnk->roce_qp = NULL; | 234 | lnk->roce_qp = NULL; |
224 | } | 235 | } |
225 | 236 | ||
@@ -462,6 +473,7 @@ static void smc_ib_cleanup_per_ibdev(struct smc_ib_device *smcibdev) | |||
462 | { | 473 | { |
463 | if (!smcibdev->initialized) | 474 | if (!smcibdev->initialized) |
464 | return; | 475 | return; |
476 | smcibdev->initialized = 0; | ||
465 | smc_wr_remove_dev(smcibdev); | 477 | smc_wr_remove_dev(smcibdev); |
466 | ib_unregister_event_handler(&smcibdev->event_handler); | 478 | ib_unregister_event_handler(&smcibdev->event_handler); |
467 | ib_destroy_cq(smcibdev->roce_cq_recv); | 479 | ib_destroy_cq(smcibdev->roce_cq_recv); |