📄 scsi_transport_iscsi.c
字号:
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 + -