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

📄 iscsi.c

📁 iscsi企业级target.很好用
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (C) 2002-2003 Ardis Technolgies <roman@ardistech.com> * * Released under the terms of the GNU GPL v2.0. */#include <linux/module.h>#include <linux/hash.h>#include <net/tcp.h>#include <scsi/scsi.h>#include "iscsi.h"#include "iscsi_dbg.h"#include "iotype.h"unsigned long debug_enable_flags;static kmem_cache_t *iscsi_cmnd_cache;static char dummy_data[1024];static int ctr_major;static char ctr_name[] = "ietctl";extern struct file_operations ctr_fops;static u32 cmnd_write_size(struct iscsi_cmnd *cmnd){	struct iscsi_scsi_cmd_hdr *hdr = cmnd_hdr(cmnd);	if (hdr->flags & ISCSI_CMD_WRITE)		return be32_to_cpu(hdr->data_length);	return 0;}static u32 cmnd_read_size(struct iscsi_cmnd *cmnd){	struct iscsi_scsi_cmd_hdr *hdr = cmnd_hdr(cmnd);	if (hdr->flags & ISCSI_CMD_READ) {		if (!(hdr->flags & ISCSI_CMD_WRITE))			return be32_to_cpu(hdr->data_length);		if (hdr->flags & ISCSI_CMD_READ) {			struct iscsi_rlength_ahdr *ahdr =				(struct iscsi_rlength_ahdr *)cmnd->pdu.ahs;			if (ahdr && ahdr->ahstype == ISCSI_AHSTYPE_RLENGTH)				return be32_to_cpu(ahdr->read_length);		}	}	return 0;}static void iscsi_device_queue_cmnd(struct iscsi_cmnd *cmnd){	set_cmnd_waitio(cmnd);	wthread_queue(cmnd);}static void iscsi_scsi_queuecmnd(struct iscsi_cmnd *cmnd){	struct iscsi_queue *queue = &cmnd->lun->queue;	dprintk(D_GENERIC, "%p\n", cmnd);	if ((cmnd->pdu.bhs.flags & ISCSI_CMD_ATTR_MASK) != ISCSI_CMD_UNTAGGED &&	    (cmnd->pdu.bhs.flags & ISCSI_CMD_ATTR_MASK) != ISCSI_CMD_SIMPLE) {		cmnd->pdu.bhs.flags &= ~ISCSI_CMD_ATTR_MASK;		cmnd->pdu.bhs.flags |= ISCSI_CMD_UNTAGGED;	}	spin_lock(&queue->queue_lock);	set_cmnd_queued(cmnd);	switch (cmnd->pdu.bhs.flags & ISCSI_CMD_ATTR_MASK) {	case ISCSI_CMD_UNTAGGED:	case ISCSI_CMD_SIMPLE:		if (!list_empty(&queue->wait_list) || queue->ordered_cmnd)			goto pending;		queue->active_cnt++;		break;	default:		BUG();	}	spin_unlock(&queue->queue_lock);	iscsi_device_queue_cmnd(cmnd);	return; pending:	assert(list_empty(&cmnd->list));	list_add_tail(&cmnd->list, &queue->wait_list);	spin_unlock(&queue->queue_lock);	return;}static void iscsi_scsi_dequeuecmnd(struct iscsi_cmnd *cmnd){	struct iscsi_queue *queue;	if (!cmnd->lun)		return;	queue = &cmnd->lun->queue;	spin_lock(&queue->queue_lock);	switch (cmnd->pdu.bhs.flags & ISCSI_CMD_ATTR_MASK) {	case ISCSI_CMD_UNTAGGED:	case ISCSI_CMD_SIMPLE:		--queue->active_cnt;		break;	case ISCSI_CMD_ORDERED:	case ISCSI_CMD_HEAD_OF_QUEUE:	case ISCSI_CMD_ACA:		BUG();	default:		/* Should the iscsi_scsi_queuecmnd func reject this ? */		break;	}	while (!list_empty(&queue->wait_list)) {		cmnd = list_entry(queue->wait_list.next, struct iscsi_cmnd, list);		switch ((cmnd->pdu.bhs.flags & ISCSI_CMD_ATTR_MASK)) {		case ISCSI_CMD_UNTAGGED:		case ISCSI_CMD_SIMPLE:			list_del_init(&cmnd->list);			queue->active_cnt++;			iscsi_device_queue_cmnd(cmnd);			break;		case ISCSI_CMD_ORDERED:		case ISCSI_CMD_HEAD_OF_QUEUE:		case ISCSI_CMD_ACA:			BUG();		}	}	spin_unlock(&queue->queue_lock);	return;}/** * create a new command. * * iscsi_cmnd_create -  * @conn: ptr to connection (for i/o) * * @return    ptr to command or NULL */struct iscsi_cmnd *cmnd_alloc(struct iscsi_conn *conn, int req){	struct iscsi_cmnd *cmnd;	/* TODO: async interface is necessary ? */	cmnd = kmem_cache_alloc(iscsi_cmnd_cache, GFP_KERNEL|__GFP_NOFAIL);	memset(cmnd, 0, sizeof(*cmnd));	INIT_LIST_HEAD(&cmnd->list);	INIT_LIST_HEAD(&cmnd->pdu_list);	INIT_LIST_HEAD(&cmnd->conn_list);	INIT_LIST_HEAD(&cmnd->hash_list);	cmnd->conn = conn;	spin_lock(&conn->list_lock);	atomic_inc(&conn->nr_cmnds);	if (req)		list_add_tail(&cmnd->conn_list, &conn->pdu_list);	spin_unlock(&conn->list_lock);	cmnd->tio = NULL;	dprintk(D_GENERIC, "%p:%p\n", conn, cmnd);	return cmnd;}/** * create a new command used as response. * * iscsi_cmnd_create_rsp_cmnd -  * @cmnd: ptr to request command * * @return    ptr to response command or NULL */static struct iscsi_cmnd *iscsi_cmnd_create_rsp_cmnd(struct iscsi_cmnd *cmnd, int final){	struct iscsi_cmnd *rsp = cmnd_alloc(cmnd->conn, 0);	if (final)		set_cmnd_final(rsp);	list_add_tail(&rsp->pdu_list, &cmnd->pdu_list);	rsp->req = cmnd;	return rsp;}static struct iscsi_cmnd *get_rsp_cmnd(struct iscsi_cmnd *req){	return list_entry(req->pdu_list.prev, struct iscsi_cmnd, pdu_list);}static void iscsi_cmnds_init_write(struct list_head *send){	struct iscsi_cmnd *cmnd = list_entry(send->next, struct iscsi_cmnd, list);	struct iscsi_conn *conn = cmnd->conn;	struct list_head *pos, *next;	spin_lock(&conn->list_lock);	list_for_each_safe(pos, next, send) {		cmnd = list_entry(pos, struct iscsi_cmnd, list);		dprintk(D_GENERIC, "%p:%x\n", cmnd, cmnd_opcode(cmnd));		list_del_init(&cmnd->list);		assert(conn == cmnd->conn);		list_add_tail(&cmnd->list, &conn->write_list);	}	spin_unlock(&conn->list_lock);	nthread_wakeup(conn->session->target);}static void iscsi_cmnd_init_write(struct iscsi_cmnd *cmnd){	LIST_HEAD(head);	if (!list_empty(&cmnd->list)) {		eprintk("%x %x %x %x %lx %lx %u %u %u %u %u %u %u %d %d\n",			cmnd_itt(cmnd), cmnd_ttt(cmnd), cmnd_opcode(cmnd),			cmnd_scsicode(cmnd), cmnd->state, cmnd->flags,			cmnd->r2t_sn, cmnd->r2t_length, cmnd->is_unsolicited_data,			cmnd->target_task_tag, cmnd->outstanding_r2t,			cmnd->hdigest, cmnd->ddigest,			list_empty(&cmnd->pdu_list), list_empty(&cmnd->hash_list));		assert(list_empty(&cmnd->list));	}	list_add(&cmnd->list, &head);	iscsi_cmnds_init_write(&head);}static void do_send_data_rsp(struct iscsi_cmnd *cmnd){	struct iscsi_conn *conn = cmnd->conn;	struct iscsi_cmnd *data_cmnd;	struct tio *tio = cmnd->tio;	struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd);	struct iscsi_data_in_hdr *rsp;	u32 pdusize, expsize, scsisize, size, offset, sn;	LIST_HEAD(send);	dprintk(D_GENERIC, "%p\n", cmnd);	pdusize = conn->session->param.max_xmit_data_length;	expsize = cmnd_read_size(cmnd);	size = min(expsize, tio->size);	offset = 0;	sn = 0;	while (1) {		data_cmnd = iscsi_cmnd_create_rsp_cmnd(cmnd, size <= pdusize);		tio_get(tio);		data_cmnd->tio = tio;		rsp = (struct iscsi_data_in_hdr *)&data_cmnd->pdu.bhs;		rsp->opcode = ISCSI_OP_SCSI_DATA_IN;		rsp->itt = req->itt;		rsp->ttt = cpu_to_be32(ISCSI_RESERVED_TAG);		rsp->buffer_offset = offset;		rsp->data_sn = cpu_to_be32(sn);		if (size <= pdusize) {			data_cmnd->pdu.datasize = size;			rsp->flags = ISCSI_FLG_FINAL | ISCSI_FLG_STATUS;			scsisize = tio->size;			if (scsisize < expsize) {				rsp->flags |= ISCSI_FLG_RESIDUAL_UNDERFLOW;				size = expsize - scsisize;			} else if (scsisize > expsize) {				rsp->flags |= ISCSI_FLG_RESIDUAL_OVERFLOW;				size = scsisize - expsize;			} else				size = 0;			rsp->residual_count = cpu_to_be32(size);			list_add_tail(&data_cmnd->list, &send);			break;		}		data_cmnd->pdu.datasize = pdusize;		size -= pdusize;		offset += pdusize;		sn++;		list_add_tail(&data_cmnd->list, &send);	}	iscsi_cmnds_init_write(&send);}static struct iscsi_cmnd *create_scsi_rsp(struct iscsi_cmnd *req){	struct iscsi_cmnd *rsp;	struct iscsi_scsi_cmd_hdr *req_hdr = cmnd_hdr(req);	struct iscsi_scsi_rsp_hdr *rsp_hdr;	rsp = iscsi_cmnd_create_rsp_cmnd(req, 1);	rsp_hdr = (struct iscsi_scsi_rsp_hdr *)&rsp->pdu.bhs;	rsp_hdr->opcode = ISCSI_OP_SCSI_RSP;	rsp_hdr->flags = ISCSI_FLG_FINAL;	rsp_hdr->response = ISCSI_RESPONSE_COMMAND_COMPLETED;	rsp_hdr->cmd_status = SAM_STAT_GOOD;	rsp_hdr->itt = req_hdr->itt;	return rsp;}void send_scsi_rsp(struct iscsi_cmnd *req, int (*func)(struct iscsi_cmnd *)){	struct iscsi_cmnd *rsp;	struct iscsi_scsi_rsp_hdr *rsp_hdr;	u32 size;	rsp = create_scsi_rsp(req);	rsp_hdr = (struct iscsi_scsi_rsp_hdr *) &rsp->pdu.bhs;	if ((size = cmnd_read_size(req)) != 0) {		rsp_hdr->flags |= ISCSI_FLG_RESIDUAL_UNDERFLOW;		rsp_hdr->residual_count = cpu_to_be32(size);	}	if (func(req) < 0)		eprintk("%x\n", cmnd_opcode(req));	iscsi_cmnd_init_write(rsp);}static struct iscsi_cmnd *create_sense_rsp(struct iscsi_cmnd *req,					   u8 sense_key, u8 asc, u8 ascq){	struct iscsi_cmnd *rsp;	struct iscsi_scsi_rsp_hdr *rsp_hdr;	struct tio *tio;	struct iscsi_sense_data *sense;	rsp = iscsi_cmnd_create_rsp_cmnd(req, 1);	rsp_hdr = (struct iscsi_scsi_rsp_hdr *)&rsp->pdu.bhs;	rsp_hdr->opcode = ISCSI_OP_SCSI_RSP;	rsp_hdr->flags = ISCSI_FLG_FINAL;	rsp_hdr->response = ISCSI_RESPONSE_COMMAND_COMPLETED;	rsp_hdr->cmd_status = SAM_STAT_CHECK_CONDITION;	rsp_hdr->itt = cmnd_hdr(req)->itt;	tio = rsp->tio = tio_alloc(1);	sense = (struct iscsi_sense_data *) page_address(tio->pvec[0]);	assert(sense);	clear_page(sense);	sense->length = cpu_to_be16(14);	sense->data[0] = 0xf0;	sense->data[2] = sense_key;	sense->data[7] = 6;	// Additional sense length	sense->data[12] = asc;	sense->data[13] = ascq;	rsp->pdu.datasize = sizeof(struct iscsi_sense_data) + 14;	tio->size = (rsp->pdu.datasize + 3) & -4;	tio->offset = 0;	return rsp;}void send_data_rsp(struct iscsi_cmnd *req, int (*func)(struct iscsi_cmnd *)){	struct iscsi_cmnd *rsp;	if (func(req) < 0) {		rsp = create_sense_rsp(req, ILLEGAL_REQUEST, 0x24, 0x0);		iscsi_cmnd_init_write(rsp);	} else		do_send_data_rsp(req);}/** * Free a command. * Also frees the additional header. * * iscsi_cmnd_remove -  * @cmnd: ptr to command */void iscsi_cmnd_remove(struct iscsi_cmnd *cmnd){	struct iscsi_conn *conn;	if (!cmnd)		return;	dprintk(D_GENERIC, "%p\n", cmnd);	conn = cmnd->conn;	kfree(cmnd->pdu.ahs);	if (!list_empty(&cmnd->list)) {		struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd);		eprintk("cmnd %p still on some list?, %x, %x, %x, %x, %x, %x, %x %lx %lx\n",			cmnd, req->opcode, req->scb[0], req->flags, req->itt,			be32_to_cpu(req->data_length),			req->cmd_sn, be32_to_cpu(cmnd->pdu.datasize), cmnd->state, conn->state);		if (cmnd->req) {			struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd->req);			eprintk("%p %x %u\n", req, req->opcode, req->scb[0]);		}		dump_stack();		BUG();	}	list_del(&cmnd->list);	spin_lock(&conn->list_lock);	atomic_dec(&conn->nr_cmnds);	list_del(&cmnd->conn_list);	spin_unlock(&conn->list_lock);	if (cmnd->tio)		tio_put(cmnd->tio);	kmem_cache_free(iscsi_cmnd_cache, cmnd);}static void cmnd_skip_pdu(struct iscsi_cmnd *cmnd){	struct iscsi_conn *conn = cmnd->conn;	struct tio *tio = cmnd->tio;	char *addr;	u32 size;	int i;	eprintk("%x %x %x %u\n", cmnd_itt(cmnd), cmnd_opcode(cmnd),		cmnd_hdr(cmnd)->scb[0], cmnd->pdu.datasize);	if (!(size = cmnd->pdu.datasize))		return;	if (tio)		assert(tio->pg_cnt > 0);	else		tio = cmnd->tio = tio_alloc(1);	addr = page_address(tio->pvec[0]);	assert(addr);	size = (size + 3) & -4;	conn->read_size = size;	for (i = 0; size > PAGE_CACHE_SIZE; i++, size -= PAGE_CACHE_SIZE) {		assert(i < ISCSI_CONN_IOV_MAX);		conn->read_iov[i].iov_base = addr;		conn->read_iov[i].iov_len = PAGE_CACHE_SIZE;	}	conn->read_iov[i].iov_base = addr;	conn->read_iov[i].iov_len = size;	conn->read_msg.msg_iov = conn->read_iov;	conn->read_msg.msg_iovlen = ++i;}static void iscsi_cmnd_reject(struct iscsi_cmnd *req, int reason){	struct iscsi_cmnd *rsp;	struct iscsi_reject_hdr *rsp_hdr;	struct tio *tio;	char *addr;	rsp = iscsi_cmnd_create_rsp_cmnd(req, 1);	rsp_hdr = (struct iscsi_reject_hdr *)&rsp->pdu.bhs;	rsp_hdr->opcode = ISCSI_OP_REJECT;	rsp_hdr->ffffffff = ISCSI_RESERVED_TAG;	rsp_hdr->reason = reason;	rsp->tio = tio = tio_alloc(1);	addr = page_address(tio->pvec[0]);	clear_page(addr);	memcpy(addr, &req->pdu.bhs, sizeof(struct iscsi_hdr));	tio->size = rsp->pdu.datasize = sizeof(struct iscsi_hdr);	cmnd_skip_pdu(req);	req->pdu.bhs.opcode = ISCSI_OP_PDU_REJECT;}static void cmnd_set_sn(struct iscsi_cmnd *cmnd, int set_stat_sn){	struct iscsi_conn *conn = cmnd->conn;	struct iscsi_session *sess = conn->session;	if (set_stat_sn)		cmnd->pdu.bhs.sn = cpu_to_be32(conn->stat_sn++);	cmnd->pdu.bhs.exp_sn = cpu_to_be32(sess->exp_cmd_sn);	cmnd->pdu.bhs.max_sn = cpu_to_be32(sess->exp_cmd_sn + sess->max_queued_cmnds);}static void update_stat_sn(struct iscsi_cmnd *cmnd){	struct iscsi_conn *conn = cmnd->conn;	u32 exp_stat_sn;	cmnd->pdu.bhs.exp_sn = exp_stat_sn = be32_to_cpu(cmnd->pdu.bhs.exp_sn);	dprintk(D_GENERIC, "%x,%x\n", cmnd_opcode(cmnd), exp_stat_sn);	if ((int)(exp_stat_sn - conn->exp_stat_sn) > 0 &&	    (int)(exp_stat_sn - conn->stat_sn) <= 0) {		// free pdu resources		cmnd->conn->exp_stat_sn = exp_stat_sn;	}}static int check_cmd_sn(struct iscsi_cmnd *cmnd){	struct iscsi_session *session = cmnd->conn->session;	u32 cmd_sn;	cmnd->pdu.bhs.sn = cmd_sn = be32_to_cpu(cmnd->pdu.bhs.sn);	dprintk(D_GENERIC, "%d(%d)\n", cmd_sn, session->exp_cmd_sn);	if ((s32)(cmd_sn - session->exp_cmd_sn) >= 0)		return 0;	eprintk("sequence error (%x,%x)\n", cmd_sn, session->exp_cmd_sn);	return -ISCSI_REASON_PROTOCOL_ERROR;}static struct iscsi_cmnd *__cmnd_find_hash(struct iscsi_session *session, u32 itt, u32 ttt){	struct list_head *head;	struct iscsi_cmnd *cmnd;	head = &session->cmnd_hash[cmnd_hashfn(itt)];	list_for_each_entry(cmnd, head, hash_list) {		if (cmnd->pdu.bhs.itt == itt) {			if ((ttt != ISCSI_RESERVED_TAG) && (ttt != cmnd->target_task_tag))				continue;			return cmnd;		}	}	return NULL;}static struct iscsi_cmnd *cmnd_find_hash(struct iscsi_session *session, u32 itt, u32 ttt){	struct iscsi_cmnd *cmnd;	spin_lock(&session->cmnd_hash_lock);	cmnd = __cmnd_find_hash(session, itt, ttt);	spin_unlock(&session->cmnd_hash_lock);	return cmnd;}static int cmnd_insert_hash(struct iscsi_cmnd *cmnd){	struct iscsi_session *session = cmnd->conn->session;	struct iscsi_cmnd *tmp;	struct list_head *head;	int err = 0;	u32 itt = cmnd->pdu.bhs.itt;	dprintk(D_GENERIC, "%p:%x\n", cmnd, itt);	if (itt == ISCSI_RESERVED_TAG) {		err = -ISCSI_REASON_PROTOCOL_ERROR;

⌨️ 快捷键说明

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