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

📄 scsi_transport_iscsi.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	rc = netlink_unicast(nls, skb, pid, MSG_DONTWAIT);	if (rc < 0) {		printk(KERN_ERR "iscsi: can not unicast skb (%d)\n", rc);		return rc;	}	return 0;}int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,		   char *data, uint32_t data_size){	struct nlmsghdr	*nlh;	struct sk_buff *skb;	struct iscsi_uevent *ev;	char *pdu;	struct iscsi_internal *priv;	int len = NLMSG_SPACE(sizeof(*ev) + sizeof(struct iscsi_hdr) +			      data_size);	priv = iscsi_if_transport_lookup(conn->transport);	if (!priv)		return -EINVAL;	skb = alloc_skb(len, GFP_ATOMIC);	if (!skb) {		iscsi_conn_error(conn, ISCSI_ERR_CONN_FAILED);		dev_printk(KERN_ERR, &conn->dev, "iscsi: can not deliver "			   "control PDU: OOM\n");		return -ENOMEM;	}	nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0);	ev = NLMSG_DATA(nlh);	memset(ev, 0, sizeof(*ev));	ev->transport_handle = iscsi_handle(conn->transport);	ev->type = ISCSI_KEVENT_RECV_PDU;	ev->r.recv_req.cid = conn->cid;	ev->r.recv_req.sid = iscsi_conn_get_sid(conn);	pdu = (char*)ev + sizeof(*ev);	memcpy(pdu, hdr, sizeof(struct iscsi_hdr));	memcpy(pdu + sizeof(struct iscsi_hdr), data, data_size);	return iscsi_unicast_skb(skb, priv->daemon_pid);}EXPORT_SYMBOL_GPL(iscsi_recv_pdu);void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error){	struct nlmsghdr	*nlh;	struct sk_buff	*skb;	struct iscsi_uevent *ev;	struct iscsi_internal *priv;	int len = NLMSG_SPACE(sizeof(*ev));	priv = iscsi_if_transport_lookup(conn->transport);	if (!priv)		return;	skb = alloc_skb(len, GFP_ATOMIC);	if (!skb) {		dev_printk(KERN_ERR, &conn->dev, "iscsi: gracefully ignored "			  "conn error (%d)\n", error);		return;	}	nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0);	ev = NLMSG_DATA(nlh);	ev->transport_handle = iscsi_handle(conn->transport);	ev->type = ISCSI_KEVENT_CONN_ERROR;	ev->r.connerror.error = error;	ev->r.connerror.cid = conn->cid;	ev->r.connerror.sid = iscsi_conn_get_sid(conn);	iscsi_broadcast_skb(skb, GFP_ATOMIC);	dev_printk(KERN_INFO, &conn->dev, "iscsi: detected conn error (%d)\n",		   error);}EXPORT_SYMBOL_GPL(iscsi_conn_error);static intiscsi_if_send_reply(int pid, int seq, int type, int done, int multi,		      void *payload, int size){	struct sk_buff	*skb;	struct nlmsghdr	*nlh;	int len = NLMSG_SPACE(size);	int flags = multi ? NLM_F_MULTI : 0;	int t = done ? NLMSG_DONE : type;	skb = alloc_skb(len, GFP_ATOMIC);	if (!skb) {		printk(KERN_ERR "Could not allocate skb to send reply.\n");		return -ENOMEM;	}	nlh = __nlmsg_put(skb, pid, seq, t, (len - sizeof(*nlh)), 0);	nlh->nlmsg_flags = flags;	memcpy(NLMSG_DATA(nlh), payload, size);	return iscsi_unicast_skb(skb, pid);}static intiscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh){	struct iscsi_uevent *ev = NLMSG_DATA(nlh);	struct iscsi_stats *stats;	struct sk_buff *skbstat;	struct iscsi_cls_conn *conn;	struct nlmsghdr	*nlhstat;	struct iscsi_uevent *evstat;	struct iscsi_internal *priv;	int len = NLMSG_SPACE(sizeof(*ev) +			      sizeof(struct iscsi_stats) +			      sizeof(struct iscsi_stats_custom) *			      ISCSI_STATS_CUSTOM_MAX);	int err = 0;	priv = iscsi_if_transport_lookup(transport);	if (!priv)		return -EINVAL;	conn = iscsi_conn_lookup(ev->u.get_stats.sid, ev->u.get_stats.cid);	if (!conn)		return -EEXIST;	do {		int actual_size;		skbstat = alloc_skb(len, GFP_ATOMIC);		if (!skbstat) {			dev_printk(KERN_ERR, &conn->dev, "iscsi: can not "				   "deliver stats: OOM\n");			return -ENOMEM;		}		nlhstat = __nlmsg_put(skbstat, priv->daemon_pid, 0, 0,				      (len - sizeof(*nlhstat)), 0);		evstat = NLMSG_DATA(nlhstat);		memset(evstat, 0, sizeof(*evstat));		evstat->transport_handle = iscsi_handle(conn->transport);		evstat->type = nlh->nlmsg_type;		evstat->u.get_stats.cid =			ev->u.get_stats.cid;		evstat->u.get_stats.sid =			ev->u.get_stats.sid;		stats = (struct iscsi_stats *)			((char*)evstat + sizeof(*evstat));		memset(stats, 0, sizeof(*stats));		transport->get_stats(conn, stats);		actual_size = NLMSG_SPACE(sizeof(struct iscsi_uevent) +					  sizeof(struct iscsi_stats) +					  sizeof(struct iscsi_stats_custom) *					  stats->custom_length);		actual_size -= sizeof(*nlhstat);		actual_size = NLMSG_LENGTH(actual_size);		skb_trim(skbstat, NLMSG_ALIGN(actual_size));		nlhstat->nlmsg_len = actual_size;		err = iscsi_unicast_skb(skbstat, priv->daemon_pid);	} while (err < 0 && err != -ECONNREFUSED);	return err;}/** * iscsi_if_destroy_session_done - send session destr. completion event * @conn: last connection for session * * This is called by HW iscsi LLDs to notify userpsace that its HW has * removed a session. **/int iscsi_if_destroy_session_done(struct iscsi_cls_conn *conn){	struct iscsi_internal *priv;	struct iscsi_cls_session *session;	struct Scsi_Host *shost;	struct iscsi_uevent *ev;	struct sk_buff  *skb;	struct nlmsghdr *nlh;	unsigned long flags;	int rc, len = NLMSG_SPACE(sizeof(*ev));	priv = iscsi_if_transport_lookup(conn->transport);	if (!priv)		return -EINVAL;	session = iscsi_dev_to_session(conn->dev.parent);	shost = iscsi_session_to_shost(session);	skb = alloc_skb(len, GFP_KERNEL);	if (!skb) {		dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "			  "session creation event\n");		return -ENOMEM;	}	nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0);	ev = NLMSG_DATA(nlh);	ev->transport_handle = iscsi_handle(conn->transport);	ev->type = ISCSI_KEVENT_DESTROY_SESSION;	ev->r.d_session.host_no = shost->host_no;	ev->r.d_session.sid = session->sid;	/*	 * this will occur if the daemon is not up, so we just warn	 * the user and when the daemon is restarted it will handle it	 */	rc = iscsi_broadcast_skb(skb, GFP_KERNEL);	if (rc < 0)		dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "			  "session destruction event. Check iscsi daemon\n");	spin_lock_irqsave(&sesslock, flags);	list_del(&session->sess_list);	spin_unlock_irqrestore(&sesslock, flags);	spin_lock_irqsave(&connlock, flags);	conn->active = 0;	list_del(&conn->conn_list);	spin_unlock_irqrestore(&connlock, flags);	return rc;}EXPORT_SYMBOL_GPL(iscsi_if_destroy_session_done);/** * iscsi_if_create_session_done - send session creation completion event * @conn: leading connection for session * * This is called by HW iscsi LLDs to notify userpsace that its HW has * created a session or a existing session is back in the logged in state. **/int iscsi_if_create_session_done(struct iscsi_cls_conn *conn){	struct iscsi_internal *priv;	struct iscsi_cls_session *session;	struct Scsi_Host *shost;	struct iscsi_uevent *ev;	struct sk_buff  *skb;	struct nlmsghdr *nlh;	unsigned long flags;	int rc, len = NLMSG_SPACE(sizeof(*ev));	priv = iscsi_if_transport_lookup(conn->transport);	if (!priv)		return -EINVAL;	session = iscsi_dev_to_session(conn->dev.parent);	shost = iscsi_session_to_shost(session);	skb = alloc_skb(len, GFP_KERNEL);	if (!skb) {		dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "			  "session creation event\n");		return -ENOMEM;	}	nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0);	ev = NLMSG_DATA(nlh);	ev->transport_handle = iscsi_handle(conn->transport);	ev->type = ISCSI_UEVENT_CREATE_SESSION;	ev->r.c_session_ret.host_no = shost->host_no;	ev->r.c_session_ret.sid = session->sid;	/*	 * this will occur if the daemon is not up, so we just warn	 * the user and when the daemon is restarted it will handle it	 */	rc = iscsi_broadcast_skb(skb, GFP_KERNEL);	if (rc < 0)		dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "			  "session creation event. Check iscsi daemon\n");	spin_lock_irqsave(&sesslock, flags);	list_add(&session->sess_list, &sesslist);	spin_unlock_irqrestore(&sesslock, flags);	spin_lock_irqsave(&connlock, flags);	list_add(&conn->conn_list, &connlist);	conn->active = 1;	spin_unlock_irqrestore(&connlock, flags);	return rc;}EXPORT_SYMBOL_GPL(iscsi_if_create_session_done);static intiscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev){	struct iscsi_transport *transport = priv->iscsi_transport;	struct iscsi_cls_session *session;	unsigned long flags;	uint32_t hostno;	session = transport->create_session(transport, &priv->t,					    ev->u.c_session.cmds_max,					    ev->u.c_session.queue_depth,					    ev->u.c_session.initial_cmdsn,					    &hostno);	if (!session)		return -ENOMEM;	spin_lock_irqsave(&sesslock, flags);	list_add(&session->sess_list, &sesslist);	spin_unlock_irqrestore(&sesslock, flags);	ev->r.c_session_ret.host_no = hostno;	ev->r.c_session_ret.sid = session->sid;	return 0;}static intiscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev){	struct iscsi_cls_conn *conn;	struct iscsi_cls_session *session;	unsigned long flags;	session = iscsi_session_lookup(ev->u.c_conn.sid);	if (!session) {		printk(KERN_ERR "iscsi: invalid session %d\n",		       ev->u.c_conn.sid);		return -EINVAL;	}	conn = transport->create_conn(session, ev->u.c_conn.cid);	if (!conn) {		printk(KERN_ERR "iscsi: couldn't create a new "			   "connection for session %d\n",			   session->sid);		return -ENOMEM;	}	ev->r.c_conn_ret.sid = session->sid;	ev->r.c_conn_ret.cid = conn->cid;	spin_lock_irqsave(&connlock, flags);	list_add(&conn->conn_list, &connlist);	conn->active = 1;	spin_unlock_irqrestore(&connlock, flags);	return 0;}static intiscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev){	unsigned long flags;	struct iscsi_cls_conn *conn;	conn = iscsi_conn_lookup(ev->u.d_conn.sid, ev->u.d_conn.cid);	if (!conn)		return -EINVAL;	spin_lock_irqsave(&connlock, flags);	conn->active = 0;	list_del(&conn->conn_list);	spin_unlock_irqrestore(&connlock, flags);	if (transport->destroy_conn)		transport->destroy_conn(conn);	return 0;}static intiscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev){	char *data = (char*)ev + sizeof(*ev);	struct iscsi_cls_conn *conn;	struct iscsi_cls_session *session;	int err = 0, value = 0;	session = iscsi_session_lookup(ev->u.set_param.sid);	conn = iscsi_conn_lookup(ev->u.set_param.sid, ev->u.set_param.cid);	if (!conn || !session)		return -EINVAL;	switch (ev->u.set_param.param) {	case ISCSI_PARAM_SESS_RECOVERY_TMO:		sscanf(data, "%d", &value);		if (value != 0)			session->recovery_tmo = value;		break;	default:		err = transport->set_param(conn, ev->u.set_param.param,					   data, ev->u.set_param.len);	}	return err;}static intiscsi_if_transport_ep(struct iscsi_transport *transport,		      struct iscsi_uevent *ev, int msg_type){	struct sockaddr *dst_addr;	int rc = 0;	switch (msg_type) {	case ISCSI_UEVENT_TRANSPORT_EP_CONNECT:		if (!transport->ep_connect)			return -EINVAL;		dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev));		rc = transport->ep_connect(dst_addr,					   ev->u.ep_connect.non_blocking,					   &ev->r.ep_connect_ret.handle);		break;	case ISCSI_UEVENT_TRANSPORT_EP_POLL:		if (!transport->ep_poll)			return -EINVAL;		ev->r.retcode = transport->ep_poll(ev->u.ep_poll.ep_handle,						   ev->u.ep_poll.timeout_ms);		break;	case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:		if (!transport->ep_disconnect)			return -EINVAL;		transport->ep_disconnect(ev->u.ep_disconnect.ep_handle);		break;	}	return rc;}static intiscsi_tgt_dscvr(struct iscsi_transport *transport,		struct iscsi_uevent *ev){	struct Scsi_Host *shost;	struct sockaddr *dst_addr;	int err;	if (!transport->tgt_dscvr)		return -EINVAL;	shost = scsi_host_lookup(ev->u.tgt_dscvr.host_no);	if (IS_ERR(shost)) {		printk(KERN_ERR "target discovery could not find host no %u\n",		       ev->u.tgt_dscvr.host_no);		return -ENODEV;	}	dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev));	err = transport->tgt_dscvr(shost, ev->u.tgt_dscvr.type,				   ev->u.tgt_dscvr.enable, dst_addr);	scsi_host_put(shost);	return err;}static intiscsi_set_host_param(struct iscsi_transport *transport,		     struct iscsi_uevent *ev){	char *data = (char*)ev + sizeof(*ev);	struct Scsi_Host *shost;	int err;	if (!transport->set_host_param)		return -ENOSYS;	shost = scsi_host_lookup(ev->u.set_host_param.host_no);	if (IS_ERR(shost)) {		printk(KERN_ERR "set_host_param could not find host no %u\n",		       ev->u.set_host_param.host_no);		return -ENODEV;	}	err = transport->set_host_param(shost, ev->u.set_host_param.param,					data, ev->u.set_host_param.len);	scsi_host_put(shost);	return err;}static intiscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh){	int err = 0;	struct iscsi_uevent *ev = NLMSG_DATA(nlh);	struct iscsi_transport *transport = NULL;	struct iscsi_internal *priv;	struct iscsi_cls_session *session;	struct iscsi_cls_conn *conn;	unsigned long flags;	priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle));	if (!priv)		return -EINVAL;	transport = priv->iscsi_transport;	if (!try_module_get(transport->owner))		return -EINVAL;	priv->daemon_pid = NETLINK_CREDS(skb)->pid;	switch (nlh->nlmsg_type) {	case ISCSI_UEVENT_CREATE_SESSION:		err = iscsi_if_create_session(priv, ev);		break;	case ISCSI_UEVENT_DESTROY_SESSION:		session = iscsi_session_lookup(ev->u.d_session.sid);		if (session) {			spin_lock_irqsave(&sesslock, flags);			list_del(&session->sess_list);			spin_unlock_irqrestore(&sesslock, flags);			transport->destroy_session(session);		} else			err = -EINVAL;		break;	case ISCSI_UEVENT_CREATE_CONN:		err = iscsi_if_create_conn(transport, ev);		break;	case ISCSI_UEVENT_DESTROY_CONN:		err = iscsi_if_destroy_conn(transport, ev);

⌨️ 快捷键说明

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