[openib-general] Re: ib_send_cm_req fails with error -22

susan ssbyrn at yahoo.com
Mon Apr 24 18:47:22 PDT 2006


susan <ssbyrn <at> yahoo.com> writes:

> 
> Sean Hefty <mshefty <at> ichips.intel.com> writes:
> 
> 
> thanks Sean! i will give it try.
> 
> susan
> 
> 

hi Sean,

cmpost utility works on my box. i found following anomalies
after looking in cmpost.c code:
 1. in my test code, i have to explicitly set path_rec.sgid\
    for ib_sa_path_rec_get routine to work. if not set then
    ib_send_cm_req() call fails with error 22 (EINVAL).
    whereas cmpost doesn't set it.
    
 2. for test code below, i get IB_CM_REQ_ERROR after calling
    ib_send_cm_req. below is the trace of primary node (that
    connects to secondary node, which starts in a listen mode).

ib call trace on primary node:
xtd: ib_register_client
xtd: set primary 1
xtd: using active port 1
xtd: ib_alloc_pd
xtd: ib_create_cm_id
xtd: ib_create_cq
xtd: ib_req_notify_cq
xtd: ib_create_qp
xtd: connect 0x2
xtd: ib_query_gid
xtd: sgid.prefix fe80000000000000, sgid.id 5ad0000030861
xtd: slid 0x1, dlid 0x2, port 1
xtd: ib_sa_path_rec_get
xtd: waiting for ib_sa_path_rec_get completion
xtd: ib_sa_path_rec_get completed with status 0, wakeup sleeping task
xtd: ib_sa_path_rec_get operation completed
xtd: ib_send_cm_req
xtd: cm_id->state = 2
xtd: waiting for connection to establish
xtd: xtd_cm_handler(0)
xtd: xtd_cm_handler(IB_CM_REQ_ERROR) event not processed
xtd: cm_id->state = 0
xtd: wait timed out

ib call trace on secondary node:
xtd: ib_register_client
xtd: set secondary 2

xtd: using active port 1
xtd: ib_alloc_pd
xtd: ib_create_cm_id
xtd: ib_create_cq
xtd: ib_req_notify_cq
xtd: ib_create_qp
xtd: ib_create_cm_id
xtd: ib_cm_listen
xtd: listening ...



------------------------TEST CODE--------------------------------

#include <linux/module.h>
#include <linux/err.h>
#include <linux/proc_fs.h>
#include <linux/pci.h>
#include <asm/uaccess.h>
#include <rdma/ib_cm.h>

#define XTD_DESCRIPTION		"sample infiniband driver for xsft"
#define XTD_AUTHOR		"symantec software"

MODULE_DESCRIPTION(XTD_DESCRIPTION);
MODULE_AUTHOR(XTD_AUTHOR);
MODULE_LICENSE("GPL");

#define PROCDIR			"xtd"
#define PROCFILE		"info"

#define MAX_CQ_WR		1
#define MAX_SEND_WR		MAX_CQ_WR
#define MAX_RECV_WR		MAX_CQ_WR
#define MAX_CQ_SIZE		MAX_SEND_WR + MAX_RECV_WR
#define MAX_TIMEOUT_MS		1000
#define MAX_BUFFER		256
#define MAX_RETRIES		1
#define MAX_WAIT_TIMEOUT	(80 * HZ)

#define SERVICE_ID		0x1000

enum xtd_loglevel_type {
	ERROR = 0,
	WARN,
	INFO1,
	INFO2,
	INFO3,
	INFO4,
	INFO5,
	INFO6,
	INFO7
};

enum xtd_role_type {
	NONE = 0,
	PRIMARY,
	SECONDARY
};

enum xtd_state_type {
	UNKNOWN = 0,
	INIT,
	CONNECTING,
	ESTABLISHED,
	DISCONNECTING,
	DISCONNECTED
};

