Newer
Older
struct iscsi_cmd_task *ctask = session->cmds[cmd_i];
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
/*
* pre-allocated x4 as much r2ts to handle race when
* target acks DataOut faster than we data_xmit() queues
* could replenish r2tqueue.
*/
/* R2T pool */
if (iscsi_pool_init(&tcp_ctask->r2tpool, session->max_r2t * 4,
(void***)&tcp_ctask->r2ts,
sizeof(struct iscsi_r2t_info))) {
goto r2t_alloc_fail;
}
/* R2T xmit queue */
tcp_ctask->r2tqueue = kfifo_alloc(
session->max_r2t * 4 * sizeof(void*), GFP_KERNEL, NULL);
if (tcp_ctask->r2tqueue == ERR_PTR(-ENOMEM)) {
iscsi_pool_free(&tcp_ctask->r2tpool,
(void**)tcp_ctask->r2ts);
goto r2t_alloc_fail;
}
}
return 0;
r2t_alloc_fail:
for (i = 0; i < cmd_i; i++) {
struct iscsi_cmd_task *ctask = session->cmds[i];
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
kfifo_free(tcp_ctask->r2tqueue);
iscsi_pool_free(&tcp_ctask->r2tpool,
(void**)tcp_ctask->r2ts);
}
return -ENOMEM;
}
static void
iscsi_r2tpool_free(struct iscsi_session *session)
{
int i;
for (i = 0; i < session->cmds_max; i++) {
struct iscsi_cmd_task *ctask = session->cmds[i];
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
kfifo_free(tcp_ctask->r2tqueue);
iscsi_pool_free(&tcp_ctask->r2tpool,
(void**)tcp_ctask->r2ts);
}
}
static int
iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param,
char *buf, int buflen)
struct iscsi_conn *conn = cls_conn->dd_data;
struct iscsi_session *session = conn->session;
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
switch(param) {
case ISCSI_PARAM_HDRDGST_EN:
iscsi_set_param(cls_conn, param, buf, buflen);
tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
tcp_conn->hdr_size += sizeof(__u32);
break;
case ISCSI_PARAM_DATADGST_EN:
iscsi_set_param(cls_conn, param, buf, buflen);
tcp_conn->sendpage = conn->datadgst_en ?
sock_no_sendpage : tcp_conn->sock->ops->sendpage;
break;
case ISCSI_PARAM_MAX_R2T:
sscanf(buf, "%d", &value);
if (session->max_r2t == roundup_pow_of_two(value))
break;
iscsi_r2tpool_free(session);
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;
switch(param) {
case ISCSI_PARAM_CONN_PORT:
spin_lock_bh(&conn->session->lock);
len = sprintf(buf, "%hu\n", conn->portal_port);
spin_unlock_bh(&conn->session->lock);
case ISCSI_PARAM_CONN_ADDRESS:
spin_lock_bh(&conn->session->lock);
len = sprintf(buf, "%s\n", conn->portal_address);
spin_unlock_bh(&conn->session->lock);
return iscsi_conn_get_param(cls_conn, param, buf);
}
return len;
}
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
static int
iscsi_tcp_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param,
char *buf)
{
struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
int len;
switch (param) {
case ISCSI_HOST_PARAM_IPADDRESS:
spin_lock_bh(&session->lock);
if (!session->leadconn)
len = -ENODEV;
else
len = sprintf(buf, "%s\n",
session->leadconn->local_address);
spin_unlock_bh(&session->lock);
break;
default:
return iscsi_host_get_param(shost, 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,
uint16_t cmds_max, uint16_t qdepth,
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, cmds_max, qdepth,
sizeof(struct iscsi_tcp_cmd_task),
sizeof(struct iscsi_tcp_mgmt_task),
initial_cmdsn, &hn);
if (!cls_session)
return NULL;
*hostno = hn;
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
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 int iscsi_tcp_slave_configure(struct scsi_device *sdev)
{
blk_queue_dma_alignment(sdev->request_queue, 0);
return 0;
}
static struct scsi_host_template iscsi_sht = {
.module = THIS_MODULE,
.name = "iSCSI Initiator over TCP/IP",
.queuecommand = iscsi_queuecommand,
.change_queue_depth = iscsi_change_queue_depth,
.can_queue = ISCSI_DEF_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,
.slave_configure = iscsi_tcp_slave_configure,
.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 |
ISCSI_USERNAME | ISCSI_PASSWORD |
ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN,
.host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS |
ISCSI_HOST_INITIATOR_NAME |
ISCSI_HOST_NETDEV_NAME,
.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,

Mike Christie
committed
/* iscsi host params */
.get_host_param = iscsi_tcp_host_get_param,

Mike Christie
committed
.set_host_param = iscsi_host_set_param,
.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))