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