| 
1 | 1 | /*  | 
2 | 2 |  * Copyright (c) 2004 Topspin Communications.  All rights reserved.  | 
 | 3 | + * Copyright (c) 2005 Voltaire, Inc.  All rights reserved.  | 
3 | 4 |  *  | 
4 | 5 |  * This software is available to you under a choice of one of two  | 
5 | 6 |  * licenses.  You may choose to be licensed under the terms of the GNU  | 
 | 
29 | 30 |  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE  | 
30 | 31 |  * SOFTWARE.  | 
31 | 32 |  *  | 
32 |  | - * $Id: sa_query.c 1389 2004-12-27 22:56:47Z roland $  | 
 | 33 | + * $Id: sa_query.c 2811 2005-07-06 18:11:43Z halr $  | 
33 | 34 |  */  | 
34 | 35 | 
 
  | 
35 | 36 | #include <linux/module.h>  | 
@@ -79,6 +80,12 @@ struct ib_sa_query {  | 
79 | 80 | 	int                 id;  | 
80 | 81 | };  | 
81 | 82 | 
 
  | 
 | 83 | +struct ib_sa_service_query {  | 
 | 84 | +	void (*callback)(int, struct ib_sa_service_rec *, void *);  | 
 | 85 | +	void *context;  | 
 | 86 | +	struct ib_sa_query sa_query;  | 
 | 87 | +};  | 
 | 88 | + | 
82 | 89 | struct ib_sa_path_query {  | 
83 | 90 | 	void (*callback)(int, struct ib_sa_path_rec *, void *);  | 
84 | 91 | 	void *context;  | 
@@ -320,6 +327,54 @@ static const struct ib_field mcmember_rec_table[] = {  | 
320 | 327 | 	  .size_bits    = 23 },  | 
321 | 328 | };  | 
322 | 329 | 
 
  | 
 | 330 | +#define SERVICE_REC_FIELD(field) \  | 
 | 331 | +	.struct_offset_bytes = offsetof(struct ib_sa_service_rec, field),	\  | 
 | 332 | +	.struct_size_bytes   = sizeof ((struct ib_sa_service_rec *) 0)->field,	\  | 
 | 333 | +	.field_name          = "sa_service_rec:" #field  | 
 | 334 | + | 
 | 335 | +static const struct ib_field service_rec_table[] = {  | 
 | 336 | +	{ SERVICE_REC_FIELD(id),  | 
 | 337 | +	  .offset_words = 0,  | 
 | 338 | +	  .offset_bits  = 0,  | 
 | 339 | +	  .size_bits    = 64 },  | 
 | 340 | +	{ SERVICE_REC_FIELD(gid),  | 
 | 341 | +	  .offset_words = 2,  | 
 | 342 | +	  .offset_bits  = 0,  | 
 | 343 | +	  .size_bits    = 128 },  | 
 | 344 | +	{ SERVICE_REC_FIELD(pkey),  | 
 | 345 | +	  .offset_words = 6,  | 
 | 346 | +	  .offset_bits  = 0,  | 
 | 347 | +	  .size_bits    = 16 },  | 
 | 348 | +	{ SERVICE_REC_FIELD(lease),  | 
 | 349 | +	  .offset_words = 7,  | 
 | 350 | +	  .offset_bits  = 0,  | 
 | 351 | +	  .size_bits    = 32 },  | 
 | 352 | +	{ SERVICE_REC_FIELD(key),  | 
 | 353 | +	  .offset_words = 8,  | 
 | 354 | +	  .offset_bits  = 0,  | 
 | 355 | +	  .size_bits    = 128 },  | 
 | 356 | +	{ SERVICE_REC_FIELD(name),  | 
 | 357 | +	  .offset_words = 12,  | 
 | 358 | +	  .offset_bits  = 0,  | 
 | 359 | +	  .size_bits    = 64*8 },  | 
 | 360 | +	{ SERVICE_REC_FIELD(data8),  | 
 | 361 | +	  .offset_words = 28,  | 
 | 362 | +	  .offset_bits  = 0,  | 
 | 363 | +	  .size_bits    = 16*8 },  | 
 | 364 | +	{ SERVICE_REC_FIELD(data16),  | 
 | 365 | +	  .offset_words = 32,  | 
 | 366 | +	  .offset_bits  = 0,  | 
 | 367 | +	  .size_bits    = 8*16 },  | 
 | 368 | +	{ SERVICE_REC_FIELD(data32),  | 
 | 369 | +	  .offset_words = 36,  | 
 | 370 | +	  .offset_bits  = 0,  | 
 | 371 | +	  .size_bits    = 4*32 },  | 
 | 372 | +	{ SERVICE_REC_FIELD(data64),  | 
 | 373 | +	  .offset_words = 40,  | 
 | 374 | +	  .offset_bits  = 0,  | 
 | 375 | +	  .size_bits    = 2*64 },  | 
 | 376 | +};  | 
 | 377 | + | 