typedef struct _xtd_msgbuf_t {
	int			opcode;
	char			data[MAX_BUFFER];
} xtd_msgbuf_t;

typedef struct _xtd_device_t {
	struct ib_device	*hcap;
	struct ib_cm_id		*cm_idp;
	struct ib_cm_id		*listen_idp;
	struct ib_pd		*pdp;
	struct ib_cq		*cqp;
	struct ib_mr		*mrp;
	struct ib_qp		*qpp;
	struct ib_sa_path_rec	path_rec;
	wait_queue_head_t	waitq;
	int			cq_size;
	int			conn_state;
	int			path_rec_qstatus;
	int			port;
	int			role;
	xtd_msgbuf_t		*msgbufp;
	u64			addr;
	u32			slid;
	u32			dlid;
	DECLARE_PCI_UNMAP_ADDR(mapping);
} xtd_device_t;

static int			xtd_debuglevel = INFO6;
static struct proc_dir_entry	*xtd_procdir = NULL;
static struct proc_dir_entry	*xtd_procfile = NULL;
static xtd_device_t		xtd_device;

static void xtd_add_one(struct ib_device *devicep);
static void xtd_remove_one(struct ib_device *devicep);

static struct ib_client	xtd_client = {
				.name = "xtd",
				.add = xtd_add_one,
				.remove = xtd_remove_one
			};

static void
xlog(int level, const char *format, ...)
{
	int	ii = 0;
	char	buffer[MAX_BUFFER];
	va_list	ap;

	if (level > xtd_debuglevel) {
		return;
	}

	va_start(ap, format);
	(void) vsprintf(&buffer[0], format, ap);
	va_end(ap);
	ii = strlen(buffer);
	buffer[ii++] = '\n';
	buffer[ii] = '\0';
	printk("xtd: %s", buffer);
	return;
}

static int
free_recv_buffer(void)
{
	dma_unmap_single(xtd_device.hcap->dma_device,
			pci_unmap_addr(&xtd_device, mapping),
			sizeof (xtd_msgbuf_t), DMA_FROM_DEVICE);

	if (xtd_device.mrp) {
		xlog(INFO3, "ib_dereg_mr");
		ib_dereg_mr(xtd_device.mrp);
		xtd_device.mrp = NULL;
	}

	kfree(xtd_device.msgbufp);
	xtd_device.msgbufp = NULL;
	return 0;
}

static int
alloc_recv_buffer(void)
{
	struct ib_recv_wr	recv_wr;
	struct ib_recv_wr	*bad_recv_wrp;
	struct ib_sge		sge;
	int			retc;

	if (xtd_device.msgbufp) {
		kfree(xtd_device.msgbufp);
	}

	xtd_device.msgbufp = (xtd_msgbuf_t *)
			kzalloc(sizeof (xtd_msgbuf_t), GFP_ATOMIC);
	if (! xtd_device.msgbufp) {
		xlog(ERROR, "alloc for xtd_msgbuf_t failed");
		return -ENOMEM;
	}

	xlog(INFO3, "ib_get_dma_mr");
	xtd_device.mrp = ib_get_dma_mr(xtd_device.pdp,
					IB_ACCESS_LOCAL_WRITE);
	if (IS_ERR(xtd_device.mrp)) {
		retc = PTR_ERR(xtd_device.mrp);
		xlog(ERROR, "ib_get_dma_mr() failed with error %d", retc);
		kfree(xtd_device.msgbufp);
		xtd_device.msgbufp = NULL;
		xtd_device.mrp = NULL;
		return retc;
	}

	xtd_device.addr = dma_map_single(xtd_device.hcap->dma_device,
			xtd_device.msgbufp, sizeof (xtd_msgbuf_t),
			DMA_FROM_DEVICE);
	if (dma_mapping_error(xtd_device.addr)) {
		xlog(ERROR, "dma_map_single() failed");
		ib_dereg_mr(xtd_device.mrp);
		xtd_device.mrp = NULL;
		kfree(xtd_device.msgbufp);
		xtd_device.msgbufp = NULL;
		return -ENOMEM;
	}

	pci_unmap_addr_set(&xtd_device, mapping, xtd_device.addr);

	sge.addr = xtd_device.addr;
	sge.length = sizeof (xtd_msgbuf_t);
	sge.lkey = xtd_device.mrp->lkey;

	recv_wr.next = NULL;
	recv_wr.sg_list = &sge;
	recv_wr.num_sge = 1;
	recv_wr.wr_id = (u64) &xtd_device;

	xlog(INFO3, "ib_post_recv");
	retc = ib_post_recv(xtd_device.qpp, &recv_wr, &bad_recv_wrp);
	if (retc) {
		xlog(ERROR, "ib_post_recv() failed with error %d", retc);
		free_recv_buffer();
		return retc;
	}

	return retc;
}

