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

📄 libiscsi.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (session->leadconn == conn) {		/*		 * leading connection? then give up on recovery.		 */		session->state = ISCSI_STATE_TERMINATE;		wake_up(&conn->ehwait);	}	spin_unlock_bh(&session->lock);	/*	 * Block until all in-progress commands for this connection	 * time out or fail.	 */	for (;;) {		spin_lock_irqsave(session->host->host_lock, flags);		if (!session->host->host_busy) { /* OK for ERL == 0 */			spin_unlock_irqrestore(session->host->host_lock, flags);			break;		}		spin_unlock_irqrestore(session->host->host_lock, flags);		msleep_interruptible(500);		printk(KERN_INFO "iscsi: scsi conn_destroy(): host_busy %d "		       "host_failed %d\n", session->host->host_busy,		       session->host->host_failed);		/*		 * force eh_abort() to unblock		 */		wake_up(&conn->ehwait);	}	/* flush queued up work because we free the connection below */	scsi_flush_work(session->host);	spin_lock_bh(&session->lock);	kfree(conn->data);	kfree(conn->persistent_address);	__kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask,		    sizeof(void*));	if (session->leadconn == conn)		session->leadconn = NULL;	spin_unlock_bh(&session->lock);	kfifo_free(conn->mgmtqueue);	iscsi_destroy_conn(cls_conn);}EXPORT_SYMBOL_GPL(iscsi_conn_teardown);int iscsi_conn_start(struct iscsi_cls_conn *cls_conn){	struct iscsi_conn *conn = cls_conn->dd_data;	struct iscsi_session *session = conn->session;	if (!session) {		printk(KERN_ERR "iscsi: can't start unbound connection\n");		return -EPERM;	}	if ((session->imm_data_en || !session->initial_r2t_en) &&	     session->first_burst > session->max_burst) {		printk("iscsi: invalid burst lengths: "		       "first_burst %d max_burst %d\n",		       session->first_burst, session->max_burst);		return -EINVAL;	}	spin_lock_bh(&session->lock);	conn->c_stage = ISCSI_CONN_STARTED;	session->state = ISCSI_STATE_LOGGED_IN;	session->queued_cmdsn = session->cmdsn;	switch(conn->stop_stage) {	case STOP_CONN_RECOVER:		/*		 * unblock eh_abort() if it is blocked. re-try all		 * commands after successful recovery		 */		conn->stop_stage = 0;		conn->tmabort_state = TMABORT_INITIAL;		session->age++;		spin_unlock_bh(&session->lock);		iscsi_unblock_session(session_to_cls(session));		wake_up(&conn->ehwait);		return 0;	case STOP_CONN_TERM:		conn->stop_stage = 0;		break;	default:		break;	}	spin_unlock_bh(&session->lock);	return 0;}EXPORT_SYMBOL_GPL(iscsi_conn_start);static voidflush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn){	struct iscsi_mgmt_task *mtask, *tmp;	/* handle pending */	while (__kfifo_get(conn->mgmtqueue, (void*)&mtask, sizeof(void*))) {		if (mtask == conn->login_mtask)			continue;		debug_scsi("flushing pending mgmt task itt 0x%x\n", mtask->itt);		__kfifo_put(session->mgmtpool.queue, (void*)&mtask,			    sizeof(void*));	}	/* handle running */	list_for_each_entry_safe(mtask, tmp, &conn->mgmt_run_list, running) {		debug_scsi("flushing running mgmt task itt 0x%x\n", mtask->itt);		list_del(&mtask->running);		if (mtask == conn->login_mtask)			continue;		__kfifo_put(session->mgmtpool.queue, (void*)&mtask,			   sizeof(void*));	}	conn->mtask = NULL;}/* Fail commands. Mutex and session lock held and recv side suspended */static void fail_all_commands(struct iscsi_conn *conn){	struct iscsi_cmd_task *ctask, *tmp;	/* flush pending */	list_for_each_entry_safe(ctask, tmp, &conn->xmitqueue, running) {		debug_scsi("failing pending sc %p itt 0x%x\n", ctask->sc,			   ctask->itt);		fail_command(conn, ctask, DID_BUS_BUSY << 16);	}	/* fail all other running */	list_for_each_entry_safe(ctask, tmp, &conn->run_list, running) {		debug_scsi("failing in progress sc %p itt 0x%x\n",			   ctask->sc, ctask->itt);		fail_command(conn, ctask, DID_BUS_BUSY << 16);	}	conn->ctask = NULL;}static void iscsi_start_session_recovery(struct iscsi_session *session,					 struct iscsi_conn *conn, int flag){	int old_stop_stage;	mutex_lock(&session->eh_mutex);	spin_lock_bh(&session->lock);	if (conn->stop_stage == STOP_CONN_TERM) {		spin_unlock_bh(&session->lock);		mutex_unlock(&session->eh_mutex);		return;	}	/*	 * The LLD either freed/unset the lock on us, or userspace called	 * stop but did not create a proper connection (connection was never	 * bound or it was unbound then stop was called).	 */	if (!conn->recv_lock) {		spin_unlock_bh(&session->lock);		mutex_unlock(&session->eh_mutex);		return;	}	/*	 * When this is called for the in_login state, we only want to clean	 * up the login task and connection. We do not need to block and set	 * the recovery state again	 */	if (flag == STOP_CONN_TERM)		session->state = ISCSI_STATE_TERMINATE;	else if (conn->stop_stage != STOP_CONN_RECOVER)		session->state = ISCSI_STATE_IN_RECOVERY;	old_stop_stage = conn->stop_stage;	conn->stop_stage = flag;	conn->c_stage = ISCSI_CONN_STOPPED;	spin_unlock_bh(&session->lock);	iscsi_suspend_tx(conn);	write_lock_bh(conn->recv_lock);	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);	write_unlock_bh(conn->recv_lock);	/*	 * for connection level recovery we should not calculate	 * header digest. conn->hdr_size used for optimization	 * in hdr_extract() and will be re-negotiated at	 * set_param() time.	 */	if (flag == STOP_CONN_RECOVER) {		conn->hdrdgst_en = 0;		conn->datadgst_en = 0;		if (session->state == ISCSI_STATE_IN_RECOVERY &&		    old_stop_stage != STOP_CONN_RECOVER) {			debug_scsi("blocking session\n");			iscsi_block_session(session_to_cls(session));		}	}	/*	 * flush queues.	 */	spin_lock_bh(&session->lock);	fail_all_commands(conn);	flush_control_queues(session, conn);	spin_unlock_bh(&session->lock);	mutex_unlock(&session->eh_mutex);}void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag){	struct iscsi_conn *conn = cls_conn->dd_data;	struct iscsi_session *session = conn->session;	switch (flag) {	case STOP_CONN_RECOVER:	case STOP_CONN_TERM:		iscsi_start_session_recovery(session, conn, flag);		break;	default:		printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag);	}}EXPORT_SYMBOL_GPL(iscsi_conn_stop);int iscsi_conn_bind(struct iscsi_cls_session *cls_session,		    struct iscsi_cls_conn *cls_conn, int is_leading){	struct iscsi_session *session = class_to_transport_session(cls_session);	struct iscsi_conn *conn = cls_conn->dd_data;	spin_lock_bh(&session->lock);	if (is_leading)		session->leadconn = conn;	spin_unlock_bh(&session->lock);	/*	 * Unblock xmitworker(), Login Phase will pass through.	 */	clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);	clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);	return 0;}EXPORT_SYMBOL_GPL(iscsi_conn_bind);int iscsi_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;	uint32_t value;	switch(param) {	case ISCSI_PARAM_MAX_RECV_DLENGTH:		sscanf(buf, "%d", &conn->max_recv_dlength);		break;	case ISCSI_PARAM_MAX_XMIT_DLENGTH:		sscanf(buf, "%d", &conn->max_xmit_dlength);		break;	case ISCSI_PARAM_HDRDGST_EN:		sscanf(buf, "%d", &conn->hdrdgst_en);		break;	case ISCSI_PARAM_DATADGST_EN:		sscanf(buf, "%d", &conn->datadgst_en);		break;	case ISCSI_PARAM_INITIAL_R2T_EN:		sscanf(buf, "%d", &session->initial_r2t_en);		break;	case ISCSI_PARAM_MAX_R2T:		sscanf(buf, "%d", &session->max_r2t);		break;	case ISCSI_PARAM_IMM_DATA_EN:		sscanf(buf, "%d", &session->imm_data_en);		break;	case ISCSI_PARAM_FIRST_BURST:		sscanf(buf, "%d", &session->first_burst);		break;	case ISCSI_PARAM_MAX_BURST:		sscanf(buf, "%d", &session->max_burst);		break;	case ISCSI_PARAM_PDU_INORDER_EN:		sscanf(buf, "%d", &session->pdu_inorder_en);		break;	case ISCSI_PARAM_DATASEQ_INORDER_EN:		sscanf(buf, "%d", &session->dataseq_inorder_en);		break;	case ISCSI_PARAM_ERL:		sscanf(buf, "%d", &session->erl);		break;	case ISCSI_PARAM_IFMARKER_EN:		sscanf(buf, "%d", &value);		BUG_ON(value);		break;	case ISCSI_PARAM_OFMARKER_EN:		sscanf(buf, "%d", &value);		BUG_ON(value);		break;	case ISCSI_PARAM_EXP_STATSN:		sscanf(buf, "%u", &conn->exp_statsn);		break;	case ISCSI_PARAM_USERNAME:		kfree(session->username);		session->username = kstrdup(buf, GFP_KERNEL);		if (!session->username)			return -ENOMEM;		break;	case ISCSI_PARAM_USERNAME_IN:		kfree(session->username_in);		session->username_in = kstrdup(buf, GFP_KERNEL);		if (!session->username_in)			return -ENOMEM;		break;	case ISCSI_PARAM_PASSWORD:		kfree(session->password);		session->password = kstrdup(buf, GFP_KERNEL);		if (!session->password)			return -ENOMEM;		break;	case ISCSI_PARAM_PASSWORD_IN:		kfree(session->password_in);		session->password_in = kstrdup(buf, GFP_KERNEL);		if (!session->password_in)			return -ENOMEM;		break;	case ISCSI_PARAM_TARGET_NAME:		/* this should not change between logins */		if (session->targetname)			break;		session->targetname = kstrdup(buf, GFP_KERNEL);		if (!session->targetname)			return -ENOMEM;		break;	case ISCSI_PARAM_TPGT:		sscanf(buf, "%d", &session->tpgt);		break;	case ISCSI_PARAM_PERSISTENT_PORT:		sscanf(buf, "%d", &conn->persistent_port);		break;	case ISCSI_PARAM_PERSISTENT_ADDRESS:		/*		 * this is the address returned in discovery so it should		 * not change between logins.		 */		if (conn->persistent_address)			break;		conn->persistent_address = kstrdup(buf, GFP_KERNEL);		if (!conn->persistent_address)			return -ENOMEM;		break;	default:		return -ENOSYS;	}	return 0;}EXPORT_SYMBOL_GPL(iscsi_set_param);int iscsi_session_get_param(struct iscsi_cls_session *cls_session,			    enum iscsi_param param, char *buf){	struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);	struct iscsi_session *session = iscsi_hostdata(shost->hostdata);	int len;	switch(param) {	case ISCSI_PARAM_INITIAL_R2T_EN:		len = sprintf(buf, "%d\n", session->initial_r2t_en);		break;	case ISCSI_PARAM_MAX_R2T:		len = sprintf(buf, "%hu\n", session->max_r2t);		break;	case ISCSI_PARAM_IMM_DATA_EN:		len = sprintf(buf, "%d\n", session->imm_data_en);		break;	case ISCSI_PARAM_FIRST_BURST:		len = sprintf(buf, "%u\n", session->first_burst);		break;	case ISCSI_PARAM_MAX_BURST:		len = sprintf(buf, "%u\n", session->max_burst);		break;	case ISCSI_PARAM_PDU_INORDER_EN:		len = sprintf(buf, "%d\n", session->pdu_inorder_en);		break;	case ISCSI_PARAM_DATASEQ_INORDER_EN:		len = sprintf(buf, "%d\n", session->dataseq_inorder_en);		break;	case ISCSI_PARAM_ERL:		len = sprintf(buf, "%d\n", session->erl);		break;	case ISCSI_PARAM_TARGET_NAME:		len = sprintf(buf, "%s\n", session->targetname);		break;	case ISCSI_PARAM_TPGT:		len = sprintf(buf, "%d\n", session->tpgt);		break;	case ISCSI_PARAM_USERNAME:		len = sprintf(buf, "%s\n", session->username);		break;	case ISCSI_PARAM_USERNAME_IN:		len = sprintf(buf, "%s\n", session->username_in);		break;	case ISCSI_PARAM_PASSWORD:		len = sprintf(buf, "%s\n", session->password);		break;	case ISCSI_PARAM_PASSWORD_IN:		len = sprintf(buf, "%s\n", session->password_in);		break;	default:		return -ENOSYS;	}	return len;}EXPORT_SYMBOL_GPL(iscsi_session_get_param);int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,			 enum iscsi_param param, char *buf){	struct iscsi_conn *conn = cls_conn->dd_data;	int len;	switch(param) {	case ISCSI_PARAM_MAX_RECV_DLENGTH:		len = sprintf(buf, "%u\n", conn->max_recv_dlength);		break;	case ISCSI_PARAM_MAX_XMIT_DLENGTH:		len = sprintf(buf, "%u\n", conn->max_xmit_dlength);		break;	case ISCSI_PARAM_HDRDGST_EN:		len = sprintf(buf, "%d\n", conn->hdrdgst_en);		break;	case ISCSI_PARAM_DATADGST_EN:		len = sprintf(buf, "%d\n", conn->datadgst_en);		break;	case ISCSI_PARAM_IFMARKER_EN:		len = sprintf(buf, "%d\n", conn->ifmarker_en);		break;	case ISCSI_PARAM_OFMARKER_EN:		len = sprintf(buf, "%d\n", conn->ofmarker_en);		break;	case ISCSI_PARAM_EXP_STATSN:		len = sprintf(buf, "%u\n", conn->exp_statsn);		break;	case ISCSI_PARAM_PERSISTENT_PORT:		len = sprintf(buf, "%d\n", conn->persistent_port);		break;	case ISCSI_PARAM_PERSISTENT_ADDRESS:		len = sprintf(buf, "%s\n", conn->persistent_address);		break;	default:		return -ENOSYS;	}	return len;}EXPORT_SYMBOL_GPL(iscsi_conn_get_param);int iscsi_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_NETDEV_NAME:		if (!session->netdev)			len = sprintf(buf, "%s\n", "default");		else			len = sprintf(buf, "%s\n", session->netdev);		break;	case ISCSI_HOST_PARAM_HWADDRESS:		if (!session->hwaddress)			len = sprintf(buf, "%s\n", "default");		else			len = sprintf(buf, "%s\n", session->hwaddress);		break;	case ISCSI_HOST_PARAM_INITIATOR_NAME:		if (!session->initiatorname)			len = sprintf(buf, "%s\n", "unknown");		else			len = sprintf(buf, "%s\n", session->initiatorname);		break;	default:		return -ENOSYS;	}	return len;}EXPORT_SYMBOL_GPL(iscsi_host_get_param);int iscsi_host_set_param(struct Scsi_Host *shost, enum iscsi_host_param param,			 char *buf, int buflen){	struct iscsi_session *session = iscsi_hostdata(shost->hostdata);	switch (param) {	case ISCSI_HOST_PARAM_NETDEV_NAME:		if (!session->netdev)			session->netdev = kstrdup(buf, GFP_KERNEL);		break;	case ISCSI_HOST_PARAM_HWADDRESS:		if (!session->hwaddress)			session->hwaddress = kstrdup(buf, GFP_KERNEL);		break;	case ISCSI_HOST_PARAM_INITIATOR_NAME:		if (!session->initiatorname)			session->initiatorname = kstrdup(buf, GFP_KERNEL);		break;	default:		return -ENOSYS;	}	return 0;}EXPORT_SYMBOL_GPL(iscsi_host_set_param);MODULE_AUTHOR("Mike Christie");MODULE_DESCRIPTION("iSCSI library functions");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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