blob: a638c296fd19abd11c320f15c9ae03b8ff5597da [file] [log] [blame]
/*
* This file is part of iser target kernel module.
*
* Copyright (c) 2013 - 2014 Mellanox Technologies. All rights reserved.
* Copyright (c) 2013 - 2014 Yan Burman (yanb@mellanox.com)
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __ISER_H__
#define __ISER_H__
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <rdma/ib_verbs.h>
#ifndef INSIDE_KERNEL_TREE
#include <linux/version.h>
#endif
#if defined(RHEL_MAJOR) && RHEL_MAJOR -0 == 5
static inline u16 vlan_dev_vlan_id(const void *dev)
{
BUG();
return 0;
}
#endif
#include <rdma/rdma_cm.h>
#include "iser_hdr.h"
enum isert_portal_state {
ISERT_PORTAL_ACTIVE,
ISERT_PORTAL_INACTIVE
};
struct isert_portal {
struct rdma_cm_id *cm_id;
struct sockaddr_storage addr;
struct list_head list_node; /* in portals list */
/* protected by dev_list_mutex */
struct list_head conn_list; /* head of conns list */
enum isert_portal_state state;
int refcnt;
};
struct isert_buf {
int sg_cnt ____cacheline_aligned;
struct scatterlist *sg;
u8 *addr;
size_t size;
enum dma_data_direction dma_dir;
unsigned int is_alloced:1;
unsigned int is_pgalloced:1;
unsigned int is_malloced:1;
};
enum isert_wr_op {
ISER_WR_RECV,
ISER_WR_SEND,
ISER_WR_RDMA_WRITE,
ISER_WR_RDMA_READ,
};
struct isert_device;
struct isert_connection;
struct isert_wr {
enum isert_wr_op wr_op;
struct isert_buf *buf;
struct isert_connection *conn;
struct isert_cmnd *pdu;
struct isert_device *isert_dev;
struct ib_sge *sge_list;
union {
struct ib_recv_wr recv_wr;
#ifdef USE_PRE_440_WR_STRUCTURE
struct ib_send_wr send_wr;
#else
struct ib_rdma_wr send_wr;
#endif
};
} ____cacheline_aligned;
#define ISER_SQ_SIZE 128
#define ISER_MAX_WCE 2048
#define ISER_MIN_SQ_SIZE 16
struct isert_cmnd {
struct iscsi_cmnd iscsi ____cacheline_aligned;
struct isert_buf buf;
struct isert_buf rdma_buf;
struct isert_wr *wr;
struct ib_sge *sg_pool;
int n_wr;
int n_sge;
struct isert_hdr *isert_hdr ____cacheline_aligned;
struct iscsi_hdr *bhs;
void *ahs;
void *data;
u8 isert_opcode;
u8 iscsi_opcode;
u8 is_rstag_valid;
u8 is_wstag_valid;
u32 rem_write_stag; /* write rkey */
u64 rem_write_va;
u32 rem_read_stag; /* read rkey */
u64 rem_read_va;
int is_fake_rx;
struct list_head pool_node; /* pool list */
};
enum isert_conn_state {
ISER_CONN_INIT = 0,
ISER_CONN_HANDSHAKE,
ISER_CONN_ACTIVE,
ISER_CONN_CLOSING,
};
struct isert_cq {
struct ib_cq *cq ____cacheline_aligned;
struct ib_wc wc[ISER_SQ_SIZE];
struct isert_device *dev;
struct workqueue_struct *cq_workqueue;
struct work_struct cq_comp_work;
int idx;
};
#define ISERT_CONNECTION_ABORTED 0
#define ISERT_DRAIN_POSTED 1
#define ISERT_DISCON_CALLED 2
#define ISERT_DRAINED_RQ 3
#define ISERT_DRAINED_SQ 4
#define ISERT_CONNECTION_CLOSE 5
#define ISERT_IN_PORTAL_LIST 6
struct isert_connection {
struct iscsi_conn iscsi ____cacheline_aligned;
int repost_threshold ____cacheline_aligned;
/* access to the following 3 fields is guarded by post_recv_lock */
int to_post_recv;
struct isert_wr *post_recv_first;
struct isert_wr *post_recv_curr;
spinlock_t post_recv_lock;
spinlock_t tx_lock ____cacheline_aligned;
/* Following two protected by tx_lock */
struct list_head tx_free_list;
struct list_head tx_busy_list;
struct rdma_cm_id *cm_id;
struct isert_device *isert_dev;
struct ib_qp *qp;
struct isert_cq *cq_desc;
enum isert_conn_state state;
struct mutex state_mutex;
u32 responder_resources;
u32 initiator_depth;
u32 max_sge;
/*
* Unprotected. Accessed only before login response is sent and when
* freeing connection
*/
struct list_head rx_buf_list;
struct isert_cmnd *login_req_pdu;
struct isert_cmnd *login_rsp_pdu;
struct isert_wr *saved_wr;
int queue_depth;
int immediate_data;
unsigned int target_recv_data_length;
int initiator_recv_data_length;
int initial_r2t;
unsigned int first_burst_length;
struct sockaddr_storage peer_addr;
size_t peer_addrsz;
struct sockaddr_storage self_addr;
struct list_head portal_node;
unsigned long flags;
struct work_struct close_work;
struct work_struct drain_work;
struct work_struct discon_work;
struct work_struct free_work;
struct isert_wr drain_wr_sq;
struct isert_wr drain_wr_rq;
struct kref kref;
struct isert_portal *portal;
void *priv_data; /* for connection tracking */
};
struct isert_device {
struct ib_device *ib_dev;
struct ib_pd *pd;
#ifndef IB_PD_HAS_LOCAL_DMA_LKEY
struct ib_mr *mr;
#endif
u32 lkey;
struct list_head devs_node;
/* conn_list and refcnt protected by dev_list_mutex */
struct list_head conn_list;
int refcnt;
struct ib_device_attr device_attr;
int num_cqs;
int *cq_qps;
struct isert_cq *cq_desc;
};
struct isert_global {
spinlock_t portal_lock;
/* protected by portal_lock */
struct list_head portal_list;
/* Number of live portal objects. Protected by portal_lock. */
int portal_cnt;
wait_queue_head_t portal_wq;
/* protected by dev_list_mutex */
struct list_head dev_list;
struct workqueue_struct *conn_wq;
};
#define _ptr_to_u64(p) (u64)(unsigned long)(p)
#define _u64_to_ptr(v) (void *)(unsigned long)(v)
/* global iser scope */
int isert_global_init(void);
int isert_datamover_cleanup(void);
void isert_portal_list_add(struct isert_portal *portal);
void isert_portal_list_remove(struct isert_portal *portal);
void isert_decrease_portal_cnt(void);
void isert_wait_for_portal_release(void);
void isert_dev_list_add(struct isert_device *isert_dev);
void isert_dev_list_remove(struct isert_device *isert_dev);
struct isert_device *isert_device_find(struct ib_device *ib_dev);
void isert_conn_queue_work(struct work_struct *w);
extern struct kmem_cache *isert_cmnd_cache;
extern struct kmem_cache *isert_conn_cache;
/* iser portal */
struct isert_portal *isert_portal_create(void);
int isert_portal_listen(struct isert_portal *portal,
struct sockaddr *sa,
size_t addr_len);
void isert_portal_release(struct isert_portal *portal);
void isert_portal_list_release_all(void);
struct isert_portal *isert_portal_start(struct sockaddr *sa, size_t addr_len);
/* iser connection */
int isert_post_recv(struct isert_connection *isert_conn,
struct isert_wr *first_wr, int num_wr);
int isert_post_send(struct isert_connection *isert_conn,
struct isert_wr *first_wr, int num_wr);
int isert_alloc_conn_resources(struct isert_connection *isert_conn);
void isert_free_conn_resources(struct isert_connection *isert_conn);
void isert_conn_free(struct isert_connection *isert_conn);
void isert_conn_disconnect(struct isert_connection *isert_conn);
void isert_post_drain(struct isert_connection *isert_conn);
void isert_sched_conn_free(struct isert_connection *isert_conn);
static inline struct isert_connection *isert_conn_zalloc(void)
{
return kmem_cache_zalloc(isert_conn_cache, GFP_KERNEL);
}
static inline void isert_conn_kfree(struct isert_connection *isert_conn)
{
kmem_cache_free(isert_conn_cache, isert_conn);
}
/* iser buf */
int isert_buf_alloc_data_buf(struct ib_device *ib_dev,
struct isert_buf *isert_buf, size_t size,
enum dma_data_direction dma_dir);
void isert_wr_set_fields(struct isert_wr *wr,
struct isert_connection *isert_conn,
struct isert_cmnd *pdu);
int isert_wr_init(struct isert_wr *wr,
enum isert_wr_op wr_op,
struct isert_buf *isert_buf,
struct isert_connection *isert_conn,
struct isert_cmnd *pdu,
struct ib_sge *sge,
int sg_offset,
int sg_cnt,
int buff_offset);
void isert_wr_release(struct isert_wr *wr);
void isert_buf_release(struct isert_buf *isert_buf);
static inline void isert_buf_init_sg(struct isert_buf *isert_buf,
struct scatterlist *sg,
int sg_cnt, size_t size)
{
isert_buf->sg_cnt = sg_cnt;
isert_buf->sg = sg;
isert_buf->size = size;
}
/* iser pdu */
static inline struct isert_cmnd *isert_pdu_alloc(void)
{
return kmem_cache_zalloc(isert_cmnd_cache, GFP_KERNEL);
}
static inline void isert_pdu_kfree(struct isert_cmnd *cmnd)
{
kmem_cache_free(isert_cmnd_cache, cmnd);
}
struct isert_cmnd *isert_rx_pdu_alloc(struct isert_connection *isert_conn,
size_t size);
struct isert_cmnd *isert_tx_pdu_alloc(struct isert_connection *isert_conn,
size_t size);
void isert_tx_pdu_init(struct isert_cmnd *isert_pdu,
struct isert_connection *isert_conn);
int isert_pdu_send(struct isert_connection *isert_conn,
struct isert_cmnd *tx_pdu);
int isert_prepare_rdma(struct isert_cmnd *isert_pdu,
struct isert_connection *isert_conn,
enum isert_wr_op op);
int isert_pdu_post_rdma_write(struct isert_connection *isert_conn,
struct isert_cmnd *isert_cmd,
struct isert_cmnd *isert_rsp,
int wr_cnt);
int isert_pdu_post_rdma_read(struct isert_connection *isert_conn,
struct isert_cmnd *isert_cmd,
int wr_cnt);
void isert_pdu_free(struct isert_cmnd *pdu);
int isert_rx_pdu_done(struct isert_cmnd *pdu);
void isert_tx_pdu_convert_from_iscsi(struct isert_cmnd *isert_cmnd,
struct iscsi_cmnd *iscsi_cmnd);
void isert_tx_pdu_init_iscsi(struct isert_cmnd *isert_pdu);
/* global */
void isert_global_cleanup(void);
int isert_get_addr_size(struct sockaddr *sa, size_t *size);
#endif