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