static int riocm_ch_connect()

in rio_cm.c [942:1019]


static int riocm_ch_connect(u16 loc_ch, struct cm_dev *cm,
			    struct cm_peer *peer, u16 rem_ch)
{
	struct rio_channel *ch = NULL;
	struct rio_ch_chan_hdr *hdr;
	int ret;
	long wret;

	ch = riocm_get_channel(loc_ch);
	if (!ch)
		return -ENODEV;

	if (!riocm_cmp_exch(ch, RIO_CM_IDLE, RIO_CM_CONNECT)) {
		ret = -EINVAL;
		goto conn_done;
	}

	ch->cmdev = cm;
	ch->rdev = peer->rdev;
	ch->context = NULL;
	ch->loc_destid = cm->mport->host_deviceid;
	ch->rem_channel = rem_ch;

	/*
	 * Send connect request to the remote RapidIO device
	 */

	hdr = kzalloc(sizeof(*hdr), GFP_KERNEL);
	if (hdr == NULL) {
		ret = -ENOMEM;
		goto conn_done;
	}

	hdr->bhdr.src_id = htonl(ch->loc_destid);
	hdr->bhdr.dst_id = htonl(peer->rdev->destid);
	hdr->bhdr.src_mbox = cmbox;
	hdr->bhdr.dst_mbox = cmbox;
	hdr->bhdr.type = RIO_CM_CHAN;
	hdr->ch_op = CM_CONN_REQ;
	hdr->dst_ch = htons(rem_ch);
	hdr->src_ch = htons(loc_ch);

	/* ATTN: the function call below relies on the fact that underlying
	 * HW-specific add_outb_message() routine copies TX data into its
	 * internal transfer buffer. Must be reviewed if mport driver uses
	 * this buffer directly.
	 */
	ret = riocm_post_send(cm, peer->rdev, hdr, sizeof(*hdr));

	if (ret != -EBUSY) {
		kfree(hdr);
	} else {
		ret = riocm_queue_req(cm, peer->rdev, hdr, sizeof(*hdr));
		if (ret)
			kfree(hdr);
	}

	if (ret) {
		riocm_cmp_exch(ch, RIO_CM_CONNECT, RIO_CM_IDLE);
		goto conn_done;
	}

	/* Wait for connect response from the remote device */
	wret = wait_for_completion_interruptible_timeout(&ch->comp,
							 RIOCM_CONNECT_TO * HZ);
	riocm_debug(WAIT, "wait on %d returns %ld", ch->id, wret);

	if (!wret)
		ret = -ETIME;
	else if (wret == -ERESTARTSYS)
		ret = -EINTR;
	else
		ret = riocm_cmp(ch, RIO_CM_CONNECTED) ? 0 : -1;

conn_done:
	riocm_put_channel(ch);
	return ret;
}