xref: /linux/drivers/infiniband/hw/mlx4/alias_GUID.c (revision 74d4943fbb8c2fd32440a0bb4a6a01290d15709b)
1a0c64a17SJack Morgenstein /*
2a0c64a17SJack Morgenstein  * Copyright (c) 2012 Mellanox Technologies. All rights reserved.
3a0c64a17SJack Morgenstein  *
4a0c64a17SJack Morgenstein  * This software is available to you under a choice of one of two
5a0c64a17SJack Morgenstein  * licenses.  You may choose to be licensed under the terms of the GNU
6a0c64a17SJack Morgenstein  * General Public License (GPL) Version 2, available from the file
7a0c64a17SJack Morgenstein  * COPYING in the main directory of this source tree, or the
8a0c64a17SJack Morgenstein  * OpenIB.org BSD license below:
9a0c64a17SJack Morgenstein  *
10a0c64a17SJack Morgenstein  *     Redistribution and use in source and binary forms, with or
11a0c64a17SJack Morgenstein  *     without modification, are permitted provided that the following
12a0c64a17SJack Morgenstein  *     conditions are met:
13a0c64a17SJack Morgenstein  *
14a0c64a17SJack Morgenstein  *      - Redistributions of source code must retain the above
15a0c64a17SJack Morgenstein  *        copyright notice, this list of conditions and the following
16a0c64a17SJack Morgenstein  *        disclaimer.
17a0c64a17SJack Morgenstein  *
18a0c64a17SJack Morgenstein  *      - Redistributions in binary form must reproduce the above
19a0c64a17SJack Morgenstein  *        copyright notice, this list of conditions and the following
20a0c64a17SJack Morgenstein  *        disclaimer in the documentation and/or other materials
21a0c64a17SJack Morgenstein  *        provided with the distribution.
22a0c64a17SJack Morgenstein  *
23a0c64a17SJack Morgenstein  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24a0c64a17SJack Morgenstein  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25a0c64a17SJack Morgenstein  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26a0c64a17SJack Morgenstein  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27a0c64a17SJack Morgenstein  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28a0c64a17SJack Morgenstein  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29a0c64a17SJack Morgenstein  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30a0c64a17SJack Morgenstein  * SOFTWARE.
31a0c64a17SJack Morgenstein  */
32a0c64a17SJack Morgenstein  /***********************************************************/
33a0c64a17SJack Morgenstein /*This file support the handling of the Alias GUID feature. */
34a0c64a17SJack Morgenstein /***********************************************************/
35a0c64a17SJack Morgenstein #include <rdma/ib_mad.h>
36a0c64a17SJack Morgenstein #include <rdma/ib_smi.h>
37a0c64a17SJack Morgenstein #include <rdma/ib_cache.h>
38a0c64a17SJack Morgenstein #include <rdma/ib_sa.h>
39a0c64a17SJack Morgenstein #include <rdma/ib_pack.h>
40a0c64a17SJack Morgenstein #include <linux/mlx4/cmd.h>
41a0c64a17SJack Morgenstein #include <linux/module.h>
42a0c64a17SJack Morgenstein #include <linux/init.h>
43a0c64a17SJack Morgenstein #include <linux/errno.h>
44a0c64a17SJack Morgenstein #include <rdma/ib_user_verbs.h>
45a0c64a17SJack Morgenstein #include <linux/delay.h>
46a0c64a17SJack Morgenstein #include "mlx4_ib.h"
47a0c64a17SJack Morgenstein 
48a0c64a17SJack Morgenstein /*
49a0c64a17SJack Morgenstein The driver keeps the current state of all guids, as they are in the HW.
50a0c64a17SJack Morgenstein Whenever we receive an smp mad GUIDInfo record, the data will be cached.
51a0c64a17SJack Morgenstein */
52a0c64a17SJack Morgenstein 
53a0c64a17SJack Morgenstein struct mlx4_alias_guid_work_context {
54a0c64a17SJack Morgenstein 	u8 port;
55a0c64a17SJack Morgenstein 	struct mlx4_ib_dev     *dev ;
56a0c64a17SJack Morgenstein 	struct ib_sa_query     *sa_query;
57a0c64a17SJack Morgenstein 	struct completion	done;
58a0c64a17SJack Morgenstein 	int			query_id;
59a0c64a17SJack Morgenstein 	struct list_head	list;
60a0c64a17SJack Morgenstein 	int			block_num;
6199ee4df6SYishai Hadas 	ib_sa_comp_mask		guid_indexes;
6299ee4df6SYishai Hadas 	u8			method;
63a0c64a17SJack Morgenstein };
64a0c64a17SJack Morgenstein 
65a0c64a17SJack Morgenstein struct mlx4_next_alias_guid_work {
66a0c64a17SJack Morgenstein 	u8 port;
67a0c64a17SJack Morgenstein 	u8 block_num;
6899ee4df6SYishai Hadas 	u8 method;
69a0c64a17SJack Morgenstein 	struct mlx4_sriov_alias_guid_info_rec_det rec_det;
70a0c64a17SJack Morgenstein };
71a0c64a17SJack Morgenstein 
7299ee4df6SYishai Hadas static int get_low_record_time_index(struct mlx4_ib_dev *dev, u8 port,
7399ee4df6SYishai Hadas 				     int *resched_delay_sec);
74a0c64a17SJack Morgenstein 
75a0c64a17SJack Morgenstein void mlx4_ib_update_cache_on_guid_change(struct mlx4_ib_dev *dev, int block_num,
76a0c64a17SJack Morgenstein 					 u8 port_num, u8 *p_data)
77a0c64a17SJack Morgenstein {
78a0c64a17SJack Morgenstein 	int i;
79a0c64a17SJack Morgenstein 	u64 guid_indexes;
80a0c64a17SJack Morgenstein 	int slave_id;
81a0c64a17SJack Morgenstein 	int port_index = port_num - 1;
82a0c64a17SJack Morgenstein 
83a0c64a17SJack Morgenstein 	if (!mlx4_is_master(dev->dev))
84a0c64a17SJack Morgenstein 		return;
85a0c64a17SJack Morgenstein 
86a0c64a17SJack Morgenstein 	guid_indexes = be64_to_cpu((__force __be64) dev->sriov.alias_guid.
87a0c64a17SJack Morgenstein 				   ports_guid[port_num - 1].
88a0c64a17SJack Morgenstein 				   all_rec_per_port[block_num].guid_indexes);
89a0c64a17SJack Morgenstein 	pr_debug("port: %d, guid_indexes: 0x%llx\n", port_num, guid_indexes);
90a0c64a17SJack Morgenstein 
91a0c64a17SJack Morgenstein 	for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) {
92a0c64a17SJack Morgenstein 		/* The location of the specific index starts from bit number 4
93a0c64a17SJack Morgenstein 		 * until bit num 11 */
94a0c64a17SJack Morgenstein 		if (test_bit(i + 4, (unsigned long *)&guid_indexes)) {
95a0c64a17SJack Morgenstein 			slave_id = (block_num * NUM_ALIAS_GUID_IN_REC) + i ;
96a0c64a17SJack Morgenstein 			if (slave_id >= dev->dev->num_slaves) {
97a0c64a17SJack Morgenstein 				pr_debug("The last slave: %d\n", slave_id);
98a0c64a17SJack Morgenstein 				return;
99a0c64a17SJack Morgenstein 			}
100a0c64a17SJack Morgenstein 
101a0c64a17SJack Morgenstein 			/* cache the guid: */
102a0c64a17SJack Morgenstein 			memcpy(&dev->sriov.demux[port_index].guid_cache[slave_id],
103a0c64a17SJack Morgenstein 			       &p_data[i * GUID_REC_SIZE],
104a0c64a17SJack Morgenstein 			       GUID_REC_SIZE);
105a0c64a17SJack Morgenstein 		} else
106a0c64a17SJack Morgenstein 			pr_debug("Guid number: %d in block: %d"
107a0c64a17SJack Morgenstein 				 " was not updated\n", i, block_num);
108a0c64a17SJack Morgenstein 	}
109a0c64a17SJack Morgenstein }
110a0c64a17SJack Morgenstein 
111a0c64a17SJack Morgenstein static __be64 get_cached_alias_guid(struct mlx4_ib_dev *dev, int port, int index)
112a0c64a17SJack Morgenstein {
113a0c64a17SJack Morgenstein 	if (index >= NUM_ALIAS_GUID_PER_PORT) {
114a0c64a17SJack Morgenstein 		pr_err("%s: ERROR: asked for index:%d\n", __func__, index);
1158a095030SDoug Ledford 		return (__force __be64) -1;
116a0c64a17SJack Morgenstein 	}
117a0c64a17SJack Morgenstein 	return *(__be64 *)&dev->sriov.demux[port - 1].guid_cache[index];
118a0c64a17SJack Morgenstein }
119a0c64a17SJack Morgenstein 
120a0c64a17SJack Morgenstein 
121c1e7e466SJack Morgenstein ib_sa_comp_mask mlx4_ib_get_aguid_comp_mask_from_ix(int index)
122a0c64a17SJack Morgenstein {
123a0c64a17SJack Morgenstein 	return IB_SA_COMP_MASK(4 + index);
124a0c64a17SJack Morgenstein }
125a0c64a17SJack Morgenstein 
126ee59fa0dSYishai Hadas void mlx4_ib_slave_alias_guid_event(struct mlx4_ib_dev *dev, int slave,
127ee59fa0dSYishai Hadas 				    int port,  int slave_init)
128ee59fa0dSYishai Hadas {
129ee59fa0dSYishai Hadas 	__be64 curr_guid, required_guid;
130ee59fa0dSYishai Hadas 	int record_num = slave / 8;
131ee59fa0dSYishai Hadas 	int index = slave % 8;
132ee59fa0dSYishai Hadas 	int port_index = port - 1;
133ee59fa0dSYishai Hadas 	unsigned long flags;
134ee59fa0dSYishai Hadas 	int do_work = 0;
135ee59fa0dSYishai Hadas 
136ee59fa0dSYishai Hadas 	spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags);
137ee59fa0dSYishai Hadas 	if (dev->sriov.alias_guid.ports_guid[port_index].state_flags &
138ee59fa0dSYishai Hadas 	    GUID_STATE_NEED_PORT_INIT)
139ee59fa0dSYishai Hadas 		goto unlock;
140ee59fa0dSYishai Hadas 	if (!slave_init) {
141ee59fa0dSYishai Hadas 		curr_guid = *(__be64 *)&dev->sriov.
142ee59fa0dSYishai Hadas 			alias_guid.ports_guid[port_index].
143ee59fa0dSYishai Hadas 			all_rec_per_port[record_num].
144ee59fa0dSYishai Hadas 			all_recs[GUID_REC_SIZE * index];
145ee59fa0dSYishai Hadas 		if (curr_guid == cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL) ||
146ee59fa0dSYishai Hadas 		    !curr_guid)
147ee59fa0dSYishai Hadas 			goto unlock;
148ee59fa0dSYishai Hadas 		required_guid = cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL);
149ee59fa0dSYishai Hadas 	} else {
150ee59fa0dSYishai Hadas 		required_guid = mlx4_get_admin_guid(dev->dev, slave, port);
151ee59fa0dSYishai Hadas 		if (required_guid == cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL))
152ee59fa0dSYishai Hadas 			goto unlock;
153ee59fa0dSYishai Hadas 	}
154ee59fa0dSYishai Hadas 	*(__be64 *)&dev->sriov.alias_guid.ports_guid[port_index].
155ee59fa0dSYishai Hadas 		all_rec_per_port[record_num].
156ee59fa0dSYishai Hadas 		all_recs[GUID_REC_SIZE * index] = required_guid;
157ee59fa0dSYishai Hadas 	dev->sriov.alias_guid.ports_guid[port_index].
158ee59fa0dSYishai Hadas 		all_rec_per_port[record_num].guid_indexes
159ee59fa0dSYishai Hadas 		|= mlx4_ib_get_aguid_comp_mask_from_ix(index);
160ee59fa0dSYishai Hadas 	dev->sriov.alias_guid.ports_guid[port_index].
161ee59fa0dSYishai Hadas 		all_rec_per_port[record_num].status
162ee59fa0dSYishai Hadas 		= MLX4_GUID_INFO_STATUS_IDLE;
163ee59fa0dSYishai Hadas 	/* set to run immediately */
164ee59fa0dSYishai Hadas 	dev->sriov.alias_guid.ports_guid[port_index].
165ee59fa0dSYishai Hadas 		all_rec_per_port[record_num].time_to_run = 0;
166ee59fa0dSYishai Hadas 	dev->sriov.alias_guid.ports_guid[port_index].
167ee59fa0dSYishai Hadas 		all_rec_per_port[record_num].
168ee59fa0dSYishai Hadas 		guids_retry_schedule[index] = 0;
169ee59fa0dSYishai Hadas 	do_work = 1;
170ee59fa0dSYishai Hadas unlock:
171ee59fa0dSYishai Hadas 	spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags);
172ee59fa0dSYishai Hadas 
173ee59fa0dSYishai Hadas 	if (do_work)
174ee59fa0dSYishai Hadas 		mlx4_ib_init_alias_guid_work(dev, port_index);
175ee59fa0dSYishai Hadas }
176ee59fa0dSYishai Hadas 
177a0c64a17SJack Morgenstein /*
178a0c64a17SJack Morgenstein  * Whenever new GUID is set/unset (guid table change) create event and
179a0c64a17SJack Morgenstein  * notify the relevant slave (master also should be notified).
180a0c64a17SJack Morgenstein  * If the GUID value is not as we have in the cache the slave will not be
181a0c64a17SJack Morgenstein  * updated; in this case it waits for the smp_snoop or the port management
182a0c64a17SJack Morgenstein  * event to call the function and to update the slave.
183a0c64a17SJack Morgenstein  * block_number - the index of the block (16 blocks available)
184a0c64a17SJack Morgenstein  * port_number - 1 or 2
185a0c64a17SJack Morgenstein  */
186a0c64a17SJack Morgenstein void mlx4_ib_notify_slaves_on_guid_change(struct mlx4_ib_dev *dev,
187a0c64a17SJack Morgenstein 					  int block_num, u8 port_num,
188a0c64a17SJack Morgenstein 					  u8 *p_data)
189a0c64a17SJack Morgenstein {
190a0c64a17SJack Morgenstein 	int i;
191a0c64a17SJack Morgenstein 	u64 guid_indexes;
192*74d4943fSOr Gerlitz 	int slave_id, slave_port;
193a0c64a17SJack Morgenstein 	enum slave_port_state new_state;
194a0c64a17SJack Morgenstein 	enum slave_port_state prev_state;
195a0c64a17SJack Morgenstein 	__be64 tmp_cur_ag, form_cache_ag;
196a0c64a17SJack Morgenstein 	enum slave_port_gen_event gen_event;
19799ee4df6SYishai Hadas 	struct mlx4_sriov_alias_guid_info_rec_det *rec;
19899ee4df6SYishai Hadas 	unsigned long flags;
19999ee4df6SYishai Hadas 	__be64 required_value;
200a0c64a17SJack Morgenstein 
201a0c64a17SJack Morgenstein 	if (!mlx4_is_master(dev->dev))
202a0c64a17SJack Morgenstein 		return;
203a0c64a17SJack Morgenstein 
20499ee4df6SYishai Hadas 	rec = &dev->sriov.alias_guid.ports_guid[port_num - 1].
20599ee4df6SYishai Hadas 			all_rec_per_port[block_num];
206a0c64a17SJack Morgenstein 	guid_indexes = be64_to_cpu((__force __be64) dev->sriov.alias_guid.
207a0c64a17SJack Morgenstein 				   ports_guid[port_num - 1].
208a0c64a17SJack Morgenstein 				   all_rec_per_port[block_num].guid_indexes);
209a0c64a17SJack Morgenstein 	pr_debug("port: %d, guid_indexes: 0x%llx\n", port_num, guid_indexes);
210a0c64a17SJack Morgenstein 
211a0c64a17SJack Morgenstein 	/*calculate the slaves and notify them*/
212a0c64a17SJack Morgenstein 	for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) {
213a0c64a17SJack Morgenstein 		/* the location of the specific index runs from bits 4..11 */
214a0c64a17SJack Morgenstein 		if (!(test_bit(i + 4, (unsigned long *)&guid_indexes)))
215a0c64a17SJack Morgenstein 			continue;
216a0c64a17SJack Morgenstein 
217a0c64a17SJack Morgenstein 		slave_id = (block_num * NUM_ALIAS_GUID_IN_REC) + i ;
218872bf2fbSYishai Hadas 		if (slave_id >= dev->dev->persist->num_vfs + 1)
219a0c64a17SJack Morgenstein 			return;
220*74d4943fSOr Gerlitz 
221*74d4943fSOr Gerlitz 		slave_port = mlx4_phys_to_slave_port(dev->dev, slave_id, port_num);
222*74d4943fSOr Gerlitz 		if (slave_port < 0) /* this port isn't available for the VF */
223*74d4943fSOr Gerlitz 			continue;
224*74d4943fSOr Gerlitz 
225a0c64a17SJack Morgenstein 		tmp_cur_ag = *(__be64 *)&p_data[i * GUID_REC_SIZE];
226a0c64a17SJack Morgenstein 		form_cache_ag = get_cached_alias_guid(dev, port_num,
227a0c64a17SJack Morgenstein 					(NUM_ALIAS_GUID_IN_REC * block_num) + i);
228a0c64a17SJack Morgenstein 		/*
229a0c64a17SJack Morgenstein 		 * Check if guid is not the same as in the cache,
230a0c64a17SJack Morgenstein 		 * If it is different, wait for the snoop_smp or the port mgmt
231a0c64a17SJack Morgenstein 		 * change event to update the slave on its port state change
232a0c64a17SJack Morgenstein 		 */
233a0c64a17SJack Morgenstein 		if (tmp_cur_ag != form_cache_ag)
234a0c64a17SJack Morgenstein 			continue;
235a0c64a17SJack Morgenstein 
23699ee4df6SYishai Hadas 		spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags);
23799ee4df6SYishai Hadas 		required_value = *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE];
23899ee4df6SYishai Hadas 
23999ee4df6SYishai Hadas 		if (required_value == cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL))
24099ee4df6SYishai Hadas 			required_value = 0;
24199ee4df6SYishai Hadas 
24299ee4df6SYishai Hadas 		if (tmp_cur_ag == required_value) {
24399ee4df6SYishai Hadas 			rec->guid_indexes = rec->guid_indexes &
24499ee4df6SYishai Hadas 			       ~mlx4_ib_get_aguid_comp_mask_from_ix(i);
24599ee4df6SYishai Hadas 		} else {
24699ee4df6SYishai Hadas 			/* may notify port down if value is 0 */
24799ee4df6SYishai Hadas 			if (tmp_cur_ag != MLX4_NOT_SET_GUID) {
24899ee4df6SYishai Hadas 				spin_unlock_irqrestore(&dev->sriov.
24999ee4df6SYishai Hadas 					alias_guid.ag_work_lock, flags);
25099ee4df6SYishai Hadas 				continue;
25199ee4df6SYishai Hadas 			}
25299ee4df6SYishai Hadas 		}
25399ee4df6SYishai Hadas 		spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock,
25499ee4df6SYishai Hadas 				       flags);
25599ee4df6SYishai Hadas 		mlx4_gen_guid_change_eqe(dev->dev, slave_id, port_num);
256a0c64a17SJack Morgenstein 		/*2 cases: Valid GUID, and Invalid Guid*/
257a0c64a17SJack Morgenstein 
258a0c64a17SJack Morgenstein 		if (tmp_cur_ag != MLX4_NOT_SET_GUID) { /*valid GUID*/
259a0c64a17SJack Morgenstein 			prev_state = mlx4_get_slave_port_state(dev->dev, slave_id, port_num);
260a0c64a17SJack Morgenstein 			new_state = set_and_calc_slave_port_state(dev->dev, slave_id, port_num,
261a0c64a17SJack Morgenstein 								  MLX4_PORT_STATE_IB_PORT_STATE_EVENT_GID_VALID,
262a0c64a17SJack Morgenstein 								  &gen_event);
263a0c64a17SJack Morgenstein 			pr_debug("slave: %d, port: %d prev_port_state: %d,"
264a0c64a17SJack Morgenstein 				 " new_port_state: %d, gen_event: %d\n",
265a0c64a17SJack Morgenstein 				 slave_id, port_num, prev_state, new_state, gen_event);
266a0c64a17SJack Morgenstein 			if (gen_event == SLAVE_PORT_GEN_EVENT_UP) {
267a0c64a17SJack Morgenstein 				pr_debug("sending PORT_UP event to slave: %d, port: %d\n",
268a0c64a17SJack Morgenstein 					 slave_id, port_num);
269a0c64a17SJack Morgenstein 				mlx4_gen_port_state_change_eqe(dev->dev, slave_id,
270a0c64a17SJack Morgenstein 							       port_num, MLX4_PORT_CHANGE_SUBTYPE_ACTIVE);
271a0c64a17SJack Morgenstein 			}
272a0c64a17SJack Morgenstein 		} else { /* request to invalidate GUID */
273a0c64a17SJack Morgenstein 			set_and_calc_slave_port_state(dev->dev, slave_id, port_num,
274a0c64a17SJack Morgenstein 						      MLX4_PORT_STATE_IB_EVENT_GID_INVALID,
275a0c64a17SJack Morgenstein 						      &gen_event);
27699ee4df6SYishai Hadas 			if (gen_event == SLAVE_PORT_GEN_EVENT_DOWN) {
277a0c64a17SJack Morgenstein 				pr_debug("sending PORT DOWN event to slave: %d, port: %d\n",
278a0c64a17SJack Morgenstein 					 slave_id, port_num);
27999ee4df6SYishai Hadas 				mlx4_gen_port_state_change_eqe(dev->dev,
28099ee4df6SYishai Hadas 							       slave_id,
28199ee4df6SYishai Hadas 							       port_num,
282a0c64a17SJack Morgenstein 							       MLX4_PORT_CHANGE_SUBTYPE_DOWN);
283a0c64a17SJack Morgenstein 			}
284a0c64a17SJack Morgenstein 		}
285a0c64a17SJack Morgenstein 	}
28699ee4df6SYishai Hadas }
287a0c64a17SJack Morgenstein 
288a0c64a17SJack Morgenstein static void aliasguid_query_handler(int status,
289a0c64a17SJack Morgenstein 				    struct ib_sa_guidinfo_rec *guid_rec,
290a0c64a17SJack Morgenstein 				    void *context)
291a0c64a17SJack Morgenstein {
292a0c64a17SJack Morgenstein 	struct mlx4_ib_dev *dev;
293a0c64a17SJack Morgenstein 	struct mlx4_alias_guid_work_context *cb_ctx = context;
294a0c64a17SJack Morgenstein 	u8 port_index ;
295a0c64a17SJack Morgenstein 	int i;
296a0c64a17SJack Morgenstein 	struct mlx4_sriov_alias_guid_info_rec_det *rec;
297a0c64a17SJack Morgenstein 	unsigned long flags, flags1;
29899ee4df6SYishai Hadas 	ib_sa_comp_mask declined_guid_indexes = 0;
29999ee4df6SYishai Hadas 	ib_sa_comp_mask applied_guid_indexes = 0;
30099ee4df6SYishai Hadas 	unsigned int resched_delay_sec = 0;
301a0c64a17SJack Morgenstein 
302a0c64a17SJack Morgenstein 	if (!context)
303a0c64a17SJack Morgenstein 		return;
304a0c64a17SJack Morgenstein 
305a0c64a17SJack Morgenstein 	dev = cb_ctx->dev;
306a0c64a17SJack Morgenstein 	port_index = cb_ctx->port - 1;
307a0c64a17SJack Morgenstein 	rec = &dev->sriov.alias_guid.ports_guid[port_index].
308a0c64a17SJack Morgenstein 		all_rec_per_port[cb_ctx->block_num];
309a0c64a17SJack Morgenstein 
310a0c64a17SJack Morgenstein 	if (status) {
311a0c64a17SJack Morgenstein 		pr_debug("(port: %d) failed: status = %d\n",
312a0c64a17SJack Morgenstein 			 cb_ctx->port, status);
31399ee4df6SYishai Hadas 		rec->time_to_run = ktime_get_real_ns() + 1 * NSEC_PER_SEC;
314a0c64a17SJack Morgenstein 		goto out;
315a0c64a17SJack Morgenstein 	}
316a0c64a17SJack Morgenstein 
317a0c64a17SJack Morgenstein 	if (guid_rec->block_num != cb_ctx->block_num) {
318a0c64a17SJack Morgenstein 		pr_err("block num mismatch: %d != %d\n",
319a0c64a17SJack Morgenstein 		       cb_ctx->block_num, guid_rec->block_num);
320a0c64a17SJack Morgenstein 		goto out;
321a0c64a17SJack Morgenstein 	}
322a0c64a17SJack Morgenstein 
323a0c64a17SJack Morgenstein 	pr_debug("lid/port: %d/%d, block_num: %d\n",
324a0c64a17SJack Morgenstein 		 be16_to_cpu(guid_rec->lid), cb_ctx->port,
325a0c64a17SJack Morgenstein 		 guid_rec->block_num);
326a0c64a17SJack Morgenstein 
327a0c64a17SJack Morgenstein 	rec = &dev->sriov.alias_guid.ports_guid[port_index].
328a0c64a17SJack Morgenstein 		all_rec_per_port[guid_rec->block_num];
329a0c64a17SJack Morgenstein 
33099ee4df6SYishai Hadas 	spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags);
331a0c64a17SJack Morgenstein 	for (i = 0 ; i < NUM_ALIAS_GUID_IN_REC; i++) {
33299ee4df6SYishai Hadas 		__be64 sm_response, required_val;
33399ee4df6SYishai Hadas 
33499ee4df6SYishai Hadas 		if (!(cb_ctx->guid_indexes &
33599ee4df6SYishai Hadas 			mlx4_ib_get_aguid_comp_mask_from_ix(i)))
33699ee4df6SYishai Hadas 			continue;
33799ee4df6SYishai Hadas 		sm_response = *(__be64 *)&guid_rec->guid_info_list
33899ee4df6SYishai Hadas 				[i * GUID_REC_SIZE];
33999ee4df6SYishai Hadas 		required_val = *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE];
34099ee4df6SYishai Hadas 		if (cb_ctx->method == MLX4_GUID_INFO_RECORD_DELETE) {
34199ee4df6SYishai Hadas 			if (required_val ==
34299ee4df6SYishai Hadas 			    cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL))
34399ee4df6SYishai Hadas 				goto next_entry;
34499ee4df6SYishai Hadas 
34599ee4df6SYishai Hadas 			/* A new value was set till we got the response */
34699ee4df6SYishai Hadas 			pr_debug("need to set new value %llx, record num %d, block_num:%d\n",
34799ee4df6SYishai Hadas 				 be64_to_cpu(required_val),
34899ee4df6SYishai Hadas 				 i, guid_rec->block_num);
34999ee4df6SYishai Hadas 			goto entry_declined;
35099ee4df6SYishai Hadas 		}
35199ee4df6SYishai Hadas 
352a0c64a17SJack Morgenstein 		/* check if the SM didn't assign one of the records.
35399ee4df6SYishai Hadas 		 * if it didn't, re-ask for.
354a0c64a17SJack Morgenstein 		 */
35599ee4df6SYishai Hadas 		if (sm_response == MLX4_NOT_SET_GUID) {
35699ee4df6SYishai Hadas 			if (rec->guids_retry_schedule[i] == 0)
357f5479601SYishai Hadas 				mlx4_ib_warn(&dev->ib_dev,
358f5479601SYishai Hadas 					     "%s:Record num %d in  block_num: %d was declined by SM\n",
359f5479601SYishai Hadas 					     __func__, i,
360f5479601SYishai Hadas 					     guid_rec->block_num);
36199ee4df6SYishai Hadas 			goto entry_declined;
362a0c64a17SJack Morgenstein 		} else {
363a0c64a17SJack Morgenstein 		       /* properly assigned record. */
364a0c64a17SJack Morgenstein 		       /* We save the GUID we just got from the SM in the
365a0c64a17SJack Morgenstein 			* admin_guid in order to be persistent, and in the
366a0c64a17SJack Morgenstein 			* request from the sm the process will ask for the same GUID */
367f5479601SYishai Hadas 			if (required_val &&
36899ee4df6SYishai Hadas 			    sm_response != required_val) {
36999ee4df6SYishai Hadas 				/* Warn only on first retry */
37099ee4df6SYishai Hadas 				if (rec->guids_retry_schedule[i] == 0)
371a0c64a17SJack Morgenstein 					mlx4_ib_warn(&dev->ib_dev, "%s: Failed to set"
372a0c64a17SJack Morgenstein 						     " admin guid after SysAdmin "
373a0c64a17SJack Morgenstein 						     "configuration. "
374a0c64a17SJack Morgenstein 						     "Record num %d in block_num:%d "
375a0c64a17SJack Morgenstein 						     "was declined by SM, "
37699ee4df6SYishai Hadas 						     "new val(0x%llx) was kept, SM returned (0x%llx)\n",
377a0c64a17SJack Morgenstein 						      __func__, i,
378a0c64a17SJack Morgenstein 						     guid_rec->block_num,
37999ee4df6SYishai Hadas 						     be64_to_cpu(required_val),
38099ee4df6SYishai Hadas 						     be64_to_cpu(sm_response));
38199ee4df6SYishai Hadas 				goto entry_declined;
382a0c64a17SJack Morgenstein 			} else {
38399ee4df6SYishai Hadas 				*(__be64 *)&rec->all_recs[i * GUID_REC_SIZE] =
38499ee4df6SYishai Hadas 					sm_response;
3852350f247SYishai Hadas 				if (required_val == 0)
3862350f247SYishai Hadas 					mlx4_set_admin_guid(dev->dev,
3872350f247SYishai Hadas 							    sm_response,
3882350f247SYishai Hadas 							    (guid_rec->block_num
3892350f247SYishai Hadas 							    * NUM_ALIAS_GUID_IN_REC) + i,
3902350f247SYishai Hadas 							    cb_ctx->port);
39199ee4df6SYishai Hadas 				goto next_entry;
392a0c64a17SJack Morgenstein 			}
393a0c64a17SJack Morgenstein 		}
39499ee4df6SYishai Hadas entry_declined:
39599ee4df6SYishai Hadas 		declined_guid_indexes |= mlx4_ib_get_aguid_comp_mask_from_ix(i);
39699ee4df6SYishai Hadas 		rec->guids_retry_schedule[i] =
39799ee4df6SYishai Hadas 			(rec->guids_retry_schedule[i] == 0) ?  1 :
39899ee4df6SYishai Hadas 			min((unsigned int)60,
39999ee4df6SYishai Hadas 			    rec->guids_retry_schedule[i] * 2);
40099ee4df6SYishai Hadas 		/* using the minimum value among all entries in that record */
40199ee4df6SYishai Hadas 		resched_delay_sec = (resched_delay_sec == 0) ?
40299ee4df6SYishai Hadas 				rec->guids_retry_schedule[i] :
40399ee4df6SYishai Hadas 				min(resched_delay_sec,
40499ee4df6SYishai Hadas 				    rec->guids_retry_schedule[i]);
40599ee4df6SYishai Hadas 		continue;
40699ee4df6SYishai Hadas 
40799ee4df6SYishai Hadas next_entry:
40899ee4df6SYishai Hadas 		rec->guids_retry_schedule[i] = 0;
409a0c64a17SJack Morgenstein 	}
41099ee4df6SYishai Hadas 
41199ee4df6SYishai Hadas 	applied_guid_indexes =  cb_ctx->guid_indexes & ~declined_guid_indexes;
41299ee4df6SYishai Hadas 	if (declined_guid_indexes ||
41399ee4df6SYishai Hadas 	    rec->guid_indexes & ~(applied_guid_indexes)) {
41499ee4df6SYishai Hadas 		pr_debug("record=%d wasn't fully set, guid_indexes=0x%llx applied_indexes=0x%llx, declined_indexes=0x%llx\n",
41599ee4df6SYishai Hadas 			 guid_rec->block_num,
41699ee4df6SYishai Hadas 			 be64_to_cpu((__force __be64)rec->guid_indexes),
41799ee4df6SYishai Hadas 			 be64_to_cpu((__force __be64)applied_guid_indexes),
41899ee4df6SYishai Hadas 			 be64_to_cpu((__force __be64)declined_guid_indexes));
41999ee4df6SYishai Hadas 		rec->time_to_run = ktime_get_real_ns() +
42099ee4df6SYishai Hadas 			resched_delay_sec * NSEC_PER_SEC;
42199ee4df6SYishai Hadas 	} else {
42299ee4df6SYishai Hadas 		rec->status = MLX4_GUID_INFO_STATUS_SET;
42399ee4df6SYishai Hadas 	}
42499ee4df6SYishai Hadas 	spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags);
425a0c64a17SJack Morgenstein 	/*
426a0c64a17SJack Morgenstein 	The func is call here to close the cases when the
427a0c64a17SJack Morgenstein 	sm doesn't send smp, so in the sa response the driver
428a0c64a17SJack Morgenstein 	notifies the slave.
429a0c64a17SJack Morgenstein 	*/
430a0c64a17SJack Morgenstein 	mlx4_ib_notify_slaves_on_guid_change(dev, guid_rec->block_num,
431a0c64a17SJack Morgenstein 					     cb_ctx->port,
432a0c64a17SJack Morgenstein 					     guid_rec->guid_info_list);
433a0c64a17SJack Morgenstein out:
434a0c64a17SJack Morgenstein 	spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
435a0c64a17SJack Morgenstein 	spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
43699ee4df6SYishai Hadas 	if (!dev->sriov.is_going_down) {
43799ee4df6SYishai Hadas 		get_low_record_time_index(dev, port_index, &resched_delay_sec);
438a0c64a17SJack Morgenstein 		queue_delayed_work(dev->sriov.alias_guid.ports_guid[port_index].wq,
439a0c64a17SJack Morgenstein 				   &dev->sriov.alias_guid.ports_guid[port_index].
44099ee4df6SYishai Hadas 				   alias_guid_work,
44199ee4df6SYishai Hadas 				   msecs_to_jiffies(resched_delay_sec * 1000));
44299ee4df6SYishai Hadas 	}
443a0c64a17SJack Morgenstein 	if (cb_ctx->sa_query) {
444a0c64a17SJack Morgenstein 		list_del(&cb_ctx->list);
445a0c64a17SJack Morgenstein 		kfree(cb_ctx);
446a0c64a17SJack Morgenstein 	} else
447a0c64a17SJack Morgenstein 		complete(&cb_ctx->done);
448a0c64a17SJack Morgenstein 	spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
449a0c64a17SJack Morgenstein 	spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
450a0c64a17SJack Morgenstein }
451a0c64a17SJack Morgenstein 
452a0c64a17SJack Morgenstein static void invalidate_guid_record(struct mlx4_ib_dev *dev, u8 port, int index)
453a0c64a17SJack Morgenstein {
454a0c64a17SJack Morgenstein 	int i;
455a0c64a17SJack Morgenstein 	u64 cur_admin_val;
456a0c64a17SJack Morgenstein 	ib_sa_comp_mask comp_mask = 0;
457a0c64a17SJack Morgenstein 
458a0c64a17SJack Morgenstein 	dev->sriov.alias_guid.ports_guid[port - 1].all_rec_per_port[index].status
45999ee4df6SYishai Hadas 		= MLX4_GUID_INFO_STATUS_SET;
460a0c64a17SJack Morgenstein 
461a0c64a17SJack Morgenstein 	/* calculate the comp_mask for that record.*/
462a0c64a17SJack Morgenstein 	for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) {
463a0c64a17SJack Morgenstein 		cur_admin_val =
464a0c64a17SJack Morgenstein 			*(u64 *)&dev->sriov.alias_guid.ports_guid[port - 1].
465a0c64a17SJack Morgenstein 			all_rec_per_port[index].all_recs[GUID_REC_SIZE * i];
466a0c64a17SJack Morgenstein 		/*
467a0c64a17SJack Morgenstein 		check the admin value: if it's for delete (~00LL) or
468a0c64a17SJack Morgenstein 		it is the first guid of the first record (hw guid) or
469a0c64a17SJack Morgenstein 		the records is not in ownership of the sysadmin and the sm doesn't
470a0c64a17SJack Morgenstein 		need to assign GUIDs, then don't put it up for assignment.
471a0c64a17SJack Morgenstein 		*/
472a0c64a17SJack Morgenstein 		if (MLX4_GUID_FOR_DELETE_VAL == cur_admin_val ||
473f5479601SYishai Hadas 		    (!index && !i))
474a0c64a17SJack Morgenstein 			continue;
475c1e7e466SJack Morgenstein 		comp_mask |= mlx4_ib_get_aguid_comp_mask_from_ix(i);
476a0c64a17SJack Morgenstein 	}
477a0c64a17SJack Morgenstein 	dev->sriov.alias_guid.ports_guid[port - 1].
47899ee4df6SYishai Hadas 		all_rec_per_port[index].guid_indexes |= comp_mask;
47999ee4df6SYishai Hadas 	if (dev->sriov.alias_guid.ports_guid[port - 1].
48099ee4df6SYishai Hadas 	    all_rec_per_port[index].guid_indexes)
48199ee4df6SYishai Hadas 		dev->sriov.alias_guid.ports_guid[port - 1].
48299ee4df6SYishai Hadas 		all_rec_per_port[index].status = MLX4_GUID_INFO_STATUS_IDLE;
48399ee4df6SYishai Hadas 
484a0c64a17SJack Morgenstein }
485a0c64a17SJack Morgenstein 
486a0c64a17SJack Morgenstein static int set_guid_rec(struct ib_device *ibdev,
48799ee4df6SYishai Hadas 			struct mlx4_next_alias_guid_work *rec)
488a0c64a17SJack Morgenstein {
489a0c64a17SJack Morgenstein 	int err;
490a0c64a17SJack Morgenstein 	struct mlx4_ib_dev *dev = to_mdev(ibdev);
491a0c64a17SJack Morgenstein 	struct ib_sa_guidinfo_rec guid_info_rec;
492a0c64a17SJack Morgenstein 	ib_sa_comp_mask comp_mask;
493a0c64a17SJack Morgenstein 	struct ib_port_attr attr;
494a0c64a17SJack Morgenstein 	struct mlx4_alias_guid_work_context *callback_context;
495a0c64a17SJack Morgenstein 	unsigned long resched_delay, flags, flags1;
49699ee4df6SYishai Hadas 	u8 port = rec->port + 1;
49799ee4df6SYishai Hadas 	int index = rec->block_num;
49899ee4df6SYishai Hadas 	struct mlx4_sriov_alias_guid_info_rec_det *rec_det = &rec->rec_det;
499a0c64a17SJack Morgenstein 	struct list_head *head =
500a0c64a17SJack Morgenstein 		&dev->sriov.alias_guid.ports_guid[port - 1].cb_list;
501a0c64a17SJack Morgenstein 
502a0c64a17SJack Morgenstein 	err = __mlx4_ib_query_port(ibdev, port, &attr, 1);
503a0c64a17SJack Morgenstein 	if (err) {
504a0c64a17SJack Morgenstein 		pr_debug("mlx4_ib_query_port failed (err: %d), port: %d\n",
505a0c64a17SJack Morgenstein 			 err, port);
506a0c64a17SJack Morgenstein 		return err;
507a0c64a17SJack Morgenstein 	}
508a0c64a17SJack Morgenstein 	/*check the port was configured by the sm, otherwise no need to send */
509a0c64a17SJack Morgenstein 	if (attr.state != IB_PORT_ACTIVE) {
510a0c64a17SJack Morgenstein 		pr_debug("port %d not active...rescheduling\n", port);
511a0c64a17SJack Morgenstein 		resched_delay = 5 * HZ;
512a0c64a17SJack Morgenstein 		err = -EAGAIN;
513a0c64a17SJack Morgenstein 		goto new_schedule;
514a0c64a17SJack Morgenstein 	}
515a0c64a17SJack Morgenstein 
516a0c64a17SJack Morgenstein 	callback_context = kmalloc(sizeof *callback_context, GFP_KERNEL);
517a0c64a17SJack Morgenstein 	if (!callback_context) {
518a0c64a17SJack Morgenstein 		err = -ENOMEM;
519a0c64a17SJack Morgenstein 		resched_delay = HZ * 5;
520a0c64a17SJack Morgenstein 		goto new_schedule;
521a0c64a17SJack Morgenstein 	}
522a0c64a17SJack Morgenstein 	callback_context->port = port;
523a0c64a17SJack Morgenstein 	callback_context->dev = dev;
524a0c64a17SJack Morgenstein 	callback_context->block_num = index;
52599ee4df6SYishai Hadas 	callback_context->guid_indexes = rec_det->guid_indexes;
52699ee4df6SYishai Hadas 	callback_context->method = rec->method;
527a0c64a17SJack Morgenstein 
528a0c64a17SJack Morgenstein 	memset(&guid_info_rec, 0, sizeof (struct ib_sa_guidinfo_rec));
529a0c64a17SJack Morgenstein 
530a0c64a17SJack Morgenstein 	guid_info_rec.lid = cpu_to_be16(attr.lid);
531a0c64a17SJack Morgenstein 	guid_info_rec.block_num = index;
532a0c64a17SJack Morgenstein 
533a0c64a17SJack Morgenstein 	memcpy(guid_info_rec.guid_info_list, rec_det->all_recs,
534a0c64a17SJack Morgenstein 	       GUID_REC_SIZE * NUM_ALIAS_GUID_IN_REC);
535a0c64a17SJack Morgenstein 	comp_mask = IB_SA_GUIDINFO_REC_LID | IB_SA_GUIDINFO_REC_BLOCK_NUM |
536a0c64a17SJack Morgenstein 		rec_det->guid_indexes;
537a0c64a17SJack Morgenstein 
538a0c64a17SJack Morgenstein 	init_completion(&callback_context->done);
539a0c64a17SJack Morgenstein 	spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
540a0c64a17SJack Morgenstein 	list_add_tail(&callback_context->list, head);
541a0c64a17SJack Morgenstein 	spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
542a0c64a17SJack Morgenstein 
543a0c64a17SJack Morgenstein 	callback_context->query_id =
544a0c64a17SJack Morgenstein 		ib_sa_guid_info_rec_query(dev->sriov.alias_guid.sa_client,
545a0c64a17SJack Morgenstein 					  ibdev, port, &guid_info_rec,
54699ee4df6SYishai Hadas 					  comp_mask, rec->method, 1000,
547a0c64a17SJack Morgenstein 					  GFP_KERNEL, aliasguid_query_handler,
548a0c64a17SJack Morgenstein 					  callback_context,
549a0c64a17SJack Morgenstein 					  &callback_context->sa_query);
550a0c64a17SJack Morgenstein 	if (callback_context->query_id < 0) {
551a0c64a17SJack Morgenstein 		pr_debug("ib_sa_guid_info_rec_query failed, query_id: "
552a0c64a17SJack Morgenstein 			 "%d. will reschedule to the next 1 sec.\n",
553a0c64a17SJack Morgenstein 			 callback_context->query_id);
554a0c64a17SJack Morgenstein 		spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
555a0c64a17SJack Morgenstein 		list_del(&callback_context->list);
556a0c64a17SJack Morgenstein 		kfree(callback_context);
557a0c64a17SJack Morgenstein 		spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
558a0c64a17SJack Morgenstein 		resched_delay = 1 * HZ;
559a0c64a17SJack Morgenstein 		err = -EAGAIN;
560a0c64a17SJack Morgenstein 		goto new_schedule;
561a0c64a17SJack Morgenstein 	}
562a0c64a17SJack Morgenstein 	err = 0;
563a0c64a17SJack Morgenstein 	goto out;
564a0c64a17SJack Morgenstein 
565a0c64a17SJack Morgenstein new_schedule:
566a0c64a17SJack Morgenstein 	spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
567a0c64a17SJack Morgenstein 	spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
568a0c64a17SJack Morgenstein 	invalidate_guid_record(dev, port, index);
569a0c64a17SJack Morgenstein 	if (!dev->sriov.is_going_down) {
570a0c64a17SJack Morgenstein 		queue_delayed_work(dev->sriov.alias_guid.ports_guid[port - 1].wq,
571a0c64a17SJack Morgenstein 				   &dev->sriov.alias_guid.ports_guid[port - 1].alias_guid_work,
572a0c64a17SJack Morgenstein 				   resched_delay);
573a0c64a17SJack Morgenstein 	}
574a0c64a17SJack Morgenstein 	spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
575a0c64a17SJack Morgenstein 	spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
576a0c64a17SJack Morgenstein 
577a0c64a17SJack Morgenstein out:
578a0c64a17SJack Morgenstein 	return err;
579a0c64a17SJack Morgenstein }
580a0c64a17SJack Morgenstein 
581f5479601SYishai Hadas static void mlx4_ib_guid_port_init(struct mlx4_ib_dev *dev, int port)
582f5479601SYishai Hadas {
583f5479601SYishai Hadas 	int j, k, entry;
584f5479601SYishai Hadas 	__be64 guid;
585f5479601SYishai Hadas 
586f5479601SYishai Hadas 	/*Check if the SM doesn't need to assign the GUIDs*/
587f5479601SYishai Hadas 	for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) {
588f5479601SYishai Hadas 		for (k = 0; k < NUM_ALIAS_GUID_IN_REC; k++) {
589f5479601SYishai Hadas 			entry = j * NUM_ALIAS_GUID_IN_REC + k;
590f5479601SYishai Hadas 			/* no request for the 0 entry (hw guid) */
591f5479601SYishai Hadas 			if (!entry || entry > dev->dev->persist->num_vfs ||
592f5479601SYishai Hadas 			    !mlx4_is_slave_active(dev->dev, entry))
593f5479601SYishai Hadas 				continue;
594f5479601SYishai Hadas 			guid = mlx4_get_admin_guid(dev->dev, entry, port);
595f5479601SYishai Hadas 			*(__be64 *)&dev->sriov.alias_guid.ports_guid[port - 1].
596f5479601SYishai Hadas 				all_rec_per_port[j].all_recs
597f5479601SYishai Hadas 				[GUID_REC_SIZE * k] = guid;
598f5479601SYishai Hadas 			pr_debug("guid was set, entry=%d, val=0x%llx, port=%d\n",
599f5479601SYishai Hadas 				 entry,
600f5479601SYishai Hadas 				 be64_to_cpu(guid),
601f5479601SYishai Hadas 				 port);
602f5479601SYishai Hadas 		}
603f5479601SYishai Hadas 	}
604f5479601SYishai Hadas }
605a0c64a17SJack Morgenstein void mlx4_ib_invalidate_all_guid_record(struct mlx4_ib_dev *dev, int port)
606a0c64a17SJack Morgenstein {
607a0c64a17SJack Morgenstein 	int i;
608a0c64a17SJack Morgenstein 	unsigned long flags, flags1;
609a0c64a17SJack Morgenstein 
610a0c64a17SJack Morgenstein 	pr_debug("port %d\n", port);
611a0c64a17SJack Morgenstein 
612a0c64a17SJack Morgenstein 	spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
613a0c64a17SJack Morgenstein 	spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
614f5479601SYishai Hadas 
615f5479601SYishai Hadas 	if (dev->sriov.alias_guid.ports_guid[port - 1].state_flags &
616f5479601SYishai Hadas 		GUID_STATE_NEED_PORT_INIT) {
617f5479601SYishai Hadas 		mlx4_ib_guid_port_init(dev, port);
618f5479601SYishai Hadas 		dev->sriov.alias_guid.ports_guid[port - 1].state_flags &=
619f5479601SYishai Hadas 			(~GUID_STATE_NEED_PORT_INIT);
620f5479601SYishai Hadas 	}
621a0c64a17SJack Morgenstein 	for (i = 0; i < NUM_ALIAS_GUID_REC_IN_PORT; i++)
622a0c64a17SJack Morgenstein 		invalidate_guid_record(dev, port, i);
623a0c64a17SJack Morgenstein 
624a0c64a17SJack Morgenstein 	if (mlx4_is_master(dev->dev) && !dev->sriov.is_going_down) {
625a0c64a17SJack Morgenstein 		/*
626a0c64a17SJack Morgenstein 		make sure no work waits in the queue, if the work is already
627a0c64a17SJack Morgenstein 		queued(not on the timer) the cancel will fail. That is not a problem
628a0c64a17SJack Morgenstein 		because we just want the work started.
629a0c64a17SJack Morgenstein 		*/
6307a9a2970SLinus Torvalds 		cancel_delayed_work(&dev->sriov.alias_guid.
631a0c64a17SJack Morgenstein 				      ports_guid[port - 1].alias_guid_work);
632a0c64a17SJack Morgenstein 		queue_delayed_work(dev->sriov.alias_guid.ports_guid[port - 1].wq,
633a0c64a17SJack Morgenstein 				   &dev->sriov.alias_guid.ports_guid[port - 1].alias_guid_work,
634a0c64a17SJack Morgenstein 				   0);
635a0c64a17SJack Morgenstein 	}
636a0c64a17SJack Morgenstein 	spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
637a0c64a17SJack Morgenstein 	spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
638a0c64a17SJack Morgenstein }
639a0c64a17SJack Morgenstein 
64099ee4df6SYishai Hadas static void set_required_record(struct mlx4_ib_dev *dev, u8 port,
64199ee4df6SYishai Hadas 				struct mlx4_next_alias_guid_work *next_rec,
64299ee4df6SYishai Hadas 				int record_index)
64399ee4df6SYishai Hadas {
64499ee4df6SYishai Hadas 	int i;
64599ee4df6SYishai Hadas 	int lowset_time_entry = -1;
64699ee4df6SYishai Hadas 	int lowest_time = 0;
64799ee4df6SYishai Hadas 	ib_sa_comp_mask delete_guid_indexes = 0;
64899ee4df6SYishai Hadas 	ib_sa_comp_mask set_guid_indexes = 0;
64999ee4df6SYishai Hadas 	struct mlx4_sriov_alias_guid_info_rec_det *rec =
65099ee4df6SYishai Hadas 			&dev->sriov.alias_guid.ports_guid[port].
65199ee4df6SYishai Hadas 			all_rec_per_port[record_index];
65299ee4df6SYishai Hadas 
65399ee4df6SYishai Hadas 	for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) {
65499ee4df6SYishai Hadas 		if (!(rec->guid_indexes &
65599ee4df6SYishai Hadas 			mlx4_ib_get_aguid_comp_mask_from_ix(i)))
65699ee4df6SYishai Hadas 			continue;
65799ee4df6SYishai Hadas 
65899ee4df6SYishai Hadas 		if (*(__be64 *)&rec->all_recs[i * GUID_REC_SIZE] ==
65999ee4df6SYishai Hadas 				cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL))
66099ee4df6SYishai Hadas 			delete_guid_indexes |=
66199ee4df6SYishai Hadas 				mlx4_ib_get_aguid_comp_mask_from_ix(i);
66299ee4df6SYishai Hadas 		else
66399ee4df6SYishai Hadas 			set_guid_indexes |=
66499ee4df6SYishai Hadas 				mlx4_ib_get_aguid_comp_mask_from_ix(i);
66599ee4df6SYishai Hadas 
66699ee4df6SYishai Hadas 		if (lowset_time_entry == -1 || rec->guids_retry_schedule[i] <=
66799ee4df6SYishai Hadas 			lowest_time) {
66899ee4df6SYishai Hadas 			lowset_time_entry = i;
66999ee4df6SYishai Hadas 			lowest_time = rec->guids_retry_schedule[i];
67099ee4df6SYishai Hadas 		}
67199ee4df6SYishai Hadas 	}
67299ee4df6SYishai Hadas 
67399ee4df6SYishai Hadas 	memcpy(&next_rec->rec_det, rec, sizeof(*rec));
67499ee4df6SYishai Hadas 	next_rec->port = port;
67599ee4df6SYishai Hadas 	next_rec->block_num = record_index;
67699ee4df6SYishai Hadas 
67799ee4df6SYishai Hadas 	if (*(__be64 *)&rec->all_recs[lowset_time_entry * GUID_REC_SIZE] ==
67899ee4df6SYishai Hadas 				cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL)) {
67999ee4df6SYishai Hadas 		next_rec->rec_det.guid_indexes = delete_guid_indexes;
68099ee4df6SYishai Hadas 		next_rec->method = MLX4_GUID_INFO_RECORD_DELETE;
68199ee4df6SYishai Hadas 	} else {
68299ee4df6SYishai Hadas 		next_rec->rec_det.guid_indexes = set_guid_indexes;
68399ee4df6SYishai Hadas 		next_rec->method = MLX4_GUID_INFO_RECORD_SET;
68499ee4df6SYishai Hadas 	}
68599ee4df6SYishai Hadas }
68699ee4df6SYishai Hadas 
68799ee4df6SYishai Hadas /* return index of record that should be updated based on lowest
68899ee4df6SYishai Hadas  * rescheduled time
68999ee4df6SYishai Hadas  */
69099ee4df6SYishai Hadas static int get_low_record_time_index(struct mlx4_ib_dev *dev, u8 port,
69199ee4df6SYishai Hadas 				     int *resched_delay_sec)
69299ee4df6SYishai Hadas {
69399ee4df6SYishai Hadas 	int record_index = -1;
69499ee4df6SYishai Hadas 	u64 low_record_time = 0;
69599ee4df6SYishai Hadas 	struct mlx4_sriov_alias_guid_info_rec_det rec;
69699ee4df6SYishai Hadas 	int j;
69799ee4df6SYishai Hadas 
69899ee4df6SYishai Hadas 	for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) {
69999ee4df6SYishai Hadas 		rec = dev->sriov.alias_guid.ports_guid[port].
70099ee4df6SYishai Hadas 			all_rec_per_port[j];
70199ee4df6SYishai Hadas 		if (rec.status == MLX4_GUID_INFO_STATUS_IDLE &&
70299ee4df6SYishai Hadas 		    rec.guid_indexes) {
70399ee4df6SYishai Hadas 			if (record_index == -1 ||
70499ee4df6SYishai Hadas 			    rec.time_to_run < low_record_time) {
70599ee4df6SYishai Hadas 				record_index = j;
70699ee4df6SYishai Hadas 				low_record_time = rec.time_to_run;
70799ee4df6SYishai Hadas 			}
70899ee4df6SYishai Hadas 		}
70999ee4df6SYishai Hadas 	}
71099ee4df6SYishai Hadas 	if (resched_delay_sec) {
71199ee4df6SYishai Hadas 		u64 curr_time = ktime_get_real_ns();
71299ee4df6SYishai Hadas 
71399ee4df6SYishai Hadas 		*resched_delay_sec = (low_record_time < curr_time) ? 0 :
71499ee4df6SYishai Hadas 			div_u64((low_record_time - curr_time), NSEC_PER_SEC);
71599ee4df6SYishai Hadas 	}
71699ee4df6SYishai Hadas 
71799ee4df6SYishai Hadas 	return record_index;
71899ee4df6SYishai Hadas }
71999ee4df6SYishai Hadas 
720a0c64a17SJack Morgenstein /* The function returns the next record that was
721a0c64a17SJack Morgenstein  * not configured (or failed to be configured) */
722a0c64a17SJack Morgenstein static int get_next_record_to_update(struct mlx4_ib_dev *dev, u8 port,
723a0c64a17SJack Morgenstein 				     struct mlx4_next_alias_guid_work *rec)
724a0c64a17SJack Morgenstein {
725a0c64a17SJack Morgenstein 	unsigned long flags;
72699ee4df6SYishai Hadas 	int record_index;
72799ee4df6SYishai Hadas 	int ret = 0;
728a0c64a17SJack Morgenstein 
729a0c64a17SJack Morgenstein 	spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags);
73099ee4df6SYishai Hadas 	record_index = get_low_record_time_index(dev, port, NULL);
73199ee4df6SYishai Hadas 
73299ee4df6SYishai Hadas 	if (record_index < 0) {
73399ee4df6SYishai Hadas 		ret = -ENOENT;
73499ee4df6SYishai Hadas 		goto out;
735a0c64a17SJack Morgenstein 	}
73699ee4df6SYishai Hadas 
73799ee4df6SYishai Hadas 	set_required_record(dev, port, rec, record_index);
73899ee4df6SYishai Hadas out:
739a0c64a17SJack Morgenstein 	spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags);
74099ee4df6SYishai Hadas 	return ret;
741a0c64a17SJack Morgenstein }
742a0c64a17SJack Morgenstein 
743a0c64a17SJack Morgenstein static void alias_guid_work(struct work_struct *work)
744a0c64a17SJack Morgenstein {
745a0c64a17SJack Morgenstein 	struct delayed_work *delay = to_delayed_work(work);
746a0c64a17SJack Morgenstein 	int ret = 0;
747a0c64a17SJack Morgenstein 	struct mlx4_next_alias_guid_work *rec;
748a0c64a17SJack Morgenstein 	struct mlx4_sriov_alias_guid_port_rec_det *sriov_alias_port =
749a0c64a17SJack Morgenstein 		container_of(delay, struct mlx4_sriov_alias_guid_port_rec_det,
750a0c64a17SJack Morgenstein 			     alias_guid_work);
751a0c64a17SJack Morgenstein 	struct mlx4_sriov_alias_guid *sriov_alias_guid = sriov_alias_port->parent;
752a0c64a17SJack Morgenstein 	struct mlx4_ib_sriov *ib_sriov = container_of(sriov_alias_guid,
753a0c64a17SJack Morgenstein 						struct mlx4_ib_sriov,
754a0c64a17SJack Morgenstein 						alias_guid);
755a0c64a17SJack Morgenstein 	struct mlx4_ib_dev *dev = container_of(ib_sriov, struct mlx4_ib_dev, sriov);
756a0c64a17SJack Morgenstein 
757a0c64a17SJack Morgenstein 	rec = kzalloc(sizeof *rec, GFP_KERNEL);
758a0c64a17SJack Morgenstein 	if (!rec) {
759a0c64a17SJack Morgenstein 		pr_err("alias_guid_work: No Memory\n");
760a0c64a17SJack Morgenstein 		return;
761a0c64a17SJack Morgenstein 	}
762a0c64a17SJack Morgenstein 
763a0c64a17SJack Morgenstein 	pr_debug("starting [port: %d]...\n", sriov_alias_port->port + 1);
764a0c64a17SJack Morgenstein 	ret = get_next_record_to_update(dev, sriov_alias_port->port, rec);
765a0c64a17SJack Morgenstein 	if (ret) {
766a0c64a17SJack Morgenstein 		pr_debug("No more records to update.\n");
767a0c64a17SJack Morgenstein 		goto out;
768a0c64a17SJack Morgenstein 	}
769a0c64a17SJack Morgenstein 
77099ee4df6SYishai Hadas 	set_guid_rec(&dev->ib_dev, rec);
771a0c64a17SJack Morgenstein out:
772a0c64a17SJack Morgenstein 	kfree(rec);
773a0c64a17SJack Morgenstein }
774a0c64a17SJack Morgenstein 
775a0c64a17SJack Morgenstein 
776a0c64a17SJack Morgenstein void mlx4_ib_init_alias_guid_work(struct mlx4_ib_dev *dev, int port)
777a0c64a17SJack Morgenstein {
778a0c64a17SJack Morgenstein 	unsigned long flags, flags1;
779a0c64a17SJack Morgenstein 
780a0c64a17SJack Morgenstein 	if (!mlx4_is_master(dev->dev))
781a0c64a17SJack Morgenstein 		return;
782a0c64a17SJack Morgenstein 	spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
783a0c64a17SJack Morgenstein 	spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
784a0c64a17SJack Morgenstein 	if (!dev->sriov.is_going_down) {
78599ee4df6SYishai Hadas 		/* If there is pending one should cancell then run, otherwise
78699ee4df6SYishai Hadas 		  * won't run till previous one is ended as same work
78799ee4df6SYishai Hadas 		  * struct is used.
78899ee4df6SYishai Hadas 		  */
78999ee4df6SYishai Hadas 		cancel_delayed_work(&dev->sriov.alias_guid.ports_guid[port].
79099ee4df6SYishai Hadas 				    alias_guid_work);
791a0c64a17SJack Morgenstein 		queue_delayed_work(dev->sriov.alias_guid.ports_guid[port].wq,
792a0c64a17SJack Morgenstein 			   &dev->sriov.alias_guid.ports_guid[port].alias_guid_work, 0);
793a0c64a17SJack Morgenstein 	}
794a0c64a17SJack Morgenstein 	spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
795a0c64a17SJack Morgenstein 	spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
796a0c64a17SJack Morgenstein }
797a0c64a17SJack Morgenstein 
798a0c64a17SJack Morgenstein void mlx4_ib_destroy_alias_guid_service(struct mlx4_ib_dev *dev)
799a0c64a17SJack Morgenstein {
800a0c64a17SJack Morgenstein 	int i;
801a0c64a17SJack Morgenstein 	struct mlx4_ib_sriov *sriov = &dev->sriov;
802a0c64a17SJack Morgenstein 	struct mlx4_alias_guid_work_context *cb_ctx;
803a0c64a17SJack Morgenstein 	struct mlx4_sriov_alias_guid_port_rec_det *det;
804a0c64a17SJack Morgenstein 	struct ib_sa_query *sa_query;
805a0c64a17SJack Morgenstein 	unsigned long flags;
806a0c64a17SJack Morgenstein 
807a0c64a17SJack Morgenstein 	for (i = 0 ; i < dev->num_ports; i++) {
808a0c64a17SJack Morgenstein 		cancel_delayed_work(&dev->sriov.alias_guid.ports_guid[i].alias_guid_work);
809a0c64a17SJack Morgenstein 		det = &sriov->alias_guid.ports_guid[i];
810a0c64a17SJack Morgenstein 		spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags);
811a0c64a17SJack Morgenstein 		while (!list_empty(&det->cb_list)) {
812a0c64a17SJack Morgenstein 			cb_ctx = list_entry(det->cb_list.next,
813a0c64a17SJack Morgenstein 					    struct mlx4_alias_guid_work_context,
814a0c64a17SJack Morgenstein 					    list);
815a0c64a17SJack Morgenstein 			sa_query = cb_ctx->sa_query;
816a0c64a17SJack Morgenstein 			cb_ctx->sa_query = NULL;
817a0c64a17SJack Morgenstein 			list_del(&cb_ctx->list);
818a0c64a17SJack Morgenstein 			spin_unlock_irqrestore(&sriov->alias_guid.ag_work_lock, flags);
819a0c64a17SJack Morgenstein 			ib_sa_cancel_query(cb_ctx->query_id, sa_query);
820a0c64a17SJack Morgenstein 			wait_for_completion(&cb_ctx->done);
821a0c64a17SJack Morgenstein 			kfree(cb_ctx);
822a0c64a17SJack Morgenstein 			spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags);
823a0c64a17SJack Morgenstein 		}
824a0c64a17SJack Morgenstein 		spin_unlock_irqrestore(&sriov->alias_guid.ag_work_lock, flags);
825a0c64a17SJack Morgenstein 	}
826a0c64a17SJack Morgenstein 	for (i = 0 ; i < dev->num_ports; i++) {
827a0c64a17SJack Morgenstein 		flush_workqueue(dev->sriov.alias_guid.ports_guid[i].wq);
828a0c64a17SJack Morgenstein 		destroy_workqueue(dev->sriov.alias_guid.ports_guid[i].wq);
829a0c64a17SJack Morgenstein 	}
830a0c64a17SJack Morgenstein 	ib_sa_unregister_client(dev->sriov.alias_guid.sa_client);
831a0c64a17SJack Morgenstein 	kfree(dev->sriov.alias_guid.sa_client);
832a0c64a17SJack Morgenstein }
833a0c64a17SJack Morgenstein 
834a0c64a17SJack Morgenstein int mlx4_ib_init_alias_guid_service(struct mlx4_ib_dev *dev)
835a0c64a17SJack Morgenstein {
836a0c64a17SJack Morgenstein 	char alias_wq_name[15];
837a0c64a17SJack Morgenstein 	int ret = 0;
838f5479601SYishai Hadas 	int i, j;
839a0c64a17SJack Morgenstein 	union ib_gid gid;
840a0c64a17SJack Morgenstein 
841a0c64a17SJack Morgenstein 	if (!mlx4_is_master(dev->dev))
842a0c64a17SJack Morgenstein 		return 0;
843a0c64a17SJack Morgenstein 	dev->sriov.alias_guid.sa_client =
844a0c64a17SJack Morgenstein 		kzalloc(sizeof *dev->sriov.alias_guid.sa_client, GFP_KERNEL);
845a0c64a17SJack Morgenstein 	if (!dev->sriov.alias_guid.sa_client)
846a0c64a17SJack Morgenstein 		return -ENOMEM;
847a0c64a17SJack Morgenstein 
848a0c64a17SJack Morgenstein 	ib_sa_register_client(dev->sriov.alias_guid.sa_client);
849a0c64a17SJack Morgenstein 
850a0c64a17SJack Morgenstein 	spin_lock_init(&dev->sriov.alias_guid.ag_work_lock);
851a0c64a17SJack Morgenstein 
852a0c64a17SJack Morgenstein 	for (i = 1; i <= dev->num_ports; ++i) {
853a0c64a17SJack Morgenstein 		if (dev->ib_dev.query_gid(&dev->ib_dev , i, 0, &gid)) {
854a0c64a17SJack Morgenstein 			ret = -EFAULT;
855a0c64a17SJack Morgenstein 			goto err_unregister;
856a0c64a17SJack Morgenstein 		}
857a0c64a17SJack Morgenstein 	}
858a0c64a17SJack Morgenstein 
859a0c64a17SJack Morgenstein 	for (i = 0 ; i < dev->num_ports; i++) {
860a0c64a17SJack Morgenstein 		memset(&dev->sriov.alias_guid.ports_guid[i], 0,
861a0c64a17SJack Morgenstein 		       sizeof (struct mlx4_sriov_alias_guid_port_rec_det));
862f5479601SYishai Hadas 		dev->sriov.alias_guid.ports_guid[i].state_flags |=
863f5479601SYishai Hadas 				GUID_STATE_NEED_PORT_INIT;
864a0c64a17SJack Morgenstein 		for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) {
865f5479601SYishai Hadas 			/* mark each val as it was deleted */
866f5479601SYishai Hadas 			memset(dev->sriov.alias_guid.ports_guid[i].
867f5479601SYishai Hadas 				all_rec_per_port[j].all_recs, 0xFF,
868f5479601SYishai Hadas 				sizeof(dev->sriov.alias_guid.ports_guid[i].
869f5479601SYishai Hadas 				all_rec_per_port[j].all_recs));
870a0c64a17SJack Morgenstein 		}
871a0c64a17SJack Morgenstein 		INIT_LIST_HEAD(&dev->sriov.alias_guid.ports_guid[i].cb_list);
872a0c64a17SJack Morgenstein 		/*prepare the records, set them to be allocated by sm*/
873f5479601SYishai Hadas 		if (mlx4_ib_sm_guid_assign)
874f5479601SYishai Hadas 			for (j = 1; j < NUM_ALIAS_GUID_PER_PORT; j++)
875f5479601SYishai Hadas 				mlx4_set_admin_guid(dev->dev, 0, j, i + 1);
876a0c64a17SJack Morgenstein 		for (j = 0 ; j < NUM_ALIAS_GUID_REC_IN_PORT; j++)
877a0c64a17SJack Morgenstein 			invalidate_guid_record(dev, i + 1, j);
878a0c64a17SJack Morgenstein 
879a0c64a17SJack Morgenstein 		dev->sriov.alias_guid.ports_guid[i].parent = &dev->sriov.alias_guid;
880a0c64a17SJack Morgenstein 		dev->sriov.alias_guid.ports_guid[i].port  = i;
881a0c64a17SJack Morgenstein 
882a0c64a17SJack Morgenstein 		snprintf(alias_wq_name, sizeof alias_wq_name, "alias_guid%d", i);
883a0c64a17SJack Morgenstein 		dev->sriov.alias_guid.ports_guid[i].wq =
884a0c64a17SJack Morgenstein 			create_singlethread_workqueue(alias_wq_name);
885a0c64a17SJack Morgenstein 		if (!dev->sriov.alias_guid.ports_guid[i].wq) {
886a0c64a17SJack Morgenstein 			ret = -ENOMEM;
887a0c64a17SJack Morgenstein 			goto err_thread;
888a0c64a17SJack Morgenstein 		}
889a0c64a17SJack Morgenstein 		INIT_DELAYED_WORK(&dev->sriov.alias_guid.ports_guid[i].alias_guid_work,
890a0c64a17SJack Morgenstein 			  alias_guid_work);
891a0c64a17SJack Morgenstein 	}
892a0c64a17SJack Morgenstein 	return 0;
893a0c64a17SJack Morgenstein 
894a0c64a17SJack Morgenstein err_thread:
895a0c64a17SJack Morgenstein 	for (--i; i >= 0; i--) {
896a0c64a17SJack Morgenstein 		destroy_workqueue(dev->sriov.alias_guid.ports_guid[i].wq);
897a0c64a17SJack Morgenstein 		dev->sriov.alias_guid.ports_guid[i].wq = NULL;
898a0c64a17SJack Morgenstein 	}
899a0c64a17SJack Morgenstein 
900a0c64a17SJack Morgenstein err_unregister:
901a0c64a17SJack Morgenstein 	ib_sa_unregister_client(dev->sriov.alias_guid.sa_client);
902a0c64a17SJack Morgenstein 	kfree(dev->sriov.alias_guid.sa_client);
903a0c64a17SJack Morgenstein 	dev->sriov.alias_guid.sa_client = NULL;
904a0c64a17SJack Morgenstein 	pr_err("init_alias_guid_service: Failed. (ret:%d)\n", ret);
905a0c64a17SJack Morgenstein 	return ret;
906a0c64a17SJack Morgenstein }
907