[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