static int
process_send(struct ib_wc *wcp)
{
	return 0;
}

static int
process_recv(struct ib_wc *wcp)
{
	return 0;
}

static int
process_completion(struct ib_wc *wcp)
{
	int	retc;

	switch(wcp->opcode) {
	case IB_WC_SEND:
			retc = process_send(wcp);
			return retc;

	case IB_WC_RECV:
			retc = process_recv(wcp);
			if (retc) {
				return retc;
			}

			retc = free_recv_buffer();
			if (retc) {
				xlog(ERROR, "free_recv_buffer() failed");
				return retc;
			}

			retc = alloc_recv_buffer();
			return retc;

	default:
			xlog(ERROR, "process_completion(%d) operation not "
						"processed", wcp->opcode);
			return -EINVAL;
	}
}

static void
xtd_path_rec_completion(int status, struct ib_sa_path_rec *resp, void *contextp)
{
	xlog(INFO4, "ib_sa_path_rec_get completed with status %d, "
					"wakeup sleeping task", status);
	xtd_device.path_rec_qstatus = 0;
	wake_up(&xtd_device.waitq);
	return;
}

static void
xtd_qp_event_handler(struct ib_event *eventp, void *contextp)
{
	return;
}

static void
xtd_completion_event_handler(struct ib_event *eventp, void *contextp)
{
	return;
}

static void
xtd_completion_handler(struct ib_cq *cqp, void *contextp)
{
	struct ib_wc	wc[MAX_CQ_WR];
	int		i;
	int		retc;

	do {
		xlog(INFO3, "ib_poll_cq");
		retc = ib_poll_cq(cqp, MAX_CQ_WR, wc);
		if (retc < 0) {
			xlog(ERROR, "ib_poll_cq() failed with error %d", retc);
			return;
		}

		for (i = 0; i < retc; i++) {
			retc = process_completion(&wc[i]);
		}

	} while (retc > 0);

	xlog(INFO3, "ib_req_notify_cq");
	retc = ib_req_notify_cq(cqp, IB_CQ_NEXT_COMP);
	if (retc != 0) {
		xlog(ERROR, "ib_req_notify_cq() failed with error %d", retc);
	}

	return;
}

static int
modify_qp(struct ib_cm_id *cm_idp, int state)
{
	struct ib_qp_attr	qp_attr;
	int			mask;
	int			retc;

	memset(&qp_attr, 0, sizeof qp_attr);
	qp_attr.qp_state = state;
	retc = ib_cm_init_qp_attr(cm_idp, &qp_attr, &mask);
	if (retc) {
		xlog(ERROR, "ib_cm_init_qp_attr() failed with error %d "
				"for state %d", retc, state);
		return retc;
	}

	if (state == IB_QPS_RTR) {
		qp_attr.rq_psn = xtd_device.qpp->qp_num;
	}

	retc = ib_modify_qp(xtd_device.qpp, &qp_attr, mask);
	if (retc) {
		xlog(ERROR, "ib_modify_qp() failed with error %d "
				"for state %d", retc, state);
		return retc;
	}

	return retc;
}

