mirror of
https://github.com/SCST-project/scst.git
synced 2026-09-26 01:44:54 +00:00
Merge r5663 from 3.0.x-iser branch
git-svn-id: http://svn.code.sf.net/p/scst/svn/branches/3.0.x@6239 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
@@ -37,5 +37,6 @@ EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG -g -fno-inline -fno-inline-functions
|
||||
|
||||
obj-m += iscsi-scst.o
|
||||
iscsi-scst-objs := iscsi.o nthread.o config.o digest.o \
|
||||
conn.o session.o target.o event.o param.o
|
||||
conn.o session.o target.o event.o param.o \
|
||||
iscsit_transport.o
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "iscsi.h"
|
||||
#include "digest.h"
|
||||
#include "iscsit_transport.h"
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
|
||||
#if defined(CONFIG_LOCKDEP) && !defined(CONFIG_SCST_PROC)
|
||||
@@ -273,7 +274,7 @@ static void conn_sysfs_del(struct iscsi_conn *conn)
|
||||
return;
|
||||
}
|
||||
|
||||
static int conn_sysfs_add(struct iscsi_conn *conn)
|
||||
int conn_sysfs_add(struct iscsi_conn *conn)
|
||||
{
|
||||
int res;
|
||||
struct iscsi_session *session = conn->session;
|
||||
@@ -345,6 +346,7 @@ out_err:
|
||||
conn_sysfs_del(conn);
|
||||
goto out;
|
||||
}
|
||||
EXPORT_SYMBOL(conn_sysfs_add);
|
||||
|
||||
#endif /* CONFIG_SCST_PROC */
|
||||
|
||||
@@ -429,7 +431,7 @@ void iscsi_make_conn_wr_active(struct iscsi_conn *conn)
|
||||
return;
|
||||
}
|
||||
|
||||
void __mark_conn_closed(struct iscsi_conn *conn, int flags)
|
||||
void iscsi_tcp_mark_conn_closed(struct iscsi_conn *conn, int flags)
|
||||
{
|
||||
spin_lock_bh(&conn->conn_thr_pool->rd_lock);
|
||||
conn->closing = 1;
|
||||
@@ -442,10 +444,16 @@ void __mark_conn_closed(struct iscsi_conn *conn, int flags)
|
||||
iscsi_make_conn_rd_active(conn);
|
||||
}
|
||||
|
||||
void __mark_conn_closed(struct iscsi_conn *conn, int flags)
|
||||
{
|
||||
conn->transport->iscsit_mark_conn_closed(conn, flags);
|
||||
}
|
||||
|
||||
void mark_conn_closed(struct iscsi_conn *conn)
|
||||
{
|
||||
__mark_conn_closed(conn, ISCSI_CONN_ACTIVE_CLOSE);
|
||||
}
|
||||
EXPORT_SYMBOL(mark_conn_closed);
|
||||
|
||||
static void __iscsi_state_change(struct sock *sk)
|
||||
{
|
||||
@@ -752,7 +760,7 @@ void conn_reinst_finished(struct iscsi_conn *conn)
|
||||
return;
|
||||
}
|
||||
|
||||
static void conn_activate(struct iscsi_conn *conn)
|
||||
int conn_activate(struct iscsi_conn *conn)
|
||||
{
|
||||
TRACE_MGMT_DBG("Enabling conn %p", conn);
|
||||
|
||||
@@ -778,7 +786,7 @@ static void conn_activate(struct iscsi_conn *conn)
|
||||
*/
|
||||
__iscsi_state_change(conn->sock->sk);
|
||||
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -820,8 +828,19 @@ out:
|
||||
return res;
|
||||
}
|
||||
|
||||
void iscsi_tcp_conn_free(struct iscsi_conn *conn)
|
||||
{
|
||||
fput(conn->file);
|
||||
conn->file = NULL;
|
||||
conn->sock = NULL;
|
||||
|
||||
free_page((unsigned long)conn->read_iov);
|
||||
|
||||
kmem_cache_free(iscsi_conn_cache, conn);
|
||||
}
|
||||
|
||||
/* target_mutex supposed to be locked */
|
||||
int conn_free(struct iscsi_conn *conn)
|
||||
void conn_free(struct iscsi_conn *conn)
|
||||
{
|
||||
struct iscsi_session *session = conn->session;
|
||||
|
||||
@@ -915,7 +934,7 @@ static int iscsi_conn_alloc(struct iscsi_session *session,
|
||||
conn->ddigest_type = session->sess_params.data_digest;
|
||||
res = digest_init(conn);
|
||||
if (res != 0)
|
||||
goto out_free_iov;
|
||||
return res;
|
||||
|
||||
conn->target = session->target;
|
||||
spin_lock_init(&conn->cmd_list_lock);
|
||||
@@ -950,6 +969,44 @@ static int iscsi_conn_alloc(struct iscsi_session *session,
|
||||
conn->nop_in_interval + ISCSI_ADD_SCHED_TIME);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(iscsi_init_conn);
|
||||
|
||||
/* target_mutex supposed to be locked */
|
||||
int iscsi_conn_alloc(struct iscsi_session *session,
|
||||
struct iscsi_kern_conn_info *info, struct iscsi_conn **new_conn,
|
||||
struct iscsit_transport *t)
|
||||
{
|
||||
struct iscsi_conn *conn;
|
||||
int res = 0;
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
|
||||
lockdep_assert_held(&session->target->target_mutex);
|
||||
#endif
|
||||
|
||||
conn = kmem_cache_zalloc(iscsi_conn_cache, GFP_KERNEL);
|
||||
if (!conn) {
|
||||
res = -ENOMEM;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
TRACE_MGMT_DBG("Creating connection %p for sid %#Lx, cid %u", conn,
|
||||
(long long unsigned int)session->sid, info->cid);
|
||||
|
||||
conn->transport = t;
|
||||
|
||||
/* Changing it, change ISCSI_CONN_IOV_MAX as well !! */
|
||||
conn->read_iov = (struct iovec *)get_zeroed_page(GFP_KERNEL);
|
||||
if (conn->read_iov == NULL) {
|
||||
res = -ENOMEM;
|
||||
goto out_err_free_conn;
|
||||
}
|
||||
|
||||
res = iscsi_init_conn(session, info, conn);
|
||||
if (res != 0)
|
||||
goto out_free_iov;
|
||||
|
||||
conn->file = fget(info->fd);
|
||||
|
||||
res = conn_setup_sock(conn);
|
||||
@@ -988,6 +1045,7 @@ int __add_conn(struct iscsi_session *session, struct iscsi_kern_conn_info *info)
|
||||
struct iscsi_conn *conn, *new_conn = NULL;
|
||||
int err;
|
||||
bool reinstatement = false;
|
||||
struct iscsit_transport *t;
|
||||
|
||||
lockdep_assert_held(&session->target->target_mutex);
|
||||
|
||||
@@ -1001,7 +1059,16 @@ int __add_conn(struct iscsi_session *session, struct iscsi_kern_conn_info *info)
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = iscsi_conn_alloc(session, info, &new_conn);
|
||||
if (session->sess_params.rdma_extensions)
|
||||
t = iscsit_get_transport(ISCSI_RDMA);
|
||||
else
|
||||
t = iscsit_get_transport(ISCSI_TCP);
|
||||
if (!t) {
|
||||
err = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = t->iscsit_conn_alloc(session, info, &new_conn, t);
|
||||
if (err != 0)
|
||||
goto out;
|
||||
|
||||
@@ -1013,7 +1080,7 @@ int __add_conn(struct iscsi_session *session, struct iscsi_kern_conn_info *info)
|
||||
__mark_conn_closed(conn, 0);
|
||||
}
|
||||
|
||||
conn_activate(new_conn);
|
||||
err = t->iscsit_conn_activate(new_conn);
|
||||
|
||||
out:
|
||||
return err;
|
||||
|
||||
+304
-158
@@ -26,6 +26,7 @@
|
||||
|
||||
#include "iscsi.h"
|
||||
#include "digest.h"
|
||||
#include "iscsit_transport.h"
|
||||
|
||||
#ifndef GENERATING_UPSTREAM_PATCH
|
||||
#if !defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
|
||||
@@ -64,11 +65,9 @@ static void cmnd_remove_data_wait_hash(struct iscsi_cmnd *cmnd);
|
||||
static void iscsi_send_task_mgmt_resp(struct iscsi_cmnd *req, int status,
|
||||
bool dropped);
|
||||
static void iscsi_check_send_delayed_tm_resp(struct iscsi_session *sess);
|
||||
static void req_cmnd_release(struct iscsi_cmnd *req);
|
||||
static int cmnd_insert_data_wait_hash(struct iscsi_cmnd *cmnd);
|
||||
static void iscsi_cmnd_init_write(struct iscsi_cmnd *rsp, int flags);
|
||||
static void iscsi_set_resid_no_scst_cmd(struct iscsi_cmnd *rsp);
|
||||
static void iscsi_set_resid(struct iscsi_cmnd *rsp);
|
||||
|
||||
static void iscsi_set_not_received_data_len(struct iscsi_cmnd *req,
|
||||
unsigned int not_received)
|
||||
@@ -242,7 +241,7 @@ static struct iscsi_cmnd *iscsi_create_tm_clone(struct iscsi_cmnd *cmnd)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
tm_clone = cmnd_alloc(cmnd->conn, NULL);
|
||||
tm_clone = cmnd->conn->transport->iscsit_alloc_cmd(cmnd->conn, NULL);
|
||||
if (tm_clone != NULL) {
|
||||
set_bit(ISCSI_CMD_ABORTED, &tm_clone->prelim_compl_flags);
|
||||
tm_clone->pdu = cmnd->pdu;
|
||||
@@ -309,14 +308,9 @@ void iscsi_fail_data_waiting_cmnd(struct iscsi_cmnd *cmnd)
|
||||
return;
|
||||
}
|
||||
|
||||
struct iscsi_cmnd *cmnd_alloc(struct iscsi_conn *conn,
|
||||
struct iscsi_cmnd *parent)
|
||||
void iscsi_cmnd_init(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd,
|
||||
struct iscsi_cmnd *parent)
|
||||
{
|
||||
struct iscsi_cmnd *cmnd;
|
||||
|
||||
/* ToDo: __GFP_NOFAIL?? */
|
||||
cmnd = kmem_cache_zalloc(iscsi_cmnd_cache, GFP_KERNEL|__GFP_NOFAIL);
|
||||
|
||||
atomic_set(&cmnd->ref_cnt, 1);
|
||||
cmnd->scst_state = ISCSI_CMD_STATE_NEW;
|
||||
cmnd->conn = conn;
|
||||
@@ -325,9 +319,6 @@ struct iscsi_cmnd *cmnd_alloc(struct iscsi_conn *conn,
|
||||
if (parent == NULL) {
|
||||
conn_get(conn);
|
||||
|
||||
#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
|
||||
atomic_set(&cmnd->net_ref_cnt, 0);
|
||||
#endif
|
||||
INIT_LIST_HEAD(&cmnd->rsp_cmd_list);
|
||||
INIT_LIST_HEAD(&cmnd->rx_ddigest_cmd_list);
|
||||
cmnd->target_task_tag = ISCSI_RESERVED_TAG_CPU32;
|
||||
@@ -336,6 +327,24 @@ struct iscsi_cmnd *cmnd_alloc(struct iscsi_conn *conn,
|
||||
list_add_tail(&cmnd->cmd_list_entry, &conn->cmd_list);
|
||||
spin_unlock_bh(&conn->cmd_list_lock);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(iscsi_cmnd_init);
|
||||
|
||||
struct iscsi_cmnd *cmnd_alloc(struct iscsi_conn *conn,
|
||||
struct iscsi_cmnd *parent)
|
||||
{
|
||||
struct iscsi_cmnd *cmnd;
|
||||
|
||||
/* ToDo: __GFP_NOFAIL?? */
|
||||
cmnd = kmem_cache_zalloc(iscsi_cmnd_cache, GFP_KERNEL|__GFP_NOFAIL);
|
||||
|
||||
iscsi_cmnd_init(conn, cmnd, parent);
|
||||
|
||||
if (parent == NULL) {
|
||||
#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
|
||||
atomic_set(&cmnd->net_ref_cnt, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
TRACE_DBG("conn %p, parent %p, cmnd %p", conn, parent, cmnd);
|
||||
return cmnd;
|
||||
@@ -496,10 +505,10 @@ void cmnd_done(struct iscsi_cmnd *cmnd)
|
||||
|
||||
list_for_each_entry_safe(rsp, t, &cmnd->rsp_cmd_list,
|
||||
rsp_cmd_list_entry) {
|
||||
cmnd_free(rsp);
|
||||
cmnd->conn->transport->iscsit_free_cmd(rsp);
|
||||
}
|
||||
|
||||
cmnd_free(cmnd);
|
||||
cmnd->conn->transport->iscsit_free_cmd(cmnd);
|
||||
} else {
|
||||
struct iscsi_cmnd *parent = cmnd->parent_req;
|
||||
|
||||
@@ -532,6 +541,7 @@ void cmnd_done(struct iscsi_cmnd *cmnd)
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(cmnd_done);
|
||||
|
||||
/*
|
||||
* Corresponding conn may also get destroyed after this function, except only
|
||||
@@ -634,7 +644,7 @@ out:
|
||||
return;
|
||||
}
|
||||
|
||||
static void req_cmnd_pre_release(struct iscsi_cmnd *req)
|
||||
void req_cmnd_pre_release(struct iscsi_cmnd *req)
|
||||
{
|
||||
struct iscsi_cmnd *c, *t;
|
||||
|
||||
@@ -694,12 +704,13 @@ static void req_cmnd_pre_release(struct iscsi_cmnd *req)
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(req_cmnd_pre_release);
|
||||
|
||||
/*
|
||||
* Corresponding conn may also get destroyed after this function, except only
|
||||
* if it's called from the read thread!
|
||||
*/
|
||||
static void req_cmnd_release(struct iscsi_cmnd *req)
|
||||
void req_cmnd_release(struct iscsi_cmnd *req)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
@@ -709,6 +720,7 @@ static void req_cmnd_release(struct iscsi_cmnd *req)
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(req_cmnd_release);
|
||||
|
||||
/*
|
||||
* Corresponding conn may also get destroyed after this function, except only
|
||||
@@ -728,6 +740,7 @@ void rsp_cmnd_release(struct iscsi_cmnd *cmnd)
|
||||
cmnd_put(cmnd);
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(rsp_cmnd_release);
|
||||
|
||||
static struct iscsi_cmnd *iscsi_alloc_rsp(struct iscsi_cmnd *parent)
|
||||
{
|
||||
@@ -735,7 +748,7 @@ static struct iscsi_cmnd *iscsi_alloc_rsp(struct iscsi_cmnd *parent)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
rsp = cmnd_alloc(parent->conn, parent);
|
||||
rsp = parent->conn->transport->iscsit_alloc_cmd(parent->conn, parent);
|
||||
|
||||
TRACE_DBG("Adding rsp %p to parent %p", rsp, parent);
|
||||
list_add_tail(&rsp->rsp_cmd_list_entry, &parent->rsp_cmd_list);
|
||||
@@ -797,7 +810,7 @@ static void iscsi_cmnds_init_write(struct list_head *send, int flags)
|
||||
spin_unlock_bh(&conn->write_list_lock);
|
||||
|
||||
if (flags & ISCSI_INIT_WRITE_WAKE)
|
||||
iscsi_make_conn_wr_active(conn);
|
||||
conn->transport->iscsit_make_conn_wr_active(conn);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -876,7 +889,7 @@ static void iscsi_set_resid_no_scst_cmd(struct iscsi_cmnd *rsp)
|
||||
return;
|
||||
}
|
||||
|
||||
static void iscsi_set_resid(struct iscsi_cmnd *rsp)
|
||||
void iscsi_set_resid(struct iscsi_cmnd *rsp)
|
||||
{
|
||||
struct iscsi_cmnd *req = rsp->parent_req;
|
||||
struct scst_cmd *scst_cmd = req->scst_cmd;
|
||||
@@ -930,6 +943,7 @@ out:
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(iscsi_set_resid);
|
||||
|
||||
static void send_data_rsp(struct iscsi_cmnd *req, u8 status, int send_status)
|
||||
{
|
||||
@@ -992,12 +1006,25 @@ static void send_data_rsp(struct iscsi_cmnd *req, u8 status, int send_status)
|
||||
return;
|
||||
}
|
||||
|
||||
static void iscsi_tcp_set_sense_data(struct iscsi_cmnd *rsp,
|
||||
const u8 *sense_buf, int sense_len)
|
||||
{
|
||||
struct scatterlist *sg;
|
||||
|
||||
sg = rsp->sg = rsp->rsp_sg;
|
||||
rsp->sg_cnt = 2;
|
||||
rsp->own_sg = 1;
|
||||
|
||||
sg_init_table(sg, 2);
|
||||
sg_set_buf(&sg[0], &rsp->sense_hdr, sizeof(rsp->sense_hdr));
|
||||
sg_set_buf(&sg[1], sense_buf, sense_len);
|
||||
}
|
||||
|
||||
static void iscsi_init_status_rsp(struct iscsi_cmnd *rsp,
|
||||
int status, const u8 *sense_buf, int sense_len)
|
||||
{
|
||||
struct iscsi_cmnd *req = rsp->parent_req;
|
||||
struct iscsi_scsi_rsp_hdr *rsp_hdr;
|
||||
struct scatterlist *sg;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
@@ -1011,16 +1038,11 @@ static void iscsi_init_status_rsp(struct iscsi_cmnd *rsp,
|
||||
if (scst_sense_valid(sense_buf)) {
|
||||
TRACE_DBG("%s", "SENSE VALID");
|
||||
|
||||
sg = rsp->sg = rsp->rsp_sg;
|
||||
rsp->sg_cnt = 2;
|
||||
rsp->own_sg = 1;
|
||||
|
||||
sg_init_table(sg, 2);
|
||||
sg_set_buf(&sg[0], &rsp->sense_hdr, sizeof(rsp->sense_hdr));
|
||||
sg_set_buf(&sg[1], sense_buf, sense_len);
|
||||
|
||||
rsp->sense_hdr.length = cpu_to_be16(sense_len);
|
||||
|
||||
rsp->conn->transport->iscsit_set_sense_data(rsp, sense_buf,
|
||||
sense_len);
|
||||
|
||||
rsp->pdu.datasize = sizeof(rsp->sense_hdr) + sense_len;
|
||||
rsp->bufflen = rsp->pdu.datasize;
|
||||
} else {
|
||||
@@ -1032,7 +1054,7 @@ static void iscsi_init_status_rsp(struct iscsi_cmnd *rsp,
|
||||
return;
|
||||
}
|
||||
|
||||
static inline struct iscsi_cmnd *create_status_rsp(struct iscsi_cmnd *req,
|
||||
struct iscsi_cmnd *create_status_rsp(struct iscsi_cmnd *req,
|
||||
int status, const u8 *sense_buf, int sense_len)
|
||||
{
|
||||
struct iscsi_cmnd *rsp;
|
||||
@@ -1048,6 +1070,26 @@ static inline struct iscsi_cmnd *create_status_rsp(struct iscsi_cmnd *req,
|
||||
TRACE_EXIT_HRES((unsigned long)rsp);
|
||||
return rsp;
|
||||
}
|
||||
EXPORT_SYMBOL(create_status_rsp);
|
||||
|
||||
static void iscsi_tcp_send_data_rsp(struct iscsi_cmnd *req, u8 *sense,
|
||||
int sense_len, u8 status,
|
||||
int is_send_status)
|
||||
{
|
||||
if ((status != SAM_STAT_CHECK_CONDITION) &&
|
||||
((cmnd_hdr(req)->flags & (ISCSI_CMD_WRITE|ISCSI_CMD_READ)) !=
|
||||
(ISCSI_CMD_WRITE|ISCSI_CMD_READ))) {
|
||||
send_data_rsp(req, status, is_send_status);
|
||||
} else {
|
||||
struct iscsi_cmnd *rsp;
|
||||
send_data_rsp(req, 0, 0);
|
||||
if (is_send_status) {
|
||||
rsp = create_status_rsp(req, status, sense,
|
||||
sense_len);
|
||||
iscsi_cmnd_init_write(rsp, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initializes data receive fields. Can be called only when they have not been
|
||||
@@ -1224,7 +1266,7 @@ static inline int iscsi_get_allowed_cmds(struct iscsi_session *sess)
|
||||
return res;
|
||||
}
|
||||
|
||||
static __be32 cmnd_set_sn(struct iscsi_cmnd *cmnd, int set_stat_sn)
|
||||
__be32 cmnd_set_sn(struct iscsi_cmnd *cmnd, int set_stat_sn)
|
||||
{
|
||||
struct iscsi_conn *conn = cmnd->conn;
|
||||
struct iscsi_session *sess = conn->session;
|
||||
@@ -1243,6 +1285,7 @@ static __be32 cmnd_set_sn(struct iscsi_cmnd *cmnd, int set_stat_sn)
|
||||
spin_unlock(&sess->sn_lock);
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL(cmnd_set_sn);
|
||||
|
||||
/* Called under sn_lock */
|
||||
static void update_stat_sn(struct iscsi_cmnd *cmnd)
|
||||
@@ -1739,7 +1782,7 @@ static int nop_out_start(struct iscsi_cmnd *cmnd)
|
||||
|
||||
size = cmnd->pdu.datasize;
|
||||
|
||||
if (size) {
|
||||
if (size && !conn->session->sess_params.rdma_extensions) {
|
||||
conn->read_msg.msg_iov = conn->read_iov;
|
||||
if (cmnd->pdu.bhs.itt != ISCSI_RESERVED_TAG) {
|
||||
struct scatterlist *sg;
|
||||
@@ -1796,16 +1839,87 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
int cmnd_rx_continue(struct iscsi_cmnd *req)
|
||||
int iscsi_cmnd_set_write_buf(struct iscsi_cmnd *req)
|
||||
{
|
||||
struct iscsi_conn *conn = req->conn;
|
||||
struct iscsi_session *session = conn->session;
|
||||
struct iscsi_scsi_cmd_hdr *req_hdr = cmnd_hdr(req);
|
||||
struct scst_cmd *scst_cmd = req->scst_cmd;
|
||||
scst_data_direction dir;
|
||||
bool unsolicited_data_expected = false;
|
||||
int res = 0;
|
||||
|
||||
req->bufflen = scst_cmd_get_write_fields(scst_cmd, &req->sg,
|
||||
&req->sg_cnt);
|
||||
unsolicited_data_expected = !(req_hdr->flags & ISCSI_CMD_FINAL);
|
||||
|
||||
if (unlikely(session->sess_params.initial_r2t &&
|
||||
unsolicited_data_expected)) {
|
||||
PRINT_ERROR("Initiator %s violated negotiated "
|
||||
"parameters: initial R2T is required (ITT %x, "
|
||||
"op %x)", session->initiator_name,
|
||||
req->pdu.bhs.itt, req_hdr->scb[0]);
|
||||
res = -EINVAL;
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
if (unlikely(!session->sess_params.immediate_data &&
|
||||
req->pdu.datasize)) {
|
||||
PRINT_ERROR("Initiator %s violated negotiated "
|
||||
"parameters: forbidden immediate data sent "
|
||||
"(ITT %x, op %x)", session->initiator_name,
|
||||
req->pdu.bhs.itt, req_hdr->scb[0]);
|
||||
res = -EINVAL;
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
if (unlikely(session->sess_params.first_burst_length < req->pdu.datasize)) {
|
||||
PRINT_ERROR("Initiator %s violated negotiated "
|
||||
"parameters: immediate data len (%d) > "
|
||||
"first_burst_length (%d) (ITT %x, op %x)",
|
||||
session->initiator_name,
|
||||
req->pdu.datasize,
|
||||
session->sess_params.first_burst_length,
|
||||
req->pdu.bhs.itt, req_hdr->scb[0]);
|
||||
res = -EINVAL;
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
req->r2t_len_to_receive = be32_to_cpu(req_hdr->data_length) -
|
||||
req->pdu.datasize;
|
||||
|
||||
/*
|
||||
* In case of residual overflow req->r2t_len_to_receive and
|
||||
* req->pdu.datasize might be > req->bufflen
|
||||
*/
|
||||
|
||||
res = cmnd_insert_data_wait_hash(req);
|
||||
|
||||
if (unsolicited_data_expected) {
|
||||
req->outstanding_r2t = 1;
|
||||
req->r2t_len_to_send = req->r2t_len_to_receive -
|
||||
min_t(unsigned int,
|
||||
session->sess_params.first_burst_length -
|
||||
req->pdu.datasize,
|
||||
req->r2t_len_to_receive);
|
||||
} else
|
||||
req->r2t_len_to_send = req->r2t_len_to_receive;
|
||||
|
||||
if (likely(res == 0))
|
||||
req_add_to_write_timeout_list(req);
|
||||
|
||||
out_close:
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL(iscsi_cmnd_set_write_buf);
|
||||
|
||||
int cmnd_rx_continue(struct iscsi_cmnd *req)
|
||||
{
|
||||
struct iscsi_conn *conn = req->conn;
|
||||
struct iscsi_scsi_cmd_hdr *req_hdr = cmnd_hdr(req);
|
||||
struct scst_cmd *scst_cmd = req->scst_cmd;
|
||||
scst_data_direction dir;
|
||||
int res = 0;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
TRACE_DBG("scsi command: %x", req_hdr->scb[0]);
|
||||
@@ -1831,48 +1945,7 @@ int cmnd_rx_continue(struct iscsi_cmnd *req)
|
||||
/* For prelim completed commands sg & K can be already set! */
|
||||
|
||||
if (dir & SCST_DATA_WRITE) {
|
||||
req->bufflen = scst_cmd_get_write_fields(scst_cmd, &req->sg,
|
||||
&req->sg_cnt);
|
||||
unsolicited_data_expected = !(req_hdr->flags & ISCSI_CMD_FINAL);
|
||||
|
||||
if (unlikely(session->sess_params.initial_r2t &&
|
||||
unsolicited_data_expected)) {
|
||||
PRINT_ERROR("Initiator %s violated negotiated "
|
||||
"parameters: initial R2T is required (ITT %x, "
|
||||
"op %x)", session->initiator_name,
|
||||
req->pdu.bhs.itt, req_hdr->scb[0]);
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
if (unlikely(!session->sess_params.immediate_data &&
|
||||
req->pdu.datasize)) {
|
||||
PRINT_ERROR("Initiator %s violated negotiated "
|
||||
"parameters: forbidden immediate data sent "
|
||||
"(ITT %x, op %x)", session->initiator_name,
|
||||
req->pdu.bhs.itt, req_hdr->scb[0]);
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
if (unlikely(session->sess_params.first_burst_length < req->pdu.datasize)) {
|
||||
PRINT_ERROR("Initiator %s violated negotiated "
|
||||
"parameters: immediate data len (%d) > "
|
||||
"first_burst_length (%d) (ITT %x, op %x)",
|
||||
session->initiator_name,
|
||||
req->pdu.datasize,
|
||||
session->sess_params.first_burst_length,
|
||||
req->pdu.bhs.itt, req_hdr->scb[0]);
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
req->r2t_len_to_receive = be32_to_cpu(req_hdr->data_length) -
|
||||
req->pdu.datasize;
|
||||
|
||||
/*
|
||||
* In case of residual overflow req->r2t_len_to_receive and
|
||||
* req->pdu.datasize might be > req->bufflen
|
||||
*/
|
||||
|
||||
res = cmnd_insert_data_wait_hash(req);
|
||||
res = iscsi_cmnd_set_write_buf(req);
|
||||
if (unlikely(res != 0)) {
|
||||
/*
|
||||
* We have to close connection, because otherwise a data
|
||||
@@ -1883,18 +1956,6 @@ int cmnd_rx_continue(struct iscsi_cmnd *req)
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
if (unsolicited_data_expected) {
|
||||
req->outstanding_r2t = 1;
|
||||
req->r2t_len_to_send = req->r2t_len_to_receive -
|
||||
min_t(unsigned int,
|
||||
session->sess_params.first_burst_length -
|
||||
req->pdu.datasize,
|
||||
req->r2t_len_to_receive);
|
||||
} else
|
||||
req->r2t_len_to_send = req->r2t_len_to_receive;
|
||||
|
||||
req_add_to_write_timeout_list(req);
|
||||
|
||||
if (req->pdu.datasize) {
|
||||
res = cmnd_prepare_recv_pdu(conn, req, 0, req->pdu.datasize);
|
||||
/* For performance better to send R2Ts ASAP */
|
||||
@@ -1916,11 +1977,9 @@ int cmnd_rx_continue(struct iscsi_cmnd *req)
|
||||
}
|
||||
|
||||
trace:
|
||||
TRACE_DBG("req=%p, dir=%d, unsolicited_data_expected=%d, "
|
||||
"r2t_len_to_receive=%d, r2t_len_to_send=%d, bufflen=%d, "
|
||||
"own_sg %d", req, dir, unsolicited_data_expected,
|
||||
req->r2t_len_to_receive, req->r2t_len_to_send, req->bufflen,
|
||||
req->own_sg);
|
||||
TRACE_DBG("req=%p, dir=%d, r2t_len_to_receive=%d, r2t_len_to_send=%d, "
|
||||
"bufflen=%d, own_sg %d", req, dir, req->r2t_len_to_receive,
|
||||
req->r2t_len_to_send, req->bufflen, req->own_sg);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
@@ -1980,7 +2039,8 @@ static int scsi_cmnd_start(struct iscsi_cmnd *req)
|
||||
scst_cmd_set_expected_out_transfer_len(scst_cmd,
|
||||
be32_to_cpu(req_hdr->data_length));
|
||||
#if !defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
|
||||
scst_cmd_set_tgt_need_alloc_data_buf(scst_cmd);
|
||||
if (conn->transport->need_alloc_write_buf)
|
||||
scst_cmd_set_tgt_need_alloc_data_buf(scst_cmd);
|
||||
#endif
|
||||
}
|
||||
} else if (req_hdr->flags & ISCSI_CMD_READ) {
|
||||
@@ -1988,7 +2048,8 @@ static int scsi_cmnd_start(struct iscsi_cmnd *req)
|
||||
scst_cmd_set_expected(scst_cmd, dir,
|
||||
be32_to_cpu(req_hdr->data_length));
|
||||
#if !defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
|
||||
scst_cmd_set_tgt_need_alloc_data_buf(scst_cmd);
|
||||
if (conn->transport->need_alloc_write_buf)
|
||||
scst_cmd_set_tgt_need_alloc_data_buf(scst_cmd);
|
||||
#endif
|
||||
} else if (req_hdr->flags & ISCSI_CMD_WRITE) {
|
||||
dir = SCST_DATA_WRITE;
|
||||
@@ -2055,7 +2116,7 @@ static int scsi_cmnd_start(struct iscsi_cmnd *req)
|
||||
scst_cmd_init_stage1_done(scst_cmd, SCST_CONTEXT_DIRECT, 0);
|
||||
|
||||
if (req->scst_state != ISCSI_CMD_STATE_RX_CMD)
|
||||
res = cmnd_rx_continue(req);
|
||||
res = req->conn->transport->iscsit_receive_cmnd_data(req);
|
||||
else {
|
||||
TRACE_DBG("Delaying req %p post processing (scst_state %d)",
|
||||
req, req->scst_state);
|
||||
@@ -2666,6 +2727,14 @@ reject:
|
||||
return;
|
||||
}
|
||||
|
||||
static void iscsi_tcp_set_req_data(struct iscsi_cmnd *req,
|
||||
struct iscsi_cmnd *rsp)
|
||||
{
|
||||
rsp->sg = req->sg;
|
||||
rsp->sg_cnt = req->sg_cnt;
|
||||
rsp->bufflen = req->bufflen;
|
||||
}
|
||||
|
||||
static void nop_out_exec(struct iscsi_cmnd *req)
|
||||
{
|
||||
struct iscsi_cmnd *rsp;
|
||||
@@ -2689,11 +2758,8 @@ static void nop_out_exec(struct iscsi_cmnd *req)
|
||||
else
|
||||
sBUG_ON(req->sg != NULL);
|
||||
|
||||
if (req->sg) {
|
||||
rsp->sg = req->sg;
|
||||
rsp->sg_cnt = req->sg_cnt;
|
||||
rsp->bufflen = req->bufflen;
|
||||
}
|
||||
if (req->bufflen)
|
||||
req->conn->transport->iscsit_set_req_data(req, rsp);
|
||||
|
||||
/* We already checked it in check_segment_length() */
|
||||
sBUG_ON(get_pgcnt(req->pdu.datasize, 0) > ISCSI_CONN_IOV_MAX);
|
||||
@@ -3146,6 +3212,7 @@ out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL(cmnd_rx_start);
|
||||
|
||||
void cmnd_rx_end(struct iscsi_cmnd *cmnd)
|
||||
{
|
||||
@@ -3177,6 +3244,48 @@ out:
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(cmnd_rx_end);
|
||||
|
||||
static ssize_t iscsi_tcp_get_initiator_ip(struct iscsi_conn *conn,
|
||||
char *buf, int size)
|
||||
{
|
||||
int pos;
|
||||
struct sock *sk;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
sk = conn->sock->sk;
|
||||
switch (sk->sk_family) {
|
||||
case AF_INET:
|
||||
pos = scnprintf(buf, size,
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
|
||||
"%u.%u.%u.%u", NIPQUAD(inet_sk(sk)->daddr));
|
||||
#else
|
||||
"%pI4", &inet_sk(sk)->inet_daddr);
|
||||
#endif
|
||||
break;
|
||||
case AF_INET6:
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
|
||||
pos = scnprintf(buf, size,
|
||||
"[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
|
||||
NIP6(inet6_sk(sk)->daddr));
|
||||
#else
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
|
||||
pos = scnprintf(buf, size, "[%p6]", &inet6_sk(sk)->daddr);
|
||||
#else
|
||||
pos = scnprintf(buf, size, "[%p6]", &sk->sk_v6_daddr);
|
||||
#endif
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
pos = scnprintf(buf, size, "Unknown family %d",
|
||||
sk->sk_family);
|
||||
break;
|
||||
}
|
||||
|
||||
TRACE_EXIT_RES(pos);
|
||||
return pos;
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
|
||||
static int iscsi_alloc_data_buf(struct scst_cmd *cmd)
|
||||
@@ -3194,11 +3303,8 @@ static int iscsi_alloc_data_buf(struct scst_cmd *cmd)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void iscsi_preprocessing_done(struct scst_cmd *scst_cmd)
|
||||
static void iscsi_tcp_preprocessing_done(struct iscsi_cmnd *req)
|
||||
{
|
||||
struct iscsi_cmnd *req = (struct iscsi_cmnd *)
|
||||
scst_cmd_get_tgt_priv(scst_cmd);
|
||||
|
||||
TRACE_DBG("req %p", req);
|
||||
|
||||
if (req->conn->rx_task == current)
|
||||
@@ -3225,8 +3331,14 @@ static void iscsi_preprocessing_done(struct scst_cmd *scst_cmd)
|
||||
}
|
||||
cmnd_put(req);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
static void iscsi_preprocessing_done(struct scst_cmd *scst_cmd)
|
||||
{
|
||||
struct iscsi_cmnd *req = (struct iscsi_cmnd *)
|
||||
scst_cmd_get_tgt_priv(scst_cmd);
|
||||
|
||||
req->conn->transport->iscsit_preprocessing_done(req);
|
||||
}
|
||||
|
||||
/* No locks */
|
||||
@@ -3287,6 +3399,52 @@ static void iscsi_try_local_processing(struct iscsi_cmnd *req)
|
||||
return;
|
||||
}
|
||||
|
||||
static int iscsi_tcp_send_locally(struct iscsi_cmnd *req,
|
||||
unsigned int cmd_count)
|
||||
{
|
||||
struct iscsi_conn *conn = req->conn;
|
||||
struct iscsi_cmnd *wr_rsp, *our_rsp;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* There's no need for protection, since we are not going to
|
||||
* dereference them.
|
||||
*/
|
||||
wr_rsp = list_first_entry(&conn->write_list, struct iscsi_cmnd,
|
||||
write_list_entry);
|
||||
our_rsp = list_first_entry(&req->rsp_cmd_list, struct iscsi_cmnd,
|
||||
rsp_cmd_list_entry);
|
||||
if (wr_rsp == our_rsp) {
|
||||
/*
|
||||
* This is our rsp, so let's try to process it locally to
|
||||
* decrease latency. We need to call pre_release before
|
||||
* processing to handle some error recovery cases.
|
||||
*/
|
||||
if (cmd_count <= 2) {
|
||||
req_cmnd_pre_release(req);
|
||||
iscsi_try_local_processing(req);
|
||||
cmnd_put(req);
|
||||
} else {
|
||||
/*
|
||||
* There's too much backend activity, so it could be
|
||||
* better to push it to the write thread.
|
||||
*/
|
||||
ret = 1;
|
||||
}
|
||||
} else
|
||||
ret = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void iscsi_tcp_conn_close(struct iscsi_conn *conn, int flags)
|
||||
{
|
||||
if (!flags)
|
||||
conn->sock->sk->sk_prot->disconnect(conn->sock->sk, 0);
|
||||
else
|
||||
conn->sock->ops->shutdown(conn->sock, flags);
|
||||
}
|
||||
|
||||
static int iscsi_xmit_response(struct scst_cmd *scst_cmd)
|
||||
{
|
||||
int is_send_status = scst_cmd_get_is_send_status(scst_cmd);
|
||||
@@ -3296,7 +3454,6 @@ static int iscsi_xmit_response(struct scst_cmd *scst_cmd)
|
||||
int status = scst_cmd_get_status(scst_cmd);
|
||||
u8 *sense = scst_cmd_get_sense_buffer(scst_cmd);
|
||||
int sense_len = scst_cmd_get_sense_buffer_len(scst_cmd);
|
||||
struct iscsi_cmnd *wr_rsp, *our_rsp;
|
||||
|
||||
EXTRACHECKS_BUG_ON(scst_cmd_atomic(scst_cmd));
|
||||
|
||||
@@ -3371,19 +3528,9 @@ static int iscsi_xmit_response(struct scst_cmd *scst_cmd)
|
||||
* so status is valid here, but in future that could change.
|
||||
* ToDo
|
||||
*/
|
||||
if ((status != SAM_STAT_CHECK_CONDITION) &&
|
||||
((cmnd_hdr(req)->flags & (ISCSI_CMD_WRITE|ISCSI_CMD_READ)) !=
|
||||
(ISCSI_CMD_WRITE|ISCSI_CMD_READ))) {
|
||||
send_data_rsp(req, status, is_send_status);
|
||||
} else {
|
||||
struct iscsi_cmnd *rsp;
|
||||
send_data_rsp(req, 0, 0);
|
||||
if (is_send_status) {
|
||||
rsp = create_status_rsp(req, status, sense,
|
||||
sense_len);
|
||||
iscsi_cmnd_init_write(rsp, 0);
|
||||
}
|
||||
}
|
||||
req->conn->transport->iscsit_send_data_rsp(req, sense,
|
||||
sense_len, status,
|
||||
is_send_status);
|
||||
} else if (is_send_status) {
|
||||
struct iscsi_cmnd *rsp;
|
||||
rsp = create_status_rsp(req, status, sense, sense_len);
|
||||
@@ -3394,32 +3541,7 @@ static int iscsi_xmit_response(struct scst_cmd *scst_cmd)
|
||||
sBUG();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* There's no need for protection, since we are not going to
|
||||
* dereference them.
|
||||
*/
|
||||
wr_rsp = list_first_entry(&conn->write_list, struct iscsi_cmnd,
|
||||
write_list_entry);
|
||||
our_rsp = list_first_entry(&req->rsp_cmd_list, struct iscsi_cmnd,
|
||||
rsp_cmd_list_entry);
|
||||
if (wr_rsp == our_rsp) {
|
||||
/*
|
||||
* This is our rsp, so let's try to process it locally to
|
||||
* decrease latency. We need to call pre_release before
|
||||
* processing to handle some error recovery cases.
|
||||
*/
|
||||
if (scst_get_active_cmd_count(scst_cmd) <= 2) {
|
||||
req_cmnd_pre_release(req);
|
||||
iscsi_try_local_processing(req);
|
||||
cmnd_put(req);
|
||||
} else {
|
||||
/*
|
||||
* There's too much backend activity, so it could be
|
||||
* better to push it to the write thread.
|
||||
*/
|
||||
goto out_push_to_wr_thread;
|
||||
}
|
||||
} else
|
||||
if (conn->transport->iscsit_send_locally(req, scst_get_active_cmd_count(scst_cmd)))
|
||||
goto out_push_to_wr_thread;
|
||||
|
||||
out:
|
||||
@@ -3428,7 +3550,7 @@ out:
|
||||
out_push_to_wr_thread:
|
||||
TRACE_DBG("Waking up write thread (conn %p)", conn);
|
||||
req_cmnd_release(req);
|
||||
iscsi_make_conn_wr_active(conn);
|
||||
conn->transport->iscsit_make_conn_wr_active(conn);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -3631,7 +3753,6 @@ static int iscsi_scsi_aen(struct scst_aen *aen)
|
||||
bool found;
|
||||
struct iscsi_cmnd *fake_req, *rsp;
|
||||
struct iscsi_async_msg_hdr *rsp_hdr;
|
||||
struct scatterlist *sg;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
@@ -3654,7 +3775,7 @@ static int iscsi_scsi_aen(struct scst_aen *aen)
|
||||
}
|
||||
|
||||
/* Create a fake request */
|
||||
fake_req = cmnd_alloc(conn, NULL);
|
||||
fake_req = conn->transport->iscsit_alloc_cmd(conn, NULL);
|
||||
if (fake_req == NULL) {
|
||||
PRINT_ERROR("%s", "Unable to alloc fake AEN request");
|
||||
goto out_err_unlock;
|
||||
@@ -3679,15 +3800,10 @@ static int iscsi_scsi_aen(struct scst_aen *aen)
|
||||
rsp_hdr->ffffffff = cpu_to_be32(0xffffffff);
|
||||
rsp_hdr->async_event = ISCSI_ASYNC_SCSI;
|
||||
|
||||
sg = rsp->sg = rsp->rsp_sg;
|
||||
rsp->sg_cnt = 2;
|
||||
rsp->own_sg = 1;
|
||||
|
||||
sg_init_table(sg, 2);
|
||||
sg_set_buf(&sg[0], &rsp->sense_hdr, sizeof(rsp->sense_hdr));
|
||||
sg_set_buf(&sg[1], sense, sense_len);
|
||||
|
||||
rsp->sense_hdr.length = cpu_to_be16(sense_len);
|
||||
|
||||
rsp->conn->transport->iscsit_set_sense_data(rsp, sense, sense_len);
|
||||
|
||||
rsp->pdu.datasize = sizeof(rsp->sense_hdr) + sense_len;
|
||||
rsp->bufflen = rsp->pdu.datasize;
|
||||
|
||||
@@ -3809,7 +3925,7 @@ void iscsi_send_nop_in(struct iscsi_conn *conn)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
req = cmnd_alloc(conn, NULL);
|
||||
req = conn->transport->iscsit_alloc_cmd(conn, NULL);
|
||||
if (req == NULL) {
|
||||
PRINT_ERROR("%s", "Unable to alloc fake Nop-In request");
|
||||
goto out_err;
|
||||
@@ -3951,6 +4067,30 @@ struct scst_tgt_template iscsi_template = {
|
||||
.get_scsi_transport_version = iscsi_get_scsi_transport_version,
|
||||
};
|
||||
|
||||
static struct iscsit_transport iscsi_tcp_transport = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "iSCSI-TCP",
|
||||
.transport_type = ISCSI_TCP,
|
||||
#if !defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
|
||||
.need_alloc_write_buf = 1,
|
||||
#endif
|
||||
.iscsit_conn_alloc = iscsi_conn_alloc,
|
||||
.iscsit_conn_activate = conn_activate,
|
||||
.iscsit_conn_free = iscsi_tcp_conn_free,
|
||||
.iscsit_alloc_cmd = cmnd_alloc,
|
||||
.iscsit_free_cmd = cmnd_free,
|
||||
.iscsit_preprocessing_done = iscsi_tcp_preprocessing_done,
|
||||
.iscsit_send_data_rsp = iscsi_tcp_send_data_rsp,
|
||||
.iscsit_make_conn_wr_active = iscsi_make_conn_wr_active,
|
||||
.iscsit_mark_conn_closed = iscsi_tcp_mark_conn_closed,
|
||||
.iscsit_conn_close = iscsi_tcp_conn_close,
|
||||
.iscsit_get_initiator_ip = iscsi_tcp_get_initiator_ip,
|
||||
.iscsit_send_locally = iscsi_tcp_send_locally,
|
||||
.iscsit_set_sense_data = iscsi_tcp_set_sense_data,
|
||||
.iscsit_set_req_data = iscsi_tcp_set_req_data,
|
||||
.iscsit_receive_cmnd_data = cmnd_rx_continue,
|
||||
};
|
||||
|
||||
static void __iscsi_threads_pool_put(struct iscsi_thread_pool *p)
|
||||
{
|
||||
struct iscsi_thread *t, *tt;
|
||||
@@ -4106,6 +4246,10 @@ static int __init iscsi_init(void)
|
||||
|
||||
PRINT_INFO("iSCSI SCST Target - version %s", ISCSI_VERSION_STRING);
|
||||
|
||||
err = iscsit_register_transport(&iscsi_tcp_transport);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
dummy_page = alloc_pages(GFP_KERNEL, 0);
|
||||
if (dummy_page == NULL) {
|
||||
PRINT_ERROR("%s", "Dummy page allocation failed");
|
||||
@@ -4256,6 +4400,8 @@ static void __exit iscsi_exit(void)
|
||||
|
||||
scst_unregister_target_template(&iscsi_template);
|
||||
|
||||
iscsit_unregister_transport(&iscsi_tcp_transport);
|
||||
|
||||
#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
|
||||
net_set_get_put_page_callbacks(NULL, NULL);
|
||||
#endif
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#endif
|
||||
#include "iscsi_hdr.h"
|
||||
#include "iscsi_dbg.h"
|
||||
#include "iscsit_transport.h"
|
||||
|
||||
#define iscsi_sense_crc_error ABORTED_COMMAND, 0x47, 0x05
|
||||
#define iscsi_sense_unexpected_unsolicited_data ABORTED_COMMAND, 0x0C, 0x0C
|
||||
@@ -57,6 +58,9 @@ struct iscsi_sess_params {
|
||||
int ifmarker;
|
||||
int ofmarkint;
|
||||
int ifmarkint;
|
||||
int rdma_extensions;
|
||||
int target_recv_data_length;
|
||||
int initiator_recv_data_length;
|
||||
};
|
||||
|
||||
struct iscsi_tgt_params {
|
||||
@@ -190,6 +194,8 @@ struct iscsi_session {
|
||||
#define ISCSI_CONN_WR_STATE_PROCESSING 3
|
||||
|
||||
struct iscsi_conn {
|
||||
struct iscsit_transport *transport;
|
||||
|
||||
struct iscsi_session *session; /* owning session */
|
||||
|
||||
/* Both protected by session->sn_lock */
|
||||
@@ -308,6 +314,7 @@ struct iscsi_conn {
|
||||
#else
|
||||
struct work_struct nop_in_delayed_work;
|
||||
#endif
|
||||
struct work_struct close_work;
|
||||
unsigned int nop_in_interval; /* in jiffies */
|
||||
unsigned int nop_in_timeout; /* in jiffies */
|
||||
struct list_head nop_req_list;
|
||||
@@ -555,7 +562,7 @@ extern struct iscsi_conn *conn_lookup(struct iscsi_session *, u16);
|
||||
extern void conn_reinst_finished(struct iscsi_conn *);
|
||||
extern int __add_conn(struct iscsi_session *, struct iscsi_kern_conn_info *);
|
||||
extern int __del_conn(struct iscsi_session *, struct iscsi_kern_conn_info *);
|
||||
extern int conn_free(struct iscsi_conn *);
|
||||
extern void conn_free(struct iscsi_conn *);
|
||||
extern void iscsi_make_conn_rd_active(struct iscsi_conn *conn);
|
||||
#define ISCSI_CONN_ACTIVE_CLOSE 1
|
||||
#define ISCSI_CONN_DELETING 2
|
||||
@@ -607,6 +614,7 @@ extern void target_del_all(void);
|
||||
extern int iscsi_procfs_init(void);
|
||||
extern void iscsi_procfs_exit(void);
|
||||
#else
|
||||
extern int conn_sysfs_add(struct iscsi_conn *conn);
|
||||
extern const struct attribute *iscsi_attrs[];
|
||||
extern int iscsi_add_attr(struct iscsi_target *target,
|
||||
const struct iscsi_kern_attr *user_info);
|
||||
@@ -829,4 +837,24 @@ static inline void iscsi_extracheck_is_rd_thread(struct iscsi_conn *conn) {}
|
||||
static inline void iscsi_extracheck_is_wr_thread(struct iscsi_conn *conn) {}
|
||||
#endif
|
||||
|
||||
extern int iscsi_conn_alloc(struct iscsi_session *session,
|
||||
struct iscsi_kern_conn_info *info, struct iscsi_conn **new_conn,
|
||||
struct iscsit_transport *t);
|
||||
|
||||
extern int conn_activate(struct iscsi_conn *conn);
|
||||
extern void iscsi_tcp_mark_conn_closed(struct iscsi_conn *conn, int flags);
|
||||
extern void iscsi_tcp_conn_free(struct iscsi_conn *conn);
|
||||
extern void iscsi_cmnd_init(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd,
|
||||
struct iscsi_cmnd *parent);
|
||||
extern struct iscsi_cmnd *iscsi_get_send_cmnd(struct iscsi_conn *conn);
|
||||
extern void start_close_conn(struct iscsi_conn *conn);
|
||||
extern __be32 cmnd_set_sn(struct iscsi_cmnd *cmnd, int set_stat_sn);
|
||||
extern void iscsi_set_resid(struct iscsi_cmnd *rsp);
|
||||
extern int iscsi_init_conn(struct iscsi_session *session,
|
||||
struct iscsi_kern_conn_info *info, struct iscsi_conn *conn);
|
||||
extern void req_cmnd_pre_release(struct iscsi_cmnd *req);
|
||||
extern void req_cmnd_release(struct iscsi_cmnd *req);
|
||||
extern struct iscsi_cmnd *create_status_rsp(struct iscsi_cmnd *req,
|
||||
int status, const u8 *sense_buf, int sense_len);
|
||||
extern int iscsi_cmnd_set_write_buf(struct iscsi_cmnd *req);
|
||||
#endif /* __ISCSI_H__ */
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
#ifndef ISCSI_DBG_H
|
||||
#define ISCSI_DBG_H
|
||||
|
||||
#ifdef LOG_PREFIX
|
||||
#undef LOG_PREFIX
|
||||
#endif
|
||||
|
||||
#define LOG_PREFIX "iscsi-scst"
|
||||
|
||||
#ifdef INSIDE_KERNEL_TREE
|
||||
@@ -53,8 +57,10 @@ extern unsigned long iscsi_get_flow_ctrl_or_mgmt_dbg_log_flag(
|
||||
|
||||
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
||||
extern unsigned long iscsi_trace_flag;
|
||||
#ifndef trace_flag
|
||||
#define trace_flag iscsi_trace_flag
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define TRACE_CONN_CLOSE(args...) TRACE_DBG_FLAG(TRACE_DEBUG|TRACE_CONN_OC, args)
|
||||
#define TRACE_CONN_CLOSE_DBG(args...) TRACE(TRACE_CONN_OC_DBG, args)
|
||||
|
||||
+26
-22
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "iscsi.h"
|
||||
#include "digest.h"
|
||||
#include "iscsit_transport.h"
|
||||
|
||||
/* Read data states */
|
||||
enum rx_state {
|
||||
@@ -407,10 +408,10 @@ static void close_conn(struct iscsi_conn *conn)
|
||||
|
||||
if (conn->active_close) {
|
||||
/* We want all our already send operations to complete */
|
||||
conn->sock->ops->shutdown(conn->sock, RCV_SHUTDOWN);
|
||||
conn->transport->iscsit_conn_close(conn, RCV_SHUTDOWN);
|
||||
} else {
|
||||
conn->sock->ops->shutdown(conn->sock,
|
||||
RCV_SHUTDOWN|SEND_SHUTDOWN);
|
||||
conn->transport->iscsit_conn_close(conn,
|
||||
RCV_SHUTDOWN|SEND_SHUTDOWN);
|
||||
}
|
||||
|
||||
mutex_lock(&session->target->target_mutex);
|
||||
@@ -486,15 +487,13 @@ static void close_conn(struct iscsi_conn *conn)
|
||||
}
|
||||
}
|
||||
|
||||
iscsi_make_conn_wr_active(conn);
|
||||
conn->transport->iscsit_make_conn_wr_active(conn);
|
||||
|
||||
/* That's for active close only, actually */
|
||||
if (time_after(jiffies, start_waiting + CONN_WAIT_TIMEOUT) &&
|
||||
!wait_expired) {
|
||||
TRACE_CONN_CLOSE("Wait time expired (conn %p, "
|
||||
"sk_state %d)",
|
||||
conn, conn->sock->sk->sk_state);
|
||||
conn->sock->ops->shutdown(conn->sock, SEND_SHUTDOWN);
|
||||
TRACE_CONN_CLOSE("Wait time expired (conn %p)", conn);
|
||||
conn->transport->iscsit_conn_close(conn, SEND_SHUTDOWN);
|
||||
wait_expired = 1;
|
||||
shut_start_waiting = jiffies;
|
||||
}
|
||||
@@ -504,9 +503,8 @@ static void close_conn(struct iscsi_conn *conn)
|
||||
conn->deleting ? CONN_DEL_SHUT_TIMEOUT :
|
||||
CONN_REG_SHUT_TIMEOUT)) {
|
||||
TRACE_CONN_CLOSE("Wait time after shutdown expired "
|
||||
"(conn %p, sk_state %d)", conn,
|
||||
conn->sock->sk->sk_state);
|
||||
conn->sock->sk->sk_prot->disconnect(conn->sock->sk, 0);
|
||||
"(conn %p)", conn);
|
||||
conn->transport->iscsit_conn_close(conn, 0);
|
||||
shut_expired = 1;
|
||||
}
|
||||
|
||||
@@ -522,17 +520,21 @@ static void close_conn(struct iscsi_conn *conn)
|
||||
|
||||
trace_conn_close(conn);
|
||||
|
||||
/* It might never be called for being closed conn */
|
||||
__iscsi_write_space_ready(conn);
|
||||
if (!conn->session->sess_params.rdma_extensions) {
|
||||
/* It might never be called for being closed conn */
|
||||
__iscsi_write_space_ready(conn);
|
||||
|
||||
iscsi_check_closewait(conn);
|
||||
iscsi_check_closewait(conn);
|
||||
}
|
||||
}
|
||||
|
||||
write_lock_bh(&conn->sock->sk->sk_callback_lock);
|
||||
conn->sock->sk->sk_state_change = conn->old_state_change;
|
||||
conn->sock->sk->sk_data_ready = conn->old_data_ready;
|
||||
conn->sock->sk->sk_write_space = conn->old_write_space;
|
||||
write_unlock_bh(&conn->sock->sk->sk_callback_lock);
|
||||
if (!conn->session->sess_params.rdma_extensions) {
|
||||
write_lock_bh(&conn->sock->sk->sk_callback_lock);
|
||||
conn->sock->sk->sk_state_change = conn->old_state_change;
|
||||
conn->sock->sk->sk_data_ready = conn->old_data_ready;
|
||||
conn->sock->sk->sk_write_space = conn->old_write_space;
|
||||
write_unlock_bh(&conn->sock->sk->sk_callback_lock);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
bool t;
|
||||
@@ -595,7 +597,7 @@ static int close_conn_thr(void *arg)
|
||||
}
|
||||
|
||||
/* No locks */
|
||||
static void start_close_conn(struct iscsi_conn *conn)
|
||||
void start_close_conn(struct iscsi_conn *conn)
|
||||
{
|
||||
struct task_struct *t;
|
||||
|
||||
@@ -611,6 +613,7 @@ static void start_close_conn(struct iscsi_conn *conn)
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(start_close_conn);
|
||||
|
||||
static inline void iscsi_conn_init_read(struct iscsi_conn *conn,
|
||||
void __user *data, size_t len)
|
||||
@@ -635,7 +638,7 @@ static void iscsi_conn_prepare_read_ahs(struct iscsi_conn *conn,
|
||||
return;
|
||||
}
|
||||
|
||||
static struct iscsi_cmnd *iscsi_get_send_cmnd(struct iscsi_conn *conn)
|
||||
struct iscsi_cmnd *iscsi_get_send_cmnd(struct iscsi_conn *conn)
|
||||
{
|
||||
struct iscsi_cmnd *cmnd = NULL;
|
||||
|
||||
@@ -674,6 +677,7 @@ static struct iscsi_cmnd *iscsi_get_send_cmnd(struct iscsi_conn *conn)
|
||||
out:
|
||||
return cmnd;
|
||||
}
|
||||
EXPORT_SYMBOL(iscsi_get_send_cmnd);
|
||||
|
||||
/* Returns number of bytes left to receive or <0 for error */
|
||||
static int do_recv(struct iscsi_conn *conn)
|
||||
@@ -831,7 +835,7 @@ static int process_read_io(struct iscsi_conn *conn, int *closed)
|
||||
switch (conn->read_state) {
|
||||
case RX_INIT_BHS:
|
||||
EXTRACHECKS_BUG_ON(conn->read_cmnd != NULL);
|
||||
cmnd = cmnd_alloc(conn, NULL);
|
||||
cmnd = conn->transport->iscsit_alloc_cmd(conn, NULL);
|
||||
conn->read_cmnd = cmnd;
|
||||
iscsi_conn_init_read(cmnd->conn,
|
||||
(void __force __user *)&cmnd->pdu.bhs,
|
||||
|
||||
@@ -98,12 +98,13 @@ static void log_params(struct iscsi_sess_params *params)
|
||||
iscsi_get_bool_value(params->data_sequence_inorder),
|
||||
params->error_recovery_level);
|
||||
PRINT_INFO(" HeaderDigest %s, DataDigest %s, OFMarker %s, "
|
||||
"IFMarker %s, OFMarkInt %d, IFMarkInt %d",
|
||||
"IFMarker %s, OFMarkInt %d, IFMarkInt %d, RDMAExtensions %s",
|
||||
iscsi_get_digest_name(params->header_digest, hdigest_name),
|
||||
iscsi_get_digest_name(params->data_digest, ddigest_name),
|
||||
iscsi_get_bool_value(params->ofmarker),
|
||||
iscsi_get_bool_value(params->ifmarker),
|
||||
params->ofmarkint, params->ifmarkint);
|
||||
params->ofmarkint, params->ifmarkint,
|
||||
iscsi_get_bool_value(params->rdma_extensions));
|
||||
}
|
||||
|
||||
/* target_mutex supposed to be locked */
|
||||
@@ -135,6 +136,11 @@ static void sess_params_check(struct iscsi_kern_params_info *info)
|
||||
CHECK_PARAM(info, iparams, ofmarker, 0, 0);
|
||||
CHECK_PARAM(info, iparams, ifmarker, 0, 0);
|
||||
|
||||
/* iSER related parameters */
|
||||
CHECK_PARAM(info, iparams, rdma_extensions, 0, 1);
|
||||
CHECK_PARAM(info, iparams, target_recv_data_length, 512, max_len);
|
||||
CHECK_PARAM(info, iparams, initiator_recv_data_length, 512, max_len);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -163,6 +169,11 @@ static void sess_params_set(struct iscsi_sess_params *params,
|
||||
SET_PARAM(params, info, iparams, ifmarker);
|
||||
SET_PARAM(params, info, iparams, ofmarkint);
|
||||
SET_PARAM(params, info, iparams, ifmarkint);
|
||||
|
||||
/* iSER related parameters */
|
||||
SET_PARAM(params, info, iparams, rdma_extensions);
|
||||
SET_PARAM(params, info, iparams, target_recv_data_length);
|
||||
SET_PARAM(params, info, iparams, initiator_recv_data_length);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -190,6 +201,11 @@ static void sess_params_get(struct iscsi_sess_params *params,
|
||||
GET_PARAM(params, info, iparams, ifmarker);
|
||||
GET_PARAM(params, info, iparams, ofmarkint);
|
||||
GET_PARAM(params, info, iparams, ifmarkint);
|
||||
|
||||
/* iSER related parameters */
|
||||
GET_PARAM(params, info, iparams, rdma_extensions);
|
||||
GET_PARAM(params, info, iparams, target_recv_data_length);
|
||||
GET_PARAM(params, info, iparams, initiator_recv_data_length);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -331,9 +331,11 @@ void target_del_all_sess(struct iscsi_target *target, int flags)
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(target_del_all_sess);
|
||||
|
||||
void target_del_all(void)
|
||||
{
|
||||
struct iscsit_transport *transport;
|
||||
struct iscsi_target *target, *t;
|
||||
bool first = true;
|
||||
|
||||
@@ -341,6 +343,14 @@ void target_del_all(void)
|
||||
|
||||
TRACE_MGMT_DBG("%s", "Deleting all targets");
|
||||
|
||||
transport = iscsit_get_transport(ISCSI_TCP);
|
||||
if (transport && transport->iscsit_close_all_portals)
|
||||
transport->iscsit_close_all_portals();
|
||||
|
||||
transport = iscsit_get_transport(ISCSI_RDMA);
|
||||
if (transport && transport->iscsit_close_all_portals)
|
||||
transport->iscsit_close_all_portals();
|
||||
|
||||
/* Not the best, ToDo */
|
||||
while (1) {
|
||||
mutex_lock(&target_mgmt_mutex);
|
||||
|
||||
Reference in New Issue
Block a user