]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/ofed/drivers/infiniband/hw/mlx4/alias_GUID.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / ofed / drivers / infiniband / hw / mlx4 / alias_GUID.c
1 /*
2  * Copyright (c) 2012 Mellanox Technologies. 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 /*This file support the handling of the Alias GUID feature. */
34 /***********************************************************/
35 #include <rdma/ib_mad.h>
36 #include <rdma/ib_smi.h>
37 #include <rdma/ib_cache.h>
38 #include <rdma/ib_sa.h>
39 #include <rdma/ib_pack.h>
40 #include <linux/mlx4/cmd.h>
41 #include <linux/module.h>
42 #include <linux/errno.h>
43 #include <rdma/ib_user_verbs.h>
44 #include <linux/delay.h>
45 #include "mlx4_ib.h"
46
47 /*
48 The driver keeps the current state of all guids, as they are in the HW.
49 Whenever we receive an smp mad GUIDInfo record, the data will be cached.
50 */
51
52 struct mlx4_alias_guid_work_context {
53         u8 port;
54         struct mlx4_ib_dev     *dev ;
55         struct ib_sa_query     *sa_query;
56         struct completion       done;
57         int                     query_id;
58         struct list_head        list;
59         int                     block_num;
60 };
61
62 struct mlx4_next_alias_guid_work {
63         u8 port;
64         u8 block_num;
65         struct mlx4_sriov_alias_guid_info_rec_det rec_det;
66 };
67
68
69 void mlx4_ib_update_cache_on_guid_change(struct mlx4_ib_dev *dev, int block_num,
70                                          u8 port_num, u8 *p_data)
71 {
72         int i;
73         u64 guid_indexes;
74         int slave_id;
75         int port_index = port_num - 1;
76
77         if (!mlx4_is_master(dev->dev))
78                 return;
79
80         guid_indexes = be64_to_cpu((__force __be64) dev->sriov.alias_guid.
81                                    ports_guid[port_num - 1].
82                                    all_rec_per_port[block_num].guid_indexes);
83         pr_debug("port: %d, guid_indexes: 0x%llx\n", port_num, (long long)guid_indexes);
84
85         for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) {
86                 /* The location of the specific index starts from bit number 4
87                  * until bit num 11 */
88                 if (test_bit(i + 4, (unsigned long *)&guid_indexes)) {
89                         slave_id = (block_num * NUM_ALIAS_GUID_IN_REC) + i ;
90                         if (slave_id >= dev->dev->num_slaves) {
91                                 pr_debug("The last slave: %d\n", slave_id);
92                                 return;
93                         }
94
95                         /* cache the guid: */
96                         memcpy(&dev->sriov.demux[port_index].guid_cache[slave_id],
97                                &p_data[i * GUID_REC_SIZE],
98                                GUID_REC_SIZE);
99                 } else
100                         pr_debug("Guid number: %d in block: %d"
101                                  " was not updated\n", i, block_num);
102         }
103 }
104
105 static __be64 get_cached_alias_guid(struct mlx4_ib_dev *dev, int port, int index)
106 {
107         if (index >= NUM_ALIAS_GUID_PER_PORT) {
108                 pr_err("%s: ERROR: asked for index:%d\n", __func__, index);
109                 return (__force __be64) -1;
110         }
111         return *(__be64 *)&dev->sriov.demux[port - 1].guid_cache[index];
112 }
113
114
115 ib_sa_comp_mask mlx4_ib_get_aguid_comp_mask_from_ix(int index)
116 {
117         return IB_SA_COMP_MASK(4 + index);
118 }
119
120 /*
121  * Whenever new GUID is set/unset (guid table change) create event and
122  * notify the relevant slave (master also should be notified).
123  * If the GUID value is not as we have in the cache the slave will not be
124  * updated; in this case it waits for the smp_snoop or the port management
125  * event to call the function and to update the slave.
126  * block_number - the index of the block (16 blocks available)
127  * port_number - 1 or 2
128  */
129 void mlx4_ib_notify_slaves_on_guid_change(struct mlx4_ib_dev *dev,
130                                           int block_num, u8 port_num,
131                                           u8 *p_data)
132 {
133         int i;
134         u64 guid_indexes;
135         int slave_id;
136         enum slave_port_state new_state;
137         enum slave_port_state prev_state;
138         __be64 tmp_cur_ag, form_cache_ag;
139         enum slave_port_gen_event gen_event;
140
141         if (!mlx4_is_master(dev->dev))
142                 return;
143
144         guid_indexes = be64_to_cpu((__force __be64) dev->sriov.alias_guid.
145                                    ports_guid[port_num - 1].
146                                    all_rec_per_port[block_num].guid_indexes);
147         pr_debug("port: %d, guid_indexes: 0x%llx\n", port_num, (long long)guid_indexes);
148
149         /*calculate the slaves and notify them*/
150         for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) {
151                 /* the location of the specific index runs from bits 4..11 */
152                 if (!(test_bit(i + 4, (unsigned long *)&guid_indexes)))
153                         continue;
154
155                 slave_id = (block_num * NUM_ALIAS_GUID_IN_REC) + i ;
156                 if (slave_id >= dev->dev->num_slaves)
157                         return;
158                 tmp_cur_ag = *(__be64 *)&p_data[i * GUID_REC_SIZE];
159                 form_cache_ag = get_cached_alias_guid(dev, port_num,
160                                         (NUM_ALIAS_GUID_IN_REC * block_num) + i);
161                 /*
162                  * Check if guid is not the same as in the cache,
163                  * If it is different, wait for the snoop_smp or the port mgmt
164                  * change event to update the slave on its port state change
165                  */
166                 if (tmp_cur_ag != form_cache_ag)
167                         continue;
168                 mlx4_gen_guid_change_eqe(dev->dev, slave_id, port_num);
169
170                 /*2 cases: Valid GUID, and Invalid Guid*/
171
172                 if (tmp_cur_ag != MLX4_NOT_SET_GUID) { /*valid GUID*/
173                         prev_state = mlx4_get_slave_port_state(dev->dev, slave_id, port_num);
174                         new_state = set_and_calc_slave_port_state(dev->dev, slave_id, port_num,
175                                                                   MLX4_PORT_STATE_IB_PORT_STATE_EVENT_GID_VALID,
176                                                                   &gen_event);
177                         pr_debug("slave: %d, port: %d prev_port_state: %d,"
178                                  " new_port_state: %d, gen_event: %d\n",
179                                  slave_id, port_num, prev_state, new_state, gen_event);
180                         if (gen_event == SLAVE_PORT_GEN_EVENT_UP) {
181                                 pr_debug("sending PORT_UP event to slave: %d, port: %d\n",
182                                          slave_id, port_num);
183                                 mlx4_gen_port_state_change_eqe(dev->dev, slave_id,
184                                                                port_num, MLX4_PORT_CHANGE_SUBTYPE_ACTIVE);
185                         }
186                 } else { /* request to invalidate GUID */
187                         set_and_calc_slave_port_state(dev->dev, slave_id, port_num,
188                                                       MLX4_PORT_STATE_IB_EVENT_GID_INVALID,
189                                                       &gen_event);
190                         pr_debug("sending PORT DOWN event to slave: %d, port: %d\n",
191                                  slave_id, port_num);
192                         mlx4_gen_port_state_change_eqe(dev->dev, slave_id, port_num,
193                                                        MLX4_PORT_CHANGE_SUBTYPE_DOWN);
194                 }
195         }
196 }
197
198 static void aliasguid_query_handler(int status,
199                                     struct ib_sa_guidinfo_rec *guid_rec,
200                                     void *context)
201 {
202         struct mlx4_ib_dev *dev;
203         struct mlx4_alias_guid_work_context *cb_ctx = context;
204         u8 port_index ;
205         int i;
206         struct mlx4_sriov_alias_guid_info_rec_det *rec;
207         unsigned long flags, flags1;
208
209         if (!context)
210                 return;
211
212         dev = cb_ctx->dev;
213         port_index = cb_ctx->port - 1;
214         rec = &dev->sriov.alias_guid.ports_guid[port_index].
215                 all_rec_per_port[cb_ctx->block_num];
216
217         if (status) {
218                 rec->status = MLX4_GUID_INFO_STATUS_IDLE;
219                 pr_debug("(port: %d) failed: status = %d\n",
220                          cb_ctx->port, status);
221                 goto out;
222         }
223
224         if (guid_rec->block_num != cb_ctx->block_num) {
225                 pr_err("block num mismatch: %d != %d\n",
226                        cb_ctx->block_num, guid_rec->block_num);
227                 goto out;
228         }
229
230         pr_debug("lid/port: %d/%d, block_num: %d\n",
231                  be16_to_cpu(guid_rec->lid), cb_ctx->port,
232                  guid_rec->block_num);
233
234         rec = &dev->sriov.alias_guid.ports_guid[port_index].
235                 all_rec_per_port[guid_rec->block_num];
236
237         rec->status = MLX4_GUID_INFO_STATUS_SET;
238         rec->method = MLX4_GUID_INFO_RECORD_SET;
239
240         for (i = 0 ; i < NUM_ALIAS_GUID_IN_REC; i++) {
241                 __be64 tmp_cur_ag;
242                 tmp_cur_ag = *(__be64 *)&guid_rec->guid_info_list[i * GUID_REC_SIZE];
243                 /* check if the SM didn't assign one of the records.
244                  * if it didn't, if it was not sysadmin request:
245                  * ask the SM to give a new GUID, (instead of the driver request).
246                  */
247                 if (tmp_cur_ag == MLX4_NOT_SET_GUID) {
248                         mlx4_ib_warn(&dev->ib_dev, "%s:Record num %d in "
249                                      "block_num: %d was declined by SM, "
250                                      "ownership by %d (0 = driver, 1=sysAdmin,"
251                                      " 2=None)\n", __func__, i,
252                                      guid_rec->block_num, rec->ownership);
253                         if (rec->ownership == MLX4_GUID_DRIVER_ASSIGN) {
254                                 /* if it is driver assign, asks for new GUID from SM*/
255                                 *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE] =
256                                         MLX4_NOT_SET_GUID;
257
258                                 /* Mark the record as not assigned, and let it
259                                  * be sent again in the next work sched.*/
260                                 rec->status = MLX4_GUID_INFO_STATUS_IDLE;
261                                 rec->guid_indexes |= mlx4_ib_get_aguid_comp_mask_from_ix(i);
262                         }
263                 } else {
264                        /* properly assigned record. */
265                        /* We save the GUID we just got from the SM in the
266                         * admin_guid in order to be persistent, and in the
267                         * request from the sm the process will ask for the same GUID */
268                         if (rec->ownership == MLX4_GUID_SYSADMIN_ASSIGN &&
269                             tmp_cur_ag != *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE]) {
270                                 /* the sysadmin assignment failed.*/
271                                 mlx4_ib_warn(&dev->ib_dev, "%s: Failed to set"
272                                              " admin guid after SysAdmin "
273                                              "configuration. "
274                                              "Record num %d in block_num:%d "
275                                              "was declined by SM, "
276                                              "new val(0x%llx) was kept\n",
277                                               __func__, i,
278                                              guid_rec->block_num,
279                                              (long long)be64_to_cpu(*(__be64 *) &
280                                                          rec->all_recs[i * GUID_REC_SIZE]));
281                         } else {
282                                 memcpy(&rec->all_recs[i * GUID_REC_SIZE],
283                                        &guid_rec->guid_info_list[i * GUID_REC_SIZE],
284                                        GUID_REC_SIZE);
285                         }
286                 }
287         }
288         /*
289         The func is call here to close the cases when the
290         sm doesn't send smp, so in the sa response the driver
291         notifies the slave.
292         */
293         mlx4_ib_notify_slaves_on_guid_change(dev, guid_rec->block_num,
294                                              cb_ctx->port,
295                                              guid_rec->guid_info_list);
296 out:
297         spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
298         spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
299         if (!dev->sriov.is_going_down)
300                 queue_delayed_work(dev->sriov.alias_guid.ports_guid[port_index].wq,
301                                    &dev->sriov.alias_guid.ports_guid[port_index].
302                                    alias_guid_work, 0);
303         if (cb_ctx->sa_query) {
304                 list_del(&cb_ctx->list);
305                 kfree(cb_ctx);
306         } else
307                 complete(&cb_ctx->done);
308         spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
309         spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
310 }
311
312 static void invalidate_guid_record(struct mlx4_ib_dev *dev, u8 port, int index)
313 {
314         int i;
315         u64 cur_admin_val;
316         ib_sa_comp_mask comp_mask = 0;
317
318         dev->sriov.alias_guid.ports_guid[port - 1].all_rec_per_port[index].status
319                 = MLX4_GUID_INFO_STATUS_IDLE;
320         dev->sriov.alias_guid.ports_guid[port - 1].all_rec_per_port[index].method
321                 = MLX4_GUID_INFO_RECORD_SET;
322
323         /* calculate the comp_mask for that record.*/
324         for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) {
325                 cur_admin_val =
326                         *(u64 *)&dev->sriov.alias_guid.ports_guid[port - 1].
327                         all_rec_per_port[index].all_recs[GUID_REC_SIZE * i];
328                 /*
329                 check the admin value: if it's for delete (~00LL) or
330                 it is the first guid of the first record (hw guid) or
331                 the records is not in ownership of the sysadmin and the sm doesn't
332                 need to assign GUIDs, then don't put it up for assignment.
333                 */
334                 if (MLX4_GUID_FOR_DELETE_VAL == cur_admin_val ||
335                     (!index && !i) ||
336                     MLX4_GUID_NONE_ASSIGN == dev->sriov.alias_guid.
337                     ports_guid[port - 1].all_rec_per_port[index].ownership)
338                         continue;
339                 comp_mask |= mlx4_ib_get_aguid_comp_mask_from_ix(i);
340         }
341         dev->sriov.alias_guid.ports_guid[port - 1].
342                 all_rec_per_port[index].guid_indexes = comp_mask;
343 }
344
345 static int set_guid_rec(struct ib_device *ibdev,
346                         u8 port, int index,
347                         struct mlx4_sriov_alias_guid_info_rec_det *rec_det)
348 {
349         int err;
350         struct mlx4_ib_dev *dev = to_mdev(ibdev);
351         struct ib_sa_guidinfo_rec guid_info_rec;
352         ib_sa_comp_mask comp_mask;
353         struct ib_port_attr attr;
354         struct mlx4_alias_guid_work_context *callback_context;
355         unsigned long resched_delay, flags, flags1;
356         struct list_head *head =
357                 &dev->sriov.alias_guid.ports_guid[port - 1].cb_list;
358
359         err = __mlx4_ib_query_port(ibdev, port, &attr, 1);
360         if (err) {
361                 pr_debug("mlx4_ib_query_port failed (err: %d), port: %d\n",
362                          err, port);
363                 return err;
364         }
365         /*check the port was configured by the sm, otherwise no need to send */
366         if (attr.state != IB_PORT_ACTIVE) {
367                 pr_debug("port %d not active...rescheduling\n", port);
368                 resched_delay = 5 * HZ;
369                 err = -EAGAIN;
370                 goto new_schedule;
371         }
372
373         callback_context = kmalloc(sizeof *callback_context, GFP_KERNEL);
374         if (!callback_context) {
375                 err = -ENOMEM;
376                 resched_delay = HZ * 5;
377                 goto new_schedule;
378         }
379         callback_context->port = port;
380         callback_context->dev = dev;
381         callback_context->block_num = index;
382
383         memset(&guid_info_rec, 0, sizeof (struct ib_sa_guidinfo_rec));
384
385         guid_info_rec.lid = cpu_to_be16(attr.lid);
386         guid_info_rec.block_num = index;
387
388         memcpy(guid_info_rec.guid_info_list, rec_det->all_recs,
389                GUID_REC_SIZE * NUM_ALIAS_GUID_IN_REC);
390         comp_mask = IB_SA_GUIDINFO_REC_LID | IB_SA_GUIDINFO_REC_BLOCK_NUM |
391                 rec_det->guid_indexes;
392
393         init_completion(&callback_context->done);
394         spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
395         list_add_tail(&callback_context->list, head);
396         spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
397
398         callback_context->query_id =
399                 ib_sa_guid_info_rec_query(dev->sriov.alias_guid.sa_client,
400                                           ibdev, port, &guid_info_rec,
401                                           comp_mask, rec_det->method, 1000,
402                                           GFP_KERNEL, aliasguid_query_handler,
403                                           callback_context,
404                                           &callback_context->sa_query);
405         if (callback_context->query_id < 0) {
406                 pr_debug("ib_sa_guid_info_rec_query failed, query_id: "
407                          "%d. will reschedule to the next 1 sec.\n",
408                          callback_context->query_id);
409                 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
410                 list_del(&callback_context->list);
411                 kfree(callback_context);
412                 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
413                 resched_delay = 1 * HZ;
414                 err = -EAGAIN;
415                 goto new_schedule;
416         }
417         err = 0;
418         goto out;
419
420 new_schedule:
421         spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
422         spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
423         invalidate_guid_record(dev, port, index);
424         if (!dev->sriov.is_going_down) {
425                 queue_delayed_work(dev->sriov.alias_guid.ports_guid[port - 1].wq,
426                                    &dev->sriov.alias_guid.ports_guid[port - 1].alias_guid_work,
427                                    resched_delay);
428         }
429         spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
430         spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
431
432 out:
433         return err;
434 }
435
436 void mlx4_ib_invalidate_all_guid_record(struct mlx4_ib_dev *dev, int port)
437 {
438         int i;
439         unsigned long flags, flags1;
440
441         pr_debug("port %d\n", port);
442
443         spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
444         spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
445         for (i = 0; i < NUM_ALIAS_GUID_REC_IN_PORT; i++)
446                 invalidate_guid_record(dev, port, i);
447
448         if (mlx4_is_master(dev->dev) && !dev->sriov.is_going_down) {
449                 /*
450                 make sure no work waits in the queue, if the work is already
451                 queued(not on the timer) the cancel will fail. That is not a problem
452                 because we just want the work started.
453                 */
454                 cancel_delayed_work(&dev->sriov.alias_guid.
455                                       ports_guid[port - 1].alias_guid_work);
456                 queue_delayed_work(dev->sriov.alias_guid.ports_guid[port - 1].wq,
457                                    &dev->sriov.alias_guid.ports_guid[port - 1].alias_guid_work,
458                                    0);
459         }
460         spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
461         spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
462 }
463
464 /* The function returns the next record that was
465  * not configured (or failed to be configured) */
466 static int get_next_record_to_update(struct mlx4_ib_dev *dev, u8 port,
467                                      struct mlx4_next_alias_guid_work *rec)
468 {
469         int j;
470         unsigned long flags;
471
472         for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) {
473                 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags);
474                 if (dev->sriov.alias_guid.ports_guid[port].all_rec_per_port[j].status ==
475                     MLX4_GUID_INFO_STATUS_IDLE) {
476                         memcpy(&rec->rec_det,
477                                &dev->sriov.alias_guid.ports_guid[port].all_rec_per_port[j],
478                                sizeof (struct mlx4_sriov_alias_guid_info_rec_det));
479                         rec->port = port;
480                         rec->block_num = j;
481                         dev->sriov.alias_guid.ports_guid[port].all_rec_per_port[j].status =
482                                 MLX4_GUID_INFO_STATUS_PENDING;
483                         spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags);
484                         return 0;
485                 }
486                 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags);
487         }
488         return -ENOENT;
489 }
490
491 static void set_administratively_guid_record(struct mlx4_ib_dev *dev, int port,
492                                              int rec_index,
493                                              struct mlx4_sriov_alias_guid_info_rec_det *rec_det)
494 {
495         dev->sriov.alias_guid.ports_guid[port].all_rec_per_port[rec_index].guid_indexes =
496                 rec_det->guid_indexes;
497         memcpy(dev->sriov.alias_guid.ports_guid[port].all_rec_per_port[rec_index].all_recs,
498                rec_det->all_recs, NUM_ALIAS_GUID_IN_REC * GUID_REC_SIZE);
499         dev->sriov.alias_guid.ports_guid[port].all_rec_per_port[rec_index].status =
500                 rec_det->status;
501 }
502
503 static void set_all_slaves_guids(struct mlx4_ib_dev *dev, int port)
504 {
505         int j;
506         struct mlx4_sriov_alias_guid_info_rec_det rec_det ;
507
508         for (j = 0 ; j < NUM_ALIAS_GUID_REC_IN_PORT ; j++) {
509                 memset(rec_det.all_recs, 0, NUM_ALIAS_GUID_IN_REC * GUID_REC_SIZE);
510                 rec_det.guid_indexes = (!j ? 0 : IB_SA_GUIDINFO_REC_GID0) |
511                         IB_SA_GUIDINFO_REC_GID1 | IB_SA_GUIDINFO_REC_GID2 |
512                         IB_SA_GUIDINFO_REC_GID3 | IB_SA_GUIDINFO_REC_GID4 |
513                         IB_SA_GUIDINFO_REC_GID5 | IB_SA_GUIDINFO_REC_GID6 |
514                         IB_SA_GUIDINFO_REC_GID7;
515                 rec_det.status = MLX4_GUID_INFO_STATUS_IDLE;
516                 set_administratively_guid_record(dev, port, j, &rec_det);
517         }
518 }
519
520 static void alias_guid_work(struct work_struct *work)
521 {
522         struct delayed_work *delay = to_delayed_work(work);
523         int ret = 0;
524         struct mlx4_next_alias_guid_work *rec;
525         struct mlx4_sriov_alias_guid_port_rec_det *sriov_alias_port =
526                 container_of(delay, struct mlx4_sriov_alias_guid_port_rec_det,
527                              alias_guid_work);
528         struct mlx4_sriov_alias_guid *sriov_alias_guid = sriov_alias_port->parent;
529         struct mlx4_ib_sriov *ib_sriov = container_of(sriov_alias_guid,
530                                                 struct mlx4_ib_sriov,
531                                                 alias_guid);
532         struct mlx4_ib_dev *dev = container_of(ib_sriov, struct mlx4_ib_dev, sriov);
533
534         rec = kzalloc(sizeof *rec, GFP_KERNEL);
535         if (!rec) {
536                 pr_err("alias_guid_work: No Memory\n");
537                 return;
538         }
539
540         pr_debug("starting [port: %d]...\n", sriov_alias_port->port + 1);
541         ret = get_next_record_to_update(dev, sriov_alias_port->port, rec);
542         if (ret) {
543                 pr_debug("No more records to update.\n");
544                 goto out;
545         }
546
547         set_guid_rec(&dev->ib_dev, rec->port + 1, rec->block_num,
548                      &rec->rec_det);
549
550 out:
551         kfree(rec);
552 }
553
554
555 void mlx4_ib_init_alias_guid_work(struct mlx4_ib_dev *dev, int port)
556 {
557         unsigned long flags, flags1;
558
559         if (!mlx4_is_master(dev->dev))
560                 return;
561         spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
562         spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
563         if (!dev->sriov.is_going_down) {
564                 queue_delayed_work(dev->sriov.alias_guid.ports_guid[port].wq,
565                            &dev->sriov.alias_guid.ports_guid[port].alias_guid_work, 0);
566         }
567         spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
568         spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
569 }
570
571 void mlx4_ib_destroy_alias_guid_service(struct mlx4_ib_dev *dev)
572 {
573         int i;
574         struct mlx4_ib_sriov *sriov = &dev->sriov;
575         struct mlx4_alias_guid_work_context *cb_ctx;
576         struct mlx4_sriov_alias_guid_port_rec_det *det;
577         struct ib_sa_query *sa_query;
578         unsigned long flags;
579
580         for (i = 0 ; i < dev->num_ports; i++) {
581                 cancel_delayed_work(&dev->sriov.alias_guid.ports_guid[i].alias_guid_work);
582                 det = &sriov->alias_guid.ports_guid[i];
583                 spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags);
584                 while (!list_empty(&det->cb_list)) {
585                         cb_ctx = list_entry(det->cb_list.next,
586                                             struct mlx4_alias_guid_work_context,
587                                             list);
588                         sa_query = cb_ctx->sa_query;
589                         cb_ctx->sa_query = NULL;
590                         list_del(&cb_ctx->list);
591                         spin_unlock_irqrestore(&sriov->alias_guid.ag_work_lock, flags);
592                         ib_sa_cancel_query(cb_ctx->query_id, sa_query);
593                         wait_for_completion(&cb_ctx->done);
594                         kfree(cb_ctx);
595                         spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags);
596                 }
597                 spin_unlock_irqrestore(&sriov->alias_guid.ag_work_lock, flags);
598         }
599         for (i = 0 ; i < dev->num_ports; i++) {
600                 flush_workqueue(dev->sriov.alias_guid.ports_guid[i].wq);
601                 destroy_workqueue(dev->sriov.alias_guid.ports_guid[i].wq);
602         }
603         ib_sa_unregister_client(dev->sriov.alias_guid.sa_client);
604         kfree(dev->sriov.alias_guid.sa_client);
605 }
606
607 int mlx4_ib_init_alias_guid_service(struct mlx4_ib_dev *dev)
608 {
609         char alias_wq_name[15];
610         int ret = 0;
611         int i, j, k;
612         union ib_gid gid;
613
614         if (!mlx4_is_master(dev->dev))
615                 return 0;
616         dev->sriov.alias_guid.sa_client =
617                 kzalloc(sizeof *dev->sriov.alias_guid.sa_client, GFP_KERNEL);
618         if (!dev->sriov.alias_guid.sa_client)
619                 return -ENOMEM;
620
621         ib_sa_register_client(dev->sriov.alias_guid.sa_client);
622
623         spin_lock_init(&dev->sriov.alias_guid.ag_work_lock);
624
625         for (i = 1; i <= dev->num_ports; ++i) {
626                 if (dev->ib_dev.query_gid(&dev->ib_dev , i, 0, &gid)) {
627                         ret = -EFAULT;
628                         goto err_unregister;
629                 }
630         }
631
632         for (i = 0 ; i < dev->num_ports; i++) {
633                 memset(&dev->sriov.alias_guid.ports_guid[i], 0,
634                        sizeof (struct mlx4_sriov_alias_guid_port_rec_det));
635                 /*Check if the SM doesn't need to assign the GUIDs*/
636                 for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) {
637                         if (mlx4_ib_sm_guid_assign) {
638                                 dev->sriov.alias_guid.ports_guid[i].
639                                         all_rec_per_port[j].
640                                         ownership = MLX4_GUID_DRIVER_ASSIGN;
641                                 continue;
642                         }
643                         dev->sriov.alias_guid.ports_guid[i].all_rec_per_port[j].
644                                         ownership = MLX4_GUID_NONE_ASSIGN;
645                         /*mark each val as it was deleted,
646                           till the sysAdmin will give it valid val*/
647                         for (k = 0; k < NUM_ALIAS_GUID_IN_REC; k++) {
648                                 *(__be64 *)&dev->sriov.alias_guid.ports_guid[i].
649                                         all_rec_per_port[j].all_recs[GUID_REC_SIZE * k] =
650                                                 cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL);
651                         }
652                 }
653                 INIT_LIST_HEAD(&dev->sriov.alias_guid.ports_guid[i].cb_list);
654                 /*prepare the records, set them to be allocated by sm*/
655                 for (j = 0 ; j < NUM_ALIAS_GUID_REC_IN_PORT; j++)
656                         invalidate_guid_record(dev, i + 1, j);
657
658                 dev->sriov.alias_guid.ports_guid[i].parent = &dev->sriov.alias_guid;
659                 dev->sriov.alias_guid.ports_guid[i].port  = i;
660                 if (mlx4_ib_sm_guid_assign)
661                         set_all_slaves_guids(dev, i);
662
663                 snprintf(alias_wq_name, sizeof alias_wq_name, "alias_guid%d", i);
664                 dev->sriov.alias_guid.ports_guid[i].wq =
665                         create_singlethread_workqueue(alias_wq_name);
666                 if (!dev->sriov.alias_guid.ports_guid[i].wq) {
667                         ret = -ENOMEM;
668                         goto err_thread;
669                 }
670                 INIT_DELAYED_WORK(&dev->sriov.alias_guid.ports_guid[i].alias_guid_work,
671                           alias_guid_work);
672         }
673         return 0;
674
675 err_thread:
676         for (--i; i >= 0; i--) {
677                 destroy_workqueue(dev->sriov.alias_guid.ports_guid[i].wq);
678                 dev->sriov.alias_guid.ports_guid[i].wq = NULL;
679         }
680
681 err_unregister:
682         ib_sa_unregister_client(dev->sriov.alias_guid.sa_client);
683         kfree(dev->sriov.alias_guid.sa_client);
684         dev->sriov.alias_guid.sa_client = NULL;
685         pr_err("init_alias_guid_service: Failed. (ret:%d)\n", ret);
686         return ret;
687 }