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