static int
query_path_rec(void)
{
	union ib_gid		sgid;
	struct ib_sa_query	*queryp;
	int			wtimeout;
	int			retc;

	xlog(INFO3, "ib_query_gid");
	retc = ib_query_gid(xtd_device.hcap, xtd_device.port, 0, &sgid);
	if (retc) {
		xlog(ERROR, "ib_query_gid() failed with error %d", retc);
		return retc;
	}

	xlog(INFO4, "sgid.prefix %llx, sgid.id %llx",
			__constant_be64_to_cpu(sgid.global.subnet_prefix),
			__constant_be64_to_cpu(sgid.global.interface_id));
	xlog(INFO4, "slid 0x%x, dlid 0x%x, port %d",
			xtd_device.slid, xtd_device.dlid, xtd_device.port);

	xtd_device.path_rec.dlid = cpu_to_be16(xtd_device.dlid);
	xtd_device.path_rec.slid = cpu_to_be16(xtd_device.slid);
	xtd_device.path_rec.sgid = sgid;
	xtd_device.path_rec.numb_path = 1;

	xlog(INFO3, "ib_sa_path_rec_get");
	xtd_device.path_rec_qstatus = 1;
	retc = ib_sa_path_rec_get(xtd_device.hcap,
				xtd_device.port,
				&xtd_device.path_rec,
				IB_SA_PATH_REC_DLID | IB_SA_PATH_REC_SLID |
				IB_SA_PATH_REC_SGID | IB_SA_PATH_REC_NUMB_PATH,
				MAX_TIMEOUT_MS,
				MAX_RETRIES,
				GFP_KERNEL,
				xtd_path_rec_completion,
				NULL,
				&queryp);
	if (retc < 0) {
		xlog(ERROR, "ib_sa_path_rec_get failed with error %d", retc);
		return retc;
	}

	xlog(INFO4, "waiting for ib_sa_path_rec_get completion");
	wtimeout = wait_event_timeout(xtd_device.waitq,
			xtd_device.path_rec_qstatus <= 0, MAX_WAIT_TIMEOUT);
	if (wtimeout == 0) {
		xlog(ERROR, "wait timed out");
		return -ETIME;
	}

	xlog(INFO4, "ib_sa_path_rec_get operation completed");
	return retc;
}

static int
find_active_port(struct ib_device *devicep)
{
	int			i;
	struct ib_port_attr	pattr;
	int			retc;

	for(i = 1; i <= devicep->phys_port_cnt; i++) {
		retc = ib_query_port(devicep, i, &pattr);
		if (retc) {
			xlog(ERROR, "ib_query_port() on port %d failed ",
				"with retc %d", i, retc);
			continue;
		}

		/*
		 * use the first active found
		 */
		if (pattr.state == IB_PORT_ACTIVE) {
			xlog(INFO4, "using active port %d", i);
			xtd_device.port = i;
			return 0;
		}
	}

	return 1;
}

static int
free_ib(void)
{
	if (xtd_device.listen_idp) {
		xlog(INFO3, "ib_destroy_listen_id");
		ib_destroy_cm_id(xtd_device.listen_idp);
		xtd_device.listen_idp = NULL;
	}

	if (xtd_device.qpp) {
		xlog(INFO3, "ib_destroy_qp");
		ib_destroy_qp(xtd_device.qpp);
		xtd_device.qpp = NULL;
	}

	if (xtd_device.cqp) {
		xlog(INFO3, "ib_destroy_cq");
		ib_destroy_cq(xtd_device.cqp);
		xtd_device.cqp = NULL;
		xtd_device.cq_size = 0;
	}

	if (xtd_device.cm_idp) {
		xlog(INFO3, "ib_destroy_cm_id");
		ib_destroy_cm_id(xtd_device.cm_idp);
		xtd_device.cm_idp = NULL;
	}

	if (xtd_device.pdp) {
		xlog(INFO3, "ib_dealloc_pd");
		ib_dealloc_pd(xtd_device.pdp);
		xtd_device.pdp = NULL;
	}

	return 0;
}

