IB/sa: Add GuidInfoRecord query support
authorErez Shitrit <erezsh@mellanox.co.il>
Tue, 19 Jun 2012 08:21:38 +0000 (11:21 +0300)
committerRoland Dreier <roland@purestorage.com>
Mon, 9 Jul 2012 01:05:06 +0000 (18:05 -0700)
This query is needed for SRIOV alias GUID support.

The query is implemented per the IB Spec definition
in section 15.2.5.18 (GuidInfoRecord).

Signed-off-by: Erez Shitrit <erezsh@mellanox.co.il>
Signed-off-by: Jack Morgenstein <jackm@dev.mellanox.co.il>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
drivers/infiniband/core/sa_query.c
include/rdma/ib_sa.h

index fbbfa24..a8905ab 100644 (file)
@@ -94,6 +94,12 @@ struct ib_sa_path_query {
        struct ib_sa_query sa_query;
 };
 
+struct ib_sa_guidinfo_query {
+       void (*callback)(int, struct ib_sa_guidinfo_rec *, void *);
+       void *context;
+       struct ib_sa_query sa_query;
+};
+
 struct ib_sa_mcmember_query {
        void (*callback)(int, struct ib_sa_mcmember_rec *, void *);
        void *context;
@@ -347,6 +353,34 @@ static const struct ib_field service_rec_table[] = {
          .size_bits    = 2*64 },
 };
 
+#define GUIDINFO_REC_FIELD(field) \
+       .struct_offset_bytes = offsetof(struct ib_sa_guidinfo_rec, field),      \
+       .struct_size_bytes   = sizeof((struct ib_sa_guidinfo_rec *) 0)->field,  \
+       .field_name          = "sa_guidinfo_rec:" #field
+
+static const struct ib_field guidinfo_rec_table[] = {
+       { GUIDINFO_REC_FIELD(lid),
+         .offset_words = 0,
+         .offset_bits  = 0,
+         .size_bits    = 16 },
+       { GUIDINFO_REC_FIELD(block_num),
+         .offset_words = 0,
+         .offset_bits  = 16,
+         .size_bits    = 8 },
+       { GUIDINFO_REC_FIELD(res1),
+         .offset_words = 0,
+         .offset_bits  = 24,
+         .size_bits    = 8 },
+       { GUIDINFO_REC_FIELD(res2),
+         .offset_words = 1,
+         .offset_bits  = 0,
+         .size_bits    = 32 },
+       { GUIDINFO_REC_FIELD(guid_info_list),
+         .offset_words = 2,
+         .offset_bits  = 0,
+         .size_bits    = 512 },
+};
+
 static void free_sm_ah(struct kref *kref)
 {
        struct ib_sa_sm_ah *sm_ah = container_of(kref, struct ib_sa_sm_ah, ref);
@@ -945,6 +979,105 @@ err1:
        return ret;
 }
 
