Skip to content
Snippets Groups Projects
iscsi_tcp.c 57.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • 		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);
    
    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;
    
    	case ISCSI_PARAM_CONN_PORT:
    		mutex_lock(&conn->xmitmutex);
    
    		if (!tcp_conn->sock) {
    
    			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);
    
    		if (!tcp_conn->sock) {
    
    			mutex_unlock(&conn->xmitmutex);
    			return -EINVAL;
    		}
    
    
    		sk = tcp_conn->sock->sk;
    
    		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);
    
    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;
    
    	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_CONN_ADDRESS |
    
    				  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) {
    
    Or Gerlitz's avatar
    Or Gerlitz committed
    		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))
    
    		return -ENODEV;
    
    }
    
    static void __exit
    iscsi_tcp_exit(void)
    {
    	iscsi_unregister_transport(&iscsi_tcp_transport);
    }
    
    module_init(iscsi_tcp_init);
    module_exit(iscsi_tcp_exit);