aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUrsula Braun <ubraun@linux.vnet.ibm.com>2018-01-26 03:28:46 -0500
committerDavid S. Miller <davem@davemloft.net>2018-01-26 10:41:56 -0500
commitda05bf2981f1035fc37d4253ccf0692faf19b8c0 (patch)
tree27ff80d935e5e41b46b8c3f67ec9cddab9a1fee7
parenta81e4affe1789a3d1010f219ad53382a760aa2ea (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.c38
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
144static 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 */
145static void smc_ib_port_event_work(struct work_struct *work) 156static 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
187void smc_ib_dealloc_protection_domain(struct smc_link *lnk) 192void 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
204static void smc_ib_qp_event_handler(struct ib_event *ibevent, void *priv) 210static 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
220void smc_ib_destroy_queue_pair(struct smc_link *lnk) 230void 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);