+/* Support GuidInfoRecord */
+static void ib_sa_guidinfo_rec_callback(struct ib_sa_query *sa_query,
+                                       int status,
+                                       struct ib_sa_mad *mad)
+{
+       struct ib_sa_guidinfo_query *query =
+               container_of(sa_query, struct ib_sa_guidinfo_query, sa_query);
+
+       if (mad) {
+               struct ib_sa_guidinfo_rec rec;
+
+               ib_unpack(guidinfo_rec_table, ARRAY_SIZE(guidinfo_rec_table),
+                         mad->data, &rec);
+               query->callback(status, &rec, query->context);
+       } else
+               query->callback(status, NULL, query->context);
+}
+
+static void ib_sa_guidinfo_rec_release(struct ib_sa_query *sa_query)
+{
+       kfree(container_of(sa_query, struct ib_sa_guidinfo_query, sa_query));
+}
+
+int ib_sa_guid_info_rec_query(struct ib_sa_client *client,
+                             struct ib_device *device, u8 port_num,
+                             struct ib_sa_guidinfo_rec *rec,
+                             ib_sa_comp_mask comp_mask, u8 method,
+                             int timeout_ms, gfp_t gfp_mask,
+                             void (*callback)(int status,
+                                              struct ib_sa_guidinfo_rec *resp,
+                                              void *context),
+                             void *context,
+                             struct ib_sa_query **sa_query)
+{
+       struct ib_sa_guidinfo_query *query;
+       struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client);
+       struct ib_sa_port *port;
+       struct ib_mad_agent *agent;
+       struct ib_sa_mad *mad;
+       int ret;
+
+       if (!sa_dev)
+               return -ENODEV;
+
+       if (method != IB_MGMT_METHOD_GET &&
+           method != IB_MGMT_METHOD_SET &&
+           method != IB_SA_METHOD_DELETE) {
+               return -EINVAL;
+       }
+
+       port  = &sa_dev->port[port_num - sa_dev->start_port];
+       agent = port->agent;
+
+       query = kmalloc(sizeof *query, gfp_mask);
+       if (!query)
+               return -ENOMEM;
+
+       query->sa_query.port = port;
+       ret = alloc_mad(&query->sa_query, gfp_mask);
+       if (ret)
+               goto err1;
+
+       ib_sa_client_get(client);
+       query->sa_query.client = client;
+       query->callback        = callback;
+       query->context         = context;
+
+       mad = query->sa_query.mad_buf->mad;
+       init_mad(mad, agent);
+
+       query->sa_query.callback = callback ? ib_sa_guidinfo_rec_callback : NULL;
+       query->sa_query.release  = ib_sa_guidinfo_rec_release;
+
+       mad->mad_hdr.method      = method;
+       mad->mad_hdr.attr_id     = cpu_to_be16(IB_SA_ATTR_GUID_INFO_REC);
+       mad->sa_hdr.comp_mask    = comp_mask;
+
+       ib_pack(guidinfo_rec_table, ARRAY_SIZE(guidinfo_rec_table), rec,
+               mad->data);
+
+       *sa_query = &query->sa_query;
+
+       ret = send_mad(&query->sa_query, timeout_ms, gfp_mask);
+       if (ret < 0)
+               goto err2;
+
+       return ret;
+
+err2:
+       *sa_query = NULL;
+       ib_sa_client_put(query->sa_query.client);
+       free_mad(&query->sa_query);
+
+err1:
+       kfree(query);
+       return ret;
+}
+EXPORT_SYMBOL(ib_sa_guid_info_rec_query);
+
 static void send_handler(struct ib_mad_agent *agent,
                         struct ib_mad_send_wc *mad_send_wc)
 {
index d44a563..8275e53 100644 (file)
@@ -251,6 +251,28 @@ struct ib_sa_service_rec {
        u64             data64[2];
 };
 
+#define IB_SA_GUIDINFO_REC_LID         IB_SA_COMP_MASK(0)
+#define IB_SA_GUIDINFO_REC_BLOCK_NUM   IB_SA_COMP_MASK(1)
+#define IB_SA_GUIDINFO_REC_RES1                IB_SA_COMP_MASK(2)
+#define IB_SA_GUIDINFO_REC_RES2                IB_SA_COMP_MASK(3)
+#define IB_SA_GUIDINFO_REC_GID0                IB_SA_COMP_MASK(4)
+#define IB_SA_GUIDINFO_REC_GID1                IB_SA_COMP_MASK(5)
+#define IB_SA_GUIDINFO_REC_GID2                IB_SA_COMP_MASK(6)
+#define IB_SA_GUIDINFO_REC_GID3                IB_SA_COMP_MASK(7)
+#define IB_SA_GUIDINFO_REC_GID4                IB_SA_COMP_MASK(8)
+#define IB_SA_GUIDINFO_REC_GID5                IB_SA_COMP_MASK(9)
+#define IB_SA_GUIDINFO_REC_GID6                IB_SA_COMP_MASK(10)
+#define IB_SA_GUIDINFO_REC_GID7                IB_SA_COMP_MASK(11)
+
+struct ib_sa_guidinfo_rec {
+       __be16  lid;
+       u8      block_num;
+       /* reserved */
+       u8      res1;
+       __be32  res2;
+       u8      guid_info_list[64];
+};
+
 struct ib_sa_client {
        atomic_t users;
        struct completion comp;
@@ -385,4 +407,15 @@ int ib_init_ah_from_path(struct ib_device *device, u8 port_num,
  */
 void ib_sa_unpack_path(void *attribute, struct ib_sa_path_rec *rec);
 
+/* Support GuidInfoRecord */
+int ib_sa_guid_info_rec_query(struct ib_sa_client *client,
+                             struct ib_device *device, u8 port_num,
+                             struct ib_sa_guidinfo_rec *rec,
+                             ib_sa_comp_mask comp_mask, u8 method,
+                             int timeout_ms, gfp_t gfp_mask,
+                             void (*callback)(int status,
+                                              struct ib_sa_guidinfo_rec *resp,
+                                              void *context),
+                             void *context,
+                             struct ib_sa_query **sa_query);
 #endif /* IB_SA_H */