[openib-general] [PATCH v2] ib_sa: add generic RMPP query interface

Sean Hefty sean.hefty at intel.com
Thu Sep 14 09:33:16 PDT 2006


Patch updated to svn tip, which includes SA registration.

The following patch adds a generic interface to send MADs to the SA.
The primary motivation of adding these calls is to expand the SA query
interface to include RMPP responses for users wanting more than a
single attribute returned from a query (e.g. multipath record queries),
but it also simplifies a userspace interface.

The implementation of existing SA query routines were layered on top
of the generic query interface.

Signed-off-by: Sean Hefty <sean.hefty at intel.com>
---
Index: include/rdma/ib_sa.h
===================================================================
--- include/rdma/ib_sa.h	(revision 9490)
+++ include/rdma/ib_sa.h	(working copy)
@@ -82,6 +82,32 @@ enum {
 	IB_SA_ATTR_INFORM_INFO_REC   = 0xf3
 };
 
+/* Length of SA attributes on the wire */
+enum {
+	IB_SA_ATTR_CLASS_PORTINFO_LEN	= 72,
+	IB_SA_ATTR_NOTICE_LEN		= 80,
+	IB_SA_ATTR_INFORM_INFO_LEN	= 36,
+	IB_SA_ATTR_NODE_REC_LEN		= 108,
+	IB_SA_ATTR_PORT_INFO_REC_LEN	= 58,
+	IB_SA_ATTR_SL2VL_REC_LEN	= 16,
+	IB_SA_ATTR_SWITCH_REC_LEN	= 21,
+	IB_SA_ATTR_LINEAR_FDB_REC_LEN	= 72,
+	IB_SA_ATTR_RANDOM_FDB_REC_LEN	= 72,
+	IB_SA_ATTR_MCAST_FDB_REC_LEN	= 72,
+	IB_SA_ATTR_SM_INFO_REC_LEN	= 25,
+	IB_SA_ATTR_LINK_REC_LEN		= 6,
+	IB_SA_ATTR_GUID_INFO_REC_LEN	= 72,
+	IB_SA_ATTR_SERVICE_REC_LEN	= 176,
+	IB_SA_ATTR_PARTITION_REC_LEN	= 72,
+	IB_SA_ATTR_PATH_REC_LEN		= 64,
+	IB_SA_ATTR_VL_ARB_REC_LEN	= 72,
+	IB_SA_ATTR_MC_MEMBER_REC_LEN	= 52,
+	IB_SA_ATTR_TRACE_REC_LEN	= 46,
+	IB_SA_ATTR_MULTI_PATH_REC_LEN	= 56,
+	IB_SA_ATTR_SERVICE_ASSOC_REC_LEN= 80,
+	IB_SA_ATTR_INFORM_INFO_REC_LEN	= 60
+};
+
 enum ib_sa_selector {
 	IB_SA_GTE  = 0,
 	IB_SA_LTE  = 1,
@@ -270,10 +296,83 @@ void ib_sa_register_client(struct ib_sa_
  */
 void ib_sa_unregister_client(struct ib_sa_client *client);
 
+struct ib_sa_iter;
+
+/**
+ * ib_sa_iter_create - Create an iterator that may be used to walk through
+ *   a list of returned SA records.
+ * @mad_recv_wc: A received response from the SA.
+ *
+ * This call allocates an iterator that is used to walk through a list of 
+ * SA records.  Users must free the iterator by calling ib_sa_iter_free.
+ */
+struct ib_sa_iter *ib_sa_iter_create(struct ib_mad_recv_wc *mad_recv_wc);
+
+/**
+ * ib_sa_iter_free - Release an iterator.
+ * @iter: The iterator to free.
+ */
+void ib_sa_iter_free(struct ib_sa_iter *iter);
+
+/**
+ * ib_sa_iter_next - Move an iterator to reference the next attribute and
+ *   return the attribute.
+ * @iter: The iterator to move.
+ *
+ * The referenced attribute will be in wire format.  The funtion returns NULL
+ * if there are no more attributes to return.
+ */
+void *ib_sa_iter_next(struct ib_sa_iter *iter);
+
+/**
+ * ib_sa_attr_size - Return the length of an SA attribute on the wire.
+ * @attr_id: Attribute identifier.
+ */
+int ib_sa_attr_size(__be16 attr_id);
+
 struct ib_sa_query;
 
 void ib_sa_cancel_query(int id, struct ib_sa_query *query);
 
+/**
+ * ib_sa_send_mad - Send a MAD to the SA.
+ * @client:SA client
+ * @device:device to send query on
+ * @port_num: port number to send query on
+ * @method:MAD method to use in the send.
+ * @attr:Reference to attribute in wire format to send in MAD.
+ * @attr_id:Attribute type identifier.
+ * @comp_mask:component mask to send in MAD
+ * @timeout_ms:time to wait for response, if one is expected
+ * @retries:number of times to retry request
+ * @gfp_mask:GFP mask to use for internal allocations
+ * @callback:function called when query completes, times out or is
+ * canceled
+ * @context:opaque user context passed to callback
+ * @sa_query:query context, used to cancel query
+ *
+ * Send a message to the SA.  If a response is expected (timeout_ms is
+ * non-zero), the callback function will be called when the query completes.
+ * Status is 0 for a successful response, -EINTR if the query
+ * is canceled, -ETIMEDOUT is the query timed out, or -EIO if an error
+ * occurred sending the query.  Mad_recv_wc will reference any returned
+ * response from the SA.  It is the responsibility of the caller to free
+ * mad_recv_wc by call ib_free_recv_mad() if it is non-NULL.
+ *
+ * If the return value of ib_sa_send_mad() is negative, it is an
+ * error code.  Otherwise it is a query ID that can be used to cancel
+ * the query.
+ */
+int ib_sa_send_mad(struct ib_sa_client *client,
+		   struct ib_device *device, u8 port_num,
+		   int method, void *attr, __be16 attr_id,
+		   ib_sa_comp_mask comp_mask,
+		   int timeout_ms, int retries, gfp_t gfp_mask,
+		   void (*callback)(int status,
+				    struct ib_mad_recv_wc *mad_recv_wc,
+				    void *context),
+		   void *context, struct ib_sa_query **query);
+
 int ib_sa_path_rec_get(struct ib_sa_client *client,
 		       struct ib_device *device, u8 port_num,
 		       struct ib_sa_path_rec *rec,
Index: core/sa_query.c
===================================================================
--- core/sa_query.c	(revision 9490)
+++ core/sa_query.c	(working copy)
@@ -73,31 +73,42 @@ struct ib_sa_device {
 };
 
 struct ib_sa_query {
-	void (*callback)(struct ib_sa_query *, int, struct ib_sa_mad *);
-	void (*release)(struct ib_sa_query *);
+	void (*callback)(int, struct ib_mad_recv_wc *, void *);
 	struct ib_sa_client    *client;
 	struct ib_sa_port      *port;
 	struct ib_mad_send_buf *mad_buf;
 	struct ib_sa_sm_ah     *sm_ah;
+	void		       *context;
 	int			id;
 };
 
 struct ib_sa_service_query {
 	void (*callback)(int, struct ib_sa_service_rec *, void *);
 	void *context;
-	struct ib_sa_query sa_query;
+	struct ib_sa_query *sa_query;
 };
 
 struct ib_sa_path_query {
 	void (*callback)(int, struct ib_sa_path_rec *, void *);
 	void *context;
-	struct ib_sa_query sa_query;
+	struct ib_sa_query *sa_query;
 };
 
 struct ib_sa_mcmember_query {
 	void (*callback)(int, struct ib_sa_mcmember_rec *, void *);
 	void *context;
-	struct ib_sa_query sa_query;
+	struct ib_sa_query *sa_query;
+};
+
+struct ib_sa_iter {
+	struct ib_mad_recv_wc *recv_wc;
+	struct ib_mad_recv_buf *recv_buf;
+	int attr_size;
+	int attr_offset;
+	int data_offset;
+	int data_left;
+	void *attr;
+	u8 attr_data[0];
 };
 
 static void ib_sa_add_one(struct ib_device *device);
@@ -532,9 +543,17 @@ EXPORT_SYMBOL(ib_init_ah_from_mcmember);
 int ib_sa_pack_attr(void *dst, void *src, int attr_id)
 {
 	switch (attr_id) {
+	case IB_SA_ATTR_SERVICE_REC:
+		ib_pack(service_rec_table, ARRAY_SIZE(service_rec_table),
+			src, dst);
+		break;
 	case IB_SA_ATTR_PATH_REC:
 		ib_pack(path_rec_table, ARRAY_SIZE(path_rec_table), src, dst);
 		break;
+	case IB_SA_ATTR_MC_MEMBER_REC:
+		ib_pack(mcmember_rec_table, ARRAY_SIZE(mcmember_rec_table),
+			src, dst);
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -545,9 +564,17 @@ EXPORT_SYMBOL(ib_sa_pack_attr);
 int ib_sa_unpack_attr(void *dst, void *src, int attr_id)
 {
 	switch (attr_id) {
+	case IB_SA_ATTR_SERVICE_REC:
+		ib_unpack(service_rec_table, ARRAY_SIZE(service_rec_table),
+			  src, dst);
+		break;
 	case IB_SA_ATTR_PATH_REC:
 		ib_unpack(path_rec_table, ARRAY_SIZE(path_rec_table), src, dst);
 		break;
+	case IB_SA_ATTR_MC_MEMBER_REC:
+		ib_unpack(mcmember_rec_table, ARRAY_SIZE(mcmember_rec_table),
+			  src, dst);
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -555,15 +582,100 @@ int ib_sa_unpack_attr(void *dst, void *s
 }
 EXPORT_SYMBOL(ib_sa_unpack_attr);
 
-static void init_mad(struct ib_sa_mad *mad, struct ib_mad_agent *agent)
+/* Return size of SA attributes on the wire. */
+int ib_sa_attr_size(__be16 attr_id)
 {
-	unsigned long flags;
+	int size;
 
-	memset(mad, 0, sizeof *mad);
+	switch (be16_to_cpu(attr_id)) {
+	case IB_SA_ATTR_CLASS_PORTINFO:
+		size = IB_SA_ATTR_CLASS_PORTINFO_LEN;
+		break;
+	case IB_SA_ATTR_NOTICE:
+		size = IB_SA_ATTR_NOTICE_LEN;
+		break;
+	case IB_SA_ATTR_INFORM_INFO:
+		size = IB_SA_ATTR_INFORM_INFO_LEN;
+		break;
+	case IB_SA_ATTR_NODE_REC:
+		size = IB_SA_ATTR_NODE_REC_LEN;
+		break;
+	case IB_SA_ATTR_PORT_INFO_REC:
+		size = IB_SA_ATTR_PORT_INFO_REC_LEN;
+		break;
+	case IB_SA_ATTR_SL2VL_REC:
+		size = IB_SA_ATTR_SL2VL_REC_LEN;
+		break;
+	case IB_SA_ATTR_SWITCH_REC:
+		size = IB_SA_ATTR_SWITCH_REC_LEN;
+		break;
+	case IB_SA_ATTR_LINEAR_FDB_REC:
+		size = IB_SA_ATTR_LINEAR_FDB_REC_LEN;
+		break;
+	case IB_SA_ATTR_RANDOM_FDB_REC:
+		size = IB_SA_ATTR_RANDOM_FDB_REC_LEN;
+		break;
+	case IB_SA_ATTR_MCAST_FDB_REC:
+		size = IB_SA_ATTR_MCAST_FDB_REC_LEN;
+		break;
+	case IB_SA_ATTR_SM_INFO_REC:
+		size = IB_SA_ATTR_SM_INFO_REC_LEN;
+		break;
+	case IB_SA_ATTR_LINK_REC:
+		size = IB_SA_ATTR_LINK_REC_LEN;
+		break;
+	case IB_SA_ATTR_GUID_INFO_REC:
+		size = IB_SA_ATTR_GUID_INFO_REC_LEN;
+		break;
+	case IB_SA_ATTR_SERVICE_REC:
+		size = IB_SA_ATTR_SERVICE_REC_LEN;
+		break;
+	case IB_SA_ATTR_PARTITION_REC:
+		size = IB_SA_ATTR_PARTITION_REC_LEN;
+		break;
+	case IB_SA_ATTR_PATH_REC:
+		size = IB_SA_ATTR_PATH_REC_LEN;
+		break;
+	case IB_SA_ATTR_VL_ARB_REC:
+		size = IB_SA_ATTR_VL_ARB_REC_LEN;
+		break;
+	case IB_SA_ATTR_MC_MEMBER_REC:
+		size = IB_SA_ATTR_MC_MEMBER_REC_LEN;
+		break;
+	case IB_SA_ATTR_TRACE_REC:
+		size = IB_SA_ATTR_TRACE_REC_LEN;
+		break;
+	case IB_SA_ATTR_MULTI_PATH_REC:
+		size = IB_SA_ATTR_MULTI_PATH_REC_LEN;
+		break;
+	case IB_SA_ATTR_SERVICE_ASSOC_REC:
+		size = IB_SA_ATTR_SERVICE_ASSOC_REC_LEN;
+		break;
+	case IB_SA_ATTR_INFORM_INFO_REC:
+		size = IB_SA_ATTR_INFORM_INFO_REC_LEN;
+		break;
+	default:
+		size = 0;
+		break;
+	}
+	return size;
+}
+EXPORT_SYMBOL(ib_sa_attr_size);
+
+static void init_mad(struct ib_sa_mad *mad, struct ib_mad_agent *agent,
+		     int method, void *attr, __be16 attr_id,
+		     ib_sa_comp_mask comp_mask)
+{
+	unsigned long flags;
 
 	mad->mad_hdr.base_version  = IB_MGMT_BASE_VERSION;
 	mad->mad_hdr.mgmt_class    = IB_MGMT_CLASS_SUBN_ADM;
 	mad->mad_hdr.class_version = IB_SA_CLASS_VERSION;
+	mad->mad_hdr.method	   = method;
+	mad->mad_hdr.attr_id	   = attr_id;
+	mad->sa_hdr.comp_mask	   = comp_mask;
+
+	memcpy(mad->data, attr, ib_sa_attr_size(attr_id));
 
 	spin_lock_irqsave(&tid_lock, flags);
 	mad->mad_hdr.tid           =
@@ -617,31 +729,162 @@ retry:
 	return ret ? ret : id;
 }
 
-static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query,
-				    int status,
-				    struct ib_sa_mad *mad)
+struct ib_sa_iter *ib_sa_iter_create(struct ib_mad_recv_wc *mad_recv_wc)
+{
+	struct ib_sa_iter *iter;
+	struct ib_sa_mad *mad = (struct ib_sa_mad *) mad_recv_wc->recv_buf.mad;
+	int attr_size, attr_offset;
+
+	attr_offset = be16_to_cpu(mad->sa_hdr.attr_offset) * 8;
+	attr_size = ib_sa_attr_size(mad->mad_hdr.attr_id);
+	if (!attr_size || attr_offset < attr_size)
+		return ERR_PTR(-EINVAL);
+
+	iter = kzalloc(sizeof *iter + attr_size, GFP_KERNEL);
+	if (!iter)
+		return ERR_PTR(-ENOMEM);
+
+	iter->data_left = mad_recv_wc->mad_len - IB_MGMT_SA_HDR;
+	iter->recv_wc = mad_recv_wc;
+	iter->recv_buf = &mad_recv_wc->recv_buf;
+	iter->attr_offset = attr_offset;
+	iter->attr_size = attr_size;
+	return iter;
+}
+EXPORT_SYMBOL(ib_sa_iter_create);
+
+void ib_sa_iter_free(struct ib_sa_iter *iter)
+{
+	kfree(iter);
+}
+EXPORT_SYMBOL(ib_sa_iter_free);
+
+void *ib_sa_iter_next(struct ib_sa_iter *iter)
+{
+	struct ib_sa_mad *mad;
+	int left, offset = 0;
+
+	while (iter->data_left >= iter->attr_offset) {
+		while (iter->data_offset < IB_MGMT_SA_DATA) {
+			mad = (struct ib_sa_mad *) iter->recv_buf->mad;
+
+			left = IB_MGMT_SA_DATA - iter->data_offset;
+			if (left < iter->attr_size) {
+				/* copy first piece of the attribute */
+				iter->attr = &iter->attr_data;
+				memcpy(iter->attr,
+				       &mad->data[iter->data_offset], left);
+				offset = left;
+				break;
+			} else if (offset) {
+				/* copy the second piece of the attribute */
+				memcpy(iter->attr + offset, &mad->data[0],
+				       iter->attr_size - offset);
+				iter->data_offset = iter->attr_size - offset;
+				offset = 0;
+			} else {
+				iter->attr = &mad->data[iter->data_offset];
+				iter->data_offset += iter->attr_size;
+			}
+
+			iter->data_left -= iter->attr_offset;
+			goto out;
+		}
+		iter->data_offset = 0;
+		iter->recv_buf = list_entry(iter->recv_buf->list.next,
+					    struct ib_mad_recv_buf, list);
+	}
+	iter->attr = NULL;
+out:
+	return iter->attr;
+}
+EXPORT_SYMBOL(ib_sa_iter_next);
+
+int ib_sa_send_mad(struct ib_sa_client *client,
+		   struct ib_device *device, u8 port_num,
+		   int method, void *attr, __be16 attr_id,
+		   ib_sa_comp_mask comp_mask,
+		   int timeout_ms, int retries, gfp_t gfp_mask,
+		   void (*callback)(int status,
+				    struct ib_mad_recv_wc *mad_recv_wc,
+				    void *context),
+		   void *context, struct ib_sa_query **query)
 {
-	struct ib_sa_path_query *query =
-		container_of(sa_query, struct ib_sa_path_query, sa_query);
+	struct ib_sa_query  *sa_query;
+	struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client);
+	struct ib_sa_port   *port;
+	struct ib_mad_agent *agent;
+	int ret;
+
+	if (!sa_dev)
+		return -ENODEV;
+
+	port  = &sa_dev->port[port_num - sa_dev->start_port];
+	agent = port->agent;
+
+	sa_query = kmalloc(sizeof *sa_query, gfp_mask);
+	if (!sa_query)
+		return -ENOMEM;
+
+	sa_query->mad_buf = ib_create_send_mad(agent, 1, 0,
+					       method == IB_SA_METHOD_GET_MULTI,
+					       IB_MGMT_SA_HDR, IB_MGMT_SA_DATA,
+					       gfp_mask);
+	if (!sa_query->mad_buf) {
+		ret = -ENOMEM;
+		goto err1;
+	}
 
-	if (mad) {
-		struct ib_sa_path_rec rec;
+	sa_query->port	   = port;
+	sa_query->callback = callback;
+	sa_query->context  = context;
 
-		ib_unpack(path_rec_table, ARRAY_SIZE(path_rec_table),
-			  mad->data, &rec);
-		query->callback(status, &rec, query->context);
-	} else
-		query->callback(status, NULL, query->context);
+	init_mad(sa_query->mad_buf->mad, agent, method, attr, attr_id,
+		 comp_mask);
+
+	ib_sa_client_get(client);
+	sa_query->client = client;
+	ret = send_mad(sa_query, timeout_ms, retries, gfp_mask);
+	if (ret < 0)
+		goto err2;
+
+	*query = sa_query;
+	return ret;
+
+err2:
+	ib_sa_client_put(sa_query->client);
+	ib_free_send_mad(sa_query->mad_buf);
+err1:
+	kfree(query);
+	return ret;
 }
+EXPORT_SYMBOL(ib_sa_send_mad);
 
-static void ib_sa_path_rec_release(struct ib_sa_query *sa_query)
+static void ib_sa_path_rec_callback(int status,
+				    struct ib_mad_recv_wc *mad_recv_wc,
+				    void *context)
 {
-	kfree(container_of(sa_query, struct ib_sa_path_query, sa_query));
+	struct ib_sa_path_query *query = context;
+
+	if (query->callback) {
+		if (mad_recv_wc) {
+			struct ib_sa_mad *mad;
+			struct ib_sa_path_rec rec;
+
+			mad = (struct ib_sa_mad *) mad_recv_wc->recv_buf.mad;
+			ib_unpack(path_rec_table, ARRAY_SIZE(path_rec_table),
+				  mad->data, &rec);
+			query->callback(status, &rec, query->context);
+		} else
+			query->callback(status, NULL, query->context);
+	}
+	if (mad_recv_wc)
+		ib_free_recv_mad(mad_recv_wc);
+	kfree(query);
 }
 
 /**
  * ib_sa_path_rec_get - Start a Path get query
- * @client:SA client
  * @device:device to send query on
  * @port_num: port number to send query on
  * @rec:Path Record to send in query
@@ -677,91 +920,54 @@ int ib_sa_path_rec_get(struct ib_sa_clie
 		       struct ib_sa_query **sa_query)
 {
 	struct ib_sa_path_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;
+	u8 path[IB_SA_ATTR_PATH_REC_LEN];
 	int ret;
 
-	if (!sa_dev)
-		return -ENODEV;
-
-	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.mad_buf = ib_create_send_mad(agent, 1, 0,
-						     0, IB_MGMT_SA_HDR,
-						     IB_MGMT_SA_DATA, gfp_mask);
-	if (!query->sa_query.mad_buf) {
-		ret = -ENOMEM;
-		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_path_rec_callback : NULL;
-	query->sa_query.release  = ib_sa_path_rec_release;
-	query->sa_query.port     = port;
-	mad->mad_hdr.method	 = IB_MGMT_METHOD_GET;
-	mad->mad_hdr.attr_id	 = cpu_to_be16(IB_SA_ATTR_PATH_REC);
-	mad->sa_hdr.comp_mask	 = comp_mask;
-
-	ib_pack(path_rec_table, ARRAY_SIZE(path_rec_table), rec, mad->data);
-
-	*sa_query = &query->sa_query;
-
-	ret = send_mad(&query->sa_query, timeout_ms, retries, gfp_mask);
+	ib_pack(path_rec_table, ARRAY_SIZE(path_rec_table), rec, path);
+	ret = ib_sa_send_mad(client, device, port_num, IB_MGMT_METHOD_GET, path,
+			     cpu_to_be16(IB_SA_ATTR_PATH_REC), comp_mask,
+			     timeout_ms, retries, gfp_mask,
+			     ib_sa_path_rec_callback, query, &query->sa_query);
 	if (ret < 0)
-		goto err2;
+		kfree(query);
 
 	return ret;
-
-err2:
-	*sa_query = NULL;
-	ib_sa_client_put(query->sa_query.client);
-	ib_free_send_mad(query->sa_query.mad_buf);
-
-err1:
-	kfree(query);
-	return ret;
 }
 EXPORT_SYMBOL(ib_sa_path_rec_get);
 
-static void ib_sa_service_rec_callback(struct ib_sa_query *sa_query,
-				    int status,
-				    struct ib_sa_mad *mad)
+static void ib_sa_service_rec_callback(int status,
+				       struct ib_mad_recv_wc *mad_recv_wc,
+				       void *context)
 {
-	struct ib_sa_service_query *query =
-		container_of(sa_query, struct ib_sa_service_query, sa_query);
+	struct ib_sa_service_query *query = context;
 
-	if (mad) {
-		struct ib_sa_service_rec rec;
-
-		ib_unpack(service_rec_table, ARRAY_SIZE(service_rec_table),
-			  mad->data, &rec);
-		query->callback(status, &rec, query->context);
-	} else
-		query->callback(status, NULL, query->context);
-}
-
-static void ib_sa_service_rec_release(struct ib_sa_query *sa_query)
-{
-	kfree(container_of(sa_query, struct ib_sa_service_query, sa_query));
+	if (query->callback) {
+		if (mad_recv_wc) {
+			struct ib_sa_mad *mad;
+			struct ib_sa_service_rec rec;
+
+			mad = (struct ib_sa_mad *) mad_recv_wc->recv_buf.mad;
+			ib_unpack(service_rec_table,
+				  ARRAY_SIZE(service_rec_table),
+				  mad->data, &rec);
+			query->callback(status, &rec, query->context);
+		} else
+			query->callback(status, NULL, query->context);
+	}
+	if (mad_recv_wc)
+		ib_free_recv_mad(mad_recv_wc);
+	kfree(query);
 }
 
 /**
  * ib_sa_service_rec_query - Start Service Record operation
- * @client:SA client
  * @device:device to send request on
  * @port_num: port number to send request on
  * @method:SA method - should be get, set, or delete
@@ -799,98 +1005,56 @@ int ib_sa_service_rec_query(struct ib_sa
 			    struct ib_sa_query **sa_query)
 {
 	struct ib_sa_service_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;
+	u8 service[IB_SA_ATTR_SERVICE_REC_LEN];
 	int ret;
 
-	if (!sa_dev)
-		return -ENODEV;
-
-	port  = &sa_dev->port[port_num - sa_dev->start_port];
-	agent = port->agent;
-
-	if (method != IB_MGMT_METHOD_GET &&
-	    method != IB_MGMT_METHOD_SET &&
-	    method != IB_SA_METHOD_DELETE)
-		return -EINVAL;
-
 	query = kmalloc(sizeof *query, gfp_mask);
 	if (!query)
 		return -ENOMEM;
 
-	query->sa_query.mad_buf = ib_create_send_mad(agent, 1, 0,
-						     0, IB_MGMT_SA_HDR,
-						     IB_MGMT_SA_DATA, gfp_mask);
-	if (!query->sa_query.mad_buf) {
-		ret = -ENOMEM;
-		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_service_rec_callback : NULL;
-	query->sa_query.release  = ib_sa_service_rec_release;
-	query->sa_query.port     = port;
-	mad->mad_hdr.method	 = method;
-	mad->mad_hdr.attr_id	 = cpu_to_be16(IB_SA_ATTR_SERVICE_REC);
-	mad->sa_hdr.comp_mask	 = comp_mask;
-
-	ib_pack(service_rec_table, ARRAY_SIZE(service_rec_table),
-		rec, mad->data);
-
-	*sa_query = &query->sa_query;
-
-	ret = send_mad(&query->sa_query, timeout_ms, retries, gfp_mask);
+	ib_pack(service_rec_table, ARRAY_SIZE(service_rec_table), rec, service);
+	ret = ib_sa_send_mad(client, device, port_num, method, service,
+			     cpu_to_be16(IB_SA_ATTR_SERVICE_REC), comp_mask,
+			     timeout_ms, retries, gfp_mask,
+			     ib_sa_service_rec_callback, query,
+			     &query->sa_query);
 	if (ret < 0)
-		goto err2;
-
-	return ret;
+		kfree(query);
 
-err2:
-	*sa_query = NULL;
-	ib_sa_client_put(query->sa_query.client);
-	ib_free_send_mad(query->sa_query.mad_buf);
-
-err1:
-	kfree(query);
 	return ret;
 }
 EXPORT_SYMBOL(ib_sa_service_rec_query);
 
-static void ib_sa_mcmember_rec_callback(struct ib_sa_query *sa_query,
-					int status,
-					struct ib_sa_mad *mad)
+static void ib_sa_mcmember_rec_callback(int status,
+				        struct ib_mad_recv_wc *mad_recv_wc,
+				        void *context)
 {
-	struct ib_sa_mcmember_query *query =
-		container_of(sa_query, struct ib_sa_mcmember_query, sa_query);
-
-	if (mad) {
-		struct ib_sa_mcmember_rec rec;
-
-		ib_unpack(mcmember_rec_table, ARRAY_SIZE(mcmember_rec_table),
-			  mad->data, &rec);
-		query->callback(status, &rec, query->context);
-	} else
-		query->callback(status, NULL, query->context);
-}
+	struct ib_sa_mcmember_query *query = context;
 
-static void ib_sa_mcmember_rec_release(struct ib_sa_query *sa_query)
-{
-	kfree(container_of(sa_query, struct ib_sa_mcmember_query, sa_query));
+	if (query->callback) {
+		if (mad_recv_wc) {
+			struct ib_sa_mad *mad;
+			struct ib_sa_mcmember_rec rec;
+
+			mad = (struct ib_sa_mad *) mad_recv_wc->recv_buf.mad;
+			ib_unpack(mcmember_rec_table,
+				  ARRAY_SIZE(mcmember_rec_table),
+				  mad->data, &rec);
+			query->callback(status, &rec, query->context);
+		} else
+			query->callback(status, NULL, query->context);
+	}
+	if (mad_recv_wc)
+		ib_free_recv_mad(mad_recv_wc);
+	kfree(query);
 }
 
 int ib_sa_mcmember_rec_query(struct ib_sa_client *client,
 			     struct ib_device *device, u8 port_num,
-			     u8 method,
-			     struct ib_sa_mcmember_rec *rec,
+			     u8 method, struct ib_sa_mcmember_rec *rec,
 			     ib_sa_comp_mask comp_mask,
 			     int timeout_ms, int retries, gfp_t gfp_mask,
 			     void (*callback)(int status,
@@ -900,64 +1064,27 @@ int ib_sa_mcmember_rec_query(struct ib_s
 			     struct ib_sa_query **sa_query)
 {
 	struct ib_sa_mcmember_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;
+	u8 mcmember[IB_SA_ATTR_MC_MEMBER_REC_LEN];
 	int ret;
 
-	if (!sa_dev)
-		return -ENODEV;
-
-	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.mad_buf = ib_create_send_mad(agent, 1, 0,
-						     0, IB_MGMT_SA_HDR,
-						     IB_MGMT_SA_DATA, gfp_mask);
-	if (!query->sa_query.mad_buf) {
-		ret = -ENOMEM;
-		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_mcmember_rec_callback : NULL;
-	query->sa_query.release  = ib_sa_mcmember_rec_release;
-	query->sa_query.port     = port;
-	mad->mad_hdr.method	 = method;
-	mad->mad_hdr.attr_id	 = cpu_to_be16(IB_SA_ATTR_MC_MEMBER_REC);
-	mad->sa_hdr.comp_mask	 = comp_mask;
-
 	ib_pack(mcmember_rec_table, ARRAY_SIZE(mcmember_rec_table),
-		rec, mad->data);
-
-	*sa_query = &query->sa_query;
-
-	ret = send_mad(&query->sa_query, timeout_ms, retries, gfp_mask);
+		rec, mcmember);
+	ret = ib_sa_send_mad(client, device, port_num, method, mcmember,
+			     cpu_to_be16(IB_SA_ATTR_MC_MEMBER_REC), comp_mask,
+			     timeout_ms, retries, gfp_mask,
+			     ib_sa_mcmember_rec_callback, query,
+			     &query->sa_query);
 	if (ret < 0)
-		goto err2;
+		kfree(query);
 
 	return ret;
-
-err2:
-	*sa_query = NULL;
-	ib_sa_client_put(query->sa_query.client);
-	ib_free_send_mad(query->sa_query.mad_buf);
-
-err1:
-	kfree(query);
-	return ret;
 }
 EXPORT_SYMBOL(ib_sa_mcmember_rec_query);
 
@@ -973,13 +1100,13 @@ static void send_handler(struct ib_mad_a
 			/* No callback -- already got recv */
 			break;
 		case IB_WC_RESP_TIMEOUT_ERR:
-			query->callback(query, -ETIMEDOUT, NULL);
+			query->callback(-ETIMEDOUT, NULL, query->context);
 			break;
 		case IB_WC_WR_FLUSH_ERR:
-			query->callback(query, -EINTR, NULL);
+			query->callback(-EINTR, NULL, query->context);
 			break;
 		default:
-			query->callback(query, -EIO, NULL);
+			query->callback(-EIO, NULL, query->context);
 			break;
 		}
 
@@ -990,7 +1117,7 @@ static void send_handler(struct ib_mad_a
         ib_free_send_mad(mad_send_wc->send_buf);
 	kref_put(&query->sm_ah->ref, free_sm_ah);
 	ib_sa_client_put(query->client);
-	query->release(query);
+	kfree(query);
 }
 
 static void recv_handler(struct ib_mad_agent *mad_agent,
@@ -1002,17 +1129,11 @@ static void recv_handler(struct ib_mad_a
 	mad_buf = (void *) (unsigned long) mad_recv_wc->wc->wr_id;
 	query = mad_buf->context[0];
 
-	if (query->callback) {
-		if (mad_recv_wc->wc->status == IB_WC_SUCCESS)
-			query->callback(query,
-					mad_recv_wc->recv_buf.mad->mad_hdr.status ?
-					-EINVAL : 0,
-					(struct ib_sa_mad *) mad_recv_wc->recv_buf.mad);
-		else
-			query->callback(query, -EIO, NULL);
-	}
-
-	ib_free_recv_mad(mad_recv_wc);
+	if (query->callback)
+		query->callback(mad_recv_wc->recv_buf.mad->mad_hdr.status ?
+				-EINVAL : 0, mad_recv_wc, query->context);
+	else
+		ib_free_recv_mad(mad_recv_wc);
 }
 
 static void ib_sa_add_one(struct ib_device *device)
@@ -1046,8 +1167,9 @@ static void ib_sa_add_one(struct ib_devi
 
 		sa_dev->port[i].agent =
 			ib_register_mad_agent(device, i + s, IB_QPT_GSI,
-					      NULL, 0, send_handler,
-					      recv_handler, sa_dev);
+					      NULL, IB_MGMT_RMPP_VERSION,
+					      send_handler, recv_handler,
+					      sa_dev);
 		if (IS_ERR(sa_dev->port[i].agent))
 			goto err;
 





More information about the general mailing list