static int
send_req(void)
{
	struct ib_cm_req_param	req;
	int			wtimeout;
	int			retc;

	memset(&req, 0, sizeof req);
	req.primary_path = &xtd_device.path_rec;
	req.service_id = __constant_cpu_to_be64(SERVICE_ID);
	req.qp_num = xtd_device.qpp->qp_num;
	req.qp_type = xtd_device.qpp->qp_type;
	req.srq = (xtd_device.qpp->srq != NULL);

	req.responder_resources = 1;
	req.initiator_depth = 1;
	req.remote_cm_response_timeout = 20;
	req.local_cm_response_timeout = 20;
	req.retry_count = 5;
	req.max_cm_retries = 5;
	req.starting_psn = xtd_device.qpp->qp_num;

	xlog(INFO3, "ib_send_cm_req");
	retc = ib_send_cm_req(xtd_device.cm_idp, &req);
	if (retc) {
		xlog(ERROR, "ib_send_cm_req() failed with error %d", retc);
		return retc;
	}

	xlog(INFO5, "cm_id->state = %x", xtd_device.cm_idp->state);
	xtd_device.conn_state = CONNECTING;
	xlog(INFO4, "waiting for connection to establish");
	wtimeout = wait_event_timeout(xtd_device.waitq,
		xtd_device.conn_state == ESTABLISHED, MAX_WAIT_TIMEOUT);
	xlog(INFO5, "cm_id->state = %x", xtd_device.cm_idp->state);
	if (wtimeout == 0) {
		xlog(ERROR, "wait timed out");
		return -ETIME;
	}

	xlog(INFO4, "connection established");
	return retc;
}

static int
disconnect(void)
{
	int	wtimeout;
	int	retc;

	xlog(INFO3, "ib_send_cm_dreq");
	retc = ib_send_cm_dreq(xtd_device.cm_idp, NULL, 0);
	if (retc) {
		xlog(ERROR, "ib_send_cm_dreq() failed with error %d", retc);
		return retc;
	}

	xtd_device.conn_state = DISCONNECTING;
	xlog(INFO4, "waiting for connection to disconnect");
	wtimeout = wait_event_timeout(xtd_device.waitq,
		xtd_device.conn_state == DISCONNECTED, MAX_WAIT_TIMEOUT);
	if (wtimeout == 0) {
		xlog(ERROR, "wait timed out");
		return -ETIME;
	}

	xlog(INFO4, "connection disconnected");
	retc = free_ib();
	if (retc) {
		xlog(ERROR, "free_ib() failed with error %d", retc);
		return retc;
	}

	return retc;
}

static int
connect(void)
{
	int	retc;

	retc = query_path_rec();
	if (retc) {
		return retc;
	}

	retc = send_req();
	return retc;
}

static int
rtu_handler(struct ib_cm_id *cm_idp, struct ib_cm_event *eventp)
{
	int				retc;

	xlog(INFO3, "modify_qp(IB_QPS_RTS)");
	retc = modify_qp(cm_idp, IB_QPS_RTS);
	if (retc) {
		return retc;
	}

	xtd_device.conn_state = ESTABLISHED;
	xlog(INFO4, "connection established");
	return retc;
}

