xref: /linux/drivers/infiniband/hw/mlx4/alias_GUID.c (revision ee59fa0d7e9af130bfc1b75524e04c101670bd5e)
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 
126*ee59fa0dSYishai Hadas void mlx4_ib_slave_alias_guid_event(struct mlx4_ib_dev *dev, int slave,
127*ee59fa0dSYishai Hadas 				    int port,  int slave_init)
128*ee59fa0dSYishai Hadas {
129*ee59fa0dSYishai Hadas 	__be64 curr_guid, required_guid;
130*ee59fa0dSYishai Hadas 	int record_num = slave / 8;
131*ee59fa0dSYishai Hadas 	int index = slave % 8;
132*ee59fa0dSYishai Hadas 	int port_index = port - 1;
133*ee59fa0dSYishai Hadas 	unsigned long flags;
134*ee59fa0dSYishai Hadas 	int do_work = 0;
135*ee59fa0dSYishai Hadas 
136*ee59fa0dSYishai Hadas 	spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags);
137*ee59fa0dSYishai Hadas 	if (dev->sriov.alias_guid.ports_guid[port_index].state_flags &
138*ee59fa0dSYishai Hadas 	    GUID_STATE_NEED_PORT_INIT)
139*ee59fa0dSYishai Hadas 		goto unlock;
140*ee59fa0dSYishai Hadas 	if (!slave_init) {
141*ee59fa0dSYishai Hadas 		curr_guid = *(__be64 *)&dev->sriov.
142*ee59fa0dSYishai Hadas 			alias_guid.ports_guid[port_index].
143*ee59fa0dSYishai Hadas 			all_rec_per_port[record_num].
144*ee59fa0dSYishai Hadas 			all_recs[GUID_REC_SIZE * index];
145*ee59fa0dSYishai Hadas 		if (curr_guid == cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL) ||
146*ee59fa0dSYishai Hadas 		    !curr_guid)
147*ee59fa0dSYishai Hadas 			goto unlock;
148*ee59fa0dSYishai Hadas 		required_guid = cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL);
149*ee59fa0dSYishai Hadas 	} else {
150*ee59fa0dSYishai Hadas 		required_guid = mlx4_get_admin_guid(dev->dev, slave, port);
151*ee59fa0dSYishai Hadas 		if (required_guid == cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL))
152*ee59fa0dSYishai Hadas 			goto unlock;
153*ee59fa0dSYishai Hadas 	}
154*ee59fa0dSYishai Hadas 	*(__be64 *)&dev->sriov.alias_guid.ports_guid[port_index].
155*ee59fa0dSYishai Hadas 		all_rec_per_port[record_num].
156*ee59fa0dSYishai Hadas 		all_recs[GUID_REC_SIZE * index] = required_guid;
157*ee59fa0dSYishai Hadas 	dev->sriov.alias_guid.ports_guid[port_index].
158*ee59fa0dSYishai Hadas 		all_rec_per_port[record_num].guid_indexes
159*ee59fa0dSYishai Hadas 		|= mlx4_ib_get_aguid_comp_mask_from_ix(index);
160*ee59fa0dSYishai Hadas 	dev->sriov.alias_guid.ports_guid[port_index].
161*ee59fa0dSYishai Hadas 		all_rec_per_port[record_num].status
162*ee59fa0dSYishai Hadas 		= MLX4_GUID_INFO_STATUS_IDLE;
163*ee59fa0dSYishai Hadas 	/* set to run immediately */
164*ee59fa0dSYishai Hadas 	dev->sriov.alias_guid.ports_guid[port_index].
165*ee59fa0dSYishai Hadas 		all_rec_per_port[record_num].time_to_run = 0;
166*ee59fa0dSYishai Hadas 	dev->sriov.alias_guid.ports_guid[port_index].
167*ee59fa0dSYishai Hadas 		all_rec_per_port[record_num].
168*ee59fa0dSYishai Hadas 		guids_retry_schedule[index] = 0;
169*ee59fa0dSYishai Hadas 	do_work = 1;
170*ee59fa0dSYishai Hadas unlock:
171*ee59fa0dSYishai Hadas 	spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags);
172*ee59fa0dSYishai Hadas 
173*ee59fa0dSYishai Hadas 	if (do_work)
174*ee59fa0dSYishai Hadas 		mlx4_ib_init_alias_guid_work(dev, port_index);
175*ee59fa0dSYishai Hadas }
176*ee59fa0dSYishai 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;
192a0c64a17SJack Morgenstein 	int slave_id;
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;
220a0c64a17SJack Morgenstein 		tmp_cur_ag = *(__be64 *)&p_data[i * GUID_REC_SIZE];
221a0c64a17SJack Morgenstein 		form_cache_ag = get_cached_alias_guid(dev, port_num,
222a0c64a17SJack Morgenstein 					(NUM_ALIAS_GUID_IN_REC * block_num) + i);
223a0c64a17SJack Morgenstein 		/*
224a0c64a17SJack Morgenstein 		 * Check if guid is not the same as in the cache,
225a0c64a17SJack Morgenstein 		 * If it is different, wait for the snoop_smp or the port mgmt
226a0c64a17SJack Morgenstein 		 * change event to update the slave on its port state change
227a0c64a17SJack Morgenstein 		 */
228a0c64a17SJack Morgenstein 		if (tmp_cur_ag != form_cache_ag)
229a0c64a17SJack Morgenstein 			continue;
230a0c64a17SJack Morgenstein 
23199ee4df6SYishai Hadas 		spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags);
23299ee4df6SYishai Hadas 		required_value = *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE];
23399ee4df6SYishai Hadas 
23499ee4df6SYishai Hadas 		if (required_value == cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL))
23599ee4df6SYishai Hadas 			required_value = 0;
23699ee4df6SYishai Hadas 
23799ee4df6SYishai Hadas 		if (tmp_cur_ag == required_value) {
23899ee4df6SYishai Hadas 			rec->guid_indexes = rec->guid_indexes &
23999ee4df6SYishai Hadas 			       ~mlx4_ib_get_aguid_comp_mask_from_ix(i);
24099ee4df6SYishai Hadas 		} else {
24199ee4df6SYishai Hadas 			/* may notify port down if value is 0 */
24299ee4df6SYishai Hadas 			if (tmp_cur_ag != MLX4_NOT_SET_GUID) {
24399ee4df6SYishai Hadas 				spin_unlock_irqrestore(&dev->sriov.
24499ee4df6SYishai Hadas 					alias_guid.ag_work_lock, flags);
24599ee4df6SYishai Hadas 				continue;
24699ee4df6SYishai Hadas 			}
24799ee4df6SYishai Hadas 		}
24899ee4df6SYishai Hadas 		spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock,
24999ee4df6SYishai Hadas 				       flags);
25099ee4df6SYishai Hadas 		mlx4_gen_guid_change_eqe(dev->dev, slave_id, port_num);
251a0c64a17SJack Morgenstein 		/*2 cases: Valid GUID, and Invalid Guid*/
252a0c64a17SJack Morgenstein 
253a0c64a17SJack Morgenstein 		if (tmp_cur_ag != MLX4_NOT_SET_GUID) { /*valid GUID*/
254a0c64a17SJack Morgenstein 			prev_state = mlx4_get_slave_port_state(dev->dev, slave_id, port_num);
255a0c64a17SJack Morgenstein 			new_state = set_and_calc_slave_port_state(dev->dev, slave_id, port_num,
256a0c64a17SJack Morgenstein 								  MLX4_PORT_STATE_IB_PORT_STATE_EVENT_GID_VALID,
257a0c64a17SJack Morgenstein 								  &gen_event);
258a0c64a17SJack Morgenstein 			pr_debug("slave: %d, port: %d prev_port_state: %d,"
259a0c64a17SJack Morgenstein 				 " new_port_state: %d, gen_event: %d\n",
260a0c64a17SJack Morgenstein 				 slave_id, port_num, prev_state, new_state, gen_event);
261a0c64a17SJack Morgenstein 			if (gen_event == SLAVE_PORT_GEN_EVENT_UP) {
262a0c64a17SJack Morgenstein 				pr_debug("sending PORT_UP event to slave: %d, port: %d\n",
263a0c64a17SJack Morgenstein 					 slave_id, port_num);
264a0c64a17SJack Morgenstein 				mlx4_gen_port_state_change_eqe(dev->dev, slave_id,
265a0c64a17SJack Morgenstein 							       port_num, MLX4_PORT_CHANGE_SUBTYPE_ACTIVE);
266a0c64a17SJack Morgenstein 			}
267a0c64a17SJack Morgenstein 		} else { /* request to invalidate GUID */
268a0c64a17SJack Morgenstein 			set_and_calc_slave_port_state(dev->dev, slave_id, port_num,
269a0c64a17SJack Morgenstein 						      MLX4_PORT_STATE_IB_EVENT_GID_INVALID,
270a0c64a17SJack Morgenstein 						      &gen_event);
27199ee4df6SYishai Hadas 			if (gen_event == SLAVE_PORT_GEN_EVENT_DOWN) {
272a0c64a17SJack Morgenstein 				pr_debug("sending PORT DOWN event to slave: %d, port: %d\n",
273a0c64a17SJack Morgenstein 					 slave_id, port_num);
27499ee4df6SYishai Hadas 				mlx4_gen_port_state_change_eqe(dev->dev,
27599ee4df6SYishai Hadas 							       slave_id,
27699ee4df6SYishai Hadas 							       port_num,
277a0c64a17SJack Morgenstein 							       MLX4_PORT_CHANGE_SUBTYPE_DOWN);
278a0c64a17SJack Morgenstein 			}
279a0c64a17SJack Morgenstein 		}
280a0c64a17SJack Morgenstein 	}
28199ee4df6SYishai Hadas }
282a0c64a17SJack Morgenstein 
283a0c64a17SJack Morgenstein static void aliasguid_query_handler(int status,
284a0c64a17SJack Morgenstein 				    struct ib_sa_guidinfo_rec *guid_rec,
285a0c64a17SJack Morgenstein 				    void *context)
286a0c64a17SJack Morgenstein {
287a0c64a17SJack Morgenstein 	struct mlx4_ib_dev *dev;
288a0c64a17SJack Morgenstein 	struct mlx4_alias_guid_work_context *cb_ctx = context;
289a0c64a17SJack Morgenstein 	u8 port_index ;
290a0c64a17SJack Morgenstein 	int i;
291a0c64a17SJack Morgenstein 	struct mlx4_sriov_alias_guid_info_rec_det *rec;
292a0c64a17SJack Morgenstein 	unsigned long flags, flags1;
29399ee4df6SYishai Hadas 	ib_sa_comp_mask declined_guid_indexes = 0;
29499ee4df6SYishai Hadas 	ib_sa_comp_mask applied_guid_indexes = 0;
29599ee4df6SYishai Hadas 	unsigned int resched_delay_sec = 0;
296a0c64a17SJack Morgenstein 
297a0c64a17SJack Morgenstein 	if (!context)
298a0c64a17SJack Morgenstein 		return;
299a0c64a17SJack Morgenstein 
300a0c64a17SJack Morgenstein 	dev = cb_ctx->dev;
301a0c64a17SJack Morgenstein 	port_index = cb_ctx->port - 1;
302a0c64a17SJack Morgenstein 	rec = &dev->sriov.alias_guid.ports_guid[port_index].
303a0c64a17SJack Morgenstein 		all_rec_per_port[cb_ctx->block_num];
304a0c64a17SJack Morgenstein 
305a0c64a17SJack Morgenstein 	if (status) {
306a0c64a17SJack Morgenstein 		pr_debug("(port: %d) failed: status = %d\n",
307a0c64a17SJack Morgenstein 			 cb_ctx->port, status);
30899ee4df6SYishai Hadas 		rec->time_to_run = ktime_get_real_ns() + 1 * NSEC_PER_SEC;
309a0c64a17SJack Morgenstein 		goto out;
310a0c64a17SJack Morgenstein 	}
311a0c64a17SJack Morgenstein 
312a0c64a17SJack Morgenstein 	if (guid_rec->block_num != cb_ctx->block_num) {
313a0c64a17SJack Morgenstein 		pr_err("block num mismatch: %d != %d\n",
314a0c64a17SJack Morgenstein 		       cb_ctx->block_num, guid_rec->block_num);
315a0c64a17SJack Morgenstein 		goto out;
316a0c64a17SJack Morgenstein 	}
317a0c64a17SJack Morgenstein 
318a0c64a17SJack Morgenstein 	pr_debug("lid/port: %d/%d, block_num: %d\n",
319a0c64a17SJack Morgenstein 		 be16_to_cpu(guid_rec->lid), cb_ctx->port,
320a0c64a17SJack Morgenstein 		 guid_rec->block_num);
321a0c64a17SJack Morgenstein 
322a0c64a17SJack Morgenstein 	rec = &dev->sriov.alias_guid.ports_guid[port_index].
323a0c64a17SJack Morgenstein 		all_rec_per_port[guid_rec->block_num];
324a0c64a17SJack Morgenstein 
32599ee4df6SYishai Hadas 	spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags);
326a0c64a17SJack Morgenstein 	for (i = 0 ; i < NUM_ALIAS_GUID_IN_REC; i++) {
32799ee4df6SYishai Hadas 		__be64 sm_response, required_val;
32899ee4df6SYishai Hadas 
32999ee4df6SYishai Hadas 		if (!(cb_ctx->guid_indexes &
33099ee4df6SYishai Hadas 			mlx4_ib_get_aguid_comp_mask_from_ix(i)))
33199ee4df6SYishai Hadas 			continue;
33299ee4df6SYishai Hadas 		sm_response = *(__be64 *)&guid_rec->guid_info_list
33399ee4df6SYishai Hadas 				[i * GUID_REC_SIZE];
33499ee4df6SYishai Hadas 		required_val = *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE];
33599ee4df6SYishai Hadas 		if (cb_ctx->method == MLX4_GUID_INFO_RECORD_DELETE) {
33699ee4df6SYishai Hadas 			if (required_val ==
33799ee4df6SYishai Hadas 			    cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL))
33899ee4df6SYishai Hadas 				goto next_entry;
33999ee4df6SYishai Hadas 
34099ee4df6SYishai Hadas 			/* A new value was set till we got the response */
34199ee4df6SYishai Hadas 			pr_debug("need to set new value %llx, record num %d, block_num:%d\n",
34299ee4df6SYishai Hadas 				 be64_to_cpu(required_val),
34399ee4df6SYishai Hadas 				 i, guid_rec->block_num);
34499ee4df6SYishai Hadas 			goto entry_declined;
34599ee4df6SYishai Hadas 		}
34699ee4df6SYishai Hadas 
347a0c64a17SJack Morgenstein 		/* check if the SM didn't assign one of the records.
34899ee4df6SYishai Hadas 		 * if it didn't, re-ask for.
349a0c64a17SJack Morgenstein 		 */
35099ee4df6SYishai Hadas 		if (sm_response == MLX4_NOT_SET_GUID) {
35199ee4df6SYishai Hadas 			if (rec->guids_retry_schedule[i] == 0)
352f5479601SYishai Hadas 				mlx4_ib_warn(&dev->ib_dev,
353f5479601SYishai Hadas 					     "%s:Record num %d in  block_num: %d was declined by SM\n",
354f5479601SYishai Hadas 					     __func__, i,
355f5479601SYishai Hadas 					     guid_rec->block_num);
35699ee4df6SYishai Hadas 			goto entry_declined;
357a0c64a17SJack Morgenstein 		} else {
358a0c64a17SJack Morgenstein 		       /* properly assigned record. */
359a0c64a17SJack Morgenstein 		       /* We save the GUID we just got from the SM in the
360a0c64a17SJack Morgenstein 			* admin_guid in order to be persistent, and in the
361a0c64a17SJack Morgenstein 			* request from the sm the process will ask for the same GUID */
362f5479601SYishai Hadas 			if (required_val &&
36399ee4df6SYishai Hadas 			    sm_response != required_val) {
36499ee4df6SYishai Hadas 				/* Warn only on first retry */
36599ee4df6SYishai Hadas 				if (rec->guids_retry_schedule[i] == 0)
366a0c64a17SJack Morgenstein 					mlx4_ib_warn(&dev->ib_dev, "%s: Failed to set"
367a0c64a17SJack Morgenstein 						     " admin guid after SysAdmin "
368a0c64a17SJack Morgenstein 						     "configuration. "
369a0c64a17SJack Morgenstein 						     "Record num %d in block_num:%d "
370a0c64a17SJack Morgenstein 						     "was declined by SM, "
37199ee4df6SYishai Hadas 						     "new val(0x%llx) was kept, SM returned (0x%llx)\n",
372a0c64a17SJack Morgenstein 						      __func__, i,
373a0c64a17SJack Morgenstein 						     guid_rec->block_num,
37499ee4df6SYishai Hadas 						     be64_to_cpu(required_val),
37599ee4df6SYishai Hadas 						     be64_to_cpu(sm_response));
37699ee4df6SYishai Hadas 				goto entry_declined;
377a0c64a17SJack Morgenstein 			} else {
37899ee4df6SYishai Hadas 				*(__be64 *)&rec->all_recs[i * GUID_REC_SIZE] =
37999ee4df6SYishai Hadas 					sm_response;
3802350f247SYishai Hadas 				if (required_val == 0)
3812350f247SYishai Hadas 					mlx4_set_admin_guid(dev->dev,
3822350f247SYishai Hadas 							    sm_response,
3832350f247SYishai Hadas 							    (guid_rec->block_num
3842350f247SYishai Hadas 							    * NUM_ALIAS_GUID_IN_REC) + i,
3852350f247SYishai Hadas 							    cb_ctx->port);
38699ee4df6SYishai Hadas 				goto next_entry;
387a0c64a17SJack Morgenstein 			}
388a0c64a17SJack Morgenstein 		}
38999ee4df6SYishai Hadas entry_declined:
39099ee4df6SYishai Hadas 		declined_guid_indexes |= mlx4_ib_get_aguid_comp_mask_from_ix(i);
39199ee4df6SYishai Hadas 		rec->guids_retry_schedule[i] =
39299ee4df6SYishai Hadas 			(rec->guids_retry_schedule[i] == 0) ?  1 :
39399ee4df6SYishai Hadas 			min((unsigned int)60,
39499ee4df6SYishai Hadas 			    rec->guids_retry_schedule[i] * 2);
39599ee4df6SYishai Hadas 		/* using the minimum value among all entries in that record */
39699ee4df6SYishai Hadas 		resched_delay_sec = (resched_delay_sec == 0) ?
39799ee4df6SYishai Hadas 				rec->guids_retry_schedule[i] :
39899ee4df6SYishai Hadas 				min(resched_delay_sec,
39999ee4df6SYishai Hadas 				    rec->guids_retry_schedule[i]);
40099ee4df6SYishai Hadas 		continue;
40199ee4df6SYishai Hadas 
40299ee4df6SYishai Hadas next_entry:
40399ee4df6SYishai Hadas 		rec->guids_retry_schedule[i] = 0;
404a0c64a17SJack Morgenstein 	}
40599ee4df6SYishai Hadas 
40699ee4df6SYishai Hadas 	applied_guid_indexes =  cb_ctx->guid_indexes & ~declined_guid_indexes;
40799ee4df6SYishai Hadas 	if (declined_guid_indexes ||
40899ee4df6SYishai Hadas 	    rec->guid_indexes & ~(applied_guid_indexes)) {
40999ee4df6SYishai Hadas 		pr_debug("record=%d wasn't fully set, guid_indexes=0x%llx applied_indexes=0x%llx, declined_indexes=0x%llx\n",
41099ee4df6SYishai Hadas 			 guid_rec->block_num,
41199ee4df6SYishai Hadas 			 be64_to_cpu((__force __be64)rec->guid_indexes),
41299ee4df6SYishai Hadas 			 be64_to_cpu((__force __be64)applied_guid_indexes),
41399ee4df6SYishai Hadas 			 be64_to_cpu((__force __be64)declined_guid_indexes));
41499ee4df6SYishai Hadas 		rec->time_to_run = ktime_get_real_ns() +
41599ee4df6SYishai Hadas 			resched_delay_sec * NSEC_PER_SEC;
41699ee4df6SYishai Hadas 	} else {
41799ee4df6SYishai Hadas 		rec->status = MLX4_GUID_INFO_STATUS_SET;
41899ee4df6SYishai Hadas 	}
41999ee4df6SYishai Hadas 	spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags);
420a0c64a17SJack Morgenstein 	/*
421a0c64a17SJack Morgenstein 	The func is call here to close the cases when the
422a0c64a17SJack Morgenstein 	sm doesn't send smp, so in the sa response the driver
423a0c64a17SJack Morgenstein 	notifies the slave.
424a0c64a17SJack Morgenstein 	*/
425a0c64a17SJack Morgenstein 	mlx4_ib_notify_slaves_on_guid_change(dev, guid_rec->block_num,
426a0c64a17SJack Morgenstein 					     cb_ctx->port,
427a0c64a17SJack Morgenstein 					     guid_rec->guid_info_list);
428a0c64a17SJack Morgenstein out:
429a0c64a17SJack Morgenstein 	spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
430a0c64a17SJack Morgenstein 	spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
43199ee4df6SYishai Hadas 	if (!dev->sriov.is_going_down) {
43299ee4df6SYishai Hadas 		get_low_record_time_index(dev, port_index, &resched_delay_sec);
433a0c64a17SJack Morgenstein 		queue_delayed_work(dev->sriov.alias_guid.ports_guid[port_index].wq,
434a0c64a17SJack Morgenstein 				   &dev->sriov.alias_guid.ports_guid[port_index].
43599ee4df6SYishai Hadas 				   alias_guid_work,
43699ee4df6SYishai Hadas 				   msecs_to_jiffies(resched_delay_sec * 1000));
43799ee4df6SYishai Hadas 	}
438a0c64a17SJack Morgenstein 	if (cb_ctx->sa_query) {
439a0c64a17SJack Morgenstein 		list_del(&cb_ctx->list);
440a0c64a17SJack Morgenstein 		kfree(cb_ctx);
441a0c64a17SJack Morgenstein 	} else
442a0c64a17SJack Morgenstein 		complete(&cb_ctx->done);
443a0c64a17SJack Morgenstein 	spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
444a0c64a17SJack Morgenstein 	spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
445a0c64a17SJack Morgenstein }
446a0c64a17SJack Morgenstein 
447a0c64a17SJack Morgenstein static void invalidate_guid_record(struct mlx4_ib_dev *dev, u8 port, int index)
448a0c64a17SJack Morgenstein {
449a0c64a17SJack Morgenstein 	int i;
450a0c64a17SJack Morgenstein 	u64 cur_admin_val;
451a0c64a17SJack Morgenstein 	ib_sa_comp_mask comp_mask = 0;
452a0c64a17SJack Morgenstein 
453a0c64a17SJack Morgenstein 	dev->sriov.alias_guid.ports_guid[port - 1].all_rec_per_port[index].status
45499ee4df6SYishai Hadas 		= MLX4_GUID_INFO_STATUS_SET;
455a0c64a17SJack Morgenstein 
456a0c64a17SJack Morgenstein 	/* calculate the comp_mask for that record.*/
457a0c64a17SJack Morgenstein 	for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) {
458a0c64a17SJack Morgenstein 		cur_admin_val =
459a0c64a17SJack Morgenstein 			*(u64 *)&dev->sriov.alias_guid.ports_guid[port - 1].
460a0c64a17SJack Morgenstein 			all_rec_per_port[index].all_recs[GUID_REC_SIZE * i];
461a0c64a17SJack Morgenstein 		/*
462a0c64a17SJack Morgenstein 		check the admin value: if it's for delete (~00LL) or
463a0c64a17SJack Morgenstein 		it is the first guid of the first record (hw guid) or
464a0c64a17SJack Morgenstein 		the records is not in ownership of the sysadmin and the sm doesn't
465a0c64a17SJack Morgenstein 		need to assign GUIDs, then don't put it up for assignment.
466a0c64a17SJack Morgenstein 		*/
467a0c64a17SJack Morgenstein 		if (MLX4_GUID_FOR_DELETE_VAL == cur_admin_val ||
468f5479601SYishai Hadas 		    (!index && !i))
469a0c64a17SJack Morgenstein 			continue;
470c1e7e466SJack Morgenstein 		comp_mask |= mlx4_ib_get_aguid_comp_mask_from_ix(i);
471a0c64a17SJack Morgenstein 	}
472a0c64a17SJack Morgenstein 	dev->sriov.alias_guid.ports_guid[port - 1].
47399ee4df6SYishai Hadas 		all_rec_per_port[index].guid_indexes |= comp_mask;
47499ee4df6SYishai Hadas 	if (dev->sriov.alias_guid.ports_guid[port - 1].
47599ee4df6SYishai Hadas 	    all_rec_per_port[index].guid_indexes)
47699ee4df6SYishai Hadas 		dev->sriov.alias_guid.ports_guid[port - 1].
47799ee4df6SYishai Hadas 		all_rec_per_port[index].status = MLX4_GUID_INFO_STATUS_IDLE;
47899ee4df6SYishai Hadas 
479a0c64a17SJack Morgenstein }
480a0c64a17SJack Morgenstein 
481a0c64a17SJack Morgenstein static int set_guid_rec(struct ib_device *ibdev,
48299ee4df6SYishai Hadas 			struct mlx4_next_alias_guid_work *rec)
483a0c64a17SJack Morgenstein {
484a0c64a17SJack Morgenstein 	int err;
485a0c64a17SJack Morgenstein 	struct mlx4_ib_dev *dev = to_mdev(ibdev);
486a0c64a17SJack Morgenstein 	struct ib_sa_guidinfo_rec guid_info_rec;
487a0c64a17SJack Morgenstein 	ib_sa_comp_mask comp_mask;
488a0c64a17SJack Morgenstein 	struct ib_port_attr attr;
489a0c64a17SJack Morgenstein 	struct mlx4_alias_guid_work_context *callback_context;
490a0c64a17SJack Morgenstein 	unsigned long resched_delay, flags, flags1;
49199ee4df6SYishai Hadas 	u8 port = rec->port + 1;
49299ee4df6SYishai Hadas 	int index = rec->block_num;
49399ee4df6SYishai Hadas 	struct mlx4_sriov_alias_guid_info_rec_det *rec_det = &rec->rec_det;
494a0c64a17SJack Morgenstein 	struct list_head *head =
495a0c64a17SJack Morgenstein 		&dev->sriov.alias_guid.ports_guid[port - 1].cb_list;
496a0c64a17SJack Morgenstein 
497a0c64a17SJack Morgenstein 	err = __mlx4_ib_query_port(ibdev, port, &attr, 1);
498a0c64a17SJack Morgenstein 	if (err) {
499a0c64a17SJack Morgenstein 		pr_debug("mlx4_ib_query_port failed (err: %d), port: %d\n",
500a0c64a17SJack Morgenstein 			 err, port);
501a0c64a17SJack Morgenstein 		return err;
502a0c64a17SJack Morgenstein 	}
503a0c64a17SJack Morgenstein 	/*check the port was configured by the sm, otherwise no need to send */
504a0c64a17SJack Morgenstein 	if (attr.state != IB_PORT_ACTIVE) {
505a0c64a17SJack Morgenstein 		pr_debug("port %d not active...rescheduling\n", port);
506a0c64a17SJack Morgenstein 		resched_delay = 5 * HZ;
507a0c64a17SJack Morgenstein 		err = -EAGAIN;
508a0c64a17SJack Morgenstein 		goto new_schedule;
509a0c64a17SJack Morgenstein 	}
510a0c64a17SJack Morgenstein 
511a0c64a17SJack Morgenstein 	callback_context = kmalloc(sizeof *callback_context, GFP_KERNEL);
512a0c64a17SJack Morgenstein 	if (!callback_context) {
513a0c64a17SJack Morgenstein 		err = -ENOMEM;
514a0c64a17SJack Morgenstein 		resched_delay = HZ * 5;
515a0c64a17SJack Morgenstein 		goto new_schedule;
516a0c64a17SJack Morgenstein 	}
517a0c64a17SJack Morgenstein 	callback_context->port = port;
518a0c64a17SJack Morgenstein 	callback_context->dev = dev;
519a0c64a17SJack Morgenstein 	callback_context->block_num = index;
52099ee4df6SYishai Hadas 	callback_context->guid_indexes = rec_det->guid_indexes;
52199ee4df6SYishai Hadas 	callback_context->method = rec->method;
522a0c64a17SJack Morgenstein 
523a0c64a17SJack Morgenstein 	memset(&guid_info_rec, 0, sizeof (struct ib_sa_guidinfo_rec));
524a0c64a17SJack Morgenstein 
525a0c64a17SJack Morgenstein 	guid_info_rec.lid = cpu_to_be16(attr.lid);
526a0c64a17SJack Morgenstein 	guid_info_rec.block_num = index;
527a0c64a17SJack Morgenstein 
528a0c64a17SJack Morgenstein 	memcpy(guid_info_rec.guid_info_list, rec_det->all_recs,
529a0c64a17SJack Morgenstein 	       GUID_REC_SIZE * NUM_ALIAS_GUID_IN_REC);
530a0c64a17SJack Morgenstein 	comp_mask = IB_SA_GUIDINFO_REC_LID | IB_SA_GUIDINFO_REC_BLOCK_NUM |
531a0c64a17SJack Morgenstein 		rec_det->guid_indexes;
532a0c64a17SJack Morgenstein 
533a0c64a17SJack Morgenstein 	init_completion(&callback_context->done);
534a0c64a17SJack Morgenstein 	spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
535a0c64a17SJack Morgenstein 	list_add_tail(&callback_context->list, head);
536a0c64a17SJack Morgenstein 	spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
537a0c64a17SJack Morgenstein 
538a0c64a17SJack Morgenstein 	callback_context->query_id =
539a0c64a17SJack Morgenstein 		ib_sa_guid_info_rec_query(dev->sriov.alias_guid.sa_client,
540a0c64a17SJack Morgenstein 					  ibdev, port, &guid_info_rec,
54199ee4df6SYishai Hadas 					  comp_mask, rec->method, 1000,
542a0c64a17SJack Morgenstein 					  GFP_KERNEL, aliasguid_query_handler,
543a0c64a17SJack Morgenstein 					  callback_context,
544a0c64a17SJack Morgenstein 					  &callback_context->sa_query);
545a0c64a17SJack Morgenstein 	if (callback_context->query_id < 0) {
546a0c64a17SJack Morgenstein 		pr_debug("ib_sa_guid_info_rec_query failed, query_id: "
547a0c64a17SJack Morgenstein 			 "%d. will reschedule to the next 1 sec.\n",
548a0c64a17SJack Morgenstein 			 callback_context->query_id);
549a0c64a17SJack Morgenstein 		spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
550a0c64a17SJack Morgenstein 		list_del(&callback_context->list);
551a0c64a17SJack Morgenstein 		kfree(callback_context);
552a0c64a17SJack Morgenstein 		spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
553a0c64a17SJack Morgenstein 		resched_delay = 1 * HZ;
554a0c64a17SJack Morgenstein 		err = -EAGAIN;
555a0c64a17SJack Morgenstein 		goto new_schedule;
556a0c64a17SJack Morgenstein 	}
557a0c64a17SJack Morgenstein 	err = 0;
558a0c64a17SJack Morgenstein 	goto out;
559a0c64a17SJack Morgenstein 
560a0c64a17SJack Morgenstein new_schedule:
561a0c64a17SJack Morgenstein 	spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
562a0c64a17SJack Morgenstein 	spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
563a0c64a17SJack Morgenstein 	invalidate_guid_record(dev, port, index);
564a0c64a17SJack Morgenstein 	if (!dev->sriov.is_going_down) {
565a0c64a17SJack Morgenstein 		queue_delayed_work(dev->sriov.alias_guid.ports_guid[port - 1].wq,
566a0c64a17SJack Morgenstein 				   &dev->sriov.alias_guid.ports_guid[port - 1].alias_guid_work,
567a0c64a17SJack Morgenstein 				   resched_delay);
568a0c64a17SJack Morgenstein 	}
569a0c64a17SJack Morgenstein 	spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
570a0c64a17SJack Morgenstein 	spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
571a0c64a17SJack Morgenstein 
572a0c64a17SJack Morgenstein out:
573a0c64a17SJack Morgenstein 	return err;
574a0c64a17SJack Morgenstein }
575a0c64a17SJack Morgenstein 
576f5479601SYishai Hadas static void mlx4_ib_guid_port_init(struct mlx4_ib_dev *dev, int port)
577f5479601SYishai Hadas {
578f5479601SYishai Hadas 	int j, k, entry;
579f5479601SYishai Hadas 	__be64 guid;
580f5479601SYishai Hadas 
581f5479601SYishai Hadas 	/*Check if the SM doesn't need to assign the GUIDs*/
582f5479601SYishai Hadas 	for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) {
583f5479601SYishai Hadas 		for (k = 0; k < NUM_ALIAS_GUID_IN_REC; k++) {
584f5479601SYishai Hadas 			entry = j * NUM_ALIAS_GUID_IN_REC + k;
585f5479601SYishai Hadas 			/* no request for the 0 entry (hw guid) */
586f5479601SYishai Hadas 			if (!entry || entry > dev->dev->persist->num_vfs ||
587f5479601SYishai Hadas 			    !mlx4_is_slave_active(dev->dev, entry))
588f5479601SYishai Hadas 				continue;
589f5479601SYishai Hadas 			guid = mlx4_get_admin_guid(dev->dev, entry, port);
590f5479601SYishai Hadas 			*(__be64 *)&dev->sriov.alias_guid.ports_guid[port - 1].
591f5479601SYishai Hadas 				all_rec_per_port[j].all_recs
592f5479601SYishai Hadas 				[GUID_REC_SIZE * k] = guid;
593f5479601SYishai Hadas 			pr_debug("guid was set, entry=%d, val=0x%llx, port=%d\n",
594f5479601SYishai Hadas 				 entry,
595f5479601SYishai Hadas 				 be64_to_cpu(guid),
596f5479601SYishai Hadas 				 port);
597f5479601SYishai Hadas 		}
598f5479601SYishai Hadas 	}
599f5479601SYishai Hadas }
600a0c64a17SJack Morgenstein void mlx4_ib_invalidate_all_guid_record(struct mlx4_ib_dev *dev, int port)
601a0c64a17SJack Morgenstein {
602a0c64a17SJack Morgenstein 	int i;
603a0c64a17SJack Morgenstein 	unsigned long flags, flags1;
604a0c64a17SJack Morgenstein 
605a0c64a17SJack Morgenstein 	pr_debug("port %d\n", port);
606a0c64a17SJack Morgenstein 
607a0c64a17SJack Morgenstein 	spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
608a0c64a17SJack Morgenstein 	spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
609f5479601SYishai Hadas 
610f5479601SYishai Hadas 	if (dev->sriov.alias_guid.ports_guid[port - 1].state_flags &
611f5479601SYishai Hadas 		GUID_STATE_NEED_PORT_INIT) {
612f5479601SYishai Hadas 		mlx4_ib_guid_port_init(dev, port);
613f5479601SYishai Hadas 		dev->sriov.alias_guid.ports_guid[port - 1].state_flags &=
614f5479601SYishai Hadas 			(~GUID_STATE_NEED_PORT_INIT);
615f5479601SYishai Hadas 	}
616a0c64a17SJack Morgenstein 	for (i = 0; i < NUM_ALIAS_GUID_REC_IN_PORT; i++)
617a0c64a17SJack Morgenstein 		invalidate_guid_record(dev, port, i);
618a0c64a17SJack Morgenstein 
619a0c64a17SJack Morgenstein 	if (mlx4_is_master(dev->dev) && !dev->sriov.is_going_down) {
620a0c64a17SJack Morgenstein 		/*
621a0c64a17SJack Morgenstein 		make sure no work waits in the queue, if the work is already
622a0c64a17SJack Morgenstein 		queued(not on the timer) the cancel will fail. That is not a problem
623a0c64a17SJack Morgenstein 		because we just want the work started.
624a0c64a17SJack Morgenstein 		*/
6257a9a2970SLinus Torvalds 		cancel_delayed_work(&dev->sriov.alias_guid.
626a0c64a17SJack Morgenstein 				      ports_guid[port - 1].alias_guid_work);
627a0c64a17SJack Morgenstein 		queue_delayed_work(dev->sriov.alias_guid.ports_guid[port - 1].wq,
628a0c64a17SJack Morgenstein 				   &dev->sriov.alias_guid.ports_guid[port - 1].alias_guid_work,
629a0c64a17SJack Morgenstein 				   0);
630a0c64a17SJack Morgenstein 	}
631a0c64a17SJack Morgenstein 	spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
632a0c64a17SJack Morgenstein 	spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
633a0c64a17SJack Morgenstein }
634a0c64a17SJack Morgenstein 
63599ee4df6SYishai Hadas static void set_required_record(struct mlx4_ib_dev *dev, u8 port,
63699ee4df6SYishai Hadas 				struct mlx4_next_alias_guid_work *next_rec,
63799ee4df6SYishai Hadas 				int record_index)
63899ee4df6SYishai Hadas {
63999ee4df6SYishai Hadas 	int i;
64099ee4df6SYishai Hadas 	int lowset_time_entry = -1;
64199ee4df6SYishai Hadas 	int lowest_time = 0;
64299ee4df6SYishai Hadas 	ib_sa_comp_mask delete_guid_indexes = 0;
64399ee4df6SYishai Hadas 	ib_sa_comp_mask set_guid_indexes = 0;
64499ee4df6SYishai Hadas 	struct mlx4_sriov_alias_guid_info_rec_det *rec =
64599ee4df6SYishai Hadas 			&dev->sriov.alias_guid.ports_guid[port].
64699ee4df6SYishai Hadas 			all_rec_per_port[record_index];
64799ee4df6SYishai Hadas 
64899ee4df6SYishai Hadas 	for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) {
64999ee4df6SYishai Hadas 		if (!(rec->guid_indexes &
65099ee4df6SYishai Hadas 			mlx4_ib_get_aguid_comp_mask_from_ix(i)))
65199ee4df6SYishai Hadas 			continue;
65299ee4df6SYishai Hadas 
65399ee4df6SYishai Hadas 		if (*(__be64 *)&rec->all_recs[i * GUID_REC_SIZE] ==
65499ee4df6SYishai Hadas 				cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL))
65599ee4df6SYishai Hadas 			delete_guid_indexes |=
65699ee4df6SYishai Hadas 				mlx4_ib_get_aguid_comp_mask_from_ix(i);
65799ee4df6SYishai Hadas 		else
65899ee4df6SYishai Hadas 			set_guid_indexes |=
65999ee4df6SYishai Hadas 				mlx4_ib_get_aguid_comp_mask_from_ix(i);
66099ee4df6SYishai Hadas 
66199ee4df6SYishai Hadas 		if (lowset_time_entry == -1 || rec->guids_retry_schedule[i] <=
66299ee4df6SYishai Hadas 			lowest_time) {
66399ee4df6SYishai Hadas 			lowset_time_entry = i;
66499ee4df6SYishai Hadas 			lowest_time = rec->guids_retry_schedule[i];
66599ee4df6SYishai Hadas 		}
66699ee4df6SYishai Hadas 	}
66799ee4df6SYishai Hadas 
66899ee4df6SYishai Hadas 	memcpy(&next_rec->rec_det, rec, sizeof(*rec));
66999ee4df6SYishai Hadas 	next_rec->port = port;
67099ee4df6SYishai Hadas 	next_rec->block_num = record_index;
67199ee4df6SYishai Hadas 
67299ee4df6SYishai Hadas 	if (*(__be64 *)&rec->all_recs[lowset_time_entry * GUID_REC_SIZE] ==
67399ee4df6SYishai Hadas 				cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL)) {
67499ee4df6SYishai Hadas 		next_rec->rec_det.guid_indexes = delete_guid_indexes;
67599ee4df6SYishai Hadas 		next_rec->method = MLX4_GUID_INFO_RECORD_DELETE;
67699ee4df6SYishai Hadas 	} else {
67799ee4df6SYishai Hadas 		next_rec->rec_det.guid_indexes = set_guid_indexes;
67899ee4df6SYishai Hadas 		next_rec->method = MLX4_GUID_INFO_RECORD_SET;
67999ee4df6SYishai Hadas 	}
68099ee4df6SYishai Hadas }
68199ee4df6SYishai Hadas 
68299ee4df6SYishai Hadas /* return index of record that should be updated based on lowest
68399ee4df6SYishai Hadas  * rescheduled time
68499ee4df6SYishai Hadas  */
68599ee4df6SYishai Hadas static int get_low_record_time_index(struct mlx4_ib_dev *dev, u8 port,
68699ee4df6SYishai Hadas 				     int *resched_delay_sec)
68799ee4df6SYishai Hadas {
68899ee4df6SYishai Hadas 	int record_index = -1;
68999ee4df6SYishai Hadas 	u64 low_record_time = 0;
69099ee4df6SYishai Hadas 	struct mlx4_sriov_alias_guid_info_rec_det rec;
69199ee4df6SYishai Hadas 	int j;
69299ee4df6SYishai Hadas 
69399ee4df6SYishai Hadas 	for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) {
69499ee4df6SYishai Hadas 		rec = dev->sriov.alias_guid.ports_guid[port].
69599ee4df6SYishai Hadas 			all_rec_per_port[j];
69699ee4df6SYishai Hadas 		if (rec.status == MLX4_GUID_INFO_STATUS_IDLE &&
69799ee4df6SYishai Hadas 		    rec.guid_indexes) {
69899ee4df6SYishai Hadas 			if (record_index == -1 ||
69999ee4df6SYishai Hadas 			    rec.time_to_run < low_record_time) {
70099ee4df6SYishai Hadas 				record_index = j;
70199ee4df6SYishai Hadas 				low_record_time = rec.time_to_run;
70299ee4df6SYishai Hadas 			}
70399ee4df6SYishai Hadas 		}
70499ee4df6SYishai Hadas 	}
70599ee4df6SYishai Hadas 	if (resched_delay_sec) {
70699ee4df6SYishai Hadas 		u64 curr_time = ktime_get_real_ns();
70799ee4df6SYishai Hadas 
70899ee4df6SYishai Hadas 		*resched_delay_sec = (low_record_time < curr_time) ? 0 :
70999ee4df6SYishai Hadas 			div_u64((low_record_time - curr_time), NSEC_PER_SEC);
71099ee4df6SYishai Hadas 	}
71199ee4df6SYishai Hadas 
71299ee4df6SYishai Hadas 	return record_index;
71399ee4df6SYishai Hadas }
71499ee4df6SYishai Hadas 
715a0c64a17SJack Morgenstein /* The function returns the next record that was
716a0c64a17SJack Morgenstein  * not configured (or failed to be configured) */
717a0c64a17SJack Morgenstein static int get_next_record_to_update(struct mlx4_ib_dev *dev, u8 port,
718a0c64a17SJack Morgenstein 				     struct mlx4_next_alias_guid_work *rec)
719a0c64a17SJack Morgenstein {
720a0c64a17SJack Morgenstein 	unsigned long flags;
72199ee4df6SYishai Hadas 	int record_index;
72299ee4df6SYishai Hadas 	int ret = 0;
723a0c64a17SJack Morgenstein 
724a0c64a17SJack Morgenstein 	spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags);
72599ee4df6SYishai Hadas 	record_index = get_low_record_time_index(dev, port, NULL);
72699ee4df6SYishai Hadas 
72799ee4df6SYishai Hadas 	if (record_index < 0) {
72899ee4df6SYishai Hadas 		ret = -ENOENT;
72999ee4df6SYishai Hadas 		goto out;
730a0c64a17SJack Morgenstein 	}
73199ee4df6SYishai Hadas 
73299ee4df6SYishai Hadas 	set_required_record(dev, port, rec, record_index);
73399ee4df6SYishai Hadas out:
734a0c64a17SJack Morgenstein 	spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags);
73599ee4df6SYishai Hadas 	return ret;
736a0c64a17SJack Morgenstein }
737a0c64a17SJack Morgenstein 
738a0c64a17SJack Morgenstein static void alias_guid_work(struct work_struct *work)
739a0c64a17SJack Morgenstein {
740a0c64a17SJack Morgenstein 	struct delayed_work *delay = to_delayed_work(work);
741a0c64a17SJack Morgenstein 	int ret = 0;
742a0c64a17SJack Morgenstein 	struct mlx4_next_alias_guid_work *rec;
743a0c64a17SJack Morgenstein 	struct mlx4_sriov_alias_guid_port_rec_det *sriov_alias_port =
744a0c64a17SJack Morgenstein 		container_of(delay, struct mlx4_sriov_alias_guid_port_rec_det,
745a0c64a17SJack Morgenstein 			     alias_guid_work);
746a0c64a17SJack Morgenstein 	struct mlx4_sriov_alias_guid *sriov_alias_guid = sriov_alias_port->parent;
747a0c64a17SJack Morgenstein 	struct mlx4_ib_sriov *ib_sriov = container_of(sriov_alias_guid,
748a0c64a17SJack Morgenstein 						struct mlx4_ib_sriov,
749a0c64a17SJack Morgenstein 						alias_guid);
750a0c64a17SJack Morgenstein 	struct mlx4_ib_dev *dev = container_of(ib_sriov, struct mlx4_ib_dev, sriov);
751a0c64a17SJack Morgenstein 
752a0c64a17SJack Morgenstein 	rec = kzalloc(sizeof *rec, GFP_KERNEL);
753a0c64a17SJack Morgenstein 	if (!rec) {
754a0c64a17SJack Morgenstein 		pr_err("alias_guid_work: No Memory\n");
755a0c64a17SJack Morgenstein 		return;
756a0c64a17SJack Morgenstein 	}
757a0c64a17SJack Morgenstein 
758a0c64a17SJack Morgenstein 	pr_debug("starting [port: %d]...\n", sriov_alias_port->port + 1);
759a0c64a17SJack Morgenstein 	ret = get_next_record_to_update(dev, sriov_alias_port->port, rec);
760a0c64a17SJack Morgenstein 	if (ret) {
761a0c64a17SJack Morgenstein 		pr_debug("No more records to update.\n");
762a0c64a17SJack Morgenstein 		goto out;
763a0c64a17SJack Morgenstein 	}
764a0c64a17SJack Morgenstein 
76599ee4df6SYishai Hadas 	set_guid_rec(&dev->ib_dev, rec);
766a0c64a17SJack Morgenstein out:
767a0c64a17SJack Morgenstein 	kfree(rec);
768a0c64a17SJack Morgenstein }
769a0c64a17SJack Morgenstein 
770a0c64a17SJack Morgenstein 
771a0c64a17SJack Morgenstein void mlx4_ib_init_alias_guid_work(struct mlx4_ib_dev *dev, int port)
772a0c64a17SJack Morgenstein {
773a0c64a17SJack Morgenstein 	unsigned long flags, flags1;
774a0c64a17SJack Morgenstein 
775a0c64a17SJack Morgenstein 	if (!mlx4_is_master(dev->dev))
776a0c64a17SJack Morgenstein 		return;
777a0c64a17SJack Morgenstein 	spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
778a0c64a17SJack Morgenstein 	spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
779a0c64a17SJack Morgenstein 	if (!dev->sriov.is_going_down) {
78099ee4df6SYishai Hadas 		/* If there is pending one should cancell then run, otherwise
78199ee4df6SYishai Hadas 		  * won't run till previous one is ended as same work
78299ee4df6SYishai Hadas 		  * struct is used.
78399ee4df6SYishai Hadas 		  */
78499ee4df6SYishai Hadas 		cancel_delayed_work(&dev->sriov.alias_guid.ports_guid[port].
78599ee4df6SYishai Hadas 				    alias_guid_work);
786a0c64a17SJack Morgenstein 		queue_delayed_work(dev->sriov.alias_guid.ports_guid[port].wq,
787a0c64a17SJack Morgenstein 			   &dev->sriov.alias_guid.ports_guid[port].alias_guid_work, 0);
788a0c64a17SJack Morgenstein 	}
789a0c64a17SJack Morgenstein 	spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
790a0c64a17SJack Morgenstein 	spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
791a0c64a17SJack Morgenstein }
792a0c64a17SJack Morgenstein 
793a0c64a17SJack Morgenstein void mlx4_ib_destroy_alias_guid_service(struct mlx4_ib_dev *dev)
794a0c64a17SJack Morgenstein {
795a0c64a17SJack Morgenstein 	int i;
796a0c64a17SJack Morgenstein 	struct mlx4_ib_sriov *sriov = &dev->sriov;
797a0c64a17SJack Morgenstein 	struct mlx4_alias_guid_work_context *cb_ctx;
798a0c64a17SJack Morgenstein 	struct mlx4_sriov_alias_guid_port_rec_det *det;
799a0c64a17SJack Morgenstein 	struct ib_sa_query *sa_query;
800a0c64a17SJack Morgenstein 	unsigned long flags;
801a0c64a17SJack Morgenstein 
802a0c64a17SJack Morgenstein 	for (i = 0 ; i < dev->num_ports; i++) {
803a0c64a17SJack Morgenstein 		cancel_delayed_work(&dev->sriov.alias_guid.ports_guid[i].alias_guid_work);
804a0c64a17SJack Morgenstein 		det = &sriov->alias_guid.ports_guid[i];
805a0c64a17SJack Morgenstein 		spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags);
806a0c64a17SJack Morgenstein 		while (!list_empty(&det->cb_list)) {
807a0c64a17SJack Morgenstein 			cb_ctx = list_entry(det->cb_list.next,
808a0c64a17SJack Morgenstein 					    struct mlx4_alias_guid_work_context,
809a0c64a17SJack Morgenstein 					    list);
810a0c64a17SJack Morgenstein 			sa_query = cb_ctx->sa_query;
811a0c64a17SJack Morgenstein 			cb_ctx->sa_query = NULL;
812a0c64a17SJack Morgenstein 			list_del(&cb_ctx->list);
813a0c64a17SJack Morgenstein 			spin_unlock_irqrestore(&sriov->alias_guid.ag_work_lock, flags);
814a0c64a17SJack Morgenstein 			ib_sa_cancel_query(cb_ctx->query_id, sa_query);
815a0c64a17SJack Morgenstein 			wait_for_completion(&cb_ctx->done);
816a0c64a17SJack Morgenstein 			kfree(cb_ctx);
817a0c64a17SJack Morgenstein 			spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags);
818a0c64a17SJack Morgenstein 		}
819a0c64a17SJack Morgenstein 		spin_unlock_irqrestore(&sriov->alias_guid.ag_work_lock, flags);
820a0c64a17SJack Morgenstein 	}
821a0c64a17SJack Morgenstein 	for (i = 0 ; i < dev->num_ports; i++) {
822a0c64a17SJack Morgenstein 		flush_workqueue(dev->sriov.alias_guid.ports_guid[i].wq);
823a0c64a17SJack Morgenstein 		destroy_workqueue(dev->sriov.alias_guid.ports_guid[i].wq);
824a0c64a17SJack Morgenstein 	}
825a0c64a17SJack Morgenstein 	ib_sa_unregister_client(dev->sriov.alias_guid.sa_client);
826a0c64a17SJack Morgenstein 	kfree(dev->sriov.alias_guid.sa_client);
827a0c64a17SJack Morgenstein }
828a0c64a17SJack Morgenstein 
829a0c64a17SJack Morgenstein int mlx4_ib_init_alias_guid_service(struct mlx4_ib_dev *dev)
830a0c64a17SJack Morgenstein {
831a0c64a17SJack Morgenstein 	char alias_wq_name[15];
832a0c64a17SJack Morgenstein 	int ret = 0;
833f5479601SYishai Hadas 	int i, j;
834a0c64a17SJack Morgenstein 	union ib_gid gid;
835a0c64a17SJack Morgenstein 
836a0c64a17SJack Morgenstein 	if (!mlx4_is_master(dev->dev))
837a0c64a17SJack Morgenstein 		return 0;
838a0c64a17SJack Morgenstein 	dev->sriov.alias_guid.sa_client =
839a0c64a17SJack Morgenstein 		kzalloc(sizeof *dev->sriov.alias_guid.sa_client, GFP_KERNEL);
840a0c64a17SJack Morgenstein 	if (!dev->sriov.alias_guid.sa_client)
841a0c64a17SJack Morgenstein 		return -ENOMEM;
842a0c64a17SJack Morgenstein 
843a0c64a17SJack Morgenstein 	ib_sa_register_client(dev->sriov.alias_guid.sa_client);
844a0c64a17SJack Morgenstein 
845a0c64a17SJack Morgenstein 	spin_lock_init(&dev->sriov.alias_guid.ag_work_lock);
846a0c64a17SJack Morgenstein 
847a0c64a17SJack Morgenstein 	for (i = 1; i <= dev->num_ports; ++i) {
848a0c64a17SJack Morgenstein 		if (dev->ib_dev.query_gid(&dev->ib_dev , i, 0, &gid)) {
849a0c64a17SJack Morgenstein 			ret = -EFAULT;
850a0c64a17SJack Morgenstein 			goto err_unregister;
851a0c64a17SJack Morgenstein 		}
852a0c64a17SJack Morgenstein 	}
853a0c64a17SJack Morgenstein 
854a0c64a17SJack Morgenstein 	for (i = 0 ; i < dev->num_ports; i++) {
855a0c64a17SJack Morgenstein 		memset(&dev->sriov.alias_guid.ports_guid[i], 0,
856a0c64a17SJack Morgenstein 		       sizeof (struct mlx4_sriov_alias_guid_port_rec_det));
857f5479601SYishai Hadas 		dev->sriov.alias_guid.ports_guid[i].state_flags |=
858f5479601SYishai Hadas 				GUID_STATE_NEED_PORT_INIT;
859a0c64a17SJack Morgenstein 		for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) {
860f5479601SYishai Hadas 			/* mark each val as it was deleted */
861f5479601SYishai Hadas 			memset(dev->sriov.alias_guid.ports_guid[i].
862f5479601SYishai Hadas 				all_rec_per_port[j].all_recs, 0xFF,
863f5479601SYishai Hadas 				sizeof(dev->sriov.alias_guid.ports_guid[i].
864f5479601SYishai Hadas 				all_rec_per_port[j].all_recs));
865a0c64a17SJack Morgenstein 		}
866a0c64a17SJack Morgenstein 		INIT_LIST_HEAD(&dev->sriov.alias_guid.ports_guid[i].cb_list);
867a0c64a17SJack Morgenstein 		/*prepare the records, set them to be allocated by sm*/
868f5479601SYishai Hadas 		if (mlx4_ib_sm_guid_assign)
869f5479601SYishai Hadas 			for (j = 1; j < NUM_ALIAS_GUID_PER_PORT; j++)
870f5479601SYishai Hadas 				mlx4_set_admin_guid(dev->dev, 0, j, i + 1);
871a0c64a17SJack Morgenstein 		for (j = 0 ; j < NUM_ALIAS_GUID_REC_IN_PORT; j++)
872a0c64a17SJack Morgenstein 			invalidate_guid_record(dev, i + 1, j);
873a0c64a17SJack Morgenstein 
874a0c64a17SJack Morgenstein 		dev->sriov.alias_guid.ports_guid[i].parent = &dev->sriov.alias_guid;
875a0c64a17SJack Morgenstein 		dev->sriov.alias_guid.ports_guid[i].port  = i;
876a0c64a17SJack Morgenstein 
877a0c64a17SJack Morgenstein 		snprintf(alias_wq_name, sizeof alias_wq_name, "alias_guid%d", i);
878a0c64a17SJack Morgenstein 		dev->sriov.alias_guid.ports_guid[i].wq =
879a0c64a17SJack Morgenstein 			create_singlethread_workqueue(alias_wq_name);
880a0c64a17SJack Morgenstein 		if (!dev->sriov.alias_guid.ports_guid[i].wq) {
881a0c64a17SJack Morgenstein 			ret = -ENOMEM;
882a0c64a17SJack Morgenstein 			goto err_thread;
883a0c64a17SJack Morgenstein 		}
884a0c64a17SJack Morgenstein 		INIT_DELAYED_WORK(&dev->sriov.alias_guid.ports_guid[i].alias_guid_work,
885a0c64a17SJack Morgenstein 			  alias_guid_work);
886a0c64a17SJack Morgenstein 	}
887a0c64a17SJack Morgenstein 	return 0;
888a0c64a17SJack Morgenstein 
889a0c64a17SJack Morgenstein err_thread:
890a0c64a17SJack Morgenstein 	for (--i; i >= 0; i--) {
891a0c64a17SJack Morgenstein 		destroy_workqueue(dev->sriov.alias_guid.ports_guid[i].wq);
892a0c64a17SJack Morgenstein 		dev->sriov.alias_guid.ports_guid[i].wq = NULL;
893a0c64a17SJack Morgenstein 	}
894a0c64a17SJack Morgenstein 
895a0c64a17SJack Morgenstein err_unregister:
896a0c64a17SJack Morgenstein 	ib_sa_unregister_client(dev->sriov.alias_guid.sa_client);
897a0c64a17SJack Morgenstein 	kfree(dev->sriov.alias_guid.sa_client);
898a0c64a17SJack Morgenstein 	dev->sriov.alias_guid.sa_client = NULL;
899a0c64a17SJack Morgenstein 	pr_err("init_alias_guid_service: Failed. (ret:%d)\n", ret);
900a0c64a17SJack Morgenstein 	return ret;
901a0c64a17SJack Morgenstein }
902