Whamcloud - gitweb
LU-16451 kfilnd: Improve CQ error logging
[fs/lustre-release.git] / lnet / klnds / kfilnd / kfilnd_cq.c
1
2 /*
3  * GPL HEADER START
4  *
5  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 only,
9  * as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License version 2 for more details (a copy is included
15  * in the LICENSE file that accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License
18  * version 2 along with this program; If not, see
19  * http://www.gnu.org/licenses/gpl-2.0.html
20  *
21  * GPL HEADER END
22  */
23 /*
24  * Copyright 2022 Hewlett Packard Enterprise Development LP
25  */
26 /*
27  * This file is part of Lustre, http://www.lustre.org/
28  */
29 /*
30  * kfilnd completion queue.
31  */
32 #include <linux/idr.h>
33 #include <linux/mutex.h>
34 #include <linux/byteorder/generic.h>
35
36 #include "kfilnd_cq.h"
37 #include "kfilnd_tn.h"
38 #include "kfilnd_ep.h"
39
40 void kfilnd_cq_process_error(struct kfilnd_ep *ep,
41                              struct kfi_cq_err_entry *error)
42 {
43         struct kfilnd_immediate_buffer *buf;
44         struct kfilnd_transaction *tn;
45         enum tn_events tn_event;
46         int status;
47
48         switch (error->flags) {
49         case KFI_MSG | KFI_RECV:
50                 if (error->err != ECANCELED) {
51                         KFILND_EP_ERROR(ep, "Dropping error receive event %d",
52                                         -error->err);
53                         return;
54                 }
55                 fallthrough;
56         case KFI_MSG | KFI_RECV | KFI_MULTI_RECV:
57                 buf = error->op_context;
58                 kfilnd_ep_imm_buffer_put(buf);
59                 return;
60
61         case KFI_TAGGED | KFI_RECV:
62         case KFI_TAGGED | KFI_RECV | KFI_REMOTE_CQ_DATA:
63         case KFI_TAGGED | KFI_RMA | KFI_READ | KFI_RECV:
64         case KFI_TAGGED | KFI_RMA | KFI_WRITE | KFI_RECV:
65                 tn = error->op_context;
66                 if (error->err == ECANCELED) {
67                         tn_event = TN_EVENT_TAG_RX_CANCEL;
68                         status = 0;
69                 } else {
70                         tn_event = TN_EVENT_TAG_RX_FAIL;
71                         status = -error->err;
72                 }
73                 break;
74
75         case KFI_MSG | KFI_SEND:
76                 tn = error->op_context;
77                 tn_event = TN_EVENT_TX_FAIL;
78                 status = -error->err;
79                 KFILND_EP_ERROR(ep,
80                                 "msg send error %d prov error %d flags %llx",
81                                 status, -error->prov_errno, error->flags);
82
83                 break;
84
85         case KFI_TAGGED | KFI_SEND:
86         case KFI_TAGGED | KFI_RMA | KFI_READ | KFI_SEND:
87         case KFI_TAGGED | KFI_RMA | KFI_WRITE | KFI_SEND:
88                 tn = error->op_context;
89                 tn_event = TN_EVENT_TAG_TX_FAIL;
90                 status = -error->err;
91                 KFILND_EP_ERROR(ep,
92                                 "tagged error %d prov error %d flags %llx",
93                                 status, -error->prov_errno, error->flags);
94                 break;
95
96         default:
97                 LBUG();
98         }
99
100         kfilnd_tn_event_handler(tn, tn_event, status);
101 }
102
103 static void kfilnd_cq_process_event(struct kfi_cq_data_entry *event)
104 {
105         struct kfilnd_immediate_buffer *buf;
106         struct kfilnd_msg *rx_msg;
107         struct kfilnd_transaction *tn;
108         enum tn_events tn_event;
109         int64_t status = 0;
110
111         switch (event->flags) {
112         case KFI_MSG | KFI_RECV:
113         case KFI_MSG | KFI_RECV | KFI_MULTI_RECV:
114                 buf = event->op_context;
115                 rx_msg = event->buf;
116
117                 kfilnd_tn_process_rx_event(buf, rx_msg, event->len);
118
119                 /* If the KFI_MULTI_RECV flag is set, the buffer was
120                  * unlinked.
121                  */
122                 if (event->flags & KFI_MULTI_RECV)
123                         kfilnd_ep_imm_buffer_put(buf);
124                 return;
125
126         case KFI_TAGGED | KFI_RECV | KFI_REMOTE_CQ_DATA:
127                 status = -1 * (int64_t)be64_to_cpu(event->data);
128                 fallthrough;
129         case KFI_TAGGED | KFI_RMA | KFI_READ | KFI_RECV:
130         case KFI_TAGGED | KFI_RMA | KFI_WRITE | KFI_RECV:
131                 tn_event = TN_EVENT_TAG_RX_OK;
132                 tn = event->op_context;
133                 break;
134
135         case KFI_TAGGED | KFI_SEND:
136         case KFI_TAGGED | KFI_RMA | KFI_READ | KFI_SEND:
137         case KFI_TAGGED | KFI_RMA | KFI_WRITE | KFI_SEND:
138                 tn = event->op_context;
139                 tn_event = TN_EVENT_TAG_TX_OK;
140                 break;
141
142         case KFI_MSG | KFI_SEND:
143                 tn = event->op_context;
144                 tn_event = TN_EVENT_TX_OK;
145                 break;
146
147         default:
148                 LBUG();
149         }
150
151         kfilnd_tn_event_handler(tn, tn_event, status);
152 }
153
154 static void kfilnd_cq_process_completion(struct work_struct *work)
155 {
156         struct kfilnd_cq_work *cq_work =
157                 container_of(work, struct kfilnd_cq_work, work);
158         struct kfilnd_cq *kfilnd_cq = cq_work->cq;
159         struct kfid_cq *cq = kfilnd_cq->cq;
160         struct kfi_cq_data_entry event;
161         struct kfi_cq_err_entry error;
162         ssize_t rc;
163         bool done = false;
164
165         /* Drain the KFI completion queue of all events and errors. */
166         while (!done) {
167                 rc = kfi_cq_read(cq, &event, 1);
168                 if (rc == -KFI_EAVAIL) {
169                         while (kfi_cq_readerr(cq, &error, 0) == 1)
170                                 kfilnd_cq_process_error(kfilnd_cq->ep, &error);
171                 } else if (rc == 1) {
172                         kfilnd_cq_process_event(&event);
173                 } else if (rc == -EAGAIN) {
174                         done = true;
175                 } else {
176                         KFILND_EP_ERROR(kfilnd_cq->ep, "Unexpected rc = %ld",
177                                         rc);
178                         done = true;
179                 }
180         }
181
182         if (kfilnd_ep_replays_pending(kfilnd_cq->ep))
183                 kfilnd_ep_flush_replay_queue(kfilnd_cq->ep);
184 }
185
186 static void kfilnd_cq_completion(struct kfid_cq *cq, void *context)
187 {
188         struct kfilnd_cq *kfilnd_cq = context;
189         struct kfilnd_cq_work *cq_work;
190         unsigned int i;
191
192         for (i = 0; i < kfilnd_cq->cq_work_count; i++) {
193                 cq_work = &kfilnd_cq->cq_works[i];
194                 queue_work_on(cq_work->work_cpu, kfilnd_wq, &cq_work->work);
195         }
196 }
197
198 #define CQ_ALLOC_SIZE(cpu_count) \
199         (sizeof(struct kfilnd_cq) + \
200          (sizeof(struct kfilnd_cq_work) * (cpu_count)))
201
202 struct kfilnd_cq *kfilnd_cq_alloc(struct kfilnd_ep *ep,
203                                   struct kfi_cq_attr *attr)
204 {
205         struct kfilnd_cq *cq;
206         cpumask_var_t *cpu_mask;
207         int rc;
208         unsigned int cpu_count = 0;
209         unsigned int cpu;
210         unsigned int i;
211         size_t alloc_size;
212         struct kfilnd_cq_work *cq_work;
213
214         cpu_mask = cfs_cpt_cpumask(lnet_cpt_table(), ep->end_cpt);
215         for_each_cpu(cpu, *cpu_mask)
216                 cpu_count++;
217
218         alloc_size = CQ_ALLOC_SIZE(cpu_count);
219         LIBCFS_CPT_ALLOC(cq, lnet_cpt_table(), ep->end_cpt, alloc_size);
220         if (!cq) {
221                 rc = -ENOMEM;
222                 KFILND_EP_ERROR(ep, "Failed to allocate memory: rc=%d", rc);
223                 goto err;
224         }
225
226         memset(cq, 0, alloc_size);
227
228         rc = kfi_cq_open(ep->end_dev->dom->domain, attr, &cq->cq,
229                          kfilnd_cq_completion, cq);
230         if (rc) {
231                 KFILND_EP_ERROR(ep, "Failed to open KFI CQ: rc=%d", rc);
232                 goto err_free_kfilnd_cq;
233         }
234
235         i = 0;
236         for_each_cpu(cpu, *cpu_mask) {
237                 cq_work = &cq->cq_works[i];
238                 cq_work->cq = cq;
239                 cq_work->work_cpu = cpu;
240                 INIT_WORK(&cq_work->work, kfilnd_cq_process_completion);
241                 i++;
242         }
243
244         cq->ep = ep;
245         cq->cq_work_count = cpu_count;
246
247         return cq;
248
249 err_free_kfilnd_cq:
250         LIBCFS_FREE(cq, alloc_size);
251 err:
252         return ERR_PTR(rc);
253 }
254
255 void kfilnd_cq_free(struct kfilnd_cq *cq)
256 {
257         flush_workqueue(kfilnd_wq);
258         kfi_close(&cq->cq->fid);
259         LIBCFS_FREE(cq, CQ_ALLOC_SIZE(cq->cq_work_count));
260 }