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 + -
显示快捷键?