⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sa_query.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 2004 Topspin Communications.  All rights reserved. * Copyright (c) 2005 Voltaire, Inc.  All rights reserved. * * This software is available to you under a choice of one of two * licenses.  You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * *     Redistribution and use in source and binary forms, with or *     without modification, are permitted provided that the following *     conditions are met: * *      - Redistributions of source code must retain the above *        copyright notice, this list of conditions and the following *        disclaimer. * *      - Redistributions in binary form must reproduce the above *        copyright notice, this list of conditions and the following *        disclaimer in the documentation and/or other materials *        provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * $Id: sa_query.c 2811 2005-07-06 18:11:43Z halr $ */#include <linux/module.h>#include <linux/init.h>#include <linux/err.h>#include <linux/random.h>#include <linux/spinlock.h>#include <linux/slab.h>#include <linux/pci.h>#include <linux/dma-mapping.h>#include <linux/kref.h>#include <linux/idr.h>#include <linux/workqueue.h>#include <rdma/ib_pack.h>#include <rdma/ib_sa.h>MODULE_AUTHOR("Roland Dreier");MODULE_DESCRIPTION("InfiniBand subnet administration query support");MODULE_LICENSE("Dual BSD/GPL");struct ib_sa_sm_ah {	struct ib_ah        *ah;	struct kref          ref;};struct ib_sa_port {	struct ib_mad_agent *agent;	struct ib_sa_sm_ah  *sm_ah;	struct work_struct   update_task;	spinlock_t           ah_lock;	u8                   port_num;};struct ib_sa_device {	int                     start_port, end_port;	struct ib_event_handler event_handler;	struct ib_sa_port port[0];};struct ib_sa_query {	void (*callback)(struct ib_sa_query *, int, struct ib_sa_mad *);	void (*release)(struct ib_sa_query *);	struct ib_sa_port      *port;	struct ib_mad_send_buf *mad_buf;	struct ib_sa_sm_ah     *sm_ah;	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_path_query {	void (*callback)(int, struct ib_sa_path_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;	struct ib_sa_query sa_query;};static void ib_sa_add_one(struct ib_device *device);static void ib_sa_remove_one(struct ib_device *device);static struct ib_client sa_client = {	.name   = "sa",	.add    = ib_sa_add_one,	.remove = ib_sa_remove_one};static spinlock_t idr_lock;static DEFINE_IDR(query_idr);static spinlock_t tid_lock;static u32 tid;#define PATH_REC_FIELD(field) \	.struct_offset_bytes = offsetof(struct ib_sa_path_rec, field),		\	.struct_size_bytes   = sizeof ((struct ib_sa_path_rec *) 0)->field,	\	.field_name          = "sa_path_rec:" #fieldstatic const struct ib_field path_rec_table[] = {	{ RESERVED,	  .offset_words = 0,	  .offset_bits  = 0,	  .size_bits    = 32 },	{ RESERVED,	  .offset_words = 1,	  .offset_bits  = 0,	  .size_bits    = 32 },	{ PATH_REC_FIELD(dgid),	  .offset_words = 2,	  .offset_bits  = 0,	  .size_bits    = 128 },	{ PATH_REC_FIELD(sgid),	  .offset_words = 6,	  .offset_bits  = 0,	  .size_bits    = 128 },	{ PATH_REC_FIELD(dlid),	  .offset_words = 10,	  .offset_bits  = 0,	  .size_bits    = 16 },	{ PATH_REC_FIELD(slid),	  .offset_words = 10,	  .offset_bits  = 16,	  .size_bits    = 16 },	{ PATH_REC_FIELD(raw_traffic),	  .offset_words = 11,	  .offset_bits  = 0,	  .size_bits    = 1 },	{ RESERVED,	  .offset_words = 11,	  .offset_bits  = 1,	  .size_bits    = 3 },	{ PATH_REC_FIELD(flow_label),	  .offset_words = 11,	  .offset_bits  = 4,	  .size_bits    = 20 },	{ PATH_REC_FIELD(hop_limit),	  .offset_words = 11,	  .offset_bits  = 24,	  .size_bits    = 8 },	{ PATH_REC_FIELD(traffic_class),	  .offset_words = 12,	  .offset_bits  = 0,	  .size_bits    = 8 },	{ PATH_REC_FIELD(reversible),	  .offset_words = 12,	  .offset_bits  = 8,	  .size_bits    = 1 },	{ PATH_REC_FIELD(numb_path),	  .offset_words = 12,	  .offset_bits  = 9,	  .size_bits    = 7 },	{ PATH_REC_FIELD(pkey),	  .offset_words = 12,	  .offset_bits  = 16,	  .size_bits    = 16 },	{ RESERVED,	  .offset_words = 13,	  .offset_bits  = 0,	  .size_bits    = 12 },	{ PATH_REC_FIELD(sl),	  .offset_words = 13,	  .offset_bits  = 12,	  .size_bits    = 4 },	{ PATH_REC_FIELD(mtu_selector),	  .offset_words = 13,	  .offset_bits  = 16,	  .size_bits    = 2 },	{ PATH_REC_FIELD(mtu),	  .offset_words = 13,	  .offset_bits  = 18,	  .size_bits    = 6 },	{ PATH_REC_FIELD(rate_selector),	  .offset_words = 13,	  .offset_bits  = 24,	  .size_bits    = 2 },	{ PATH_REC_FIELD(rate),	  .offset_words = 13,	  .offset_bits  = 26,	  .size_bits    = 6 },	{ PATH_REC_FIELD(packet_life_time_selector),	  .offset_words = 14,	  .offset_bits  = 0,	  .size_bits    = 2 },	{ PATH_REC_FIELD(packet_life_time),	  .offset_words = 14,	  .offset_bits  = 2,	  .size_bits    = 6 },	{ PATH_REC_FIELD(preference),	  .offset_words = 14,	  .offset_bits  = 8,	  .size_bits    = 8 },	{ RESERVED,	  .offset_words = 14,	  .offset_bits  = 16,	  .size_bits    = 48 },};#define MCMEMBER_REC_FIELD(field) \	.struct_offset_bytes = offsetof(struct ib_sa_mcmember_rec, field),	\	.struct_size_bytes   = sizeof ((struct ib_sa_mcmember_rec *) 0)->field,	\	.field_name          = "sa_mcmember_rec:" #fieldstatic const struct ib_field mcmember_rec_table[] = {	{ MCMEMBER_REC_FIELD(mgid),	  .offset_words = 0,	  .offset_bits  = 0,	  .size_bits    = 128 },	{ MCMEMBER_REC_FIELD(port_gid),	  .offset_words = 4,	  .offset_bits  = 0,	  .size_bits    = 128 },	{ MCMEMBER_REC_FIELD(qkey),	  .offset_words = 8,	  .offset_bits  = 0,	  .size_bits    = 32 },	{ MCMEMBER_REC_FIELD(mlid),	  .offset_words = 9,	  .offset_bits  = 0,	  .size_bits    = 16 },	{ MCMEMBER_REC_FIELD(mtu_selector),	  .offset_words = 9,	  .offset_bits  = 16,	  .size_bits    = 2 },	{ MCMEMBER_REC_FIELD(mtu),	  .offset_words = 9,	  .offset_bits  = 18,	  .size_bits    = 6 },	{ MCMEMBER_REC_FIELD(traffic_class),	  .offset_words = 9,	  .offset_bits  = 24,	  .size_bits    = 8 },	{ MCMEMBER_REC_FIELD(pkey),	  .offset_words = 10,	  .offset_bits  = 0,	  .size_bits    = 16 },	{ MCMEMBER_REC_FIELD(rate_selector),	  .offset_words = 10,	  .offset_bits  = 16,	  .size_bits    = 2 },	{ MCMEMBER_REC_FIELD(rate),	  .offset_words = 10,	  .offset_bits  = 18,	  .size_bits    = 6 },	{ MCMEMBER_REC_FIELD(packet_life_time_selector),	  .offset_words = 10,	  .offset_bits  = 24,	  .size_bits    = 2 },	{ MCMEMBER_REC_FIELD(packet_life_time),	  .offset_words = 10,	  .offset_bits  = 26,	  .size_bits    = 6 },	{ MCMEMBER_REC_FIELD(sl),	  .offset_words = 11,	  .offset_bits  = 0,	  .size_bits    = 4 },	{ MCMEMBER_REC_FIELD(flow_label),	  .offset_words = 11,	  .offset_bits  = 4,	  .size_bits    = 20 },	{ MCMEMBER_REC_FIELD(hop_limit),	  .offset_words = 11,	  .offset_bits  = 24,	  .size_bits    = 8 },	{ MCMEMBER_REC_FIELD(scope),	  .offset_words = 12,	  .offset_bits  = 0,	  .size_bits    = 4 },	{ MCMEMBER_REC_FIELD(join_state),	  .offset_words = 12,	  .offset_bits  = 4,	  .size_bits    = 4 },	{ MCMEMBER_REC_FIELD(proxy_join),	  .offset_words = 12,	  .offset_bits  = 8,	  .size_bits    = 1 },	{ RESERVED,	  .offset_words = 12,	  .offset_bits  = 9,	  .size_bits    = 23 },};#define SERVICE_REC_FIELD(field) \	.struct_offset_bytes = offsetof(struct ib_sa_service_rec, field),	\	.struct_size_bytes   = sizeof ((struct ib_sa_service_rec *) 0)->field,	\	.field_name          = "sa_service_rec:" #fieldstatic const struct ib_field service_rec_table[] = {	{ SERVICE_REC_FIELD(id),	  .offset_words = 0,	  .offset_bits  = 0,	  .size_bits    = 64 },	{ SERVICE_REC_FIELD(gid),	  .offset_words = 2,	  .offset_bits  = 0,	  .size_bits    = 128 },	{ SERVICE_REC_FIELD(pkey),	  .offset_words = 6,	  .offset_bits  = 0,	  .size_bits    = 16 },	{ SERVICE_REC_FIELD(lease),	  .offset_words = 7,	  .offset_bits  = 0,	  .size_bits    = 32 },	{ SERVICE_REC_FIELD(key),	  .offset_words = 8,	  .offset_bits  = 0,	  .size_bits    = 128 },	{ SERVICE_REC_FIELD(name),	  .offset_words = 12,	  .offset_bits  = 0,	  .size_bits    = 64*8 },	{ SERVICE_REC_FIELD(data8),	  .offset_words = 28,	  .offset_bits  = 0,	  .size_bits    = 16*8 },	{ SERVICE_REC_FIELD(data16),	  .offset_words = 32,	  .offset_bits  = 0,	  .size_bits    = 8*16 },	{ SERVICE_REC_FIELD(data32),	  .offset_words = 36,	  .offset_bits  = 0,	  .size_bits    = 4*32 },	{ SERVICE_REC_FIELD(data64),	  .offset_words = 40,	  .offset_bits  = 0,	  .size_bits    = 2*64 },};static void free_sm_ah(struct kref *kref){	struct ib_sa_sm_ah *sm_ah = container_of(kref, struct ib_sa_sm_ah, ref);	ib_destroy_ah(sm_ah->ah);	kfree(sm_ah);}static void update_sm_ah(void *port_ptr){	struct ib_sa_port *port = port_ptr;	struct ib_sa_sm_ah *new_ah, *old_ah;	struct ib_port_attr port_attr;	struct ib_ah_attr   ah_attr;	if (ib_query_port(port->agent->device, port->port_num, &port_attr)) {		printk(KERN_WARNING "Couldn't query port\n");		return;	}	new_ah = kmalloc(sizeof *new_ah, GFP_KERNEL);	if (!new_ah) {		printk(KERN_WARNING "Couldn't allocate new SM AH\n");		return;	}	kref_init(&new_ah->ref);	memset(&ah_attr, 0, sizeof ah_attr);	ah_attr.dlid     = port_attr.sm_lid;	ah_attr.sl       = port_attr.sm_sl;	ah_attr.port_num = port->port_num;	new_ah->ah = ib_create_ah(port->agent->qp->pd, &ah_attr);	if (IS_ERR(new_ah->ah)) {		printk(KERN_WARNING "Couldn't create new SM AH\n");		kfree(new_ah);		return;	}	spin_lock_irq(&port->ah_lock);	old_ah = port->sm_ah;	port->sm_ah = new_ah;	spin_unlock_irq(&port->ah_lock);	if (old_ah)		kref_put(&old_ah->ref, free_sm_ah);}static void ib_sa_event(struct ib_event_handler *handler, struct ib_event *event){	if (event->event == IB_EVENT_PORT_ERR    ||	    event->event == IB_EVENT_PORT_ACTIVE ||	    event->event == IB_EVENT_LID_CHANGE  ||	    event->event == IB_EVENT_PKEY_CHANGE ||	    event->event == IB_EVENT_SM_CHANGE) {		struct ib_sa_device *sa_dev;		sa_dev = container_of(handler, typeof(*sa_dev), event_handler);		schedule_work(&sa_dev->port[event->element.port_num -					    sa_dev->start_port].update_task);	}}/** * ib_sa_cancel_query - try to cancel an SA query * @id:ID of query to cancel * @query:query pointer to cancel * * Try to cancel an SA query.  If the id and query don't match up or * the query has already completed, nothing is done.  Otherwise the * query is canceled and will complete with a status of -EINTR. */void ib_sa_cancel_query(int id, struct ib_sa_query *query){	unsigned long flags;	struct ib_mad_agent *agent;	struct ib_mad_send_buf *mad_buf;	spin_lock_irqsave(&idr_lock, flags);	if (idr_find(&query_idr, id) != query) {		spin_unlock_irqrestore(&idr_lock, flags);		return;	}	agent = query->port->agent;	mad_buf = query->mad_buf;	spin_unlock_irqrestore(&idr_lock, flags);	ib_cancel_mad(agent, mad_buf);}EXPORT_SYMBOL(ib_sa_cancel_query);static void init_mad(struct ib_sa_mad *mad, struct ib_mad_agent *agent){	unsigned long flags;	memset(mad, 0, sizeof *mad);	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;	spin_lock_irqsave(&tid_lock, flags);	mad->mad_hdr.tid           =		cpu_to_be64(((u64) agent->hi_tid) << 32 | tid++);	spin_unlock_irqrestore(&tid_lock, flags);}static int send_mad(struct ib_sa_query *query, int timeout_ms){	unsigned long flags;	int ret, id;retry:	if (!idr_pre_get(&query_idr, GFP_ATOMIC))		return -ENOMEM;	spin_lock_irqsave(&idr_lock, flags);	ret = idr_get_new(&query_idr, query, &id);	spin_unlock_irqrestore(&idr_lock, flags);	if (ret == -EAGAIN)		goto retry;	if (ret)		return ret;	query->mad_buf->timeout_ms  = timeout_ms;	query->mad_buf->context[0] = query;	query->id = id;	spin_lock_irqsave(&query->port->ah_lock, flags);	kref_get(&query->port->sm_ah->ref);	query->sm_ah = query->port->sm_ah;	spin_unlock_irqrestore(&query->port->ah_lock, flags);	query->mad_buf->ah = query->sm_ah->ah;	ret = ib_post_send_mad(query->mad_buf, NULL);	if (ret) {		spin_lock_irqsave(&idr_lock, flags);		idr_remove(&query_idr, id);		spin_unlock_irqrestore(&idr_lock, flags);		kref_put(&query->sm_ah->ref, free_sm_ah);	}	/*

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -