Newer
Older
iscsi_set_param(cls_conn, param, buf, buflen);
if (session->max_r2t & (session->max_r2t - 1))
session->max_r2t = roundup_pow_of_two(session->max_r2t);
if (iscsi_r2tpool_alloc(session))
return -ENOMEM;
break;
default:
return iscsi_set_param(cls_conn, param, buf, buflen);
}
return 0;
}
static int
iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn,
enum iscsi_param param, char *buf)
struct iscsi_conn *conn = cls_conn->dd_data;
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
struct inet_sock *inet;
struct ipv6_pinfo *np;
struct sock *sk;
int len;
switch(param) {
case ISCSI_PARAM_CONN_PORT:
mutex_lock(&conn->xmitmutex);
mutex_unlock(&conn->xmitmutex);
return -EINVAL;
}
inet = inet_sk(tcp_conn->sock->sk);
len = sprintf(buf, "%hu\n", be16_to_cpu(inet->dport));
mutex_unlock(&conn->xmitmutex);
case ISCSI_PARAM_CONN_ADDRESS:
mutex_lock(&conn->xmitmutex);
mutex_unlock(&conn->xmitmutex);
return -EINVAL;
}
if (sk->sk_family == PF_INET) {
inet = inet_sk(sk);
len = sprintf(buf, "%u.%u.%u.%u\n",
NIPQUAD(inet->daddr));
} else {
np = inet6_sk(sk);
len = sprintf(buf,
"%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
NIP6(np->daddr));
}
mutex_unlock(&conn->xmitmutex);
break;
default:
return iscsi_conn_get_param(cls_conn, param, buf);
}
return len;
}
iscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats)
struct iscsi_conn *conn = cls_conn->dd_data;
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
stats->txdata_octets = conn->txdata_octets;
stats->rxdata_octets = conn->rxdata_octets;
stats->scsicmd_pdus = conn->scsicmd_pdus_cnt;
stats->dataout_pdus = conn->dataout_pdus_cnt;
stats->scsirsp_pdus = conn->scsirsp_pdus_cnt;
stats->datain_pdus = conn->datain_pdus_cnt;
stats->r2t_pdus = conn->r2t_pdus_cnt;
stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt;
stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt;
stats->custom_length = 3;
strcpy(stats->custom[0].desc, "tx_sendpage_failures");
stats->custom[0].value = tcp_conn->sendpage_failures_cnt;
strcpy(stats->custom[1].desc, "rx_discontiguous_hdr");
stats->custom[1].value = tcp_conn->discontiguous_hdr_cnt;
strcpy(stats->custom[2].desc, "eh_abort_cnt");
stats->custom[2].value = conn->eh_abort_cnt;
}
static struct iscsi_cls_session *
iscsi_tcp_session_create(struct iscsi_transport *iscsit,
struct scsi_transport_template *scsit,
uint32_t initial_cmdsn, uint32_t *hostno)
struct iscsi_cls_session *cls_session;
struct iscsi_session *session;
uint32_t hn;
int cmd_i;
cls_session = iscsi_session_setup(iscsit, scsit,
sizeof(struct iscsi_tcp_cmd_task),
sizeof(struct iscsi_tcp_mgmt_task),
initial_cmdsn, &hn);
if (!cls_session)
return NULL;
*hostno = hn;
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
session = class_to_transport_session(cls_session);
for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) {
struct iscsi_cmd_task *ctask = session->cmds[cmd_i];
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
ctask->hdr = &tcp_ctask->hdr;
}
for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) {
struct iscsi_mgmt_task *mtask = session->mgmt_cmds[cmd_i];
struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data;
mtask->hdr = &tcp_mtask->hdr;
}
if (iscsi_r2tpool_alloc(class_to_transport_session(cls_session)))
goto r2tpool_alloc_fail;
return cls_session;
r2tpool_alloc_fail:
iscsi_session_teardown(cls_session);
return NULL;
}
static void iscsi_tcp_session_destroy(struct iscsi_cls_session *cls_session)
{
iscsi_r2tpool_free(class_to_transport_session(cls_session));
iscsi_session_teardown(cls_session);
static struct scsi_host_template iscsi_sht = {
.name = "iSCSI Initiator over TCP/IP",
.queuecommand = iscsi_queuecommand,
.change_queue_depth = iscsi_change_queue_depth,
.can_queue = ISCSI_XMIT_CMDS_MAX - 1,
.sg_tablesize = ISCSI_SG_TABLESIZE,
.cmd_per_lun = ISCSI_DEF_CMD_PER_LUN,
.eh_abort_handler = iscsi_eh_abort,
.eh_host_reset_handler = iscsi_eh_host_reset,
.use_clustering = DISABLE_CLUSTERING,
.proc_name = "iscsi_tcp",
.this_id = -1,
};
static struct iscsi_transport iscsi_tcp_transport = {
.owner = THIS_MODULE,
.name = "tcp",
.caps = CAP_RECOVERY_L0 | CAP_MULTI_R2T | CAP_HDRDGST
| CAP_DATADGST,
.param_mask = ISCSI_MAX_RECV_DLENGTH |
ISCSI_MAX_XMIT_DLENGTH |
ISCSI_HDRDGST_EN |
ISCSI_DATADGST_EN |
ISCSI_INITIAL_R2T_EN |
ISCSI_MAX_R2T |
ISCSI_IMM_DATA_EN |
ISCSI_FIRST_BURST |
ISCSI_MAX_BURST |
ISCSI_PDU_INORDER_EN |
ISCSI_DATASEQ_INORDER_EN |
ISCSI_ERL |
ISCSI_CONN_PORT |
ISCSI_EXP_STATSN |
ISCSI_PERSISTENT_PORT |
ISCSI_PERSISTENT_ADDRESS |
ISCSI_TARGET_NAME |
ISCSI_TPGT,
.host_template = &iscsi_sht,
.conndata_size = sizeof(struct iscsi_conn),
.max_conn = 1,
.max_cmd_len = ISCSI_TCP_MAX_CMD_LEN,
/* session management */
.create_session = iscsi_tcp_session_create,
.destroy_session = iscsi_tcp_session_destroy,
/* connection management */
.create_conn = iscsi_tcp_conn_create,
.bind_conn = iscsi_tcp_conn_bind,
.destroy_conn = iscsi_tcp_conn_destroy,
.set_param = iscsi_conn_set_param,
.get_conn_param = iscsi_tcp_conn_get_param,
.get_session_param = iscsi_session_get_param,
.start_conn = iscsi_conn_start,
.stop_conn = iscsi_tcp_conn_stop,
.send_pdu = iscsi_conn_send_pdu,
.get_stats = iscsi_conn_get_stats,
.init_cmd_task = iscsi_tcp_cmd_init,
.init_mgmt_task = iscsi_tcp_mgmt_init,
.xmit_cmd_task = iscsi_tcp_ctask_xmit,
.xmit_mgmt_task = iscsi_tcp_mtask_xmit,
.cleanup_cmd_task = iscsi_tcp_cleanup_ctask,
/* recovery */
.session_recovery_timedout = iscsi_session_recovery_timedout,
};
static int __init
iscsi_tcp_init(void)
{
if (iscsi_max_lun < 1) {
printk(KERN_ERR "iscsi_tcp: Invalid max_lun value of %u\n",
iscsi_max_lun);
return -EINVAL;
}
iscsi_tcp_transport.max_lun = iscsi_max_lun;
if (!iscsi_register_transport(&iscsi_tcp_transport))