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

📄 cm.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
	while (node) {		timewait_info = rb_entry(node, struct cm_timewait_info,					 remote_id_node);		if (remote_id < timewait_info->work.remote_id)			node = node->rb_left;		else if (remote_id > timewait_info->work.remote_id)			node = node->rb_right;		else if (remote_ca_guid < timewait_info->remote_ca_guid)			node = node->rb_left;		else if (remote_ca_guid > timewait_info->remote_ca_guid)			node = node->rb_right;		else			return timewait_info;	}	return NULL;}static struct cm_timewait_info * cm_insert_remote_qpn(struct cm_timewait_info						      *timewait_info){	struct rb_node **link = &cm.remote_qp_table.rb_node;	struct rb_node *parent = NULL;	struct cm_timewait_info *cur_timewait_info;	__be64 remote_ca_guid = timewait_info->remote_ca_guid;	__be32 remote_qpn = timewait_info->remote_qpn;	while (*link) {		parent = *link;		cur_timewait_info = rb_entry(parent, struct cm_timewait_info,					     remote_qp_node);		if (remote_qpn < cur_timewait_info->remote_qpn)			link = &(*link)->rb_left;		else if (remote_qpn > cur_timewait_info->remote_qpn)			link = &(*link)->rb_right;		else if (remote_ca_guid < cur_timewait_info->remote_ca_guid)			link = &(*link)->rb_left;		else if (remote_ca_guid > cur_timewait_info->remote_ca_guid)			link = &(*link)->rb_right;		else			return cur_timewait_info;	}	timewait_info->inserted_remote_qp = 1;	rb_link_node(&timewait_info->remote_qp_node, parent, link);	rb_insert_color(&timewait_info->remote_qp_node, &cm.remote_qp_table);	return NULL;}static struct cm_id_private * cm_insert_remote_sidr(struct cm_id_private						    *cm_id_priv){	struct rb_node **link = &cm.remote_sidr_table.rb_node;	struct rb_node *parent = NULL;	struct cm_id_private *cur_cm_id_priv;	union ib_gid *port_gid = &cm_id_priv->av.dgid;	__be32 remote_id = cm_id_priv->id.remote_id;	while (*link) {		parent = *link;		cur_cm_id_priv = rb_entry(parent, struct cm_id_private,					  sidr_id_node);		if (remote_id < cur_cm_id_priv->id.remote_id)			link = &(*link)->rb_left;		else if (remote_id > cur_cm_id_priv->id.remote_id)			link = &(*link)->rb_right;		else {			int cmp;			cmp = memcmp(port_gid, &cur_cm_id_priv->av.dgid,				     sizeof *port_gid);			if (cmp < 0)				link = &(*link)->rb_left;			else if (cmp > 0)				link = &(*link)->rb_right;			else				return cur_cm_id_priv;		}	}	rb_link_node(&cm_id_priv->sidr_id_node, parent, link);	rb_insert_color(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table);	return NULL;}static void cm_reject_sidr_req(struct cm_id_private *cm_id_priv,			       enum ib_cm_sidr_status status){	struct ib_cm_sidr_rep_param param;	memset(&param, 0, sizeof param);	param.status = status;	ib_send_cm_sidr_rep(&cm_id_priv->id, &param);}struct ib_cm_id *ib_create_cm_id(struct ib_device *device,				 ib_cm_handler cm_handler,				 void *context){	struct cm_id_private *cm_id_priv;	int ret;	cm_id_priv = kzalloc(sizeof *cm_id_priv, GFP_KERNEL);	if (!cm_id_priv)		return ERR_PTR(-ENOMEM);	cm_id_priv->id.state = IB_CM_IDLE;	cm_id_priv->id.device = device;	cm_id_priv->id.cm_handler = cm_handler;	cm_id_priv->id.context = context;	cm_id_priv->id.remote_cm_qpn = 1;	ret = cm_alloc_id(cm_id_priv);	if (ret)		goto error;	spin_lock_init(&cm_id_priv->lock);	init_waitqueue_head(&cm_id_priv->wait);	INIT_LIST_HEAD(&cm_id_priv->work_list);	atomic_set(&cm_id_priv->work_count, -1);	atomic_set(&cm_id_priv->refcount, 1);	return &cm_id_priv->id;error:	kfree(cm_id_priv);	return ERR_PTR(-ENOMEM);}EXPORT_SYMBOL(ib_create_cm_id);static struct cm_work * cm_dequeue_work(struct cm_id_private *cm_id_priv){	struct cm_work *work;	if (list_empty(&cm_id_priv->work_list))		return NULL;	work = list_entry(cm_id_priv->work_list.next, struct cm_work, list);	list_del(&work->list);	return work;}static void cm_free_work(struct cm_work *work){	if (work->mad_recv_wc)		ib_free_recv_mad(work->mad_recv_wc);	kfree(work);}static inline int cm_convert_to_ms(int iba_time){	/* approximate conversion to ms from 4.096us x 2^iba_time */	return 1 << max(iba_time - 8, 0);}static void cm_cleanup_timewait(struct cm_timewait_info *timewait_info){	unsigned long flags;	if (!timewait_info->inserted_remote_id &&	    !timewait_info->inserted_remote_qp)	    return;	spin_lock_irqsave(&cm.lock, flags);	if (timewait_info->inserted_remote_id) {		rb_erase(&timewait_info->remote_id_node, &cm.remote_id_table);		timewait_info->inserted_remote_id = 0;	}	if (timewait_info->inserted_remote_qp) {		rb_erase(&timewait_info->remote_qp_node, &cm.remote_qp_table);		timewait_info->inserted_remote_qp = 0;	}	spin_unlock_irqrestore(&cm.lock, flags);}static struct cm_timewait_info * cm_create_timewait_info(__be32 local_id){	struct cm_timewait_info *timewait_info;	timewait_info = kzalloc(sizeof *timewait_info, GFP_KERNEL);	if (!timewait_info)		return ERR_PTR(-ENOMEM);	timewait_info->work.local_id = local_id;	INIT_WORK(&timewait_info->work.work, cm_work_handler,		  &timewait_info->work);	timewait_info->work.cm_event.event = IB_CM_TIMEWAIT_EXIT;	return timewait_info;}static void cm_enter_timewait(struct cm_id_private *cm_id_priv){	int wait_time;	/*	 * The cm_id could be destroyed by the user before we exit timewait.	 * To protect against this, we search for the cm_id after exiting	 * timewait before notifying the user that we've exited timewait.	 */	cm_id_priv->id.state = IB_CM_TIMEWAIT;	wait_time = cm_convert_to_ms(cm_id_priv->local_ack_timeout);	queue_delayed_work(cm.wq, &cm_id_priv->timewait_info->work.work,			   msecs_to_jiffies(wait_time));	cm_id_priv->timewait_info = NULL;}static void cm_reset_to_idle(struct cm_id_private *cm_id_priv){	cm_id_priv->id.state = IB_CM_IDLE;	if (cm_id_priv->timewait_info) {		cm_cleanup_timewait(cm_id_priv->timewait_info);		kfree(cm_id_priv->timewait_info);		cm_id_priv->timewait_info = NULL;	}}void ib_destroy_cm_id(struct ib_cm_id *cm_id){	struct cm_id_private *cm_id_priv;	struct cm_work *work;	unsigned long flags;	cm_id_priv = container_of(cm_id, struct cm_id_private, id);retest:	spin_lock_irqsave(&cm_id_priv->lock, flags);	switch (cm_id->state) {	case IB_CM_LISTEN:		cm_id->state = IB_CM_IDLE;		spin_unlock_irqrestore(&cm_id_priv->lock, flags);		spin_lock_irqsave(&cm.lock, flags);		rb_erase(&cm_id_priv->service_node, &cm.listen_service_table);		spin_unlock_irqrestore(&cm.lock, flags);		break;	case IB_CM_SIDR_REQ_SENT:		cm_id->state = IB_CM_IDLE;		ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);		spin_unlock_irqrestore(&cm_id_priv->lock, flags);		break;	case IB_CM_SIDR_REQ_RCVD:		spin_unlock_irqrestore(&cm_id_priv->lock, flags);		cm_reject_sidr_req(cm_id_priv, IB_SIDR_REJECT);		break;	case IB_CM_REQ_SENT:	case IB_CM_MRA_REQ_RCVD:	case IB_CM_REP_SENT:	case IB_CM_MRA_REP_RCVD:		ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);		/* Fall through */	case IB_CM_REQ_RCVD:	case IB_CM_MRA_REQ_SENT:	case IB_CM_REP_RCVD:	case IB_CM_MRA_REP_SENT:		spin_unlock_irqrestore(&cm_id_priv->lock, flags);		ib_send_cm_rej(cm_id, IB_CM_REJ_TIMEOUT,			       &cm_id_priv->av.port->cm_dev->ca_guid,			       sizeof cm_id_priv->av.port->cm_dev->ca_guid,			       NULL, 0);		break;	case IB_CM_ESTABLISHED:		spin_unlock_irqrestore(&cm_id_priv->lock, flags);		ib_send_cm_dreq(cm_id, NULL, 0);		goto retest;	case IB_CM_DREQ_SENT:		ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);		cm_enter_timewait(cm_id_priv);		spin_unlock_irqrestore(&cm_id_priv->lock, flags);		break;	case IB_CM_DREQ_RCVD:		spin_unlock_irqrestore(&cm_id_priv->lock, flags);		ib_send_cm_drep(cm_id, NULL, 0);		break;	default:		spin_unlock_irqrestore(&cm_id_priv->lock, flags);		break;	}	cm_free_id(cm_id->local_id);	atomic_dec(&cm_id_priv->refcount);	wait_event(cm_id_priv->wait, !atomic_read(&cm_id_priv->refcount));	while ((work = cm_dequeue_work(cm_id_priv)) != NULL)		cm_free_work(work);	if (cm_id_priv->private_data && cm_id_priv->private_data_len)		kfree(cm_id_priv->private_data);	kfree(cm_id_priv);}EXPORT_SYMBOL(ib_destroy_cm_id);int ib_cm_listen(struct ib_cm_id *cm_id,		 __be64 service_id,		 __be64 service_mask){	struct cm_id_private *cm_id_priv, *cur_cm_id_priv;	unsigned long flags;	int ret = 0;	service_mask = service_mask ? service_mask :		       __constant_cpu_to_be64(~0ULL);	service_id &= service_mask;	if ((service_id & IB_SERVICE_ID_AGN_MASK) == IB_CM_ASSIGN_SERVICE_ID &&	    (service_id != IB_CM_ASSIGN_SERVICE_ID))		return -EINVAL;	cm_id_priv = container_of(cm_id, struct cm_id_private, id);	BUG_ON(cm_id->state != IB_CM_IDLE);	cm_id->state = IB_CM_LISTEN;	spin_lock_irqsave(&cm.lock, flags);	if (service_id == IB_CM_ASSIGN_SERVICE_ID) {		cm_id->service_id = cpu_to_be64(cm.listen_service_id++);		cm_id->service_mask = __constant_cpu_to_be64(~0ULL);	} else {		cm_id->service_id = service_id;		cm_id->service_mask = service_mask;	}	cur_cm_id_priv = cm_insert_listen(cm_id_priv);	spin_unlock_irqrestore(&cm.lock, flags);	if (cur_cm_id_priv) {		cm_id->state = IB_CM_IDLE;		ret = -EBUSY;	}	return ret;}EXPORT_SYMBOL(ib_cm_listen);static __be64 cm_form_tid(struct cm_id_private *cm_id_priv,			  enum cm_msg_sequence msg_seq){	u64 hi_tid, low_tid;	hi_tid   = ((u64) cm_id_priv->av.port->mad_agent->hi_tid) << 32;	low_tid  = (u64) ((__force u32)cm_id_priv->id.local_id |			  (msg_seq << 30));	return cpu_to_be64(hi_tid | low_tid);}static void cm_format_mad_hdr(struct ib_mad_hdr *hdr,			      __be16 attr_id, __be64 tid){	hdr->base_version  = IB_MGMT_BASE_VERSION;	hdr->mgmt_class	   = IB_MGMT_CLASS_CM;	hdr->class_version = IB_CM_CLASS_VERSION;	hdr->method	   = IB_MGMT_METHOD_SEND;	hdr->attr_id	   = attr_id;	hdr->tid	   = tid;}static void cm_format_req(struct cm_req_msg *req_msg,			  struct cm_id_private *cm_id_priv,			  struct ib_cm_req_param *param){	cm_format_mad_hdr(&req_msg->hdr, CM_REQ_ATTR_ID,			  cm_form_tid(cm_id_priv, CM_MSG_SEQUENCE_REQ));	req_msg->local_comm_id = cm_id_priv->id.local_id;	req_msg->service_id = param->service_id;	req_msg->local_ca_guid = cm_id_priv->av.port->cm_dev->ca_guid;	cm_req_set_local_qpn(req_msg, cpu_to_be32(param->qp_num));	cm_req_set_resp_res(req_msg, param->responder_resources);	cm_req_set_init_depth(req_msg, param->initiator_depth);	cm_req_set_remote_resp_timeout(req_msg,				       param->remote_cm_response_timeout);	cm_req_set_qp_type(req_msg, param->qp_type);	cm_req_set_flow_ctrl(req_msg, param->flow_control);	cm_req_set_starting_psn(req_msg, cpu_to_be32(param->starting_psn));	cm_req_set_local_resp_timeout(req_msg,				      param->local_cm_response_timeout);	cm_req_set_retry_count(req_msg, param->retry_count);	req_msg->pkey = param->primary_path->pkey;	cm_req_set_path_mtu(req_msg, param->primary_path->mtu);	cm_req_set_rnr_retry_count(req_msg, param->rnr_retry_count);	cm_req_set_max_cm_retries(req_msg, param->max_cm_retries);	cm_req_set_srq(req_msg, param->srq);	req_msg->primary_local_lid = param->primary_path->slid;	req_msg->primary_remote_lid = param->primary_path->dlid;	req_msg->primary_local_gid = param->primary_path->sgid;	req_msg->primary_remote_gid = param->primary_path->dgid;	cm_req_set_primary_flow_label(req_msg, param->primary_path->flow_label);	cm_req_set_primary_packet_rate(req_msg, param->primary_path->rate);	req_msg->primary_traffic_class = param->primary_path->traffic_class;	req_msg->primary_hop_limit = param->primary_path->hop_limit;	cm_req_set_primary_sl(req_msg, param->primary_path->sl);	cm_req_set_primary_subnet_local(req_msg, 1); /* local only... */	cm_req_set_primary_local_ack_timeout(req_msg,		min(31, param->primary_path->packet_life_time + 1));	if (param->alternate_path) {		req_msg->alt_local_lid = param->alternate_path->slid;		req_msg->alt_remote_lid = param->alternate_path->dlid;		req_msg->alt_local_gid = param->alternate_path->sgid;		req_msg->alt_remote_gid = param->alternate_path->dgid;		cm_req_set_alt_flow_label(req_msg,					  param->alternate_path->flow_label);		cm_req_set_alt_packet_rate(req_msg, param->alternate_path->rate);		req_msg->alt_traffic_class = param->alternate_path->traffic_class;		req_msg->alt_hop_limit = param->alternate_path->hop_limit;		cm_req_set_alt_sl(req_msg, param->alternate_path->sl);		cm_req_set_alt_subnet_local(req_msg, 1); /* local only... */		cm_req_set_alt_local_ack_timeout(req_msg,			min(31, param->alternate_path->packet_life_time + 1));	}	if (param->private_data && param->private_data_len)		memcpy(req_msg->private_data, param->private_data,		       param->private_data_len);}static inline int cm_validate_req_param(struct ib_cm_req_param *param){	/* peer-to-peer not supported */	if (param->peer_to_peer)		return -EINVAL;	if (!param->primary_path)		return -EINVAL;	if (param->qp_type != IB_QPT_RC && param->qp_type != IB_QPT_UC)		return -EINVAL;	if (param->private_data &&	    param->private_data_len > IB_CM_REQ_PRIVATE_DATA_SIZE)		return -EINVAL;	if (param->alternate_path &&	    (param->alternate_path->pkey != param->primary_path->pkey ||	     param->alternate_path->mtu != param->primary_path->mtu))		return -EINVAL;	return 0;}int ib_send_cm_req(struct ib_cm_id *cm_id,		   struct ib_cm_req_param *param){	struct cm_id_private *cm_id_priv;	struct cm_req_msg *req_msg;	unsigned long flags;	int ret;	ret = cm_validate_req_param(param);	if (ret)		return ret;	/* Verify that we're not in timewait. */	cm_id_priv = container_of(cm_id, struct cm_id_private, id);	spin_lock_irqsave(&cm_id_priv->lock, flags);	if (cm_id->state != IB_CM_IDLE) {		spin_unlock_irqrestore(&cm_id_priv->lock, flags);		ret = -EINVAL;

⌨️ 快捷键说明

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