📄 iscsi_initiator.c
字号:
* already zeroed out the entire PDU header in setup_command() above, * we don't need to do anything else here in this case. */ if (lun) { pack_lun(lun, conn->connection_flags & USE_FLAT_SPACE_LUN, (__u8 *)&iscsi_cmd->lun); } iscsi_cmd->xfer_len = htonl(Cmnd->request_bufflen); TRACE(TRACE_DEBUG, "Xfer len for queuecommand %d\n", Cmnd->request_bufflen); /* copy the SCSI CDB into the PDU */ memcpy(iscsi_cmd->cdb, Cmnd->cmnd, Cmnd->cmd_len); if (Cmnd->sc_data_direction == SCSI_DATA_WRITE) { /* SCSI Command has write data to be sent. * Mark the cmd to be built when xmit_thread wakes up in order * to avoid any potential sleep hazards in * build_write_command(), since we may be in an interrupt * context here. */ new_command->need_write_built |= CMD_NEEDS_WRITE_BUILT; TRACE(TRACE_DEBUG, "command %p marked for write\n", new_command); } else { /* not a write, probably a read, but check out of curiousity */ /* always set the F_BIT if it is not a WRITE SCSI Commamnd */ if (likely(Cmnd->sc_data_direction == SCSI_DATA_READ)) { iscsi_cmd->flags = F_BIT | R_BIT; } else { /* direction given as neither Read nor Write */ TRACE(TRACE_DEBUG, "sc_data_direction %u not READ or WRITE\n", Cmnd->sc_data_direction); if (unlikely(Cmnd->request_bufflen != 0)) { TRACE_ERROR("request_bufflen %u not zero when " "sc_data_direction %u not READ or " "WRITE\n", Cmnd->request_bufflen, Cmnd->sc_data_direction); iscsi_cmd->flags = F_BIT | R_BIT; } else { /* no data expected to be transfered, * not READ or WRITE, so only set the F bit */ iscsi_cmd->flags = F_BIT; } } } /* attach the new SCSI Request command to end of pending commands list * this also sets the ITT and the CmdSN. */ attach_pending_command(new_command, conn, 1);out: TRACE(TRACE_ENTER_LEAVE, "Leave scsi_to_iscsi, retval %d\n", retval); return retval;}/***************************************************************************** This function is called by the system when the abort_timer set in* the iscsi_initiator_abort function expires. This function wakes up* the thread/process which is waiting on the task_mgt_sem semaphore.****************************************************************************/static voidabort_timer_function(unsigned long data){ TRACE(TRACE_ENTER_LEAVE, "Enter abort_timer_function\n"); up((struct semaphore *) data); TRACE(TRACE_ENTER_LEAVE, "Leave abort_timer_function\n");}static voiddump_command_info(struct command *related_command, struct connection *related_connection, struct session *related_session){ int delta_t; struct r2t_cookie *cookie; delta_t = jiffies - related_command->time_stamp; printk (" SCpnt %p, op 0x%02x, flags 0x%02x, time_stamp %u, delta_t %d\n", related_command->SCpnt, related_command->header_opcode, related_command->header_flags, related_command->time_stamp, delta_t); printk(" recvd_length %u, data_offset %u, still_to_send %u, " "wait_to_send %u, cmd_state 0x%02x\n", related_command->recvd_length, related_command->data_offset, related_command->still_to_send, related_command->tx_wait_to_send, related_command->cmd_state); if (related_command->SCpnt) { printk( " request_bufflen %u, recv_so_far %u, " "data_in_sn %u, direction %c\n", related_command->SCpnt->request_bufflen, related_command->r2t_range_list.limit, related_command->data_in_sn, related_command->SCpnt->sc_data_direction == SCSI_DATA_WRITE ? 'W' : 'R'); } printk(" tx_size %u, tx_sent_so_far %u, r2t_sn %u, n_r2t_cookies %u, " "msg_flags 0x%08x\n", related_command->tx_size, related_command->tx_sent_so_far, related_command->r2t_sn, related_command->n_r2t_cookies, related_command->cmd_msg_flags); delta_t = related_session->max_cmd_sn - ntohl(related_command->iscsi_cmd.cmd_sn); printk(" short_command %p, max_cmd_sn %u, cmd_sn %u, delta %d\n", related_connection->short_command, related_session->max_cmd_sn, ntohl(related_command->iscsi_cmd.cmd_sn), delta_t); if (list_empty(&related_command->r2t_cookies)) { printk(" No R2T cookies\n"); } else { list_for_each_entry(cookie,&related_command->r2t_cookies,link) { printk ("cookie TTT %u, data_out_sn %u, r2t_xfer_length " "%d, offset %u\n", ntohl(cookie->target_xfer_tag), cookie->data_out_sn, (int) cookie->r2t_xfer_length, cookie->offset); } }}/* * when called, NO LOCKS SHOULD BE LOCKED! * Searches iscsi structures for Cmnd * Returns 1 on success, 0 on failure to find this command * On success, it has filled in the last 3 parameters : * session, connection, and related command * with session->sess_lock LOCKED. * On failure, these last 3 parameters are unchanged /undefined * and session->sess_lock is NOT LOCKED. */static intfind_aborted_command(struct scsi_cmnd * Cmnd, struct session **found_session, struct connection **found_connection, struct command **found_command, int print_on_success, unsigned long *lock_flags){ struct session *related_session; struct connection *related_connection = NULL; struct command *related_command; struct iscsi_hostdata *hostdata; int retval = 0; /* assume failure */ __u32 target_id; unsigned long flags; UNH_LOCK(&host_data_lock, flags);/* Ming Zhang, mingz@ele.uri.edu */#ifdef K26 target_id = Cmnd->device->id; hostdata = (struct iscsi_hostdata *) Cmnd->device->host->hostdata;#else target_id = Cmnd->target; hostdata = (struct iscsi_hostdata *) Cmnd->host->hostdata;#endif if (unlikely(hostdata != global_hostdata)) { TRACE_ERROR ("Hostdata struct %p not same as global_hostdata %p\n", hostdata, global_hostdata); UNH_UNLOCK(&host_data_lock, flags); goto out; } /* Find out the session that corresponds to this target ID */ related_session = find_session_by_id(target_id, hostdata); if (unlikely(related_session == NULL)) { TRACE_ERROR("No session for target %u\n", target_id); UNH_UNLOCK(&host_data_lock, flags); goto out; } UNH_LOCK(&related_session->sess_lock, *lock_flags); UNH_UNLOCK(&host_data_lock, flags); /* check if the session is in full feature phase or not */ if (unlikely( related_session->session_state != SESSION_FULL_FEATURE_PHASE || (related_connection = related_session->connection_head) == NULL || related_connection->rx_thread == NULL || related_connection->tx_thread == NULL || related_connection->connection_state != CONNECTION_FULL_FEATURE_PHASE)) { TRACE_ERROR("No connection to target %u\n", target_id); UNH_UNLOCK(&related_session->sess_lock, *lock_flags); goto out; } /* search for the PDU containing the SCSI command * which has to be aborted */ for (; related_connection; related_connection = related_connection->next) { list_for_each_entry(related_command, &related_connection->pending_commands, link) { if (related_command->SCpnt == Cmnd) { if (likely((related_command->iscsi_cmd. opcode & ISCSI_OPCODE) ==ISCSI_INIT_SCSI_CMND)) goto found_command_match; TRACE_ERROR ("Related Cmnd %p for target %u has " "opcode 0x%02x, expected 0x%02x\n", Cmnd, target_id, related_command->iscsi_cmd.opcode & ISCSI_OPCODE, ISCSI_INIT_SCSI_CMND); UNH_UNLOCK(&related_session->sess_lock, *lock_flags); goto out; } } } /* did not find the command to abort, dump pending cmnds */ TRACE_ERROR("No related SCSI Cmnd %p for target %u\n", Cmnd, target_id); for (related_connection = related_session->connection_head; related_connection != NULL; related_connection = related_connection->next) { printk (" pending cmds for connection %p, CID %u, jiffies %lu\n", related_connection, related_connection->connection_id, jiffies); list_for_each_entry(related_command, &related_connection->pending_commands, link) { dump_command_info(related_command, related_connection, related_session); } } UNH_UNLOCK(&related_session->sess_lock, *lock_flags); goto out;found_command_match: /* successfully found the matching command to be aborted * session->sess_lock is LOCKED */ if (print_on_success) { TRACE_ERROR("Aborting SCSI Cmnd with ITT %u, CmndSN %u, " "jiffies %lu\n", related_command->init_task_tag, ntohl(related_command->iscsi_cmd.cmd_sn), jiffies); dump_command_info(related_command, related_connection, related_session); } *found_session = related_session; *found_connection = related_connection; *found_command = related_command; retval = 1;out: return retval;}/* * the session->sess_lock MUST be held by the calling process/thread. * Allocates, sets up, and sends a task management pdu to target, * then waits (up to a time limit) for a response from the target, * and finally frees the task management command structure. * Returns NULL in value of related_command on any error. */static voidtm_send_and_wait(struct scsi_cmnd * Cmnd, struct session *related_session, struct connection *conn, struct command **related_command, unsigned long *lock_flags){ struct timer_list abort_timer; struct command *task_mgt_command; struct iscsi_init_task_mgt_command *task_mgt_command_hdr; __u32 related_itt, lun; task_mgt_command = setup_command(NULL, conn); if (unlikely(task_mgt_command == NULL)) { *related_command = NULL; goto out; } related_itt = (*related_command)->init_task_tag; task_mgt_command->task_mgt_function = TMF_ABORT_TASK; task_mgt_command->task_mgt_response = FUNCTION_REJECTED; /* fill up the task_mgt_header info. -- command should be immediate */ task_mgt_command_hdr = (struct iscsi_init_task_mgt_command *) &task_mgt_command->iscsi_cmd; task_mgt_command_hdr->opcode = (ISCSI_INIT_TASK_MGMT_CMND | I_BIT); task_mgt_command_hdr->function = (TMF_ABORT_TASK | F_BIT);/* Ming Zhang, mingz@ele.uri.edu */#ifdef K26 lun = Cmnd->device->lun;#else lun = Cmnd->lun;#endif /* SAM-2, section 4.12.2 LUN 0 address * "To address the LUN 0 of a SCSI device the peripheral device * address method shall be used." * * What this means is that whenever the LUN is 0, the full 8 bytes of * the LUN field in the iscsi PDU will also be 0. Because we have * already zeroed out the entire PDU header in setup_command() above, * we don't need to do anything else here in this case. */ if (lun) { pack_lun(lun, conn->connection_flags & USE_FLAT_SPACE_LUN, (__u8 *)&task_mgt_command_hdr->lun); } task_mgt_command_hdr->ref_task_tag = htonl(related_itt); task_mgt_command_hdr->ref_cmd_sn = (*related_command)->iscsi_cmd.cmd_sn; /* attach the new task mgt command to end of pending commands list * this also assigns the ITT and sets the CmdSN. */ attach_pending_command(task_mgt_command, conn, 1); TRACE(TRACE_DEBUG, "Waiting to get task mgt. rsp from the target\n"); /* set up timer and wait on task_mgt_sem until the timer expires */ /* or we receive the task management response from the target */ init_timer(&abort_timer); abort_timer.expires = jiffies + ABORT_TIMEOUT; abort_timer.data = (__u32) &conn->task_mgt_sem; abort_timer.function = abort_timer_function; add_timer(&abort_timer); /* release our exclusive access to the iscsi structures while waiting */ UNH_UNLOCK(&related_session->sess_lock, *lock_flags); /* wait for our timer to expire */ down(&conn->task_mgt_sem); del_timer_sync(&abort_timer); TRACE(TRACE_DEBUG, "Awake after down on task mgt. sem\n"); TRACE(TRACE_DEBUG, "Task mgt response 0x%02x\n", task_mgt_command->task_mgt_response); /* we have to do all this all over again because we may have been "away" for a long time and our operating environment could have changed during that interval -- the session and/or connection could have been closed (unlikely) or the command could have completed and been removed from the pending commands list (more likely). */ if (!find_aborted_command(Cmnd, &related_session, &conn, related_command, 0, lock_flags)) { /* command must have "disappeared" while we were away! */ /* get lock so we can free the tm command structure */ UNH_LOCK(&related_session->sess_lock, *lock_flags); *related_command = NULL; } else { /* Successfully found matching command (again) to be aborted. * Corresponding session, connection and command are valid. * Session lock is held. ITT must be same as it was before. */ if (unlikely((*related_command)->init_task_tag != related_itt)){ /* command changed while we were away! */ TRACE_ERROR("Aborted command ITT now %u, used to be %u\n", (*related_command)->init_task_tag, related_itt); *related_command = NULL; } } /* free the task_mgt_command structure */ task_mgt_command->cmd_state |= CMD_STATE_RXDONE | CMD_STATE_TXDONE; free_pending_command(task_mgt_command, conn);out: return;}/*************************************************************************** * when called, NO LOCKS SHOULD BE LOCKED! * This function is called by the SCSI Mid-level when it has to abort any * SCSI Command. This function will check if the command has been sent to the * target for satisfying the request. If it has been sent, then this function * will set up TCP buffers to send out a Task Mgt. Command. * When called by the SCSI Mid-level (from linux/drivers/scsi/scsi_error.c) * the io_request_lock (or equivalent) is held by the caller. * ****************************************************************************/static intiscsi_initiator_abort(struct scsi_cmnd * Cmnd){ unsigned long lock_flags; /* pessimistic assumption */ int retval = FAILED; struct session *related_session; struct connection *related_connection; struct command *related_command;#if defined(CONFIG_ISCSI_DEBUG) __u32 save_trace;#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -