Showing error 1733

User: Jiri Slaby
Error type: Invalid Pointer Dereference
Error type description: A pointer which is invalid is being dereferenced
File location: drivers/infiniband/hw/mlx4/mad.c
Line in file: 215
Project: Linux Kernel
Project version: 2.6.28
Tools: Smatch (1.59)
Entered: 2013-09-10 20:24:52 UTC


Source:

  1/*
  2 * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved.
  3 *
  4 * This software is available to you under a choice of one of two
  5 * licenses.  You may choose to be licensed under the terms of the GNU
  6 * General Public License (GPL) Version 2, available from the file
  7 * COPYING in the main directory of this source tree, or the
  8 * OpenIB.org BSD license below:
  9 *
 10 *     Redistribution and use in source and binary forms, with or
 11 *     without modification, are permitted provided that the following
 12 *     conditions are met:
 13 *
 14 *      - Redistributions of source code must retain the above
 15 *        copyright notice, this list of conditions and the following
 16 *        disclaimer.
 17 *
 18 *      - Redistributions in binary form must reproduce the above
 19 *        copyright notice, this list of conditions and the following
 20 *        disclaimer in the documentation and/or other materials
 21 *        provided with the distribution.
 22 *
 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 30 * SOFTWARE.
 31 */
 32
 33#include <rdma/ib_mad.h>
 34#include <rdma/ib_smi.h>
 35
 36#include <linux/mlx4/cmd.h>
 37
 38#include "mlx4_ib.h"
 39
 40enum {
 41        MLX4_IB_VENDOR_CLASS1 = 0x9,
 42        MLX4_IB_VENDOR_CLASS2 = 0xa
 43};
 44
 45int mlx4_MAD_IFC(struct mlx4_ib_dev *dev, int ignore_mkey, int ignore_bkey,
 46                 int port, struct ib_wc *in_wc, struct ib_grh *in_grh,
 47                 void *in_mad, void *response_mad)
 48{
 49        struct mlx4_cmd_mailbox *inmailbox, *outmailbox;
 50        void *inbox;
 51        int err;
 52        u32 in_modifier = port;
 53        u8 op_modifier = 0;
 54
 55        inmailbox = mlx4_alloc_cmd_mailbox(dev->dev);
 56        if (IS_ERR(inmailbox))
 57                return PTR_ERR(inmailbox);
 58        inbox = inmailbox->buf;
 59
 60        outmailbox = mlx4_alloc_cmd_mailbox(dev->dev);
 61        if (IS_ERR(outmailbox)) {
 62                mlx4_free_cmd_mailbox(dev->dev, inmailbox);
 63                return PTR_ERR(outmailbox);
 64        }
 65
 66        memcpy(inbox, in_mad, 256);
 67
 68        /*
 69         * Key check traps can't be generated unless we have in_wc to
 70         * tell us where to send the trap.
 71         */
 72        if (ignore_mkey || !in_wc)
 73                op_modifier |= 0x1;
 74        if (ignore_bkey || !in_wc)
 75                op_modifier |= 0x2;
 76
 77        if (in_wc) {
 78                struct {
 79                        __be32                my_qpn;
 80                        u32                reserved1;
 81                        __be32                rqpn;
 82                        u8                sl;
 83                        u8                g_path;
 84                        u16                reserved2[2];
 85                        __be16                pkey;
 86                        u32                reserved3[11];
 87                        u8                grh[40];
 88                } *ext_info;
 89
 90                memset(inbox + 256, 0, 256);
 91                ext_info = inbox + 256;
 92
 93                ext_info->my_qpn = cpu_to_be32(in_wc->qp->qp_num);
 94                ext_info->rqpn   = cpu_to_be32(in_wc->src_qp);
 95                ext_info->sl     = in_wc->sl << 4;
 96                ext_info->g_path = in_wc->dlid_path_bits |
 97                        (in_wc->wc_flags & IB_WC_GRH ? 0x80 : 0);
 98                ext_info->pkey   = cpu_to_be16(in_wc->pkey_index);
 99
100                if (in_grh)
101                        memcpy(ext_info->grh, in_grh, 40);
102
103                op_modifier |= 0x4;
104
105                in_modifier |= in_wc->slid << 16;
106        }
107
108        err = mlx4_cmd_box(dev->dev, inmailbox->dma, outmailbox->dma,
109                           in_modifier, op_modifier,
110                           MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C);
111
112        if (!err)
113                memcpy(response_mad, outmailbox->buf, 256);
114
115        mlx4_free_cmd_mailbox(dev->dev, inmailbox);
116        mlx4_free_cmd_mailbox(dev->dev, outmailbox);
117
118        return err;
119}
120
121static void update_sm_ah(struct mlx4_ib_dev *dev, u8 port_num, u16 lid, u8 sl)
122{
123        struct ib_ah *new_ah;
124        struct ib_ah_attr ah_attr;
125
126        if (!dev->send_agent[port_num - 1][0])
127                return;
128
129        memset(&ah_attr, 0, sizeof ah_attr);
130        ah_attr.dlid     = lid;
131        ah_attr.sl       = sl;
132        ah_attr.port_num = port_num;
133
134        new_ah = ib_create_ah(dev->send_agent[port_num - 1][0]->qp->pd,
135                              &ah_attr);
136        if (IS_ERR(new_ah))
137                return;
138
139        spin_lock(&dev->sm_lock);
140        if (dev->sm_ah[port_num - 1])
141                ib_destroy_ah(dev->sm_ah[port_num - 1]);
142        dev->sm_ah[port_num - 1] = new_ah;
143        spin_unlock(&dev->sm_lock);
144}
145
146/*
147 * Snoop SM MADs for port info and P_Key table sets, so we can
148 * synthesize LID change and P_Key change events.
149 */
150static void smp_snoop(struct ib_device *ibdev, u8 port_num, struct ib_mad *mad)
151{
152        struct ib_event event;
153
154        if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
155             mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) &&
156            mad->mad_hdr.method == IB_MGMT_METHOD_SET) {
157                if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO) {
158                        struct ib_port_info *pinfo =
159                                (struct ib_port_info *) ((struct ib_smp *) mad)->data;
160
161                        update_sm_ah(to_mdev(ibdev), port_num,
162                                     be16_to_cpu(pinfo->sm_lid),
163                                     pinfo->neighbormtu_mastersmsl & 0xf);
164
165                        event.device               = ibdev;
166                        event.element.port_num = port_num;
167
168                        if (pinfo->clientrereg_resv_subnetto & 0x80)
169                                event.event    = IB_EVENT_CLIENT_REREGISTER;
170                        else
171                                event.event    = IB_EVENT_LID_CHANGE;
172
173                        ib_dispatch_event(&event);
174                }
175
176                if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PKEY_TABLE) {
177                        event.device               = ibdev;
178                        event.event               = IB_EVENT_PKEY_CHANGE;
179                        event.element.port_num = port_num;
180                        ib_dispatch_event(&event);
181                }
182        }
183}
184
185static void node_desc_override(struct ib_device *dev,
186                               struct ib_mad *mad)
187{
188        if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
189             mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) &&
190            mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP &&
191            mad->mad_hdr.attr_id == IB_SMP_ATTR_NODE_DESC) {
192                spin_lock(&to_mdev(dev)->sm_lock);
193                memcpy(((struct ib_smp *) mad)->data, dev->node_desc, 64);
194                spin_unlock(&to_mdev(dev)->sm_lock);
195        }
196}
197
198static void forward_trap(struct mlx4_ib_dev *dev, u8 port_num, struct ib_mad *mad)
199{
200        int qpn = mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_SUBN_LID_ROUTED;
201        struct ib_mad_send_buf *send_buf;
202        struct ib_mad_agent *agent = dev->send_agent[port_num - 1][qpn];
203        int ret;
204
205        if (agent) {
206                send_buf = ib_create_send_mad(agent, qpn, 0, 0, IB_MGMT_MAD_HDR,
207                                              IB_MGMT_MAD_DATA, GFP_ATOMIC);
208                /*
209                 * We rely here on the fact that MLX QPs don't use the
210                 * address handle after the send is posted (this is
211                 * wrong following the IB spec strictly, but we know
212                 * it's OK for our devices).
213                 */
214                spin_lock(&dev->sm_lock);
215                memcpy(send_buf->mad, mad, sizeof *mad);
216                if ((send_buf->ah = dev->sm_ah[port_num - 1]))
217                        ret = ib_post_send_mad(send_buf, NULL);
218                else
219                        ret = -EINVAL;
220                spin_unlock(&dev->sm_lock);
221
222                if (ret)
223                        ib_free_send_mad(send_buf);
224        }
225}
226
227int mlx4_ib_process_mad(struct ib_device *ibdev, int mad_flags,        u8 port_num,
228                        struct ib_wc *in_wc, struct ib_grh *in_grh,
229                        struct ib_mad *in_mad, struct ib_mad *out_mad)
230{
231        u16 slid;
232        int err;
233
234        slid = in_wc ? in_wc->slid : be16_to_cpu(IB_LID_PERMISSIVE);
235
236        if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP && slid == 0) {
237                forward_trap(to_mdev(ibdev), port_num, in_mad);
238                return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
239        }
240
241        if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
242            in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) {
243                if (in_mad->mad_hdr.method   != IB_MGMT_METHOD_GET &&
244                    in_mad->mad_hdr.method   != IB_MGMT_METHOD_SET &&
245                    in_mad->mad_hdr.method   != IB_MGMT_METHOD_TRAP_REPRESS)
246                        return IB_MAD_RESULT_SUCCESS;
247
248                /*
249                 * Don't process SMInfo queries or vendor-specific
250                 * MADs -- the SMA can't handle them.
251                 */
252                if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO ||
253                    ((in_mad->mad_hdr.attr_id & IB_SMP_ATTR_VENDOR_MASK) ==
254                     IB_SMP_ATTR_VENDOR_MASK))
255                        return IB_MAD_RESULT_SUCCESS;
256        } else if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT ||
257                   in_mad->mad_hdr.mgmt_class == MLX4_IB_VENDOR_CLASS1   ||
258                   in_mad->mad_hdr.mgmt_class == MLX4_IB_VENDOR_CLASS2   ||
259                   in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_CONG_MGMT) {
260                if (in_mad->mad_hdr.method  != IB_MGMT_METHOD_GET &&
261                    in_mad->mad_hdr.method  != IB_MGMT_METHOD_SET)
262                        return IB_MAD_RESULT_SUCCESS;
263        } else
264                return IB_MAD_RESULT_SUCCESS;
265
266        err = mlx4_MAD_IFC(to_mdev(ibdev),
267                           mad_flags & IB_MAD_IGNORE_MKEY,
268                           mad_flags & IB_MAD_IGNORE_BKEY,
269                           port_num, in_wc, in_grh, in_mad, out_mad);
270        if (err)
271                return IB_MAD_RESULT_FAILURE;
272
273        if (!out_mad->mad_hdr.status) {
274                smp_snoop(ibdev, port_num, in_mad);
275                node_desc_override(ibdev, out_mad);
276        }
277
278        /* set return bit in status of directed route responses */
279        if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
280                out_mad->mad_hdr.status |= cpu_to_be16(1 << 15);
281
282        if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS)
283                /* no response for trap repress */
284                return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
285
286        return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
287}
288
289static void send_handler(struct ib_mad_agent *agent,
290                         struct ib_mad_send_wc *mad_send_wc)
291{
292        ib_free_send_mad(mad_send_wc->send_buf);
293}
294
295int mlx4_ib_mad_init(struct mlx4_ib_dev *dev)
296{
297        struct ib_mad_agent *agent;
298        int p, q;
299        int ret;
300
301        for (p = 0; p < dev->num_ports; ++p)
302                for (q = 0; q <= 1; ++q) {
303                        agent = ib_register_mad_agent(&dev->ib_dev, p + 1,
304                                                      q ? IB_QPT_GSI : IB_QPT_SMI,
305                                                      NULL, 0, send_handler,
306                                                      NULL, NULL);
307                        if (IS_ERR(agent)) {
308                                ret = PTR_ERR(agent);
309                                goto err;
310                        }
311                        dev->send_agent[p][q] = agent;
312                }
313
314        return 0;
315
316err:
317        for (p = 0; p < dev->num_ports; ++p)
318                for (q = 0; q <= 1; ++q)
319                        if (dev->send_agent[p][q])
320                                ib_unregister_mad_agent(dev->send_agent[p][q]);
321
322        return ret;
323}
324
325void mlx4_ib_mad_cleanup(struct mlx4_ib_dev *dev)
326{
327        struct ib_mad_agent *agent;
328        int p, q;
329
330        for (p = 0; p < dev->num_ports; ++p) {
331                for (q = 0; q <= 1; ++q) {
332                        agent = dev->send_agent[p][q];
333                        dev->send_agent[p][q] = NULL;
334                        ib_unregister_mad_agent(agent);
335                }
336
337                if (dev->sm_ah[p])
338                        ib_destroy_ah(dev->sm_ah[p]);
339        }
340}