static int
rep_handler(struct ib_cm_id *cm_idp, struct ib_cm_event *eventp)
{
	int				retc;

	xlog(INFO3, "modify_qp(IB_QPS_INIT)");
	retc = modify_qp(cm_idp, IB_QPS_INIT);
	if (retc) {
		return retc;
	}

	xlog(INFO3, "modify_qp(IB_QPS_RTR)");
	retc = modify_qp(cm_idp, IB_QPS_RTR);
	if (retc) {
		return retc;
	}

	xlog(INFO3, "modify_qp(IB_QPS_RTS)");
	retc = modify_qp(cm_idp, IB_QPS_RTS);
	if (retc) {
		return retc;
	}

	retc = alloc_recv_buffer();
	if (retc) {
		return retc;
	}

	xlog(INFO3, "ib_send_cm_rtu");
	retc = ib_send_cm_rtu(xtd_device.cm_idp, NULL, 0);
	if (retc) {
		xlog(ERROR, "ib_send_cm_rtu() failed with error %d", retc);
		return retc;
	}

	xtd_device.conn_state = ESTABLISHED;
	xlog(INFO4, "connection established, wakeup sleeping task");
	wake_up(&xtd_device.waitq);
	return retc;
}

static int
req_handler(struct ib_cm_id *cm_idp, struct ib_cm_event *eventp)
{
	struct ib_cm_req_event_param	req;
	struct ib_cm_rep_param		rep;
	int				retc;

	xtd_device.cm_idp = cm_idp;
	req = eventp->param.req_rcvd;

	xlog(INFO3, "modify_qp(IB_QPS_INIT)");
	retc = modify_qp(cm_idp, IB_QPS_INIT);
	if (retc) {
		return retc;
	}

	xlog(INFO3, "modify_qp(IB_QPS_RTR)");
	retc = modify_qp(cm_idp, IB_QPS_RTR);
	if (retc) {
		return retc;
	}

	retc = alloc_recv_buffer();
	if (retc) {
		return retc;
	}

	memset(&rep, 0, sizeof rep);
	rep.qp_num = xtd_device.qpp->qp_num;
	rep.srq = (xtd_device.qpp->srq != NULL);
	rep.starting_psn = xtd_device.qpp->qp_num;
	rep.responder_resources = req.responder_resources;
	rep.initiator_depth = req.initiator_depth;
	rep.target_ack_delay = 20;
	rep.flow_control = req.flow_control;
	rep.rnr_retry_count = req.rnr_retry_count;
	xlog(INFO3, "ib_send_cm_rep");
	retc = ib_send_cm_rep(xtd_device.cm_idp, &rep);
	if (retc) {
		xlog(ERROR, "ib_send_cm_rep() failed with error %d", retc);
		return retc;
	}

	return retc;
}

static int
xtd_cm_handler(struct ib_cm_id *cm_idp, struct ib_cm_event *eventp)
{
	int	retc;

	xlog(INFO4, "xtd_cm_handler(%d)", eventp->event);
	switch(eventp->event) {
	case IB_CM_REQ_RECEIVED:
			retc = req_handler(cm_idp, eventp);
			break;

	case IB_CM_REP_RECEIVED:
			retc = rep_handler(cm_idp, eventp);
			break;

	case IB_CM_RTU_RECEIVED:
			retc = rtu_handler(cm_idp, eventp);
			break;

	case IB_CM_DREQ_RECEIVED:
			xlog(INFO3, "ib_send_cm_drep");
			retc = ib_send_cm_drep(cm_idp, NULL, 0);
			if (retc) {
				xlog(ERROR, "ib_send_cm_rtu() failed with "
						"error %d", retc);
			}

			free_ib();
			break;

	case IB_CM_DREP_RECEIVED:
			xtd_device.conn_state = DISCONNECTED;
			xlog(INFO4, "drep received, wakeup sleeping task");
			wake_up(&xtd_device.waitq);
			break;

	case IB_CM_REQ_ERROR:
			xlog(ERROR, "xtd_cm_handler(IB_CM_REQ_ERROR) event "
					"not processed", eventp->event);
			break;

	default:
			xlog(ERROR, "xtd_cm_handler(%d) event not processed",
							eventp->event);
			break;
	}

	return 0;
}

