mad_rmpp.c

来自「linux2.6.16版本」· C语言 代码 · 共 934 行 · 第 1/2 页

C
934
字号
		len -= size;		buf += size;	}}EXPORT_SYMBOL(ib_coalesce_recv_mad);static struct ib_mad_recv_wc *continue_rmpp(struct ib_mad_agent_private *agent,	      struct ib_mad_recv_wc *mad_recv_wc){	struct mad_rmpp_recv *rmpp_recv;	struct ib_mad_recv_buf *prev_buf;	struct ib_mad_recv_wc *done_wc;	int seg_num;	unsigned long flags;	rmpp_recv = acquire_rmpp_recv(agent, mad_recv_wc);	if (!rmpp_recv)		goto drop1;	seg_num = get_seg_num(&mad_recv_wc->recv_buf);	spin_lock_irqsave(&rmpp_recv->lock, flags);	if ((rmpp_recv->state == RMPP_STATE_TIMEOUT) ||	    (seg_num > rmpp_recv->newwin))		goto drop3;	if ((seg_num <= rmpp_recv->last_ack) ||	    (rmpp_recv->state == RMPP_STATE_COMPLETE)) {		spin_unlock_irqrestore(&rmpp_recv->lock, flags);		ack_recv(rmpp_recv, mad_recv_wc);		goto drop2;	}	prev_buf = find_seg_location(&rmpp_recv->rmpp_wc->rmpp_list, seg_num);	if (!prev_buf)		goto drop3;	done_wc = NULL;	list_add(&mad_recv_wc->recv_buf.list, &prev_buf->list);	if (rmpp_recv->cur_seg_buf == prev_buf) {		update_seg_num(rmpp_recv, &mad_recv_wc->recv_buf);		if (get_last_flag(rmpp_recv->cur_seg_buf)) {			rmpp_recv->state = RMPP_STATE_COMPLETE;			spin_unlock_irqrestore(&rmpp_recv->lock, flags);			done_wc = complete_rmpp(rmpp_recv);			goto out;		} else if (rmpp_recv->seg_num == rmpp_recv->newwin) {			rmpp_recv->newwin += window_size(agent);			spin_unlock_irqrestore(&rmpp_recv->lock, flags);			ack_recv(rmpp_recv, mad_recv_wc);			goto out;		}	}	spin_unlock_irqrestore(&rmpp_recv->lock, flags);out:	deref_rmpp_recv(rmpp_recv);	return done_wc;drop3:	spin_unlock_irqrestore(&rmpp_recv->lock, flags);drop2:	deref_rmpp_recv(rmpp_recv);drop1:	ib_free_recv_mad(mad_recv_wc);	return NULL;}static struct ib_mad_recv_wc *start_rmpp(struct ib_mad_agent_private *agent,	   struct ib_mad_recv_wc *mad_recv_wc){	struct mad_rmpp_recv *rmpp_recv;	unsigned long flags;	rmpp_recv = create_rmpp_recv(agent, mad_recv_wc);	if (!rmpp_recv) {		ib_free_recv_mad(mad_recv_wc);		return NULL;	}	spin_lock_irqsave(&agent->lock, flags);	if (insert_rmpp_recv(agent, rmpp_recv)) {		spin_unlock_irqrestore(&agent->lock, flags);		/* duplicate first MAD */		destroy_rmpp_recv(rmpp_recv);		return continue_rmpp(agent, mad_recv_wc);	}	atomic_inc(&rmpp_recv->refcount);	if (get_last_flag(&mad_recv_wc->recv_buf)) {		rmpp_recv->state = RMPP_STATE_COMPLETE;		spin_unlock_irqrestore(&agent->lock, flags);		complete_rmpp(rmpp_recv);	} else {		spin_unlock_irqrestore(&agent->lock, flags);		/* 40 seconds until we can find the packet lifetimes */		queue_delayed_work(agent->qp_info->port_priv->wq,				   &rmpp_recv->timeout_work,				   msecs_to_jiffies(40000));		rmpp_recv->newwin += window_size(agent);		ack_recv(rmpp_recv, mad_recv_wc);		mad_recv_wc = NULL;	}	deref_rmpp_recv(rmpp_recv);	return mad_recv_wc;}static inline u64 get_seg_addr(struct ib_mad_send_wr_private *mad_send_wr){	return mad_send_wr->sg_list[0].addr + mad_send_wr->data_offset +	       (sizeof(struct ib_rmpp_mad) - mad_send_wr->data_offset) *	       (mad_send_wr->seg_num - 1);}static int send_next_seg(struct ib_mad_send_wr_private *mad_send_wr){	struct ib_rmpp_mad *rmpp_mad;	int timeout;	u32 paylen;	rmpp_mad = mad_send_wr->send_buf.mad;	ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE);	rmpp_mad->rmpp_hdr.seg_num = cpu_to_be32(mad_send_wr->seg_num);	if (mad_send_wr->seg_num == 1) {		rmpp_mad->rmpp_hdr.rmpp_rtime_flags |= IB_MGMT_RMPP_FLAG_FIRST;		paylen = mad_send_wr->total_seg * IB_MGMT_RMPP_DATA -			 mad_send_wr->pad;		rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(paylen);		mad_send_wr->sg_list[0].length = sizeof(struct ib_rmpp_mad);	} else {		mad_send_wr->send_wr.num_sge = 2;		mad_send_wr->sg_list[0].length = mad_send_wr->data_offset;		mad_send_wr->sg_list[1].addr = get_seg_addr(mad_send_wr);		mad_send_wr->sg_list[1].length = sizeof(struct ib_rmpp_mad) -						 mad_send_wr->data_offset;		mad_send_wr->sg_list[1].lkey = mad_send_wr->sg_list[0].lkey;		rmpp_mad->rmpp_hdr.paylen_newwin = 0;	}	if (mad_send_wr->seg_num == mad_send_wr->total_seg) {		rmpp_mad->rmpp_hdr.rmpp_rtime_flags |= IB_MGMT_RMPP_FLAG_LAST;		paylen = IB_MGMT_RMPP_DATA - mad_send_wr->pad;		rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(paylen);	}	/* 2 seconds for an ACK until we can find the packet lifetime */	timeout = mad_send_wr->send_buf.timeout_ms;	if (!timeout || timeout > 2000)		mad_send_wr->timeout = msecs_to_jiffies(2000);	mad_send_wr->seg_num++;	return ib_send_mad(mad_send_wr);}static void abort_send(struct ib_mad_agent_private *agent, __be64 tid,		       u8 rmpp_status){	struct ib_mad_send_wr_private *mad_send_wr;	struct ib_mad_send_wc wc;	unsigned long flags;	spin_lock_irqsave(&agent->lock, flags);	mad_send_wr = ib_find_send_mad(agent, tid);	if (!mad_send_wr)		goto out;	/* Unmatched send */	if ((mad_send_wr->last_ack == mad_send_wr->total_seg) ||	    (!mad_send_wr->timeout) || (mad_send_wr->status != IB_WC_SUCCESS))		goto out;	/* Send is already done */	ib_mark_mad_done(mad_send_wr);	spin_unlock_irqrestore(&agent->lock, flags);	wc.status = IB_WC_REM_ABORT_ERR;	wc.vendor_err = rmpp_status;	wc.send_buf = &mad_send_wr->send_buf;	ib_mad_complete_send_wr(mad_send_wr, &wc);	return;out:	spin_unlock_irqrestore(&agent->lock, flags);}static void process_rmpp_ack(struct ib_mad_agent_private *agent,			     struct ib_mad_recv_wc *mad_recv_wc){	struct ib_mad_send_wr_private *mad_send_wr;	struct ib_rmpp_mad *rmpp_mad;	unsigned long flags;	int seg_num, newwin, ret;	rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad;	if (rmpp_mad->rmpp_hdr.rmpp_status) {		abort_send(agent, rmpp_mad->mad_hdr.tid,			   IB_MGMT_RMPP_STATUS_BAD_STATUS);		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);		return;	}	seg_num = be32_to_cpu(rmpp_mad->rmpp_hdr.seg_num);	newwin = be32_to_cpu(rmpp_mad->rmpp_hdr.paylen_newwin);	if (newwin < seg_num) {		abort_send(agent, rmpp_mad->mad_hdr.tid,			   IB_MGMT_RMPP_STATUS_W2S);		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_W2S);		return;	}	spin_lock_irqsave(&agent->lock, flags);	mad_send_wr = ib_find_send_mad(agent, rmpp_mad->mad_hdr.tid);	if (!mad_send_wr)		goto out;	/* Unmatched ACK */	if ((mad_send_wr->last_ack == mad_send_wr->total_seg) ||	    (!mad_send_wr->timeout) || (mad_send_wr->status != IB_WC_SUCCESS))		goto out;	/* Send is already done */	if (seg_num > mad_send_wr->total_seg || seg_num > mad_send_wr->newwin) {		spin_unlock_irqrestore(&agent->lock, flags);		abort_send(agent, rmpp_mad->mad_hdr.tid,			   IB_MGMT_RMPP_STATUS_S2B);		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_S2B);		return;	}	if (newwin < mad_send_wr->newwin || seg_num < mad_send_wr->last_ack)		goto out;	/* Old ACK */	if (seg_num > mad_send_wr->last_ack) {		mad_send_wr->last_ack = seg_num;		mad_send_wr->retries = mad_send_wr->send_buf.retries;	}	mad_send_wr->newwin = newwin;	if (mad_send_wr->last_ack == mad_send_wr->total_seg) {		/* If no response is expected, the ACK completes the send */		if (!mad_send_wr->send_buf.timeout_ms) {			struct ib_mad_send_wc wc;			ib_mark_mad_done(mad_send_wr);			spin_unlock_irqrestore(&agent->lock, flags);			wc.status = IB_WC_SUCCESS;			wc.vendor_err = 0;			wc.send_buf = &mad_send_wr->send_buf;			ib_mad_complete_send_wr(mad_send_wr, &wc);			return;		}		if (mad_send_wr->refcount == 1)			ib_reset_mad_timeout(mad_send_wr,					     mad_send_wr->send_buf.timeout_ms);	} else if (mad_send_wr->refcount == 1 &&		   mad_send_wr->seg_num < mad_send_wr->newwin &&		   mad_send_wr->seg_num <= mad_send_wr->total_seg) {		/* Send failure will just result in a timeout/retry */		ret = send_next_seg(mad_send_wr);		if (ret)			goto out;		mad_send_wr->refcount++;		list_del(&mad_send_wr->agent_list);		list_add_tail(&mad_send_wr->agent_list,			      &mad_send_wr->mad_agent_priv->send_list);	}out:	spin_unlock_irqrestore(&agent->lock, flags);}static struct ib_mad_recv_wc *process_rmpp_data(struct ib_mad_agent_private *agent,		  struct ib_mad_recv_wc *mad_recv_wc){	struct ib_rmpp_hdr *rmpp_hdr;	u8 rmpp_status;	rmpp_hdr = &((struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad)->rmpp_hdr;	if (rmpp_hdr->rmpp_status) {		rmpp_status = IB_MGMT_RMPP_STATUS_BAD_STATUS;		goto bad;	}	if (rmpp_hdr->seg_num == __constant_htonl(1)) {		if (!(ib_get_rmpp_flags(rmpp_hdr) & IB_MGMT_RMPP_FLAG_FIRST)) {			rmpp_status = IB_MGMT_RMPP_STATUS_BAD_SEG;			goto bad;		}		return start_rmpp(agent, mad_recv_wc);	} else {		if (ib_get_rmpp_flags(rmpp_hdr) & IB_MGMT_RMPP_FLAG_FIRST) {			rmpp_status = IB_MGMT_RMPP_STATUS_BAD_SEG;			goto bad;		}		return continue_rmpp(agent, mad_recv_wc);	}bad:	nack_recv(agent, mad_recv_wc, rmpp_status);	ib_free_recv_mad(mad_recv_wc);	return NULL;}static void process_rmpp_stop(struct ib_mad_agent_private *agent,			      struct ib_mad_recv_wc *mad_recv_wc){	struct ib_rmpp_mad *rmpp_mad;	rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad;	if (rmpp_mad->rmpp_hdr.rmpp_status != IB_MGMT_RMPP_STATUS_RESX) {		abort_send(agent, rmpp_mad->mad_hdr.tid,			   IB_MGMT_RMPP_STATUS_BAD_STATUS);		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);	} else		abort_send(agent, rmpp_mad->mad_hdr.tid,			   rmpp_mad->rmpp_hdr.rmpp_status);}static void process_rmpp_abort(struct ib_mad_agent_private *agent,			       struct ib_mad_recv_wc *mad_recv_wc){	struct ib_rmpp_mad *rmpp_mad;	rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad;	if (rmpp_mad->rmpp_hdr.rmpp_status < IB_MGMT_RMPP_STATUS_ABORT_MIN ||	    rmpp_mad->rmpp_hdr.rmpp_status > IB_MGMT_RMPP_STATUS_ABORT_MAX) {		abort_send(agent, rmpp_mad->mad_hdr.tid,			   IB_MGMT_RMPP_STATUS_BAD_STATUS);		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);	} else		abort_send(agent, rmpp_mad->mad_hdr.tid,			   rmpp_mad->rmpp_hdr.rmpp_status);}struct ib_mad_recv_wc *ib_process_rmpp_recv_wc(struct ib_mad_agent_private *agent,			struct ib_mad_recv_wc *mad_recv_wc){	struct ib_rmpp_mad *rmpp_mad;	rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad;	if (!(rmpp_mad->rmpp_hdr.rmpp_rtime_flags & IB_MGMT_RMPP_FLAG_ACTIVE))		return mad_recv_wc;	if (rmpp_mad->rmpp_hdr.rmpp_version != IB_MGMT_RMPP_VERSION) {		abort_send(agent, rmpp_mad->mad_hdr.tid,			   IB_MGMT_RMPP_STATUS_UNV);		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_UNV);		goto out;	}	switch (rmpp_mad->rmpp_hdr.rmpp_type) {	case IB_MGMT_RMPP_TYPE_DATA:		return process_rmpp_data(agent, mad_recv_wc);	case IB_MGMT_RMPP_TYPE_ACK:		process_rmpp_ack(agent, mad_recv_wc);		break;	case IB_MGMT_RMPP_TYPE_STOP:		process_rmpp_stop(agent, mad_recv_wc);		break;	case IB_MGMT_RMPP_TYPE_ABORT:		process_rmpp_abort(agent, mad_recv_wc);		break;	default:		abort_send(agent, rmpp_mad->mad_hdr.tid,			   IB_MGMT_RMPP_STATUS_BADT);		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BADT);		break;	}out:	ib_free_recv_mad(mad_recv_wc);	return NULL;}int ib_send_rmpp_mad(struct ib_mad_send_wr_private *mad_send_wr){	struct ib_rmpp_mad *rmpp_mad;	int i, total_len, ret;	rmpp_mad = mad_send_wr->send_buf.mad;	if (!(ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &	      IB_MGMT_RMPP_FLAG_ACTIVE))		return IB_RMPP_RESULT_UNHANDLED;	if (rmpp_mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_DATA)		return IB_RMPP_RESULT_INTERNAL;	if (mad_send_wr->send_wr.num_sge > 1)		return -EINVAL;		/* TODO: support num_sge > 1 */	mad_send_wr->seg_num = 1;	mad_send_wr->newwin = 1;	mad_send_wr->data_offset = data_offset(rmpp_mad->mad_hdr.mgmt_class);	total_len = 0;	for (i = 0; i < mad_send_wr->send_wr.num_sge; i++)		total_len += mad_send_wr->send_wr.sg_list[i].length;        mad_send_wr->total_seg = (total_len - mad_send_wr->data_offset) /			(sizeof(struct ib_rmpp_mad) - mad_send_wr->data_offset);	mad_send_wr->pad = total_len - IB_MGMT_RMPP_HDR -			   be32_to_cpu(rmpp_mad->rmpp_hdr.paylen_newwin);	/* We need to wait for the final ACK even if there isn't a response */	mad_send_wr->refcount += (mad_send_wr->timeout == 0);	ret = send_next_seg(mad_send_wr);	if (!ret)		return IB_RMPP_RESULT_CONSUMED;	return ret;}int ib_process_rmpp_send_wc(struct ib_mad_send_wr_private *mad_send_wr,			    struct ib_mad_send_wc *mad_send_wc){	struct ib_rmpp_mad *rmpp_mad;	int ret;	rmpp_mad = mad_send_wr->send_buf.mad;	if (!(ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &	      IB_MGMT_RMPP_FLAG_ACTIVE))		return IB_RMPP_RESULT_UNHANDLED; /* RMPP not active */	if (rmpp_mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_DATA)		return IB_RMPP_RESULT_INTERNAL;	 /* ACK, STOP, or ABORT */	if (mad_send_wc->status != IB_WC_SUCCESS ||	    mad_send_wr->status != IB_WC_SUCCESS)		return IB_RMPP_RESULT_PROCESSED; /* Canceled or send error */	if (!mad_send_wr->timeout)		return IB_RMPP_RESULT_PROCESSED; /* Response received */	if (mad_send_wr->last_ack == mad_send_wr->total_seg) {		mad_send_wr->timeout =			msecs_to_jiffies(mad_send_wr->send_buf.timeout_ms);		return IB_RMPP_RESULT_PROCESSED; /* Send done */	}	if (mad_send_wr->seg_num > mad_send_wr->newwin ||	    mad_send_wr->seg_num > mad_send_wr->total_seg)		return IB_RMPP_RESULT_PROCESSED; /* Wait for ACK */	ret = send_next_seg(mad_send_wr);	if (ret) {		mad_send_wc->status = IB_WC_GENERAL_ERR;		return IB_RMPP_RESULT_PROCESSED;	}	return IB_RMPP_RESULT_CONSUMED;}int ib_retry_rmpp(struct ib_mad_send_wr_private *mad_send_wr){	struct ib_rmpp_mad *rmpp_mad;	int ret;	rmpp_mad = mad_send_wr->send_buf.mad;	if (!(ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &	      IB_MGMT_RMPP_FLAG_ACTIVE))		return IB_RMPP_RESULT_UNHANDLED; /* RMPP not active */	if (mad_send_wr->last_ack == mad_send_wr->total_seg)		return IB_RMPP_RESULT_PROCESSED;	mad_send_wr->seg_num = mad_send_wr->last_ack + 1;	ret = send_next_seg(mad_send_wr);	if (ret)		return IB_RMPP_RESULT_PROCESSED;	return IB_RMPP_RESULT_CONSUMED;}

⌨️ 快捷键说明

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