]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/dev/mlx5/mlx5_ib/mlx5_ib_mad.c
MFC r322810 and r322830:
[FreeBSD/stable/10.git] / sys / dev / mlx5 / mlx5_ib / mlx5_ib_mad.c
1 /*-
2  * Copyright (c) 2013-2015, Mellanox Technologies, Ltd.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  * $FreeBSD$
26  */
27
28 #include <rdma/ib_mad.h>
29 #include <rdma/ib_smi.h>
30 #include <rdma/ib_pma.h>
31 #include "mlx5_ib.h"
32 #include <dev/mlx5/vport.h>
33
34 #define MAX_U32 0xffffffffULL
35 #define MAX_U16 0xffffUL
36
37 /* Counters should be saturate once they reach their maximum value */
38 #define ASSIGN_32BIT_COUNTER(counter, value) do {       \
39         if ((value) > MAX_U32)                          \
40                 counter = cpu_to_be32(MAX_U32);         \
41         else                                            \
42                 counter = cpu_to_be32(value);           \
43 } while (0)
44
45 /* Counters should be saturate once they reach their maximum value */
46 #define ASSIGN_16BIT_COUNTER(counter, value) do {       \
47         if ((value) > MAX_U16)                          \
48                 counter = cpu_to_be16(MAX_U16);         \
49         else                                            \
50                 counter = cpu_to_be16(value);           \
51 } while (0)
52
53 enum {
54         MLX5_IB_VENDOR_CLASS1 = 0x9,
55         MLX5_IB_VENDOR_CLASS2 = 0xa
56 };
57
58 int mlx5_MAD_IFC(struct mlx5_ib_dev *dev, int ignore_mkey, int ignore_bkey,
59                  u8 port, struct ib_wc *in_wc, struct ib_grh *in_grh,
60                  void *in_mad, void *response_mad)
61 {
62         u8 op_modifier = 0;
63
64         /* Key check traps can't be generated unless we have in_wc to
65          * tell us where to send the trap.
66          */
67         if (ignore_mkey || !in_wc)
68                 op_modifier |= 0x1;
69         if (ignore_bkey || !in_wc)
70                 op_modifier |= 0x2;
71
72         return mlx5_core_mad_ifc(dev->mdev, in_mad, response_mad, op_modifier, port);
73 }
74
75 static int process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
76                        struct ib_wc *in_wc, struct ib_grh *in_grh,
77                        struct ib_mad *in_mad, struct ib_mad *out_mad)
78 {
79         u16 slid;
80         int err;
81
82         slid = in_wc ? in_wc->slid : be16_to_cpu(IB_LID_PERMISSIVE);
83
84         if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP && slid == 0)
85                 return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
86
87         if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
88             in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) {
89                 if (in_mad->mad_hdr.method   != IB_MGMT_METHOD_GET &&
90                     in_mad->mad_hdr.method   != IB_MGMT_METHOD_SET &&
91                     in_mad->mad_hdr.method   != IB_MGMT_METHOD_TRAP_REPRESS)
92                         return IB_MAD_RESULT_SUCCESS;
93
94                 /* Don't process SMInfo queries -- the SMA can't handle them.
95                  */
96                 if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO)
97                         return IB_MAD_RESULT_SUCCESS;
98         } else if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT ||
99                    in_mad->mad_hdr.mgmt_class == MLX5_IB_VENDOR_CLASS1   ||
100                    in_mad->mad_hdr.mgmt_class == MLX5_IB_VENDOR_CLASS2   ||
101                    in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_CONG_MGMT) {
102                 if (in_mad->mad_hdr.method  != IB_MGMT_METHOD_GET &&
103                     in_mad->mad_hdr.method  != IB_MGMT_METHOD_SET)
104                         return IB_MAD_RESULT_SUCCESS;
105         } else {
106                 return IB_MAD_RESULT_SUCCESS;
107         }
108
109         err = mlx5_MAD_IFC(to_mdev(ibdev),
110                            mad_flags & IB_MAD_IGNORE_MKEY,
111                            mad_flags & IB_MAD_IGNORE_BKEY,
112                            port_num, in_wc, in_grh, in_mad, out_mad);
113         if (err)
114                 return IB_MAD_RESULT_FAILURE;
115
116         /* set return bit in status of directed route responses */
117         if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
118                 out_mad->mad_hdr.status |= cpu_to_be16(1 << 15);
119
120         if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS)
121                 /* no response for trap repress */
122                 return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
123
124         return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
125 }
126
127 static void pma_cnt_ext_assign(struct ib_pma_portcounters_ext *pma_cnt_ext,
128                                struct mlx5_vport_counters *vc)
129 {
130         pma_cnt_ext->port_xmit_data = cpu_to_be64((vc->transmitted_ib_unicast.octets +
131                                                    vc->transmitted_ib_multicast.octets) >> 2);
132         pma_cnt_ext->port_rcv_data = cpu_to_be64((vc->received_ib_unicast.octets +
133                                                   vc->received_ib_multicast.octets) >> 2);
134         pma_cnt_ext->port_xmit_packets = cpu_to_be64(vc->transmitted_ib_unicast.packets +
135                                                      vc->transmitted_ib_multicast.packets);
136         pma_cnt_ext->port_rcv_packets = cpu_to_be64(vc->received_ib_unicast.packets +
137                                                     vc->received_ib_multicast.packets);
138         pma_cnt_ext->port_unicast_xmit_packets = cpu_to_be64(vc->transmitted_ib_unicast.packets);
139         pma_cnt_ext->port_unicast_rcv_packets = cpu_to_be64(vc->received_ib_unicast.packets);
140         pma_cnt_ext->port_multicast_xmit_packets = cpu_to_be64(vc->transmitted_ib_multicast.packets);
141         pma_cnt_ext->port_multicast_rcv_packets = cpu_to_be64(vc->received_ib_multicast.packets);
142 }
143
144 static void pma_cnt_assign(struct ib_pma_portcounters *pma_cnt,
145                            struct mlx5_vport_counters *vc)
146 {
147         ASSIGN_32BIT_COUNTER(pma_cnt->port_xmit_data,
148                              (vc->transmitted_ib_unicast.octets +
149                               vc->transmitted_ib_multicast.octets) >> 2);
150         ASSIGN_32BIT_COUNTER(pma_cnt->port_rcv_data,
151                              (vc->received_ib_unicast.octets +
152                               vc->received_ib_multicast.octets) >> 2);
153         ASSIGN_32BIT_COUNTER(pma_cnt->port_xmit_packets,
154                              vc->transmitted_ib_unicast.packets +
155                              vc->transmitted_ib_multicast.packets);
156         ASSIGN_32BIT_COUNTER(pma_cnt->port_rcv_packets,
157                              vc->received_ib_unicast.packets +
158                              vc->received_ib_multicast.packets);
159 }
160
161 static int process_pma_cmd(struct ib_device *ibdev, u8 port_num,
162                            struct ib_mad *in_mad, struct ib_mad *out_mad)
163 {
164         struct mlx5_ib_dev *dev = to_mdev(ibdev);
165         struct mlx5_vport_counters *vc;
166         int err;
167         int ext;
168
169         vc = kzalloc(sizeof(*vc), GFP_KERNEL);
170         if (!vc)
171                 return -ENOMEM;
172
173         ext = in_mad->mad_hdr.attr_id == IB_PMA_PORT_COUNTERS_EXT;
174
175         err = mlx5_get_vport_counters(dev->mdev, port_num, vc);
176         if (!err) {
177                 if (ext) {
178                         struct ib_pma_portcounters_ext *pma_cnt_ext =
179                                 (struct ib_pma_portcounters_ext *)(out_mad->data + 40);
180
181                         pma_cnt_ext_assign(pma_cnt_ext, vc);
182                 } else {
183                         struct ib_pma_portcounters *pma_cnt =
184                                 (struct ib_pma_portcounters *)(out_mad->data + 40);
185
186                         ASSIGN_16BIT_COUNTER(pma_cnt->port_rcv_errors,
187                                              (u16)vc->received_errors.packets);
188
189                         pma_cnt_assign(pma_cnt, vc);
190                 }
191                 err = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
192         }
193
194         kfree(vc);
195         return err;
196 }
197
198 int mlx5_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
199                         struct ib_wc *in_wc, struct ib_grh *in_grh,
200                         struct ib_mad *in_mad, struct ib_mad *out_mad)
201 {
202         struct mlx5_ib_dev *dev = to_mdev(ibdev);
203         struct mlx5_core_dev *mdev = dev->mdev;
204
205         memset(out_mad->data, 0, sizeof(out_mad->data));
206
207         if (MLX5_CAP_GEN(mdev, vport_counters) &&
208             in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT &&
209             in_mad->mad_hdr.method == IB_MGMT_METHOD_GET) {
210                 /* TBD: read error counters from the PPCNT */
211                 return process_pma_cmd(ibdev, port_num, in_mad, out_mad);
212         } else {
213                 return process_mad(ibdev, mad_flags, port_num, in_wc, in_grh,
214                                    in_mad, out_mad);
215         }
216 }
217
218 int mlx5_query_ext_port_caps(struct mlx5_ib_dev *dev, u8 port)
219 {
220         struct ib_smp *in_mad  = NULL;
221         struct ib_smp *out_mad = NULL;
222         int err = -ENOMEM;
223         u16 packet_error;
224
225         in_mad  = kzalloc(sizeof(*in_mad), GFP_KERNEL);
226         out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
227         if (!in_mad || !out_mad)
228                 goto out;
229
230         init_query_mad(in_mad);
231         in_mad->attr_id = MLX5_ATTR_EXTENDED_PORT_INFO;
232         in_mad->attr_mod = cpu_to_be32(port);
233
234         err = mlx5_MAD_IFC(dev, 1, 1, 1, NULL, NULL, in_mad, out_mad);
235
236         packet_error = be16_to_cpu(out_mad->status);
237
238         dev->mdev->port_caps[port - 1].ext_port_cap = (!err && !packet_error) ?
239                 MLX_EXT_PORT_CAP_FLAG_EXTENDED_PORT_INFO : 0;
240
241 out:
242         kfree(in_mad);
243         kfree(out_mad);
244         return err;
245 }
246
247 int mlx5_query_smp_attr_node_info_mad_ifc(struct ib_device *ibdev,
248                                           struct ib_smp *out_mad)
249 {
250         struct ib_smp *in_mad = NULL;
251         int err = -ENOMEM;
252
253         in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL);
254         if (!in_mad)
255                 return -ENOMEM;
256
257         init_query_mad(in_mad);
258         in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;
259
260         err = mlx5_MAD_IFC(to_mdev(ibdev), 1, 1, 1, NULL, NULL, in_mad,
261                            out_mad);
262
263         kfree(in_mad);
264         return err;
265 }
266
267 int mlx5_query_system_image_guid_mad_ifc(struct ib_device *ibdev,
268                                          __be64 *sys_image_guid)
269 {
270         struct ib_smp *out_mad = NULL;
271         int err = -ENOMEM;
272
273         out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
274         if (!out_mad)
275                 return -ENOMEM;
276
277         err = mlx5_query_smp_attr_node_info_mad_ifc(ibdev, out_mad);
278         if (err)
279                 goto out;
280
281         memcpy(sys_image_guid, out_mad->data + 4, 8);
282
283 out:
284         kfree(out_mad);
285
286         return err;
287 }
288
289 int mlx5_query_max_pkeys_mad_ifc(struct ib_device *ibdev,
290                                  u16 *max_pkeys)
291 {
292         struct ib_smp *out_mad = NULL;
293         int err = -ENOMEM;
294
295         out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
296         if (!out_mad)
297                 return -ENOMEM;
298
299         err = mlx5_query_smp_attr_node_info_mad_ifc(ibdev, out_mad);
300         if (err)
301                 goto out;
302
303         *max_pkeys = be16_to_cpup((__be16 *)(out_mad->data + 28));
304
305 out:
306         kfree(out_mad);
307
308         return err;
309 }
310
311 int mlx5_query_vendor_id_mad_ifc(struct ib_device *ibdev,
312                                  u32 *vendor_id)
313 {
314         struct ib_smp *out_mad = NULL;
315         int err = -ENOMEM;
316
317         out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
318         if (!out_mad)
319                 return -ENOMEM;
320
321         err = mlx5_query_smp_attr_node_info_mad_ifc(ibdev, out_mad);
322         if (err)
323                 goto out;
324
325         *vendor_id = be32_to_cpup((__be32 *)(out_mad->data + 36)) & 0xffff;
326
327 out:
328         kfree(out_mad);
329
330         return err;
331 }
332
333 int mlx5_query_node_desc_mad_ifc(struct mlx5_ib_dev *dev, char *node_desc)
334 {
335         struct ib_smp *in_mad  = NULL;
336         struct ib_smp *out_mad = NULL;
337         int err = -ENOMEM;
338
339         in_mad  = kzalloc(sizeof(*in_mad), GFP_KERNEL);
340         out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
341         if (!in_mad || !out_mad)
342                 goto out;
343
344         init_query_mad(in_mad);
345         in_mad->attr_id = IB_SMP_ATTR_NODE_DESC;
346
347         err = mlx5_MAD_IFC(dev, 1, 1, 1, NULL, NULL, in_mad, out_mad);
348         if (err)
349                 goto out;
350
351         memcpy(node_desc, out_mad->data, 64);
352 out:
353         kfree(in_mad);
354         kfree(out_mad);
355         return err;
356 }
357
358 int mlx5_query_node_guid_mad_ifc(struct mlx5_ib_dev *dev, u64 *node_guid)
359 {
360         struct ib_smp *in_mad  = NULL;
361         struct ib_smp *out_mad = NULL;
362         int err = -ENOMEM;
363
364         in_mad  = kzalloc(sizeof(*in_mad), GFP_KERNEL);
365         out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
366         if (!in_mad || !out_mad)
367                 goto out;
368
369         init_query_mad(in_mad);
370         in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;
371
372         err = mlx5_MAD_IFC(dev, 1, 1, 1, NULL, NULL, in_mad, out_mad);
373         if (err)
374                 goto out;
375
376         memcpy(&dev->ib_dev.node_guid, out_mad->data + 12, 8);
377 out:
378         kfree(in_mad);
379         kfree(out_mad);
380         return err;
381 }
382
383 int mlx5_query_pkey_mad_ifc(struct ib_device *ibdev, u8 port, u16 index,
384                             u16 *pkey)
385 {
386         struct ib_smp *in_mad  = NULL;
387         struct ib_smp *out_mad = NULL;
388         int err = -ENOMEM;
389
390         in_mad  = kzalloc(sizeof(*in_mad), GFP_KERNEL);
391         out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
392         if (!in_mad || !out_mad)
393                 goto out;
394
395         init_query_mad(in_mad);
396         in_mad->attr_id  = IB_SMP_ATTR_PKEY_TABLE;
397         in_mad->attr_mod = cpu_to_be32(index / 32);
398
399         err = mlx5_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad,
400                            out_mad);
401         if (err)
402                 goto out;
403
404         *pkey = be16_to_cpu(((__be16 *)out_mad->data)[index % 32]);
405
406 out:
407         kfree(in_mad);
408         kfree(out_mad);
409         return err;
410 }
411
412 int mlx5_query_gids_mad_ifc(struct ib_device *ibdev, u8 port, int index,
413                             union ib_gid *gid)
414 {
415         struct ib_smp *in_mad  = NULL;
416         struct ib_smp *out_mad = NULL;
417         int err = -ENOMEM;
418
419         in_mad  = kzalloc(sizeof(*in_mad), GFP_KERNEL);
420         out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
421         if (!in_mad || !out_mad)
422                 goto out;
423
424         init_query_mad(in_mad);
425         in_mad->attr_id  = IB_SMP_ATTR_PORT_INFO;
426         in_mad->attr_mod = cpu_to_be32(port);
427
428         err = mlx5_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad,
429                            out_mad);
430         if (err)
431                 goto out;
432
433         memcpy(gid->raw, out_mad->data + 8, 8);
434
435         init_query_mad(in_mad);
436         in_mad->attr_id  = IB_SMP_ATTR_GUID_INFO;
437         in_mad->attr_mod = cpu_to_be32(index / 8);
438
439         err = mlx5_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad,
440                            out_mad);
441         if (err)
442                 goto out;
443
444         memcpy(gid->raw + 8, out_mad->data + (index % 8) * 8, 8);
445
446 out:
447         kfree(in_mad);
448         kfree(out_mad);
449         return err;
450 }
451
452 int mlx5_query_port_mad_ifc(struct ib_device *ibdev, u8 port,
453                             struct ib_port_attr *props)
454 {
455         struct mlx5_ib_dev *dev = to_mdev(ibdev);
456         struct mlx5_core_dev *mdev = dev->mdev;
457         struct ib_smp *in_mad  = NULL;
458         struct ib_smp *out_mad = NULL;
459         int ext_active_speed;
460         int err = -ENOMEM;
461
462         if (port < 1 || port > MLX5_CAP_GEN(mdev, num_ports)) {
463                 mlx5_ib_warn(dev, "invalid port number %d\n", port);
464                 return -EINVAL;
465         }
466
467         in_mad  = kzalloc(sizeof(*in_mad), GFP_KERNEL);
468         out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
469         if (!in_mad || !out_mad)
470                 goto out;
471
472         memset(props, 0, sizeof(*props));
473
474         init_query_mad(in_mad);
475         in_mad->attr_id  = IB_SMP_ATTR_PORT_INFO;
476         in_mad->attr_mod = cpu_to_be32(port);
477
478         err = mlx5_MAD_IFC(dev, 1, 1, port, NULL, NULL, in_mad, out_mad);
479         if (err) {
480                 mlx5_ib_warn(dev, "err %d\n", err);
481                 goto out;
482         }
483
484         props->lid              = be16_to_cpup((__be16 *)(out_mad->data + 16));
485         props->lmc              = out_mad->data[34] & 0x7;
486         props->sm_lid           = be16_to_cpup((__be16 *)(out_mad->data + 18));
487         props->sm_sl            = out_mad->data[36] & 0xf;
488         props->state            = out_mad->data[32] & 0xf;
489         props->phys_state       = out_mad->data[33] >> 4;
490         props->port_cap_flags   = be32_to_cpup((__be32 *)(out_mad->data + 20));
491         props->gid_tbl_len      = out_mad->data[50];
492         props->max_msg_sz       = 1 << MLX5_CAP_GEN(mdev, log_max_msg);
493         props->pkey_tbl_len     = mdev->port_caps[port - 1].pkey_table_len;
494         props->bad_pkey_cntr    = be16_to_cpup((__be16 *)(out_mad->data + 46));
495         props->qkey_viol_cntr   = be16_to_cpup((__be16 *)(out_mad->data + 48));
496         props->active_width     = out_mad->data[31] & 0xf;
497         props->active_speed     = out_mad->data[35] >> 4;
498         props->max_mtu          = out_mad->data[41] & 0xf;
499         props->active_mtu       = out_mad->data[36] >> 4;
500         props->subnet_timeout   = out_mad->data[51] & 0x1f;
501         props->max_vl_num       = out_mad->data[37] >> 4;
502         props->init_type_reply  = out_mad->data[41] >> 4;
503
504         /* Check if extended speeds (EDR/FDR/...) are supported */
505         if (props->port_cap_flags & IB_PORT_EXTENDED_SPEEDS_SUP) {
506                 ext_active_speed = out_mad->data[62] >> 4;
507
508                 switch (ext_active_speed) {
509                 case 1:
510                         props->active_speed = 16; /* FDR */
511                         break;
512                 case 2:
513                         props->active_speed = 32; /* EDR */
514                         break;
515                 }
516         }
517
518         /* If reported active speed is QDR, check if is FDR-10 */
519         if (props->active_speed == 4) {
520                 if (mdev->port_caps[port - 1].ext_port_cap &
521                     MLX_EXT_PORT_CAP_FLAG_EXTENDED_PORT_INFO) {
522                         init_query_mad(in_mad);
523                         in_mad->attr_id = MLX5_ATTR_EXTENDED_PORT_INFO;
524                         in_mad->attr_mod = cpu_to_be32(port);
525
526                         err = mlx5_MAD_IFC(dev, 1, 1, port,
527                                            NULL, NULL, in_mad, out_mad);
528                         if (err)
529                                 goto out;
530
531                         /* Checking LinkSpeedActive for FDR-10 */
532                         if (out_mad->data[15] & 0x1)
533                                 props->active_speed = 8;
534                 }
535         }
536
537 out:
538         kfree(in_mad);
539         kfree(out_mad);
540
541         return err;
542 }