323 | 378 | static void free_sm_ah(struct kref *kref)  | 
324 | 379 | {  | 
325 | 380 | 	struct ib_sa_sm_ah *sm_ah = container_of(kref, struct ib_sa_sm_ah, ref);  | 
@@ -443,7 +498,6 @@ static int send_mad(struct ib_sa_query *query, int timeout_ms)  | 
443 | 498 | 				 .remote_qpn  = 1,  | 
444 | 499 | 				 .remote_qkey = IB_QP1_QKEY,  | 
445 | 500 | 				 .timeout_ms  = timeout_ms,  | 
446 |  | -				 .retries     = 0  | 
447 | 501 | 			 }  | 
448 | 502 | 		 }  | 
449 | 503 | 	};  | 
@@ -596,6 +650,114 @@ int ib_sa_path_rec_get(struct ib_device *device, u8 port_num,  | 
596 | 650 | }  | 
597 | 651 | EXPORT_SYMBOL(ib_sa_path_rec_get);  | 
598 | 652 | 
 
  | 
 | 653 | +static void ib_sa_service_rec_callback(struct ib_sa_query *sa_query,  | 
 | 654 | +				    int status,  | 
 | 655 | +				    struct ib_sa_mad *mad)  | 
 | 656 | +{  | 
 | 657 | +	struct ib_sa_service_query *query =  | 
 | 658 | +		container_of(sa_query, struct ib_sa_service_query, sa_query);  | 
 | 659 | + | 
 | 660 | +	if (mad) {  | 
 | 661 | +		struct ib_sa_service_rec rec;  | 
 | 662 | + | 
 | 663 | +		ib_unpack(service_rec_table, ARRAY_SIZE(service_rec_table),  | 
 | 664 | +			  mad->data, &rec);  | 
 | 665 | +		query->callback(status, &rec, query->context);  | 
 | 666 | +	} else  | 
 | 667 | +		query->callback(status, NULL, query->context);  | 
 | 668 | +}  | 
 | 669 | + | 
 | 670 | +static void ib_sa_service_rec_release(struct ib_sa_query *sa_query)  | 
 | 671 | +{  | 
 | 672 | +	kfree(sa_query->mad);  | 
 | 673 | +	kfree(container_of(sa_query, struct ib_sa_service_query, sa_query));  | 
 | 674 | +}  | 
 | 675 | + | 
 | 676 | +/**  | 
 | 677 | + * ib_sa_service_rec_query - Start Service Record operation  | 
 | 678 | + * @device:device to send request on  | 
 | 679 | + * @port_num: port number to send request on  | 
 | 680 | + * @method:SA method - should be get, set, or delete  | 
 | 681 | + * @rec:Service Record to send in request  | 
 | 682 | + * @comp_mask:component mask to send in request  | 
 | 683 | + * @timeout_ms:time to wait for response  | 
 | 684 | + * @gfp_mask:GFP mask to use for internal allocations  | 
 | 685 | + * @callback:function called when request completes, times out or is  | 
 | 686 | + * canceled  | 
 | 687 | + * @context:opaque user context passed to callback  | 
 | 688 | + * @sa_query:request context, used to cancel request  | 
 | 689 | + *  | 
 | 690 | + * Send a Service Record set/get/delete to the SA to register,  | 
 | 691 | + * unregister or query a service record.  | 
 | 692 | + * The callback function will be called when the request completes (or  | 
 | 693 | + * fails); status is 0 for a successful response, -EINTR if the query  | 
 | 694 | + * is canceled, -ETIMEDOUT is the query timed out, or -EIO if an error  | 
 | 695 | + * occurred sending the query.  The resp parameter of the callback is  | 
 | 696 | + * only valid if status is 0.  | 
 | 697 | + *  | 
 | 698 | + * If the return value of ib_sa_service_rec_query() is negative, it is an  | 
 | 699 | + * error code.  Otherwise it is a request ID that can be used to cancel  | 
 | 700 | + * the query.  | 
 | 701 | + */  | 
 | 702 | +int ib_sa_service_rec_query(struct ib_device *device, u8 port_num, u8 method,  | 
 | 703 | +			    struct ib_sa_service_rec *rec,  | 
 | 704 | +			    ib_sa_comp_mask comp_mask,  | 
 | 705 | +			    int timeout_ms, int gfp_mask,  | 
 | 706 | +			    void (*callback)(int status,  | 
 | 707 | +					     struct ib_sa_service_rec *resp,  | 
 | 708 | +					     void *context),  | 
 | 709 | +			    void *context,  | 
 | 710 | +			    struct ib_sa_query **sa_query)  | 
 | 711 | +{  | 
 | 712 | +	struct ib_sa_service_query *query;  | 
 | 713 | +	struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client);  | 
 | 714 | +	struct ib_sa_port   *port   = &sa_dev->port[port_num - sa_dev->start_port];  | 
 | 715 | +	struct ib_mad_agent *agent  = port->agent;  | 
 | 716 | +	int ret;  | 
 | 717 | + | 
 | 718 | +	if (method != IB_MGMT_METHOD_GET &&  | 
 | 719 | +	    method != IB_MGMT_METHOD_SET &&  | 
 | 720 | +	    method != IB_SA_METHOD_DELETE)  | 
 | 721 | +		return -EINVAL;  | 
 | 722 | + | 
 | 723 | +	query = kmalloc(sizeof *query, gfp_mask);  | 
 | 724 | +	if (!query)  | 
 | 725 | +		return -ENOMEM;  | 
 | 726 | +	query->sa_query.mad = kmalloc(sizeof *query->sa_query.mad, gfp_mask);  | 
 | 727 | +	if (!query->sa_query.mad) {  | 
 | 728 | +		kfree(query);  | 
 | 729 | +		return -ENOMEM;  | 
 | 730 | +	}  | 
 | 731 | + | 
 | 732 | +	query->callback = callback;  | 
 | 733 | +	query->context  = context;  | 
 | 734 | + | 
 | 735 | +	init_mad(query->sa_query.mad, agent);  | 
 | 736 | + | 
 | 737 | +	query->sa_query.callback              = callback ? ib_sa_service_rec_callback : NULL;  | 
 | 738 | +	query->sa_query.release               = ib_sa_service_rec_release;  | 
 | 739 | +	query->sa_query.port                  = port;  | 
 | 740 | +	query->sa_query.mad->mad_hdr.method   = method;  | 
 | 741 | +	query->sa_query.mad->mad_hdr.attr_id  =  | 
 | 742 | +				cpu_to_be16(IB_SA_ATTR_SERVICE_REC);  | 
 | 743 | +	query->sa_query.mad->sa_hdr.comp_mask = comp_mask;  | 
 | 744 | + | 
 | 745 | +	ib_pack(service_rec_table, ARRAY_SIZE(service_rec_table),  | 
 | 746 | +		rec, query->sa_query.mad->data);  | 
 | 747 | + | 
 | 748 | +	*sa_query = &query->sa_query;  | 
 | 749 | + | 
 | 750 | +	ret = send_mad(&query->sa_query, timeout_ms);  | 
 | 751 | +	if (ret < 0) {  | 
 | 752 | +		*sa_query = NULL;  | 
 | 753 | +		kfree(query->sa_query.mad);  | 
 | 754 | +		kfree(query);  | 
 | 755 | +	}  | 
 | 756 | + | 
 | 757 | +	return ret;  | 
 | 758 | +}  | 
 | 759 | +EXPORT_SYMBOL(ib_sa_service_rec_query);  | 
 | 760 | + | 
599 | 761 | static void ib_sa_mcmember_rec_callback(struct ib_sa_query *sa_query,  | 
600 | 762 | 					int status,  | 
601 | 763 | 					struct ib_sa_mad *mad)  | 
 | 
0 commit comments