static int
setrole_secondary(void)
{
	int	retc;

	xlog(INFO3, "ib_create_cm_id");
	xtd_device.listen_idp = ib_create_cm_id(xtd_device.hcap,
							xtd_cm_handler, NULL);
	if (IS_ERR(xtd_device.listen_idp)) {
		retc = PTR_ERR(xtd_device.listen_idp);
		xlog(ERROR, "ib_create_cm_id(listen) failed with error %lld",
									retc);
		xtd_device.listen_idp = NULL;
		free_ib();
		return retc;
	}

	xlog(INFO3, "ib_cm_listen");
	retc = ib_cm_listen(xtd_device.listen_idp,
			__constant_cpu_to_be64(SERVICE_ID), 0, NULL);
	if (retc) {
		xlog(ERROR, "ib_cm_listen() failed with retc %d", retc);
	}

	xlog(INFO3, "listening ...");
	return retc;
}

static int
init_ib(int role)
{
	struct ib_qp_init_attr	qp_attr;
	int			retc;

	retc = find_active_port(xtd_device.hcap);
	if (retc) {
		xlog(WARN, "xtd_add_one: no active port found, "
				"defaulting to port 1");
		xtd_device.port = 1;
	}

	xlog(INFO3, "ib_alloc_pd");
	xtd_device.pdp = ib_alloc_pd(xtd_device.hcap);
	if (IS_ERR(xtd_device.pdp)) {
		retc = PTR_ERR(xtd_device.pdp);
		xlog(ERROR, "ib_alloc_pd() failed with error %d", retc);
		xtd_device.pdp = NULL;
		return retc;
	}

	xlog(INFO3, "ib_create_cm_id");
	xtd_device.cm_idp = ib_create_cm_id(xtd_device.hcap,
							xtd_cm_handler, NULL);
	if (IS_ERR(xtd_device.cm_idp)) {
		retc = PTR_ERR(xtd_device.cm_idp);
		xlog(ERROR, "ib_create_cm_id() failed with error %lld", retc);
		xtd_device.cm_idp = NULL;
		free_ib();
		return retc;
	}

	xlog(INFO3, "ib_create_cq");
	xtd_device.cqp = ib_create_cq(xtd_device.hcap,
				xtd_completion_handler,
				xtd_completion_event_handler,
				NULL, MAX_CQ_SIZE);
	if (IS_ERR(xtd_device.cqp)) {
		retc = PTR_ERR(xtd_device.cqp);
		xlog(ERROR, "ib_create_cq() failed with error %d", retc);
		xtd_device.cqp = NULL;
		free_ib();
		return retc;
	}

	xtd_device.cq_size = xtd_device.cqp->cqe;
	xlog(INFO3, "ib_req_notify_cq");
	retc = ib_req_notify_cq(xtd_device.cqp, IB_CQ_NEXT_COMP);
	if (retc != 0) {
		xlog(ERROR, "ib_req_notify_cq() failed with error %d", retc);
		free_ib();
		return retc;
	}

	memset(&qp_attr, 0, sizeof qp_attr);
	qp_attr.event_handler = xtd_qp_event_handler;
	qp_attr.cap.max_send_wr = MAX_SEND_WR;
	qp_attr.cap.max_recv_wr = MAX_RECV_WR;
	qp_attr.cap.max_send_sge = 1;
	qp_attr.cap.max_recv_sge = 1;
	qp_attr.sq_sig_type = IB_SIGNAL_ALL_WR;
	qp_attr.qp_type = IB_QPT_RC;
	qp_attr.send_cq = xtd_device.cqp;
	qp_attr.recv_cq = xtd_device.cqp;

	xlog(INFO3, "ib_create_qp");
	xtd_device.qpp = ib_create_qp(xtd_device.pdp, &qp_attr);
	if (IS_ERR(xtd_device.qpp)) {
		retc = PTR_ERR(xtd_device.qpp);
		xlog(ERROR, "ib_create_qp() failed with error %d", retc);
		xtd_device.qpp = NULL;
		free_ib();
		return retc;
	}

	xtd_device.conn_state = INIT;
	init_waitqueue_head(&xtd_device.waitq);

	if (role == SECONDARY) {
		retc = setrole_secondary();
	}

	return retc;
}

