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

📄 iscsi.c

📁 iscsi企业级target.很好用
💻 C
📖 第 1 页 / 共 3 页
字号:
		goto out;	}	head = &session->cmnd_hash[cmnd_hashfn(cmnd->pdu.bhs.itt)];	spin_lock(&session->cmnd_hash_lock);	tmp = __cmnd_find_hash(session, itt, ISCSI_RESERVED_TAG);	if (!tmp) {		list_add_tail(&cmnd->hash_list, head);		set_cmnd_hashed(cmnd);	} else		err = -ISCSI_REASON_TASK_IN_PROGRESS;	spin_unlock(&session->cmnd_hash_lock);	if (!err) {		update_stat_sn(cmnd);		err = check_cmd_sn(cmnd);	}out:	return err;}static void __cmnd_remove_hash(struct iscsi_cmnd *cmnd){	list_del(&cmnd->hash_list);}static void cmnd_remove_hash(struct iscsi_cmnd *cmnd){	struct iscsi_session *session = cmnd->conn->session;	struct iscsi_cmnd *tmp;	spin_lock(&session->cmnd_hash_lock);	tmp = __cmnd_find_hash(session, cmnd->pdu.bhs.itt, ISCSI_RESERVED_TAG);	if (tmp && tmp == cmnd)		__cmnd_remove_hash(tmp);	else		eprintk("%p:%x not found\n", cmnd, cmnd_itt(cmnd));	spin_unlock(&session->cmnd_hash_lock);}static void cmnd_skip_data(struct iscsi_cmnd *req){	struct iscsi_cmnd *rsp;	struct iscsi_scsi_rsp_hdr *rsp_hdr;	u32 size;	rsp = get_rsp_cmnd(req);	rsp_hdr = (struct iscsi_scsi_rsp_hdr *)&rsp->pdu.bhs;	if (cmnd_opcode(rsp) != ISCSI_OP_SCSI_RSP) {		eprintk("unexpected response command %u\n", cmnd_opcode(rsp));		return;	}	size = cmnd_write_size(req);	if (size) {		rsp_hdr->flags |= ISCSI_FLG_RESIDUAL_UNDERFLOW;		rsp_hdr->residual_count = cpu_to_be32(size);	}	size = cmnd_read_size(req);	if (size) {		if (cmnd_hdr(req)->flags & ISCSI_CMD_WRITE) {			rsp_hdr->flags |= ISCSI_FLG_BIRESIDUAL_UNDERFLOW;			rsp_hdr->bi_residual_count = cpu_to_be32(size);		} else {			rsp_hdr->flags |= ISCSI_FLG_RESIDUAL_UNDERFLOW;			rsp_hdr->residual_count = cpu_to_be32(size);		}	}	req->pdu.bhs.opcode =		(req->pdu.bhs.opcode & ~ISCSI_OPCODE_MASK) | ISCSI_OP_SCSI_REJECT;	cmnd_skip_pdu(req);}static int cmnd_recv_pdu(struct iscsi_conn *conn, struct tio *tio, u32 offset, u32 size){	int idx, i;	char *addr;	dprintk(D_GENERIC, "%p %u,%u\n", tio, offset, size);	offset += tio->offset;	if (!(offset < tio->offset + tio->size) ||	    !(offset + size <= tio->offset + tio->size)) {		eprintk("%u %u %u %u", offset, size, tio->offset, tio->size);		return -EIO;	}	assert(offset < tio->offset + tio->size);	assert(offset + size <= tio->offset + tio->size);	idx = offset >> PAGE_CACHE_SHIFT;	offset &= ~PAGE_CACHE_MASK;	conn->read_msg.msg_iov = conn->read_iov;	conn->read_size = size = (size + 3) & -4;	conn->read_overflow = 0;	i = 0;	while (1) {		assert(tio->pvec[idx]);		addr = page_address(tio->pvec[idx]);		assert(addr);		conn->read_iov[i].iov_base =  addr + offset;		if (offset + size <= PAGE_CACHE_SIZE) {			conn->read_iov[i].iov_len = size;			conn->read_msg.msg_iovlen = ++i;			break;		}		conn->read_iov[i].iov_len = PAGE_CACHE_SIZE - offset;		size -= conn->read_iov[i].iov_len;		offset = 0;		if (++i >= ISCSI_CONN_IOV_MAX) {			conn->read_msg.msg_iovlen = i;			conn->read_overflow = size;			conn->read_size -= size;			break;		}		idx++;	}	return 0;}static void set_offset_and_length(struct iet_volume *lu, u8 *cmd, loff_t *off, u32 *len){	assert(lu);	switch (cmd[0]) {	case READ_6:	case WRITE_6:		*off = ((cmd[1] & 0x1f) << 16) + (cmd[2] << 8) + cmd[3];		*len = cmd[4];		if (!*len)			*len = 256;		break;	case READ_10:	case WRITE_10:	case WRITE_VERIFY:		*off = be32_to_cpu(*(u32 *)&cmd[2]);		*len = (cmd[7] << 8) + cmd[8];		break;	case READ_16:	case WRITE_16:		*off = be64_to_cpu(*(u64 *)&cmd[2]);		*len = be32_to_cpu(*(u32 *)&cmd[10]);		break;	default:		BUG();	}	*off <<= lu->blk_shift;	*len <<= lu->blk_shift;}static u32 translate_lun(u16 * data){	u8 *p = (u8 *) data;	u32 lun = ~0U;	switch (*p >> 6) {	case 0:		lun = p[1];		break;	case 1:		lun = (0x3f & p[0]) << 8 | p[1];		break;	case 2:	case 3:	default:		eprintk("%u %u %u %u\n", data[0], data[1], data[2], data[3]);		break;	}	return lun;}static void send_r2t(struct iscsi_cmnd *req){	struct iscsi_cmnd *rsp;	struct iscsi_r2t_hdr *rsp_hdr;	u32 length, offset, burst;	LIST_HEAD(send);	length = req->r2t_length;	burst = req->conn->session->param.max_burst_length;	offset = be32_to_cpu(cmnd_hdr(req)->data_length) - length;	do {		rsp = iscsi_cmnd_create_rsp_cmnd(req, 0);		rsp->pdu.bhs.ttt = req->target_task_tag;		rsp_hdr = (struct iscsi_r2t_hdr *)&rsp->pdu.bhs;		rsp_hdr->opcode = ISCSI_OP_R2T;		rsp_hdr->flags = ISCSI_FLG_FINAL;		memcpy(rsp_hdr->lun, cmnd_hdr(req)->lun, 8);		rsp_hdr->itt = cmnd_hdr(req)->itt;		rsp_hdr->r2t_sn = cpu_to_be32(req->r2t_sn++);		rsp_hdr->buffer_offset = cpu_to_be32(offset);		if (length > burst) {			rsp_hdr->data_length = cpu_to_be32(burst);			length -= burst;			offset += burst;		} else {			rsp_hdr->data_length = cpu_to_be32(length);			length = 0;		}		dprintk(D_WRITE, "%x %u %u %u %u\n", cmnd_itt(req),			be32_to_cpu(rsp_hdr->data_length),			be32_to_cpu(rsp_hdr->buffer_offset),			be32_to_cpu(rsp_hdr->r2t_sn), req->outstanding_r2t);		list_add_tail(&rsp->list, &send);		if (++req->outstanding_r2t >= req->conn->session->param.max_outstanding_r2t)			break;	} while (length);	iscsi_cmnds_init_write(&send);}static void scsi_cmnd_exec(struct iscsi_cmnd *cmnd){	if (cmnd->r2t_length) {		if (!cmnd->is_unsolicited_data)			send_r2t(cmnd);	} else {		if (cmnd->lun) {			iscsi_scsi_queuecmnd(cmnd);		} else {			iscsi_device_queue_cmnd(cmnd);		}	}}static int noop_out_start(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd){	u32 size, tmp;	int i, err = 0;	if (cmnd_ttt(cmnd) != cpu_to_be32(ISCSI_RESERVED_TAG)) {		/*		 * We don't request a NOP-Out by sending a NOP-In.		 * See 10.18.2 in the draft 20.		 */		eprintk("initiator bug %x\n", cmnd_itt(cmnd));		err = -ISCSI_REASON_PROTOCOL_ERROR;		goto out;	}	if (cmnd_itt(cmnd) == cpu_to_be32(ISCSI_RESERVED_TAG)) {		if (!(cmnd->pdu.bhs.opcode & ISCSI_OP_IMMEDIATE))			eprintk("%s\n","initiator bug!");		update_stat_sn(cmnd);		err = check_cmd_sn(cmnd);		goto out;	} else if ((err = cmnd_insert_hash(cmnd)) < 0) {		eprintk("ignore this request %x\n", cmnd_itt(cmnd));		goto out;	}	if ((size = cmnd->pdu.datasize)) {		size = (size + 3) & -4;		conn->read_msg.msg_iov = conn->read_iov;		if (cmnd->pdu.bhs.itt != cpu_to_be32(ISCSI_RESERVED_TAG)) {			struct tio *tio;			int pg_cnt = get_pgcnt(size, 0);			assert(pg_cnt < ISCSI_CONN_IOV_MAX);			cmnd->tio = tio = tio_alloc(pg_cnt);			tio_set(tio, size, 0);			for (i = 0; i < pg_cnt; i++) {				conn->read_iov[i].iov_base					= page_address(tio->pvec[i]);				tmp = min_t(u32, size, PAGE_CACHE_SIZE);				conn->read_iov[i].iov_len = tmp;				conn->read_size += tmp;				size -= tmp;			}		} else {			for (i = 0; i < ISCSI_CONN_IOV_MAX; i++) {				conn->read_iov[i].iov_base = dummy_data;				tmp = min_t(u32, size, sizeof(dummy_data));				conn->read_iov[i].iov_len = tmp;				conn->read_size += tmp;				size -= tmp;			}		}		assert(!size);		conn->read_overflow = size;		conn->read_msg.msg_iovlen = i;	}out:	return err;}static u32 get_next_ttt(struct iscsi_session *session){	u32 ttt;	if (session->next_ttt == ISCSI_RESERVED_TAG)		session->next_ttt++;	ttt = session->next_ttt++;	return cpu_to_be32(ttt);}static void scsi_cmnd_start(struct iscsi_conn *conn, struct iscsi_cmnd *req){	struct iscsi_scsi_cmd_hdr *req_hdr = cmnd_hdr(req);	dprintk(D_GENERIC, "scsi command: %02x\n", req_hdr->scb[0]);	req->lun = volume_get(conn->session->target, translate_lun(req_hdr->lun));	if (!req->lun) {		switch (req_hdr->scb[0]) {		case INQUIRY:		case REPORT_LUNS:			break;		default:			eprintk("%x %x\n", cmnd_itt(req), req_hdr->scb[0]);			create_sense_rsp(req, ILLEGAL_REQUEST, 0x25, 0x0);			cmnd_skip_data(req);			goto out;		}	} else		set_cmnd_lunit(req);	switch (req_hdr->scb[0]) {	case SERVICE_ACTION_IN:		if ((req_hdr->scb[1] & 0x1f) != 0x10)			goto error;	case INQUIRY:	case REPORT_LUNS:	case TEST_UNIT_READY:	case SYNCHRONIZE_CACHE:	case VERIFY:	case VERIFY_16:	case START_STOP:	case READ_CAPACITY:	case MODE_SENSE:	case REQUEST_SENSE:	case RESERVE:	case RELEASE:	case RESERVE_10:	case RELEASE_10:	{		if (!(req_hdr->flags & ISCSI_CMD_FINAL) || req->pdu.datasize) {			/* unexpected unsolicited data */			eprintk("%x %x\n", cmnd_itt(req), req_hdr->scb[0]);			create_sense_rsp(req, ABORTED_COMMAND, 0xc, 0xc);			cmnd_skip_data(req);		}		break;	}	case READ_6:	case READ_10:	case READ_16:	{		loff_t offset;		u32 length;		if (!(req_hdr->flags & ISCSI_CMD_FINAL) || req->pdu.datasize) {			/* unexpected unsolicited data */			eprintk("%x %x\n", cmnd_itt(req), req_hdr->scb[0]);			create_sense_rsp(req, ABORTED_COMMAND, 0xc, 0xc);			cmnd_skip_data(req);		}		set_offset_and_length(req->lun, req_hdr->scb, &offset, &length);		req->tio = tio_alloc(get_pgcnt(length, offset));		tio_set(req->tio, length, offset);		break;	}	case WRITE_6:	case WRITE_10:	case WRITE_16:	case WRITE_VERIFY:	{		struct iscsi_sess_param *param = &conn->session->param;		loff_t offset;		u32 length;		req->r2t_length = be32_to_cpu(req_hdr->data_length) - req->pdu.datasize;		req->is_unsolicited_data = !(req_hdr->flags & ISCSI_CMD_FINAL);		req->target_task_tag = get_next_ttt(conn->session);		if (!param->immediate_data && req->pdu.datasize)			eprintk("%x %x\n", cmnd_itt(req), req_hdr->scb[0]);		if (param->initial_r2t && !(req_hdr->flags & ISCSI_CMD_FINAL))			eprintk("%x %x\n", cmnd_itt(req), req_hdr->scb[0]);		if (req_hdr->scb[0] == WRITE_VERIFY && req_hdr->scb[1] & 0x02)			eprintk("Verification is ignored %x\n", cmnd_itt(req));		set_offset_and_length(req->lun, req_hdr->scb, &offset, &length);		if (cmnd_write_size(req) != length)			eprintk("%x %u %u\n", cmnd_itt(req), cmnd_write_size(req), length);		req->tio = tio_alloc(get_pgcnt(length, offset));		tio_set(req->tio, length, offset);		if (req->pdu.datasize) {			if (cmnd_recv_pdu(conn, req->tio, 0, req->pdu.datasize) < 0)				assert(0);		}		break;	}	error:	default:		eprintk("Unsupported %x\n", req_hdr->scb[0]);		create_sense_rsp(req, ILLEGAL_REQUEST, 0x20, 0x0);		cmnd_skip_data(req);		break;	}out:	return;}static void data_out_start(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd){	struct iscsi_data_out_hdr *req = (struct iscsi_data_out_hdr *)&cmnd->pdu.bhs;	struct iscsi_cmnd *scsi_cmnd = NULL;	u32 offset = be32_to_cpu(req->buffer_offset);	update_stat_sn(cmnd);	cmnd->req = scsi_cmnd = cmnd_find_hash(conn->session, req->itt, req->ttt);	if (!scsi_cmnd) {		eprintk("unable to find scsi task %x %x\n",			cmnd_itt(cmnd), cmnd_ttt(cmnd));		goto skip_data;	}	if (scsi_cmnd->r2t_length < cmnd->pdu.datasize) {		eprintk("invalid data len %x %u %u\n",			cmnd_itt(scsi_cmnd), cmnd->pdu.datasize, scsi_cmnd->r2t_length);		goto skip_data;	}	if (scsi_cmnd->r2t_length + offset != cmnd_write_size(scsi_cmnd)) {		eprintk("%x %u %u %u\n", cmnd_itt(scsi_cmnd), scsi_cmnd->r2t_length,			offset,	cmnd_write_size(scsi_cmnd));		goto skip_data;	}	scsi_cmnd->r2t_length -= cmnd->pdu.datasize;	if (req->ttt == cpu_to_be32(ISCSI_RESERVED_TAG)) {		/* unsolicited burst data */		if (scsi_cmnd->pdu.bhs.flags & ISCSI_FLG_FINAL) {			eprintk("unexpected data from %x %x\n",				cmnd_itt(cmnd), cmnd_ttt(cmnd));			goto skip_data;		}	}	dprintk(D_WRITE, "%u %p %p %p %u %u\n", req->ttt, cmnd, scsi_cmnd,		scsi_cmnd->tio, offset, cmnd->pdu.datasize);	if (cmnd_recv_pdu(conn, scsi_cmnd->tio, offset, cmnd->pdu.datasize) < 0)		goto skip_data;	return;skip_data:	cmnd->pdu.bhs.opcode = ISCSI_OP_DATA_REJECT;	cmnd_skip_pdu(cmnd);	return;}static void data_out_end(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd){	struct iscsi_data_out_hdr *req = (struct iscsi_data_out_hdr *) &cmnd->pdu.bhs;	struct iscsi_cmnd *scsi_cmnd;	u32 offset;	assert(cmnd);	scsi_cmnd = cmnd->req;	assert(scsi_cmnd);	if (conn->read_overflow) {		eprintk("%x %u\n", cmnd_itt(cmnd), conn->read_overflow);		assert(scsi_cmnd->tio);		offset = be32_to_cpu(req->buffer_offset);		offset += cmnd->pdu.datasize - conn->read_overflow;		if (cmnd_recv_pdu(conn, scsi_cmnd->tio, offset, conn->read_overflow) < 0)			assert(0);		return;	}	if (req->ttt == cpu_to_be32(ISCSI_RESERVED_TAG)) {		if (req->flags & ISCSI_FLG_FINAL) {			scsi_cmnd->is_unsolicited_data = 0;			if (!cmnd_pending(scsi_cmnd))				scsi_cmnd_exec(scsi_cmnd);		}	} else {		/* TODO : proper error handling */		if (!(req->flags & ISCSI_FLG_FINAL) && scsi_cmnd->r2t_length == 0)			eprintk("initiator error %x\n", cmnd_itt(scsi_cmnd));		if (!(req->flags & ISCSI_FLG_FINAL))			goto out;		scsi_cmnd->outstanding_r2t--;		if (scsi_cmnd->r2t_length == 0)			assert(list_empty(&scsi_cmnd->pdu_list));		scsi_cmnd_exec(scsi_cmnd);	}out:	iscsi_cmnd_remove(cmnd);	return;}static int __cmnd_abort(struct iscsi_cmnd *cmnd){	if (!cmnd_waitio(cmnd)) {		cmnd_release(cmnd, 1);		return 0;	} else		return -ISCSI_RESPONSE_UNKNOWN_TASK;}static int cmnd_abort(struct iscsi_session *session, u32 itt){	struct iscsi_cmnd *cmnd;	int err =  -ISCSI_RESPONSE_UNKNOWN_TASK;	if ((cmnd = cmnd_find_hash(session, itt, ISCSI_RESERVED_TAG))) {		eprintk("%x %x %x %u %u %u %u\n", cmnd_itt(cmnd), cmnd_opcode(cmnd),			cmnd->r2t_length, cmnd_scsicode(cmnd),			cmnd_write_size(cmnd), cmnd->is_unsolicited_data,			cmnd->outstanding_r2t);		err = __cmnd_abort(cmnd);	}	return err;}static int target_reset(struct iscsi_cmnd *req, u32 lun, int all){	struct iscsi_target *target = req->conn->session->target;	struct iscsi_session *session;	struct iscsi_conn *conn;	struct iscsi_cmnd *cmnd, *tmp;	list_for_each_entry(session, &target->session_list, list) {		list_for_each_entry(conn, &session->conn_list, list) {			list_for_each_entry_safe(cmnd, tmp, &conn->pdu_list, conn_list) {

⌨️ 快捷键说明

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