iscsi-task.c

来自「iSCSI协议在LINUX下的源码.源代码是IBM公布的.主要是结合其OSD设备」· C语言 代码 · 共 639 行 · 第 1/2 页

C
639
字号
		sc->resid = ntohl(stsrh->residual_count);	else if (stsrh->flags & ISCSI_FLAG_DATA_OVERFLOW)		/*		 * FIXME: not sure how to tell the SCSI layer		 * of an overflow, so just give it an error		 */		/* Ignore it till the scsi ml is able to handle it */		/* sc->result = DID_ERROR << 16 | stsrh->cmd_status; */		;	else if (test_bit(ISCSI_TASK_READ, &task->flags) &&		 task->rxdata != sc->request_bufflen)		/*		 * All the read data did not arrive. we don't know		 * which parts of the buffer didn't get data, so		 * report the whole buffer missing		 */		sc->resid = sc->request_bufflen;}voidiscsi_process_task_response(struct iscsi_task *task,			    struct iscsi_scsi_rsp_hdr *stsrh,			    unsigned char *sense_data, unsigned int sense_len){	struct scsi_cmnd *sc = task->scsi_cmnd;	iscsi_process_task_status(task, (struct iscsi_hdr *)stsrh);	/*	 * If the target bothered to send sense (even without a check	 * condition), we pass it along, since it may indicate a problem,	 * and it's safer to report a possible problem than it is to assume	 * everything is fine.	 */	if (sense_len) {		memset(sc->sense_buffer, 0, sizeof(sc->sense_buffer));		memcpy(sc->sense_buffer, sense_data,		       min((size_t)sense_len, sizeof(sc->sense_buffer)));	}}static voidiscsi_tmf_times_out(struct iscsi_task *task){	struct iscsi_session *session = task->session;	spin_lock(&session->task_lock);	iscsi_host_err(session, "itt %u timed out\n", task->itt);	iscsi_complete_tmf_task(task, ISCSI_TASK_TMF_FAILED);	spin_unlock(&session->task_lock);}intiscsi_exec_task_mgmt(struct iscsi_task *task, unsigned long timeout){	struct iscsi_session *session = task->session;	DECLARE_COMPLETION(complete);	unsigned int reject_retry = 40;	struct timer_list timer;	init_timer(&timer);	/*	 * Did the last task mgmt fn timeout?	 */	if (session->last_mgmt_itt != ISCSI_RSVD_TASK_TAG) {		iscsi_host_info(session, "Outstanding task mgmt function %u "			       "exists.\n", session->last_mgmt_itt);		return -1;	} retry:	/*	 * TODO merge with session timer when it is fixed (need	 * to mod_timer here then) ???	 */	if (timeout) {		timer.data = (unsigned long)task;		timer.expires = jiffies + timeout * HZ;		timer.function = (void (*)(unsigned long))iscsi_tmf_times_out;		add_timer(&timer);	}	session->mgmt_task_complete = &complete;	queue_active_task(task);	session->last_mgmt_itt = task->itt;	spin_unlock_bh(&session->task_lock);	iscsi_host_info(session, "Waking tx_thread to send task mgmt "			"function itt %u\n", task->itt);	iscsi_wake_tx_thread(TX_TMF, session);	wait_for_completion(&complete);	del_singleshot_timer_sync(&timer);	spin_lock_bh(&session->task_lock);	session->mgmt_task_complete = NULL;	/*	 * we do not retry aborts on immediate rejects here, instead	 * the caller should redrive it	 */	if (!test_bit(ISCSI_TASK_ABORT, &task->flags) &&	    __test_and_clear_bit(ISCSI_TASK_IMM_REJECT, &task->flags)) {		iscsi_host_err(session, "itt %u recieved immediate "			       "reject. Sleeping for %u ms before retry\n",			       task->itt, reject_retry);		if (reject_retry <= 1280) {			spin_unlock_bh(&session->task_lock);			msleep_interruptible(reject_retry);			spin_lock_bh(&session->task_lock);			reject_retry *= 2;			goto retry;		}	}	return test_bit(ISCSI_TASK_TMF_SUCCESS, &task->flags) ? 0 : -1;}static voidiscsi_set_direction(struct iscsi_task *task){	switch (task->scsi_cmnd->sc_data_direction) {	case DMA_FROM_DEVICE:		__set_bit(ISCSI_TASK_READ, &task->flags);		break;	case DMA_TO_DEVICE:		__set_bit(ISCSI_TASK_WRITE, &task->flags);		break;	case DMA_BIDIRECTIONAL:		/* We do not yet support this */	case DMA_NONE:		break;	}}/** * iscsi_run_pending_queue - process pending tasks. * @session: the session to process. * * Note: *    Caller must not hold the task lock. **/voidiscsi_run_pending_queue(struct iscsi_session *session){	struct iscsi_task *task;	spin_lock_bh(&session->task_lock);	while (!signal_pending(current)) {		if (!iscsi_sna_lte(session->cmd_sn, session->max_cmd_sn))			break;		if (test_bit(SESSION_LOGOUT_REQUESTED, &session->control_bits))			break;		if (list_empty(&session->pending_queue))			break;		task = list_entry(session->pending_queue.next,				  struct iscsi_task, queue);		list_del_init(&task->queue);		iscsi_set_direction(task);		queue_active_task(task);		__iscsi_get_task(task);		iscsi_queue_unsolicited_data(task);		spin_unlock_bh(&session->task_lock);		/*		 * we don't bother to check if the xmit works, since if it		 * fails, the session will drop, and all tasks and cmnds		 * will be completed by the drop.		 */		iscsi_send_scsi_cmnd(task);		spin_lock_bh(&session->task_lock);		__iscsi_put_task(task);	}	spin_unlock_bh(&session->task_lock);}static voidfail_task(struct iscsi_task *task, int result){	struct scsi_cmnd *sc = task->scsi_cmnd;	sc->resid = sc->request_bufflen;	sc->result = result << 16;	sc->sense_buffer[0] = 0x70;	sc->sense_buffer[2] = NOT_READY;	sc->sense_buffer[7] = 0x0;	iscsi_host_err(task->session, "Failing command cdb 0x%02x task %u "		       "with return code = 0x%x\n", sc->cmnd[0], task->itt,		       sc->result);	/*	 * was it pending	 */	if (task->itt == ISCSI_RSVD_TASK_TAG)		__iscsi_complete_task(task);	else {		if (!list_empty(&task->task_group_link)) {			list_del_init(&task->task_group_link);			__iscsi_put_task(task);		}		iscsi_complete_task(task);	}}/** * iscsi_flush_queues - Flush the active and pending queues. * @session: session to search tasks for * @lun: if lun is a valid value then only work on tasks on that lun * if lun is greater than or equal to ISCSI_MAX_LUNS then work on all tasks * @result: this should be a scsi-ml host_byte value * * Note: *    Caller must hold the task lock. *    The driver uses DID_BUS_BUSY to inidcate that it may be worth it *    to retry the command, but scsi-ml should have the final say (for *    tape, failfast, etc). And it uses DID_NO_CONNECT to indicate *    the session is gone and according to the replacment timeout not *    coming back so there is no point in retyring **/voidiscsi_flush_queues(struct iscsi_session *session, unsigned int lun, int result){	struct iscsi_task *task, *tmp;	/*	 * failing a task that is being aborted will lead to	 * the TMF task being removed too, or completing a tmf could	 * result in multiple tasks being removed. The task lock can also	 * be dropped by iscsi_complete_tmf_task.	 */ restart:        list_for_each_entry_safe(task, tmp, &session->active_queue, queue) {		if (lun < ISCSI_MAX_LUNS && task->lun != lun)			continue;		if (task->scsi_cmnd)			fail_task(task, result);		else			/*			 * This should only occur during session drops or			 * session replacement timeouts. We report success			 * since we are not going to get a response and all			 * the cmnds are going to be returned back to scsi-ml.			 */			iscsi_complete_tmf_task(task, ISCSI_TASK_TMF_SUCCESS);		goto restart;	}	list_for_each_entry_safe(task, tmp, &session->pending_queue, queue) {		if (lun < ISCSI_MAX_LUNS && task->lun != lun)			continue;		/*		 * These commands have not even been sent, so there is		 * no requirement to fail the command, but for a requeue		 * there is no way to tell that the incoming commands		 * were meant to be placed before the pending head or tail.		 */		fail_task(task, result);	}}/* * must hold the task_lock to call this * TODO: if we cannot use the block layer tags we * should use a non-linear algorithm. */struct iscsi_task *iscsi_find_session_task(struct iscsi_session *session, u32 itt){	struct iscsi_task *task = NULL;	list_for_each_entry(task, &session->active_queue, queue)		if (task->itt == itt) {			__iscsi_get_task(task);			return task;		}	return NULL;}/* * must hold the task_lock when calling this, and must release the * handle acquired when adding the task to the collection */inline struct iscsi_task *iscsi_dequeue_r2t(struct iscsi_session *session){	struct list_head *p;	if (!list_empty(&session->tx_task_head)) {		p = session->tx_task_head.next;		list_del_init(p);		return list_entry(p, struct iscsi_task, task_group_link);	}	return NULL;}/* * Add a task to the collection.  Must hold the task_lock to do this. * This acquires a handle to the task that must be released when * the task is dequeued and that caller is done using it */inline voidiscsi_queue_r2t(struct iscsi_session *session, struct iscsi_task *task){	if (list_empty(&task->task_group_link)) {		__iscsi_get_task(task);			list_add_tail(&task->task_group_link, &session->tx_task_head);	}}

⌨️ 快捷键说明

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