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

📄 iscsi-xmit-pdu.c

📁 iSCSI协议在LINUX下的源码.源代码是IBM公布的.主要是结合其OSD设备用的.
💻 C
📖 第 1 页 / 共 2 页
字号:
}voidiscsi_send_logout(struct iscsi_session *session){	struct iscsi_logout_hdr stlh;	u32 itt;	int rc;	spin_lock_bh(&session->task_lock);	itt = iscsi_alloc_itt(session);	spin_unlock_bh(&session->task_lock);	memset(&stlh, 0, sizeof(stlh));	stlh.opcode = ISCSI_OP_LOGOUT_CMD | ISCSI_OP_IMMEDIATE;	stlh.flags = ISCSI_FLAG_FINAL | (ISCSI_LOGOUT_REASON_CLOSE_SESSION &					 ISCSI_FLAG_LOGOUT_REASON_MASK);	stlh.itt = htonl(itt);	stlh.cmdsn = htonl(session->cmd_sn);	stlh.expstatsn = htonl(session->exp_stat_sn);	rc = iscsi_send_header(session, (struct iscsi_hdr *)&stlh,			       session->header_digest);	if (rc != ISCSI_IO_SUCCESS) {		iscsi_host_err(session, "xmit_logout failed\n");		/* drop here ? */		iscsi_drop_session(session);	}}/** * iscsi_send_data_out - send a SCSI Data-out PDU * @task: iscsi task * @ttt: target transfer tag * @data_offset: offset of transfer within the complete transfer * @data_len: data trasnfer length * * Note: *   If command PDUs are small (no immediate data), we *   start new commands as soon as possible, so that we can *   overlap the R2T latency with the time it takes to *   send data for commands already issued.  This increases *   throughput without significantly increasing the completion *   time of commands already issued. **/static intiscsi_send_data_out(struct iscsi_task *task, u32 ttt, u32 data_offset,		    u32 data_len){	struct iscsi_session *session = task->session;	struct scsi_cmnd *sc = task->scsi_cmnd;	struct scatterlist tmpsg, *sg;	struct iscsi_data_hdr stdh;	u32 data_sn = 0, dlen, remaining, sg_offset;	int i, rc = ISCSI_IO_SUCCESS;	memset(&stdh, 0, sizeof(stdh));	stdh.opcode = ISCSI_OP_SCSI_DATA;	stdh.itt = htonl(task->itt);	stdh.ttt = ttt;	/*	 * Find the right sg entry and offset into it if needed.	 * Why do we not cache this index for DataPDUInOrder?	 */	sg_offset = data_offset;	sg = sc->request_buffer;	for (i = 0; i < sc->use_sg; i++) {		if (sg_offset < sg->length)			break;		else {			sg_offset -= sg->length;			sg++;		}	}	/*	 * check that the target did not send us some bad values. just	 * let the cmnd timeout if it does.	 */	if (sc->request_bufflen < data_offset + data_len ||	    (sc->use_sg && i >= sc->use_sg)) {		iscsi_host_err(session, "iscsi_send_data_out - invalid write. "			       "len %u, offset %u, request_bufflen %u, usg_sg "			       "%u, task %u\n", data_len, data_offset,			       sc->request_bufflen, sc->use_sg, task->itt);		return ISCSI_IO_INVALID_OP;	}	/*	 * PDU loop - might need to send multiple PDUs to satisfy	 * the transfer, or we can also send a zero length PDU	 */	remaining = data_len;	do {		if (signal_pending(current)) {			rc = ISCSI_IO_INTR;			break;		}		if (!session->immediate_data) 			iscsi_run_pending_queue(session);		stdh.datasn = htonl(data_sn++);		stdh.offset = htonl(data_offset);		stdh.expstatsn = htonl(session->exp_stat_sn);		if (session->max_xmit_data_segment_len && 		    remaining > session->max_xmit_data_segment_len) 			/* enforce the target's data segment limit */			dlen = session->max_xmit_data_segment_len;		 else {			/* final PDU of a data burst */			dlen = remaining;			stdh.flags = ISCSI_FLAG_FINAL;		}		hton24(stdh.dlength, dlen);		rc = iscsi_send_header(session, (struct iscsi_hdr *)&stdh,				       session->header_digest);		if (rc != ISCSI_IO_SUCCESS) {			iscsi_drop_session(session);			break;		}		if (sc->use_sg)			rc = iscsi_send_sg_data(session, sc->request_buffer,						&i, &sg_offset, sc->use_sg,						dlen, session->data_digest);		else {			sg_init_one(&tmpsg, sc->request_buffer, dlen);			rc = iscsi_send_sg_data(session, &tmpsg, &i,						&sg_offset, 1, dlen,						session->data_digest);		}		if (rc != ISCSI_IO_SUCCESS &&		    rc != ISCSI_IO_INVALID_OP)			iscsi_drop_session(session);		data_offset += dlen;		remaining -= dlen;	} while (remaining > 0 && rc == ISCSI_IO_SUCCESS);	return rc;}static inline unsignedget_immediate_data_len(struct iscsi_session *session, struct scsi_cmnd *sc){	int len;	if (!session->immediate_data)		return 0;	if (session->first_burst_len)		len = min(session->first_burst_len,			  session->max_xmit_data_segment_len);	else		len = session->max_xmit_data_segment_len;	return min_t(unsigned, len, sc->request_bufflen);}/* * iscsi_queue_r2t may be called so the task lock must be held * why not handle this in iscsi_send_scsi_cmnd? */voidiscsi_queue_unsolicited_data(struct iscsi_task *task){	unsigned imm_data_len;	struct iscsi_session *session = task->session;	struct scsi_cmnd *sc = task->scsi_cmnd;	/*	 * With ImmediateData, we may or may not have to send	 * additional Data PDUs, depending on the amount of data, and	 * the Max PDU Length, and the first_burst_len.	 */	if (!test_bit(ISCSI_TASK_WRITE, &task->flags) ||	    !sc->request_bufflen || session->initial_r2t)		return;	/*	 * queue up unsolicited data PDUs. the implied initial R2T	 * doesn't count against the MaxOutstandingR2T, so we can't use	 * the normal R2T * fields of the task for the implied initial	 * R2T. Use a special flag for the implied initial R2T, and	 * let the rx thread update tasks in the tx_tasks collection	 * if an R2T comes in before the implied initial R2T has been	 * processed.	 */	if (session->immediate_data) {		imm_data_len = get_immediate_data_len(session, sc);		/*		 * Only queue unsolicited data out PDUs if there is more		 * data in the request, and the FirstBurstLength hasn't		 * already been satisfied with the ImmediateData that		 * will be sent below via iscsi_send_scsi_cmnd().		 */		if (sc->request_bufflen <= imm_data_len ||		    imm_data_len >= session->first_burst_len)			return;	}	__set_bit(ISCSI_TASK_INITIAL_R2T, &task->flags);	iscsi_queue_r2t(session, task);	set_bit(TX_DATA, &session->control_bits);	set_bit(TX_WAKE, &session->control_bits);}/** * iscsi_send_r2t_data - see if we need to send more data. * @session: iscsi session * * Note: *   This may call iscsi_run_pending_queue under some conditions. **/voidiscsi_send_r2t_data(struct iscsi_session *session){	struct iscsi_task *task;	struct scsi_cmnd *sc;	u32 ttt, offset, len;	unsigned implied_len, imm_data_len;	int rc;	spin_lock_bh(&session->task_lock); retry:	task = iscsi_dequeue_r2t(session);	if (!task)		goto done;	rc = ISCSI_IO_SUCCESS;	/*	 * save the values that get set when we receive an R2T from	 * the target, so that we can receive another one while	 * we're sending data.	 */	ttt = task->ttt;	offset = task->data_offset;	len = task->data_length;	task->ttt = ISCSI_RSVD_TASK_TAG;	spin_unlock_bh(&session->task_lock);	/*	 * implied initial R2T	 * (ISCSI_TASK_INITIAL_R2T bit is only accessed by tx	 * thread so we do not need atomic ops)	 */	if (__test_and_clear_bit(ISCSI_TASK_INITIAL_R2T, &task->flags)) {		sc = task->scsi_cmnd;		/*		 * FirstBurstLength == 0 means no limit when		 * ImmediateData == 0 (not documented in README?)		 */		if (!session->first_burst_len)			implied_len = sc->request_bufflen;		else			implied_len = min_t(unsigned, session->first_burst_len,					    sc->request_bufflen);		if (session->immediate_data) {			imm_data_len = get_immediate_data_len(session, sc);			implied_len -= imm_data_len;		} else			imm_data_len = 0;		rc = iscsi_send_data_out(task, ISCSI_RSVD_TASK_TAG,					 imm_data_len, implied_len);	}	/* normal R2T from the target */	if (ttt != ISCSI_RSVD_TASK_TAG && rc == ISCSI_IO_SUCCESS)		iscsi_send_data_out(task, ttt, offset, len);	spin_lock_bh(&session->task_lock);	__iscsi_put_task(task);	if (!signal_pending(current))		goto retry; done:	spin_unlock_bh(&session->task_lock);}/** * iscsi_send_scsi_cmnd - Transmit iSCSI Command PDU. * @task: iSCSI task to be transmitted * * Description: *     The header digest on the cmd PDU is calculated before sending the cmd. *     If ImmediateData is enabled, data digest is computed and data is sent *     along with cmd PDU. **/voidiscsi_send_scsi_cmnd(struct iscsi_task *task){	struct iscsi_scsi_cmd_hdr stsch;	struct iscsi_session *session = task->session;	struct scsi_cmnd *sc = task->scsi_cmnd;	int rc, first_sg = 0;	struct scatterlist tmpsg;	u32 imm_data_len = 0,  sg_offset = 0;	memset(&stsch, 0, sizeof(stsch));	if (test_bit(ISCSI_TASK_READ, &task->flags)) {		stsch.flags |= ISCSI_FLAG_CMD_READ;		stsch.data_length = htonl(sc->request_bufflen);	} else if (test_bit(ISCSI_TASK_WRITE, &task->flags)) {		stsch.flags |= ISCSI_FLAG_CMD_WRITE;		stsch.data_length = htonl(sc->request_bufflen);	}	/* tagged command queueing */	stsch.flags |= (iscsi_command_attr(sc) & ISCSI_FLAG_CMD_ATTR_MASK);	stsch.opcode = ISCSI_OP_SCSI_CMD;	stsch.itt = htonl(task->itt);	task->cmdsn = session->cmd_sn;	stsch.cmdsn = htonl(session->cmd_sn);	stsch.expstatsn = htonl(session->exp_stat_sn);	/*	 * set the final bit when there are no unsolicited Data-out	 * PDUs following the command PDU	 */	if (!test_bit(ISCSI_TASK_INITIAL_R2T, &task->flags))		stsch.flags |= ISCSI_FLAG_FINAL;	/* single level LUN format puts LUN in byte 1, 0 everywhere else */	stsch.lun[1] = sc->device->lun;	memcpy(stsch.scb, sc->cmnd, min_t(size_t, sizeof(stsch.scb),					  sc->cmd_len));	if (session->immediate_data &&	    sc->sc_data_direction == DMA_TO_DEVICE) {		if (!sc->request_bufflen)			/* zero len write? just let it timeout */			return;		imm_data_len = get_immediate_data_len(session, sc);		/* put the data length in the PDU header */		hton24(stsch.dlength, imm_data_len);		stsch.data_length = htonl(sc->request_bufflen);	}	rc = iscsi_send_header(session, (struct iscsi_hdr *)&stsch,			       session->header_digest);	if (rc != ISCSI_IO_SUCCESS) {		iscsi_host_err(session, "iscsi_send_scsi_cmnd failed to send "			       "scsi cmnd header\n");		iscsi_drop_session(session);		return;	}	if (!imm_data_len)		goto done;	if (sc->use_sg)		rc = iscsi_send_sg_data(session, sc->request_buffer,					&first_sg, &sg_offset, sc->use_sg,					imm_data_len, session->data_digest);	else {		sg_init_one(&tmpsg, sc->request_buffer, imm_data_len);		rc = iscsi_send_sg_data(session, &tmpsg, &first_sg,					&sg_offset, 1, imm_data_len,					session->data_digest);	}	if (rc != ISCSI_IO_SUCCESS) {		iscsi_host_err(session, "iscsi_send_scsi_cmnd failed to send "			       "scsi cmnd data (%u bytes)\n", imm_data_len);		if (rc != ISCSI_IO_INVALID_OP)			iscsi_drop_session(session);	} done:	session->cmd_sn++;}

⌨️ 快捷键说明

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