int
xtd_proc_write(struct file *file, const char *buffer,
		unsigned long length, void *data)
{
	char		command[MAX_BUFFER];
	int		retc = 0;

	if (length > MAX_BUFFER) {
		xlog(ERROR, "user buffer overflow when writing to proc");
		return -EINVAL;
	}

	if (! buffer) {
		xlog(ERROR, "user buffer was null when writing to proc");
		return -EINVAL;
	}

	memset(&command, 0, sizeof command);
	retc = copy_from_user(&command, buffer, length);
	if (retc) {
		xlog(ERROR, "copy_from_user() failed");
		return retc;
	}

	xlog(INFO1, "%s", command);
	if (strncmp("set primary", command, 11) == 0) {
		xtd_device.slid = simple_strtoul(&command[12], NULL, 16);
		retc = init_ib(PRIMARY);
		return length;
	}

	if (strncmp("set secondary", command, 13) == 0) {
		xtd_device.slid = simple_strtoul(&command[14], NULL, 16);
		retc = init_ib(SECONDARY);
		return length;
	}

	if (strncmp("connect", command, 7) == 0) {
		xtd_device.dlid = simple_strtoul(&command[8], NULL, 16);
		retc = connect();
		return length;
	}

	if (strncmp("disconnect", command, 10) == 0) {
		retc = disconnect();
		return length;
	}

	return length;
}

static int
clean_procfs(void)
{
	if (xtd_procfile) {
		remove_proc_entry(PROCDIR"/"PROCFILE, NULL);
		xtd_procfile = NULL;
	}

	if (xtd_procdir) {
		remove_proc_entry(PROCDIR, NULL);
		xtd_procdir = NULL;
	}

	return 0;
}

static int
make_procfs(void)
{
	int	error = 0;

	xtd_procdir = proc_mkdir(PROCDIR, NULL);
	if (! xtd_procdir) {
		xlog(ERROR, "proc_mkdir(%s) failed", PROCDIR);
		error = -ENOMEM;
		goto err_out;
	}

	xtd_procfile = create_proc_entry(PROCFILE,
					0644, xtd_procdir);
	if (! xtd_procfile) {
		xlog(ERROR, "create_proc_entry(%s) failed",
					PROCDIR"/"PROCFILE);
		error = -ENOMEM;
		clean_procfs();
		goto err_out;
	}

	xtd_procfile->owner = THIS_MODULE;
	xtd_procfile->write_proc = xtd_proc_write;

err_out:
	return error;
}

static void
xtd_remove_one(struct ib_device *devicep)
{
	memset(&xtd_device, 0, sizeof (xtd_device));
	return;
}

static void
xtd_add_one(struct ib_device *devicep)
{
	int	type;

	type = rdma_node_get_transport(devicep->node_type);
	if (type != RDMA_TRANSPORT_IB) {
		xlog(ERROR, "transport is not RDMA_TRANSPORT_IB, returned %d",
									type);
		return;
	}

	memset(&xtd_device, 0, sizeof (xtd_device));
	xtd_device.hcap = devicep;
	return;
}

static int __init
xtd_init(void)
{
	int	retc;

	retc = make_procfs();
	if (retc) {
		return retc;
	}

	xlog(INFO3, "ib_register_client");
	retc = ib_register_client(&xtd_client);
	if (retc) {
		xlog(ERROR, "ib_register_client failed with retc=%d",
				retc);
		clean_procfs();
		return retc;
	}

	return retc;
}

static void __exit
xtd_exit(void)
{
	free_ib();
	xlog(INFO3, "ib_unregister_client");
	ib_unregister_client(&xtd_client);
	clean_procfs();
	return;
}

module_init(xtd_init);
module_exit(xtd_exit);





More information about the general mailing list