⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scsi_transport_iscsi.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		break;	case ISCSI_UEVENT_BIND_CONN:		session = iscsi_session_lookup(ev->u.b_conn.sid);		conn = iscsi_conn_lookup(ev->u.b_conn.sid, ev->u.b_conn.cid);		if (session && conn)			ev->r.retcode =	transport->bind_conn(session, conn,					ev->u.b_conn.transport_eph,					ev->u.b_conn.is_leading);		else			err = -EINVAL;		break;	case ISCSI_UEVENT_SET_PARAM:		err = iscsi_set_param(transport, ev);		break;	case ISCSI_UEVENT_START_CONN:		conn = iscsi_conn_lookup(ev->u.start_conn.sid, ev->u.start_conn.cid);		if (conn)			ev->r.retcode = transport->start_conn(conn);		else			err = -EINVAL;		break;	case ISCSI_UEVENT_STOP_CONN:		conn = iscsi_conn_lookup(ev->u.stop_conn.sid, ev->u.stop_conn.cid);		if (conn)			transport->stop_conn(conn, ev->u.stop_conn.flag);		else			err = -EINVAL;		break;	case ISCSI_UEVENT_SEND_PDU:		conn = iscsi_conn_lookup(ev->u.send_pdu.sid, ev->u.send_pdu.cid);		if (conn)			ev->r.retcode =	transport->send_pdu(conn,				(struct iscsi_hdr*)((char*)ev + sizeof(*ev)),				(char*)ev + sizeof(*ev) + ev->u.send_pdu.hdr_size,				ev->u.send_pdu.data_size);		else			err = -EINVAL;		break;	case ISCSI_UEVENT_GET_STATS:		err = iscsi_if_get_stats(transport, nlh);		break;	case ISCSI_UEVENT_TRANSPORT_EP_CONNECT:	case ISCSI_UEVENT_TRANSPORT_EP_POLL:	case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:		err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type);		break;	case ISCSI_UEVENT_TGT_DSCVR:		err = iscsi_tgt_dscvr(transport, ev);		break;	case ISCSI_UEVENT_SET_HOST_PARAM:		err = iscsi_set_host_param(transport, ev);		break;	default:		err = -ENOSYS;		break;	}	module_put(transport->owner);	return err;}/* * Get message from skb.  Each message is processed by iscsi_if_recv_msg. * Malformed skbs with wrong lengths or invalid creds are not processed. */static voidiscsi_if_rx(struct sk_buff *skb){	mutex_lock(&rx_queue_mutex);	while (skb->len >= NLMSG_SPACE(0)) {		int err;		uint32_t rlen;		struct nlmsghdr	*nlh;		struct iscsi_uevent *ev;		nlh = nlmsg_hdr(skb);		if (nlh->nlmsg_len < sizeof(*nlh) ||		    skb->len < nlh->nlmsg_len) {			break;		}		ev = NLMSG_DATA(nlh);		rlen = NLMSG_ALIGN(nlh->nlmsg_len);		if (rlen > skb->len)			rlen = skb->len;		err = iscsi_if_recv_msg(skb, nlh);		if (err) {			ev->type = ISCSI_KEVENT_IF_ERROR;			ev->iferror = err;		}		do {			/*			 * special case for GET_STATS:			 * on success - sending reply and stats from			 * inside of if_recv_msg(),			 * on error - fall through.			 */			if (ev->type == ISCSI_UEVENT_GET_STATS && !err)				break;			err = iscsi_if_send_reply(				NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,				nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));		} while (err < 0 && err != -ECONNREFUSED);		skb_pull(skb, rlen);	}	mutex_unlock(&rx_queue_mutex);}#define iscsi_cdev_to_conn(_cdev) \	iscsi_dev_to_conn(_cdev->dev)#define ISCSI_CLASS_ATTR(_prefix,_name,_mode,_show,_store)		\struct class_device_attribute class_device_attr_##_prefix##_##_name =	\	__ATTR(_name,_mode,_show,_store)/* * iSCSI connection attrs */#define iscsi_conn_attr_show(param)					\static ssize_t								\show_conn_param_##param(struct class_device *cdev, char *buf)		\{									\	struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev);		\	struct iscsi_transport *t = conn->transport;			\	return t->get_conn_param(conn, param, buf);			\}#define iscsi_conn_attr(field, param)					\	iscsi_conn_attr_show(param)					\static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_param_##param,	\			NULL);iscsi_conn_attr(max_recv_dlength, ISCSI_PARAM_MAX_RECV_DLENGTH);iscsi_conn_attr(max_xmit_dlength, ISCSI_PARAM_MAX_XMIT_DLENGTH);iscsi_conn_attr(header_digest, ISCSI_PARAM_HDRDGST_EN);iscsi_conn_attr(data_digest, ISCSI_PARAM_DATADGST_EN);iscsi_conn_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN);iscsi_conn_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN);iscsi_conn_attr(persistent_port, ISCSI_PARAM_PERSISTENT_PORT);iscsi_conn_attr(port, ISCSI_PARAM_CONN_PORT);iscsi_conn_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN);iscsi_conn_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS);iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS);#define iscsi_cdev_to_session(_cdev) \	iscsi_dev_to_session(_cdev->dev)/* * iSCSI session attrs */#define iscsi_session_attr_show(param, perm)				\static ssize_t								\show_session_param_##param(struct class_device *cdev, char *buf)	\{									\	struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \	struct iscsi_transport *t = session->transport;			\									\	if (perm && !capable(CAP_SYS_ADMIN))				\		return -EACCES;						\	return t->get_session_param(session, param, buf);		\}#define iscsi_session_attr(field, param, perm)				\	iscsi_session_attr_show(param, perm)				\static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_param_##param, \			NULL);iscsi_session_attr(targetname, ISCSI_PARAM_TARGET_NAME, 0);iscsi_session_attr(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN, 0);iscsi_session_attr(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T, 0);iscsi_session_attr(immediate_data, ISCSI_PARAM_IMM_DATA_EN, 0);iscsi_session_attr(first_burst_len, ISCSI_PARAM_FIRST_BURST, 0);iscsi_session_attr(max_burst_len, ISCSI_PARAM_MAX_BURST, 0);iscsi_session_attr(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN, 0);iscsi_session_attr(data_seq_in_order, ISCSI_PARAM_DATASEQ_INORDER_EN, 0);iscsi_session_attr(erl, ISCSI_PARAM_ERL, 0);iscsi_session_attr(tpgt, ISCSI_PARAM_TPGT, 0);iscsi_session_attr(username, ISCSI_PARAM_USERNAME, 1);iscsi_session_attr(username_in, ISCSI_PARAM_USERNAME_IN, 1);iscsi_session_attr(password, ISCSI_PARAM_PASSWORD, 1);iscsi_session_attr(password_in, ISCSI_PARAM_PASSWORD_IN, 1);#define iscsi_priv_session_attr_show(field, format)			\static ssize_t								\show_priv_session_##field(struct class_device *cdev, char *buf)		\{									\	struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);\	return sprintf(buf, format"\n", session->field);		\}#define iscsi_priv_session_attr(field, format)				\	iscsi_priv_session_attr_show(field, format)			\static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO, show_priv_session_##field, \			NULL)iscsi_priv_session_attr(recovery_tmo, "%d");/* * iSCSI host attrs */#define iscsi_host_attr_show(param)					\static ssize_t								\show_host_param_##param(struct class_device *cdev, char *buf)		\{									\	struct Scsi_Host *shost = transport_class_to_shost(cdev);	\	struct iscsi_internal *priv = to_iscsi_internal(shost->transportt); \	return priv->iscsi_transport->get_host_param(shost, param, buf); \}#define iscsi_host_attr(field, param)					\	iscsi_host_attr_show(param)					\static ISCSI_CLASS_ATTR(host, field, S_IRUGO, show_host_param_##param,	\			NULL);iscsi_host_attr(netdev, ISCSI_HOST_PARAM_NETDEV_NAME);iscsi_host_attr(hwaddress, ISCSI_HOST_PARAM_HWADDRESS);iscsi_host_attr(ipaddress, ISCSI_HOST_PARAM_IPADDRESS);iscsi_host_attr(initiatorname, ISCSI_HOST_PARAM_INITIATOR_NAME);#define SETUP_PRIV_SESSION_RD_ATTR(field)				\do {									\	priv->session_attrs[count] = &class_device_attr_priv_sess_##field; \	count++;							\} while (0)#define SETUP_SESSION_RD_ATTR(field, param_flag)			\do {									\	if (tt->param_mask & param_flag) {				\		priv->session_attrs[count] = &class_device_attr_sess_##field; \		count++;						\	}								\} while (0)#define SETUP_CONN_RD_ATTR(field, param_flag)				\do {									\	if (tt->param_mask & param_flag) {				\		priv->conn_attrs[count] = &class_device_attr_conn_##field; \		count++;						\	}								\} while (0)#define SETUP_HOST_RD_ATTR(field, param_flag)				\do {									\	if (tt->host_param_mask & param_flag) {				\		priv->host_attrs[count] = &class_device_attr_host_##field; \		count++;						\	}								\} while (0)static int iscsi_session_match(struct attribute_container *cont,			   struct device *dev){	struct iscsi_cls_session *session;	struct Scsi_Host *shost;	struct iscsi_internal *priv;	if (!iscsi_is_session_dev(dev))		return 0;	session = iscsi_dev_to_session(dev);	shost = iscsi_session_to_shost(session);	if (!shost->transportt)		return 0;	priv = to_iscsi_internal(shost->transportt);	if (priv->session_cont.ac.class != &iscsi_session_class.class)		return 0;	return &priv->session_cont.ac == cont;}static int iscsi_conn_match(struct attribute_container *cont,			   struct device *dev){	struct iscsi_cls_session *session;	struct iscsi_cls_conn *conn;	struct Scsi_Host *shost;	struct iscsi_internal *priv;	if (!iscsi_is_conn_dev(dev))		return 0;	conn = iscsi_dev_to_conn(dev);	session = iscsi_dev_to_session(conn->dev.parent);	shost = iscsi_session_to_shost(session);	if (!shost->transportt)		return 0;	priv = to_iscsi_internal(shost->transportt);	if (priv->conn_cont.ac.class != &iscsi_connection_class.class)		return 0;	return &priv->conn_cont.ac == cont;}static int iscsi_host_match(struct attribute_container *cont,			    struct device *dev){	struct Scsi_Host *shost;	struct iscsi_internal *priv;	if (!scsi_is_host_device(dev))		return 0;	shost = dev_to_shost(dev);	if (!shost->transportt  ||	    shost->transportt->host_attrs.ac.class != &iscsi_host_class.class)		return 0;        priv = to_iscsi_internal(shost->transportt);        return &priv->t.host_attrs.ac == cont;}struct scsi_transport_template *iscsi_register_transport(struct iscsi_transport *tt){	struct iscsi_internal *priv;	unsigned long flags;	int count = 0, err;	BUG_ON(!tt);	priv = iscsi_if_transport_lookup(tt);	if (priv)		return NULL;	priv = kzalloc(sizeof(*priv), GFP_KERNEL);	if (!priv)		return NULL;	INIT_LIST_HEAD(&priv->list);	priv->daemon_pid = -1;	priv->iscsi_transport = tt;	priv->t.user_scan = iscsi_user_scan;	priv->cdev.class = &iscsi_transport_class;	snprintf(priv->cdev.class_id, BUS_ID_SIZE, "%s", tt->name);	err = class_device_register(&priv->cdev);	if (err)		goto free_priv;	err = sysfs_create_group(&priv->cdev.kobj, &iscsi_transport_group);	if (err)		goto unregister_cdev;	/* host parameters */	priv->t.host_attrs.ac.attrs = &priv->host_attrs[0];	priv->t.host_attrs.ac.class = &iscsi_host_class.class;	priv->t.host_attrs.ac.match = iscsi_host_match;	priv->t.host_size = sizeof(struct iscsi_host);	transport_container_register(&priv->t.host_attrs);	SETUP_HOST_RD_ATTR(netdev, ISCSI_HOST_NETDEV_NAME);	SETUP_HOST_RD_ATTR(ipaddress, ISCSI_HOST_IPADDRESS);	SETUP_HOST_RD_ATTR(hwaddress, ISCSI_HOST_HWADDRESS);	SETUP_HOST_RD_ATTR(initiatorname, ISCSI_HOST_INITIATOR_NAME);	BUG_ON(count > ISCSI_HOST_ATTRS);	priv->host_attrs[count] = NULL;	count = 0;	/* connection parameters */	priv->conn_cont.ac.attrs = &priv->conn_attrs[0];	priv->conn_cont.ac.class = &iscsi_connection_class.class;	priv->conn_cont.ac.match = iscsi_conn_match;	transport_container_register(&priv->conn_cont);	SETUP_CONN_RD_ATTR(max_recv_dlength, ISCSI_MAX_RECV_DLENGTH);	SETUP_CONN_RD_ATTR(max_xmit_dlength, ISCSI_MAX_XMIT_DLENGTH);	SETUP_CONN_RD_ATTR(header_digest, ISCSI_HDRDGST_EN);	SETUP_CONN_RD_ATTR(data_digest, ISCSI_DATADGST_EN);	SETUP_CONN_RD_ATTR(ifmarker, ISCSI_IFMARKER_EN);	SETUP_CONN_RD_ATTR(ofmarker, ISCSI_OFMARKER_EN);	SETUP_CONN_RD_ATTR(address, ISCSI_CONN_ADDRESS);	SETUP_CONN_RD_ATTR(port, ISCSI_CONN_PORT);	SETUP_CONN_RD_ATTR(exp_statsn, ISCSI_EXP_STATSN);	SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS);	SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT);	BUG_ON(count > ISCSI_CONN_ATTRS);	priv->conn_attrs[count] = NULL;	count = 0;	/* session parameters */	priv->session_cont.ac.attrs = &priv->session_attrs[0];	priv->session_cont.ac.class = &iscsi_session_class.class;	priv->session_cont.ac.match = iscsi_session_match;	transport_container_register(&priv->session_cont);	SETUP_SESSION_RD_ATTR(initial_r2t, ISCSI_INITIAL_R2T_EN);	SETUP_SESSION_RD_ATTR(max_outstanding_r2t, ISCSI_MAX_R2T);	SETUP_SESSION_RD_ATTR(immediate_data, ISCSI_IMM_DATA_EN);	SETUP_SESSION_RD_ATTR(first_burst_len, ISCSI_FIRST_BURST);	SETUP_SESSION_RD_ATTR(max_burst_len, ISCSI_MAX_BURST);	SETUP_SESSION_RD_ATTR(data_pdu_in_order, ISCSI_PDU_INORDER_EN);	SETUP_SESSION_RD_ATTR(data_seq_in_order, ISCSI_DATASEQ_INORDER_EN);	SETUP_SESSION_RD_ATTR(erl, ISCSI_ERL);	SETUP_SESSION_RD_ATTR(targetname, ISCSI_TARGET_NAME);	SETUP_SESSION_RD_ATTR(tpgt, ISCSI_TPGT);	SETUP_SESSION_RD_ATTR(password, ISCSI_USERNAME);	SETUP_SESSION_RD_ATTR(password_in, ISCSI_USERNAME_IN);	SETUP_SESSION_RD_ATTR(username, ISCSI_PASSWORD);	SETUP_SESSION_RD_ATTR(username_in, ISCSI_PASSWORD_IN);	SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo);	BUG_ON(count > ISCSI_SESSION_ATTRS);	priv->session_attrs[count] = NULL;	spin_lock_irqsave(&iscsi_transport_lock, flags);	list_add(&priv->list, &iscsi_transports);	spin_unlock_irqrestore(&iscsi_transport_lock, flags);	printk(KERN_NOTICE "iscsi: registered transport (%s)\n", tt->name);	return &priv->t;unregister_cdev:	class_device_unregister(&priv->cdev);free_priv:	kfree(priv);	return NULL;}EXPORT_SYMBOL_GPL(iscsi_register_transport);int iscsi_unregister_transport(struct iscsi_transport *tt){	struct iscsi_internal *priv;	unsigned long flags;	BUG_ON(!tt);	mutex_lock(&rx_queue_mutex);	priv = iscsi_if_transport_lookup(tt);	BUG_ON (!priv);	spin_lock_irqsave(&iscsi_transport_lock, flags);	list_del(&priv->list);	spin_unlock_irqrestore(&iscsi_transport_lock, flags);	transport_container_unregister(&priv->conn_cont);	transport_container_unregister(&priv->session_cont);	transport_container_unregister(&priv->t.host_attrs);	sysfs_remove_group(&priv->cdev.kobj, &iscsi_transport_group);	class_device_unregister(&priv->cdev);	mutex_unlock(&rx_queue_mutex);	return 0;}EXPORT_SYMBOL_GPL(iscsi_unregister_transport);static __init int iscsi_transport_init(void){	int err;	printk(KERN_INFO "Loading iSCSI transport class v%s.\n",		ISCSI_TRANSPORT_VERSION);	atomic_set(&iscsi_session_nr, 0);	err = class_register(&iscsi_transport_class);	if (err)		return err;	err = transport_class_register(&iscsi_host_class);	if (err)		goto unregister_transport_class;	err = transport_class_register(&iscsi_connection_class);	if (err)		goto unregister_host_class;	err = transport_class_register(&iscsi_session_class);	if (err)		goto unregister_conn_class;	nls = netlink_kernel_create(&init_net, NETLINK_ISCSI, 1, iscsi_if_rx, NULL,			THIS_MODULE);	if (!nls) {		err = -ENOBUFS;		goto unregister_session_class;	}	return 0;unregister_session_class:	transport_class_unregister(&iscsi_session_class);unregister_conn_class:	transport_class_unregister(&iscsi_connection_class);unregister_host_class:	transport_class_unregister(&iscsi_host_class);unregister_transport_class:	class_unregister(&iscsi_transport_class);	return err;}static void __exit iscsi_transport_exit(void){	sock_release(nls->sk_socket);	transport_class_unregister(&iscsi_connection_class);	transport_class_unregister(&iscsi_session_class);	transport_class_unregister(&iscsi_host_class);	class_unregister(&iscsi_transport_class);}module_init(iscsi_transport_init);module_exit(iscsi_transport_exit);MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, "	      "Dmitry Yusupov <dmitry_yus@yahoo.com>, "	      "Alex Aizman <itn780@yahoo.com>");MODULE_DESCRIPTION("iSCSI Transport Interface");MODULE_LICENSE("GPL");MODULE_VERSION(ISCSI_TRANSPORT_VERSION);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -