1255932Salfred/*
2255932Salfred * Copyright (c) 2012 Mellanox Technologies. All rights reserved.
3255932Salfred *
4255932Salfred * This software is available to you under a choice of one of two
5255932Salfred * licenses.  You may choose to be licensed under the terms of the GNU
6255932Salfred * General Public License (GPL) Version 2, available from the file
7255932Salfred * COPYING in the main directory of this source tree, or the
8255932Salfred * OpenIB.org BSD license below:
9255932Salfred *
10255932Salfred *     Redistribution and use in source and binary forms, with or
11255932Salfred *     without modification, are permitted provided that the following
12255932Salfred *     conditions are met:
13255932Salfred *
14255932Salfred *      - Redistributions of source code must retain the above
15255932Salfred *        copyright notice, this list of conditions and the following
16255932Salfred *        disclaimer.
17255932Salfred *
18255932Salfred *      - Redistributions in binary form must reproduce the above
19255932Salfred *        copyright notice, this list of conditions and the following
20255932Salfred *        disclaimer in the documentation and/or other materials
21255932Salfred *        provided with the distribution.
22255932Salfred *
23255932Salfred * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24255932Salfred * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25255932Salfred * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26255932Salfred * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27255932Salfred * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28255932Salfred * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29255932Salfred * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30255932Salfred * SOFTWARE.
31255932Salfred */
32255932Salfred /***********************************************************/
33255932Salfred/*This file support the handling of the Alias GUID feature. */
34255932Salfred/***********************************************************/
35255932Salfred#include <rdma/ib_mad.h>
36255932Salfred#include <rdma/ib_smi.h>
37255932Salfred#include <rdma/ib_cache.h>
38255932Salfred#include <rdma/ib_sa.h>
39255932Salfred#include <rdma/ib_pack.h>
40255932Salfred#include <linux/mlx4/cmd.h>
41255932Salfred#include <linux/module.h>
42255932Salfred#include <linux/init.h>
43255932Salfred#include <linux/errno.h>
44255932Salfred#include <rdma/ib_user_verbs.h>
45255932Salfred#include <linux/delay.h>
46255932Salfred#include "mlx4_ib.h"
47255932Salfred
48255932Salfred/*
49255932SalfredThe driver keeps the current state of all guids, as they are in the HW.
50255932SalfredWhenever we receive an smp mad GUIDInfo record, the data will be cached.
51255932Salfred*/
52255932Salfred
53255932Salfredstruct mlx4_alias_guid_work_context {
54255932Salfred	u8 port;
55255932Salfred	struct mlx4_ib_dev     *dev ;
56255932Salfred	struct ib_sa_query     *sa_query;
57255932Salfred	struct completion	done;
58255932Salfred	int			query_id;
59255932Salfred	struct list_head	list;
60255932Salfred	int			block_num;
61255932Salfred};
62255932Salfred
63255932Salfredstruct mlx4_next_alias_guid_work {
64255932Salfred	u8 port;
65255932Salfred	u8 block_num;
66255932Salfred	struct mlx4_sriov_alias_guid_info_rec_det rec_det;
67255932Salfred};
68255932Salfred
69255932Salfred
70255932Salfredvoid mlx4_ib_update_cache_on_guid_change(struct mlx4_ib_dev *dev, int block_num,
71255932Salfred					 u8 port_num, u8 *p_data)
72255932Salfred{
73255932Salfred	int i;
74255932Salfred	u64 guid_indexes;
75255932Salfred	int slave_id;
76255932Salfred	int port_index = port_num - 1;
77255932Salfred
78255932Salfred	if (!mlx4_is_master(dev->dev))
79255932Salfred		return;
80255932Salfred
81255932Salfred	guid_indexes = be64_to_cpu((__force __be64) dev->sriov.alias_guid.
82255932Salfred				   ports_guid[port_num - 1].
83255932Salfred				   all_rec_per_port[block_num].guid_indexes);
84255932Salfred	pr_debug("port: %d, guid_indexes: 0x%llx\n", port_num, guid_indexes);
85255932Salfred
86255932Salfred	for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) {
87255932Salfred		/* The location of the specific index starts from bit number 4
88255932Salfred		 * until bit num 11 */
89255932Salfred		if (test_bit(i + 4, (unsigned long *)&guid_indexes)) {
90255932Salfred			slave_id = (block_num * NUM_ALIAS_GUID_IN_REC) + i ;
91255932Salfred			if (slave_id >= dev->dev->num_slaves) {
92255932Salfred				pr_debug("The last slave: %d\n", slave_id);
93255932Salfred				return;
94255932Salfred			}
95255932Salfred
96255932Salfred			/* cache the guid: */
97255932Salfred			memcpy(&dev->sriov.demux[port_index].guid_cache[slave_id],
98255932Salfred			       &p_data[i * GUID_REC_SIZE],
99255932Salfred			       GUID_REC_SIZE);
100255932Salfred		} else
101255932Salfred			pr_debug("Guid number: %d in block: %d"
102255932Salfred				 " was not updated\n", i, block_num);
103255932Salfred	}
104255932Salfred}
105255932Salfred
106255932Salfredstatic __be64 get_cached_alias_guid(struct mlx4_ib_dev *dev, int port, int index)
107255932Salfred{
108255932Salfred	if (index >= NUM_ALIAS_GUID_PER_PORT) {
109255932Salfred		pr_err("%s: ERROR: asked for index:%d\n", __func__, index);
110255932Salfred		return (__force __be64) -1;
111255932Salfred	}
112255932Salfred	return *(__be64 *)&dev->sriov.demux[port - 1].guid_cache[index];
113255932Salfred}
114255932Salfred
115255932Salfred
116255932Salfredib_sa_comp_mask mlx4_ib_get_aguid_comp_mask_from_ix(int index)
117255932Salfred{
118255932Salfred	return IB_SA_COMP_MASK(4 + index);
119255932Salfred}
120255932Salfred
121255932Salfred/*
122255932Salfred * Whenever new GUID is set/unset (guid table change) create event and
123255932Salfred * notify the relevant slave (master also should be notified).
124255932Salfred * If the GUID value is not as we have in the cache the slave will not be
125255932Salfred * updated; in this case it waits for the smp_snoop or the port management
126255932Salfred * event to call the function and to update the slave.
127255932Salfred * block_number - the index of the block (16 blocks available)
128255932Salfred * port_number - 1 or 2
129255932Salfred */
130255932Salfredvoid mlx4_ib_notify_slaves_on_guid_change(struct mlx4_ib_dev *dev,
131255932Salfred					  int block_num, u8 port_num,
132255932Salfred					  u8 *p_data)
133255932Salfred{
134255932Salfred	int i;
135255932Salfred	u64 guid_indexes;
136255932Salfred	int slave_id;
137255932Salfred	enum slave_port_state new_state;
138255932Salfred	enum slave_port_state prev_state;
139255932Salfred	__be64 tmp_cur_ag, form_cache_ag;
140255932Salfred	enum slave_port_gen_event gen_event;
141255932Salfred
142255932Salfred	if (!mlx4_is_master(dev->dev))
143255932Salfred		return;
144255932Salfred
145255932Salfred	guid_indexes = be64_to_cpu((__force __be64) dev->sriov.alias_guid.
146255932Salfred				   ports_guid[port_num - 1].
147255932Salfred				   all_rec_per_port[block_num].guid_indexes);
148255932Salfred	pr_debug("port: %d, guid_indexes: 0x%llx\n", port_num, guid_indexes);
149255932Salfred
150255932Salfred	/*calculate the slaves and notify them*/
151255932Salfred	for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) {
152255932Salfred		/* the location of the specific index runs from bits 4..11 */
153255932Salfred		if (!(test_bit(i + 4, (unsigned long *)&guid_indexes)))
154255932Salfred			continue;
155255932Salfred
156255932Salfred		slave_id = (block_num * NUM_ALIAS_GUID_IN_REC) + i ;
157255932Salfred		if (slave_id >= dev->dev->num_slaves)
158255932Salfred			return;
159255932Salfred		tmp_cur_ag = *(__be64 *)&p_data[i * GUID_REC_SIZE];
160255932Salfred		form_cache_ag = get_cached_alias_guid(dev, port_num,
161255932Salfred					(NUM_ALIAS_GUID_IN_REC * block_num) + i);
162255932Salfred		/*
163255932Salfred		 * Check if guid is not the same as in the cache,
164255932Salfred		 * If it is different, wait for the snoop_smp or the port mgmt
165255932Salfred		 * change event to update the slave on its port state change
166255932Salfred		 */
167255932Salfred		if (tmp_cur_ag != form_cache_ag)
168255932Salfred			continue;
169255932Salfred		mlx4_gen_guid_change_eqe(dev->dev, slave_id, port_num);
170255932Salfred
171255932Salfred		/*2 cases: Valid GUID, and Invalid Guid*/
172255932Salfred
173255932Salfred		if (tmp_cur_ag != MLX4_NOT_SET_GUID) { /*valid GUID*/
174255932Salfred			prev_state = mlx4_get_slave_port_state(dev->dev, slave_id, port_num);
175255932Salfred			new_state = set_and_calc_slave_port_state(dev->dev, slave_id, port_num,
176255932Salfred								  MLX4_PORT_STATE_IB_PORT_STATE_EVENT_GID_VALID,
177255932Salfred								  &gen_event);
178255932Salfred			pr_debug("slave: %d, port: %d prev_port_state: %d,"
179255932Salfred				 " new_port_state: %d, gen_event: %d\n",
180255932Salfred				 slave_id, port_num, prev_state, new_state, gen_event);
181255932Salfred			if (gen_event == SLAVE_PORT_GEN_EVENT_UP) {
182255932Salfred				pr_debug("sending PORT_UP event to slave: %d, port: %d\n",
183255932Salfred					 slave_id, port_num);
184255932Salfred				mlx4_gen_port_state_change_eqe(dev->dev, slave_id,
185255932Salfred							       port_num, MLX4_PORT_CHANGE_SUBTYPE_ACTIVE);
186255932Salfred			}
187255932Salfred		} else { /* request to invalidate GUID */
188255932Salfred			set_and_calc_slave_port_state(dev->dev, slave_id, port_num,
189255932Salfred						      MLX4_PORT_STATE_IB_EVENT_GID_INVALID,
190255932Salfred						      &gen_event);
191255932Salfred			pr_debug("sending PORT DOWN event to slave: %d, port: %d\n",
192255932Salfred				 slave_id, port_num);
193255932Salfred			mlx4_gen_port_state_change_eqe(dev->dev, slave_id, port_num,
194255932Salfred						       MLX4_PORT_CHANGE_SUBTYPE_DOWN);
195255932Salfred		}
196255932Salfred	}
197255932Salfred}
198255932Salfred
199255932Salfredstatic void aliasguid_query_handler(int status,
200255932Salfred				    struct ib_sa_guidinfo_rec *guid_rec,
201255932Salfred				    void *context)
202255932Salfred{
203255932Salfred	struct mlx4_ib_dev *dev;
204255932Salfred	struct mlx4_alias_guid_work_context *cb_ctx = context;
205255932Salfred	u8 port_index ;
206255932Salfred	int i;
207255932Salfred	struct mlx4_sriov_alias_guid_info_rec_det *rec;
208255932Salfred	unsigned long flags, flags1;
209255932Salfred
210255932Salfred	if (!context)
211255932Salfred		return;
212255932Salfred
213255932Salfred	dev = cb_ctx->dev;
214255932Salfred	port_index = cb_ctx->port - 1;
215255932Salfred	rec = &dev->sriov.alias_guid.ports_guid[port_index].
216255932Salfred		all_rec_per_port[cb_ctx->block_num];
217255932Salfred
218255932Salfred	if (status) {
219255932Salfred		rec->status = MLX4_GUID_INFO_STATUS_IDLE;
220255932Salfred		pr_debug("(port: %d) failed: status = %d\n",
221255932Salfred			 cb_ctx->port, status);
222255932Salfred		goto out;
223255932Salfred	}
224255932Salfred
225255932Salfred	if (guid_rec->block_num != cb_ctx->block_num) {
226255932Salfred		pr_err("block num mismatch: %d != %d\n",
227255932Salfred		       cb_ctx->block_num, guid_rec->block_num);
228255932Salfred		goto out;
229255932Salfred	}
230255932Salfred
231255932Salfred	pr_debug("lid/port: %d/%d, block_num: %d\n",
232255932Salfred		 be16_to_cpu(guid_rec->lid), cb_ctx->port,
233255932Salfred		 guid_rec->block_num);
234255932Salfred
235255932Salfred	rec = &dev->sriov.alias_guid.ports_guid[port_index].
236255932Salfred		all_rec_per_port[guid_rec->block_num];
237255932Salfred
238255932Salfred	rec->status = MLX4_GUID_INFO_STATUS_SET;
239255932Salfred	rec->method = MLX4_GUID_INFO_RECORD_SET;
240255932Salfred
241255932Salfred	for (i = 0 ; i < NUM_ALIAS_GUID_IN_REC; i++) {
242255932Salfred		__be64 tmp_cur_ag;
243255932Salfred		tmp_cur_ag = *(__be64 *)&guid_rec->guid_info_list[i * GUID_REC_SIZE];
244255932Salfred		/* check if the SM didn't assign one of the records.
245255932Salfred		 * if it didn't, if it was not sysadmin request:
246255932Salfred		 * ask the SM to give a new GUID, (instead of the driver request).
247255932Salfred		 */
248255932Salfred		if (tmp_cur_ag == MLX4_NOT_SET_GUID) {
249255932Salfred			mlx4_ib_warn(&dev->ib_dev, "%s:Record num %d in "
250255932Salfred				     "block_num: %d was declined by SM, "
251255932Salfred				     "ownership by %d (0 = driver, 1=sysAdmin,"
252255932Salfred				     " 2=None)\n", __func__, i,
253255932Salfred				     guid_rec->block_num, rec->ownership);
254255932Salfred			if (rec->ownership == MLX4_GUID_DRIVER_ASSIGN) {
255255932Salfred				/* if it is driver assign, asks for new GUID from SM*/
256255932Salfred				*(__be64 *)&rec->all_recs[i * GUID_REC_SIZE] =
257255932Salfred					MLX4_NOT_SET_GUID;
258255932Salfred
259255932Salfred				/* Mark the record as not assigned, and let it
260255932Salfred				 * be sent again in the next work sched.*/
261255932Salfred				rec->status = MLX4_GUID_INFO_STATUS_IDLE;
262255932Salfred				rec->guid_indexes |= mlx4_ib_get_aguid_comp_mask_from_ix(i);
263255932Salfred			}
264255932Salfred		} else {
265255932Salfred		       /* properly assigned record. */
266255932Salfred		       /* We save the GUID we just got from the SM in the
267255932Salfred			* admin_guid in order to be persistent, and in the
268255932Salfred			* request from the sm the process will ask for the same GUID */
269255932Salfred			if (rec->ownership == MLX4_GUID_SYSADMIN_ASSIGN &&
270255932Salfred			    tmp_cur_ag != *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE]) {
271255932Salfred				/* the sysadmin assignment failed.*/
272255932Salfred				mlx4_ib_warn(&dev->ib_dev, "%s: Failed to set"
273255932Salfred					     " admin guid after SysAdmin "
274255932Salfred					     "configuration. "
275255932Salfred					     "Record num %d in block_num:%d "
276255932Salfred					     "was declined by SM, "
277255932Salfred					     "new val(0x%llx) was kept\n",
278255932Salfred					      __func__, i,
279255932Salfred					     guid_rec->block_num,
280255932Salfred					     (long long)be64_to_cpu(*(__be64 *) &
281255932Salfred							 rec->all_recs[i * GUID_REC_SIZE]));
282255932Salfred			} else {
283255932Salfred				memcpy(&rec->all_recs[i * GUID_REC_SIZE],
284255932Salfred				       &guid_rec->guid_info_list[i * GUID_REC_SIZE],
285255932Salfred				       GUID_REC_SIZE);
286255932Salfred			}
287255932Salfred		}
288255932Salfred	}
289255932Salfred	/*
290255932Salfred	The func is call here to close the cases when the
291255932Salfred	sm doesn't send smp, so in the sa response the driver
292255932Salfred	notifies the slave.
293255932Salfred	*/
294255932Salfred	mlx4_ib_notify_slaves_on_guid_change(dev, guid_rec->block_num,
295255932Salfred					     cb_ctx->port,
296255932Salfred					     guid_rec->guid_info_list);
297255932Salfredout:
298255932Salfred	spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
299255932Salfred	spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
300255932Salfred	if (!dev->sriov.is_going_down)
301255932Salfred		queue_delayed_work(dev->sriov.alias_guid.ports_guid[port_index].wq,
302255932Salfred				   &dev->sriov.alias_guid.ports_guid[port_index].
303255932Salfred				   alias_guid_work, 0);
304255932Salfred	if (cb_ctx->sa_query) {
305255932Salfred		list_del(&cb_ctx->list);
306255932Salfred		kfree(cb_ctx);
307255932Salfred	} else
308255932Salfred		complete(&cb_ctx->done);
309255932Salfred	spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
310255932Salfred	spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
311255932Salfred}
312255932Salfred
313255932Salfredstatic void invalidate_guid_record(struct mlx4_ib_dev *dev, u8 port, int index)
314255932Salfred{
315255932Salfred	int i;
316255932Salfred	u64 cur_admin_val;
317255932Salfred	ib_sa_comp_mask comp_mask = 0;
318255932Salfred
319255932Salfred	dev->sriov.alias_guid.ports_guid[port - 1].all_rec_per_port[index].status
320255932Salfred		= MLX4_GUID_INFO_STATUS_IDLE;
321255932Salfred	dev->sriov.alias_guid.ports_guid[port - 1].all_rec_per_port[index].method
322255932Salfred		= MLX4_GUID_INFO_RECORD_SET;
323255932Salfred
324255932Salfred	/* calculate the comp_mask for that record.*/
325255932Salfred	for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) {
326255932Salfred		cur_admin_val =
327255932Salfred			*(u64 *)&dev->sriov.alias_guid.ports_guid[port - 1].
328255932Salfred			all_rec_per_port[index].all_recs[GUID_REC_SIZE * i];
329255932Salfred		/*
330255932Salfred		check the admin value: if it's for delete (~00LL) or
331255932Salfred		it is the first guid of the first record (hw guid) or
332255932Salfred		the records is not in ownership of the sysadmin and the sm doesn't
333255932Salfred		need to assign GUIDs, then don't put it up for assignment.
334255932Salfred		*/
335255932Salfred		if (MLX4_GUID_FOR_DELETE_VAL == cur_admin_val ||
336255932Salfred		    (!index && !i) ||
337255932Salfred		    MLX4_GUID_NONE_ASSIGN == dev->sriov.alias_guid.
338255932Salfred		    ports_guid[port - 1].all_rec_per_port[index].ownership)
339255932Salfred			continue;
340255932Salfred		comp_mask |= mlx4_ib_get_aguid_comp_mask_from_ix(i);
341255932Salfred	}
342255932Salfred	dev->sriov.alias_guid.ports_guid[port - 1].
343255932Salfred		all_rec_per_port[index].guid_indexes = comp_mask;
344255932Salfred}
345255932Salfred
346255932Salfredstatic int set_guid_rec(struct ib_device *ibdev,
347255932Salfred			u8 port, int index,
348255932Salfred			struct mlx4_sriov_alias_guid_info_rec_det *rec_det)
349255932Salfred{
350255932Salfred	int err;
351255932Salfred	struct mlx4_ib_dev *dev = to_mdev(ibdev);
352255932Salfred	struct ib_sa_guidinfo_rec guid_info_rec;
353255932Salfred	ib_sa_comp_mask comp_mask;
354255932Salfred	struct ib_port_attr attr;
355255932Salfred	struct mlx4_alias_guid_work_context *callback_context;
356255932Salfred	unsigned long resched_delay, flags, flags1;
357255932Salfred	struct list_head *head =
358255932Salfred		&dev->sriov.alias_guid.ports_guid[port - 1].cb_list;
359255932Salfred
360255932Salfred	err = __mlx4_ib_query_port(ibdev, port, &attr, 1);
361255932Salfred	if (err) {
362255932Salfred		pr_debug("mlx4_ib_query_port failed (err: %d), port: %d\n",
363255932Salfred			 err, port);
364255932Salfred		return err;
365255932Salfred	}
366255932Salfred	/*check the port was configured by the sm, otherwise no need to send */
367255932Salfred	if (attr.state != IB_PORT_ACTIVE) {
368255932Salfred		pr_debug("port %d not active...rescheduling\n", port);
369255932Salfred		resched_delay = 5 * HZ;
370255932Salfred		err = -EAGAIN;
371255932Salfred		goto new_schedule;
372255932Salfred	}
373255932Salfred
374255932Salfred	callback_context = kmalloc(sizeof *callback_context, GFP_KERNEL);
375255932Salfred	if (!callback_context) {
376255932Salfred		err = -ENOMEM;
377255932Salfred		resched_delay = HZ * 5;
378255932Salfred		goto new_schedule;
379255932Salfred	}
380255932Salfred	callback_context->port = port;
381255932Salfred	callback_context->dev = dev;
382255932Salfred	callback_context->block_num = index;
383255932Salfred
384255932Salfred	memset(&guid_info_rec, 0, sizeof (struct ib_sa_guidinfo_rec));
385255932Salfred
386255932Salfred	guid_info_rec.lid = cpu_to_be16(attr.lid);
387255932Salfred	guid_info_rec.block_num = index;
388255932Salfred
389255932Salfred	memcpy(guid_info_rec.guid_info_list, rec_det->all_recs,
390255932Salfred	       GUID_REC_SIZE * NUM_ALIAS_GUID_IN_REC);
391255932Salfred	comp_mask = IB_SA_GUIDINFO_REC_LID | IB_SA_GUIDINFO_REC_BLOCK_NUM |
392255932Salfred		rec_det->guid_indexes;
393255932Salfred
394255932Salfred	init_completion(&callback_context->done);
395255932Salfred	spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
396255932Salfred	list_add_tail(&callback_context->list, head);
397255932Salfred	spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
398255932Salfred
399255932Salfred	callback_context->query_id =
400255932Salfred		ib_sa_guid_info_rec_query(dev->sriov.alias_guid.sa_client,
401255932Salfred					  ibdev, port, &guid_info_rec,
402255932Salfred					  comp_mask, rec_det->method, 1000,
403255932Salfred					  GFP_KERNEL, aliasguid_query_handler,
404255932Salfred					  callback_context,
405255932Salfred					  &callback_context->sa_query);
406255932Salfred	if (callback_context->query_id < 0) {
407255932Salfred		pr_debug("ib_sa_guid_info_rec_query failed, query_id: "
408255932Salfred			 "%d. will reschedule to the next 1 sec.\n",
409255932Salfred			 callback_context->query_id);
410255932Salfred		spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
411255932Salfred		list_del(&callback_context->list);
412255932Salfred		kfree(callback_context);
413255932Salfred		spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
414255932Salfred		resched_delay = 1 * HZ;
415255932Salfred		err = -EAGAIN;
416255932Salfred		goto new_schedule;
417255932Salfred	}
418255932Salfred	err = 0;
419255932Salfred	goto out;
420255932Salfred
421255932Salfrednew_schedule:
422255932Salfred	spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
423255932Salfred	spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
424255932Salfred	invalidate_guid_record(dev, port, index);
425255932Salfred	if (!dev->sriov.is_going_down) {
426255932Salfred		queue_delayed_work(dev->sriov.alias_guid.ports_guid[port - 1].wq,
427255932Salfred				   &dev->sriov.alias_guid.ports_guid[port - 1].alias_guid_work,
428255932Salfred				   resched_delay);
429255932Salfred	}
430255932Salfred	spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
431255932Salfred	spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
432255932Salfred
433255932Salfredout:
434255932Salfred	return err;
435255932Salfred}
436255932Salfred
437255932Salfredvoid mlx4_ib_invalidate_all_guid_record(struct mlx4_ib_dev *dev, int port)
438255932Salfred{
439255932Salfred	int i;
440255932Salfred	unsigned long flags, flags1;
441255932Salfred
442255932Salfred	pr_debug("port %d\n", port);
443255932Salfred
444255932Salfred	spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
445255932Salfred	spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
446255932Salfred	for (i = 0; i < NUM_ALIAS_GUID_REC_IN_PORT; i++)
447255932Salfred		invalidate_guid_record(dev, port, i);
448255932Salfred
449255932Salfred	if (mlx4_is_master(dev->dev) && !dev->sriov.is_going_down) {
450255932Salfred		/*
451255932Salfred		make sure no work waits in the queue, if the work is already
452255932Salfred		queued(not on the timer) the cancel will fail. That is not a problem
453255932Salfred		because we just want the work started.
454255932Salfred		*/
455255932Salfred		cancel_delayed_work(&dev->sriov.alias_guid.
456255932Salfred				      ports_guid[port - 1].alias_guid_work);
457255932Salfred		queue_delayed_work(dev->sriov.alias_guid.ports_guid[port - 1].wq,
458255932Salfred				   &dev->sriov.alias_guid.ports_guid[port - 1].alias_guid_work,
459255932Salfred				   0);
460255932Salfred	}
461255932Salfred	spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
462255932Salfred	spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
463255932Salfred}
464255932Salfred
465255932Salfred/* The function returns the next record that was
466255932Salfred * not configured (or failed to be configured) */
467255932Salfredstatic int get_next_record_to_update(struct mlx4_ib_dev *dev, u8 port,
468255932Salfred				     struct mlx4_next_alias_guid_work *rec)
469255932Salfred{
470255932Salfred	int j;
471255932Salfred	unsigned long flags;
472255932Salfred
473255932Salfred	for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) {
474255932Salfred		spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags);
475255932Salfred		if (dev->sriov.alias_guid.ports_guid[port].all_rec_per_port[j].status ==
476255932Salfred		    MLX4_GUID_INFO_STATUS_IDLE) {
477255932Salfred			memcpy(&rec->rec_det,
478255932Salfred			       &dev->sriov.alias_guid.ports_guid[port].all_rec_per_port[j],
479255932Salfred			       sizeof (struct mlx4_sriov_alias_guid_info_rec_det));
480255932Salfred			rec->port = port;
481255932Salfred			rec->block_num = j;
482255932Salfred			dev->sriov.alias_guid.ports_guid[port].all_rec_per_port[j].status =
483255932Salfred				MLX4_GUID_INFO_STATUS_PENDING;
484255932Salfred			spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags);
485255932Salfred			return 0;
486255932Salfred		}
487255932Salfred		spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags);
488255932Salfred	}
489255932Salfred	return -ENOENT;
490255932Salfred}
491255932Salfred
492255932Salfredstatic void set_administratively_guid_record(struct mlx4_ib_dev *dev, int port,
493255932Salfred					     int rec_index,
494255932Salfred					     struct mlx4_sriov_alias_guid_info_rec_det *rec_det)
495255932Salfred{
496255932Salfred	dev->sriov.alias_guid.ports_guid[port].all_rec_per_port[rec_index].guid_indexes =
497255932Salfred		rec_det->guid_indexes;
498255932Salfred	memcpy(dev->sriov.alias_guid.ports_guid[port].all_rec_per_port[rec_index].all_recs,
499255932Salfred	       rec_det->all_recs, NUM_ALIAS_GUID_IN_REC * GUID_REC_SIZE);
500255932Salfred	dev->sriov.alias_guid.ports_guid[port].all_rec_per_port[rec_index].status =
501255932Salfred		rec_det->status;
502255932Salfred}
503255932Salfred
504255932Salfredstatic void set_all_slaves_guids(struct mlx4_ib_dev *dev, int port)
505255932Salfred{
506255932Salfred	int j;
507255932Salfred	struct mlx4_sriov_alias_guid_info_rec_det rec_det ;
508255932Salfred
509255932Salfred	for (j = 0 ; j < NUM_ALIAS_GUID_REC_IN_PORT ; j++) {
510255932Salfred		memset(rec_det.all_recs, 0, NUM_ALIAS_GUID_IN_REC * GUID_REC_SIZE);
511255932Salfred		rec_det.guid_indexes = (!j ? 0 : IB_SA_GUIDINFO_REC_GID0) |
512255932Salfred			IB_SA_GUIDINFO_REC_GID1 | IB_SA_GUIDINFO_REC_GID2 |
513255932Salfred			IB_SA_GUIDINFO_REC_GID3 | IB_SA_GUIDINFO_REC_GID4 |
514255932Salfred			IB_SA_GUIDINFO_REC_GID5 | IB_SA_GUIDINFO_REC_GID6 |
515255932Salfred			IB_SA_GUIDINFO_REC_GID7;
516255932Salfred		rec_det.status = MLX4_GUID_INFO_STATUS_IDLE;
517255932Salfred		set_administratively_guid_record(dev, port, j, &rec_det);
518255932Salfred	}
519255932Salfred}
520255932Salfred
521255932Salfredstatic void alias_guid_work(struct work_struct *work)
522255932Salfred{
523255932Salfred	struct delayed_work *delay = to_delayed_work(work);
524255932Salfred	int ret = 0;
525255932Salfred	struct mlx4_next_alias_guid_work *rec;
526255932Salfred	struct mlx4_sriov_alias_guid_port_rec_det *sriov_alias_port =
527255932Salfred		container_of(delay, struct mlx4_sriov_alias_guid_port_rec_det,
528255932Salfred			     alias_guid_work);
529255932Salfred	struct mlx4_sriov_alias_guid *sriov_alias_guid = sriov_alias_port->parent;
530255932Salfred	struct mlx4_ib_sriov *ib_sriov = container_of(sriov_alias_guid,
531255932Salfred						struct mlx4_ib_sriov,
532255932Salfred						alias_guid);
533255932Salfred	struct mlx4_ib_dev *dev = container_of(ib_sriov, struct mlx4_ib_dev, sriov);
534255932Salfred
535255932Salfred	rec = kzalloc(sizeof *rec, GFP_KERNEL);
536255932Salfred	if (!rec) {
537255932Salfred		pr_err("alias_guid_work: No Memory\n");
538255932Salfred		return;
539255932Salfred	}
540255932Salfred
541255932Salfred	pr_debug("starting [port: %d]...\n", sriov_alias_port->port + 1);
542255932Salfred	ret = get_next_record_to_update(dev, sriov_alias_port->port, rec);
543255932Salfred	if (ret) {
544255932Salfred		pr_debug("No more records to update.\n");
545255932Salfred		goto out;
546255932Salfred	}
547255932Salfred
548255932Salfred	set_guid_rec(&dev->ib_dev, rec->port + 1, rec->block_num,
549255932Salfred		     &rec->rec_det);
550255932Salfred
551255932Salfredout:
552255932Salfred	kfree(rec);
553255932Salfred}
554255932Salfred
555255932Salfred
556255932Salfredvoid mlx4_ib_init_alias_guid_work(struct mlx4_ib_dev *dev, int port)
557255932Salfred{
558255932Salfred	unsigned long flags, flags1;
559255932Salfred
560255932Salfred	if (!mlx4_is_master(dev->dev))
561255932Salfred		return;
562255932Salfred	spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
563255932Salfred	spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
564255932Salfred	if (!dev->sriov.is_going_down) {
565255932Salfred		queue_delayed_work(dev->sriov.alias_guid.ports_guid[port].wq,
566255932Salfred			   &dev->sriov.alias_guid.ports_guid[port].alias_guid_work, 0);
567255932Salfred	}
568255932Salfred	spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
569255932Salfred	spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
570255932Salfred}
571255932Salfred
572255932Salfredvoid mlx4_ib_destroy_alias_guid_service(struct mlx4_ib_dev *dev)
573255932Salfred{
574255932Salfred	int i;
575255932Salfred	struct mlx4_ib_sriov *sriov = &dev->sriov;
576255932Salfred	struct mlx4_alias_guid_work_context *cb_ctx;
577255932Salfred	struct mlx4_sriov_alias_guid_port_rec_det *det;
578255932Salfred	struct ib_sa_query *sa_query;
579255932Salfred	unsigned long flags;
580255932Salfred
581255932Salfred	for (i = 0 ; i < dev->num_ports; i++) {
582255932Salfred		cancel_delayed_work(&dev->sriov.alias_guid.ports_guid[i].alias_guid_work);
583255932Salfred		det = &sriov->alias_guid.ports_guid[i];
584255932Salfred		spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags);
585255932Salfred		while (!list_empty(&det->cb_list)) {
586255932Salfred			cb_ctx = list_entry(det->cb_list.next,
587255932Salfred					    struct mlx4_alias_guid_work_context,
588255932Salfred					    list);
589255932Salfred			sa_query = cb_ctx->sa_query;
590255932Salfred			cb_ctx->sa_query = NULL;
591255932Salfred			list_del(&cb_ctx->list);
592255932Salfred			spin_unlock_irqrestore(&sriov->alias_guid.ag_work_lock, flags);
593255932Salfred			ib_sa_cancel_query(cb_ctx->query_id, sa_query);
594255932Salfred			wait_for_completion(&cb_ctx->done);
595255932Salfred			kfree(cb_ctx);
596255932Salfred			spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags);
597255932Salfred		}
598255932Salfred		spin_unlock_irqrestore(&sriov->alias_guid.ag_work_lock, flags);
599255932Salfred	}
600255932Salfred	for (i = 0 ; i < dev->num_ports; i++) {
601255932Salfred		flush_workqueue(dev->sriov.alias_guid.ports_guid[i].wq);
602255932Salfred		destroy_workqueue(dev->sriov.alias_guid.ports_guid[i].wq);
603255932Salfred	}
604255932Salfred	ib_sa_unregister_client(dev->sriov.alias_guid.sa_client);
605255932Salfred	kfree(dev->sriov.alias_guid.sa_client);
606255932Salfred}
607255932Salfred
608255932Salfredint mlx4_ib_init_alias_guid_service(struct mlx4_ib_dev *dev)
609255932Salfred{
610255932Salfred	char alias_wq_name[15];
611255932Salfred	int ret = 0;
612255932Salfred	int i, j, k;
613255932Salfred	union ib_gid gid;
614255932Salfred
615255932Salfred	if (!mlx4_is_master(dev->dev))
616255932Salfred		return 0;
617255932Salfred	dev->sriov.alias_guid.sa_client =
618255932Salfred		kzalloc(sizeof *dev->sriov.alias_guid.sa_client, GFP_KERNEL);
619255932Salfred	if (!dev->sriov.alias_guid.sa_client)
620255932Salfred		return -ENOMEM;
621255932Salfred
622255932Salfred	ib_sa_register_client(dev->sriov.alias_guid.sa_client);
623255932Salfred
624255932Salfred	spin_lock_init(&dev->sriov.alias_guid.ag_work_lock);
625255932Salfred
626255932Salfred	for (i = 1; i <= dev->num_ports; ++i) {
627255932Salfred		if (dev->ib_dev.query_gid(&dev->ib_dev , i, 0, &gid)) {
628255932Salfred			ret = -EFAULT;
629255932Salfred			goto err_unregister;
630255932Salfred		}
631255932Salfred	}
632255932Salfred
633255932Salfred	for (i = 0 ; i < dev->num_ports; i++) {
634255932Salfred		memset(&dev->sriov.alias_guid.ports_guid[i], 0,
635255932Salfred		       sizeof (struct mlx4_sriov_alias_guid_port_rec_det));
636255932Salfred		/*Check if the SM doesn't need to assign the GUIDs*/
637255932Salfred		for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) {
638255932Salfred			if (mlx4_ib_sm_guid_assign) {
639255932Salfred				dev->sriov.alias_guid.ports_guid[i].
640255932Salfred					all_rec_per_port[j].
641255932Salfred					ownership = MLX4_GUID_DRIVER_ASSIGN;
642255932Salfred				continue;
643255932Salfred			}
644255932Salfred			dev->sriov.alias_guid.ports_guid[i].all_rec_per_port[j].
645255932Salfred					ownership = MLX4_GUID_NONE_ASSIGN;
646255932Salfred			/*mark each val as it was deleted,
647255932Salfred			  till the sysAdmin will give it valid val*/
648255932Salfred			for (k = 0; k < NUM_ALIAS_GUID_IN_REC; k++) {
649255932Salfred				*(__be64 *)&dev->sriov.alias_guid.ports_guid[i].
650255932Salfred					all_rec_per_port[j].all_recs[GUID_REC_SIZE * k] =
651255932Salfred						cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL);
652255932Salfred			}
653255932Salfred		}
654255932Salfred		INIT_LIST_HEAD(&dev->sriov.alias_guid.ports_guid[i].cb_list);
655255932Salfred		/*prepare the records, set them to be allocated by sm*/
656255932Salfred		for (j = 0 ; j < NUM_ALIAS_GUID_REC_IN_PORT; j++)
657255932Salfred			invalidate_guid_record(dev, i + 1, j);
658255932Salfred
659255932Salfred		dev->sriov.alias_guid.ports_guid[i].parent = &dev->sriov.alias_guid;
660255932Salfred		dev->sriov.alias_guid.ports_guid[i].port  = i;
661255932Salfred		if (mlx4_ib_sm_guid_assign)
662255932Salfred			set_all_slaves_guids(dev, i);
663255932Salfred
664255932Salfred		snprintf(alias_wq_name, sizeof alias_wq_name, "alias_guid%d", i);
665255932Salfred		dev->sriov.alias_guid.ports_guid[i].wq =
666255932Salfred			create_singlethread_workqueue(alias_wq_name);
667255932Salfred		if (!dev->sriov.alias_guid.ports_guid[i].wq) {
668255932Salfred			ret = -ENOMEM;
669255932Salfred			goto err_thread;
670255932Salfred		}
671255932Salfred		INIT_DELAYED_WORK(&dev->sriov.alias_guid.ports_guid[i].alias_guid_work,
672255932Salfred			  alias_guid_work);
673255932Salfred	}
674255932Salfred	return 0;
675255932Salfred
676255932Salfrederr_thread:
677255932Salfred	for (--i; i >= 0; i--) {
678255932Salfred		destroy_workqueue(dev->sriov.alias_guid.ports_guid[i].wq);
679255932Salfred		dev->sriov.alias_guid.ports_guid[i].wq = NULL;
680255932Salfred	}
681255932Salfred
682255932Salfrederr_unregister:
683255932Salfred	ib_sa_unregister_client(dev->sriov.alias_guid.sa_client);
684255932Salfred	kfree(dev->sriov.alias_guid.sa_client);
685255932Salfred	dev->sriov.alias_guid.sa_client = NULL;
686255932Salfred	pr_err("init_alias_guid_service: Failed. (ret:%d)\n", ret);
687255932Salfred	return ret;
688255932Salfred}
689