📄 iscsi_initiator.c
字号:
connid = conn->connection_id; TRACE(TRACE_DEBUG, "Only connection available is %p, id %u -" "Create new connection for recovery\n", conn, connid); targ_data = &global_hostdata->target_data[sess->scsi_target_id]; restore_global_data(targ_data); targ_data->nop_period = 0; targ_data->init_sess_flags = 0; targ_data->init_conn_flags = 0; global_hostdata->init_sessrec_flg = 0; /* find a connection id that is not yet used in this session */ retry: connid++; for (this_conn = sess->connection_head; this_conn; this_conn = this_conn->next) { if (this_conn->connection_id == connid) { /* this id already in use, try the next one */ goto retry; } } /* find a lun that is already in use in this session */ lun = find_used_lun(sess); if (unlikely(lun < 0)) { retval = 0; goto out; } /* got the lun, now create a new recovery session */ if (dup_inet_struct(conn->ip_address, &new_ip_address, &new_ip_length) < 0 || create_session(sess->scsi_target_id, new_ip_address, new_ip_length, lun, connid, global_host) != 0) { TRACE_ERROR("Unable to create recovery connection\n"); retval = 0; goto out; } /* if any luns were assigned to old connection, reassign them */ if (conn->assigned_lun_count) { UNH_LOCK(&host_data_lock, flags); UNH_LOCK(&sess->sess_lock, lock_flags); for (lun = 0; lun < MAX_LUNS; lun++) { if (conn == sess->lun_assignments[lun]) { locked_drop_lun_from_sess(lun, sess, 0); locked_add_lun_to_sess(lun, sess); } } UNH_UNLOCK(&sess->sess_lock, lock_flags); UNH_UNLOCK(&host_data_lock, flags); } retval = 1;out: TRACE(TRACE_ENTER_LEAVE, "Leaving create_rec_conn, retval = %d\n", retval); return retval;}/* * when called, NO LOCKS SHOULD BE LOCKED! * release a socket and free the connection structure */void __attribute__ ((no_instrument_function))free_connection(struct connection *conn){ char ip_string[INET6_ADDRSTRLEN+2], port_string[8]; if (conn->sock != NULL) { TRACE(TRACE_NET, "Releasing socket %p\n", conn->sock); if (cnv_inet_to_string(conn->ip_address, ip_string, port_string) > 0) { printk("Disconnected from %s:%s\n", ip_string, port_string); } sock_release(conn->sock); TRACE(TRACE_NET, "Released socket %p\n", conn->sock); conn->sock = NULL; } TRACE(TRACE_NET, "Free ip_address %p\n", conn->ip_address); my_kfree((void **)&conn->ip_address, "ip_address"); TRACE(TRACE_NET, "Free local_ip_address %p\n", conn->local_ip_address); my_kfree((void **)&conn->local_ip_address, "local_ip_address"); TRACE(TRACE_DEBUG, "%s Free conn %p\n", current->comm, conn); my_kfree((void **)&conn, "connection");}/* * when called, NO LOCKS SHOULD BE LOCKED! * clear disconnected and unused connections - SAI */void __attribute__ ((no_instrument_function))clear_free_conn(struct session *sess){ struct connection *prev, *conn; if (!sess->connection_head) { TRACE_ERROR("No Valid connections available\n"); return; } if (sess->nconnections <= 1 && sess->connection_head->connection_state==CONNECTION_RECOVERING) { /* No connections available - Need to create a new one - SAI */ create_rec_conn(sess->connection_head); } for (prev = NULL, conn = sess->connection_head; conn != NULL; conn = conn->next) { if ((conn->connection_state == CONNECTION_NOT_PRESENT)) { TRACE(TRACE_ISCSI, "Releasing connection %p\n", conn); if (prev == NULL) sess->connection_head = conn->next; else prev->next = conn->next; /* Adjust the round robin connection head - SAI */ if (conn == sess->rr_conn_head) { sess->rr_conn_head = prev; } free_connection(conn); break; } prev = conn; } return;}/* * executed by scsi midlevel process and rx thread * the session->sess_lock MUST be held by the calling process/thread. * performs round-robin scheduling by picking up at last connection we * scheduled and moving to next one that is in full feature phase. * Returns pointer to next connection to schedule, and leaves session's * rr_conn_head pointing to it. */static struct connection * __attribute__ ((no_instrument_function))do_round_robin(struct session *session){ int nconn; struct connection *conn; if ((conn = session->rr_conn_head) == NULL || (conn = conn->next) == NULL) conn = session->connection_head; for (nconn = 0; nconn < session->nconnections; nconn++) { if (conn->connection_state == CONNECTION_FULL_FEATURE_PHASE) break; if ((conn = conn->next) == NULL) conn = session->connection_head; } return session->rr_conn_head = conn;}/* * executed by scsi midlevel process and rx thread * the session->sess_lock MUST be held by the calling process/thread. * Multiple Connection Scheduling Algorithm - SAI */struct connection * __attribute__ ((no_instrument_function))get_connection(struct scsi_cmnd * Cmnd, struct session *sess){ struct connection *conn; TRACE(TRACE_ENTER_LEAVE, "Entering get_connection\n"); switch (sess->sched_scheme) { case CONN_SCHED_RR: /* get the next connection in the round-robin */ if (sess->nconnections == 1) conn = sess->connection_head; else { conn = do_round_robin(sess); } break; case CONN_SCHED_LUN: /* get the connection assigned to this LUN */#ifdef K26 conn = sess->lun_assignments[Cmnd->device->lun];#else conn = sess->lun_assignments[Cmnd->lun];#endif break; default: /* use only one connection */ conn = sess->connection_head; break; } TRACE(TRACE_ENTER_LEAVE, "Leaving get_connection\n"); return conn;}/****************************************************************************** When called, io_request_lock is held by the midlevel caller.* This function is called by the SCSI Mid-level whenever a Read/Write Request* has to be satisfied. This function will set up TCP buffers for sending SCSI* Command and, if the negotiated ImmediateData is 1, ImmediateData. After* setting up the TCP buffers, the tx thread is woken up which is waiting on* tx_sem.* Parameters: struct scsi_cmnd,* done function which is called when any SCSI Command is satisfied.* Return Value: 0, on success* -1, on failure (any non-zero value seems to work)** Note that the done() function should not be called until queuecommand returns!******************************************************************************/static intiscsi_initiator_queuecommand(struct scsi_cmnd * Cmnd, void (*done) (struct scsi_cmnd *)){ int retval = 0; /* assume this function will succeed */ __u32 target_id; struct iscsi_hostdata *hostdata; struct session *current_session; unsigned long flags, lock_flags;/* Ming Zhang, mingz@ele.uri.edu */#ifdef K26 target_id = Cmnd->device->id;#else target_id = Cmnd->target;#endif TRACE(TRACE_ENTER_LEAVE, "Enter iscsi_initiator_queuecommand, target id %u\n", target_id);/* RDR */#ifndef K26 /* must not hold io_request_lock when trying to get our locks */ spin_unlock(&io_request_lock);#endif /* get exclusive access to the iscsi structures */ UNH_LOCK(&host_data_lock, flags); if (unlikely(global_host == NULL || global_hostdata == NULL)) { TRACE_ERROR("queuecommand called after shutdown\n"); retval = -1; goto out; } /* get pointer to hostdata struct registered to the SCSI Mid-level *//* Ming Zhang, mingz@ele.uri.edu */#ifdef K26 hostdata = (struct iscsi_hostdata *) Cmnd->device->host->hostdata;#else 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); retval = -1; goto out; } /* tell Mid-level when I am done receiving the SCSI Cmnd info. */ Cmnd->scsi_done = done; /* Find out the session corresponding to the target_id */ current_session = find_session_by_id(target_id, hostdata); /* Check that we have finished the Login Phase * with the concerned target and are now in the * full feature phase of a normal session */ if (unlikely(current_session == NULL || current_session->session_state != SESSION_FULL_FEATURE_PHASE || current_session->connection_head == NULL || current_session->connection_head->rx_thread == NULL || current_session->connection_head->tx_thread == NULL || current_session->oper_param->SessionType)) { /* Check to see if session recovery is active - SAI */ if (global_hostdata && global_hostdata->init_sessrec_flg) { /* changes for session recovery new 18_04 - SAI */ TRACE(TRACE_ISCSI, "iscsi_initiator_queuecommand : " "Recovery in Progress for target %u\n", target_id); /* create a new session recovery structure or * get the already existing session recovery * structure depending on whether one or * multiple sessions participate in session * recovery - new 18_04 SAI */ /* NOTE XXX jpd 7/18/2003 * this section has changed in ref20_17 compared * to ref20_10 (RPM 1.2.0) . * Needs investigations for lock spliting * per-session. I don't know why these are commented * out . */ /* create and store in a recovery session - SAI */ set_rec_group(Cmnd); goto out; } printk("iscsi Target %u not logged in\n", target_id); Cmnd->result = DID_NO_CONNECT << 16; if (likely(done != NULL)) /* should not do this before queuecommand returns! */ done(Cmnd); goto out; } UNH_LOCK(¤t_session->sess_lock, lock_flags); retval = scsi_to_iscsi(Cmnd, current_session); UNH_UNLOCK(¤t_session->sess_lock, lock_flags);out: /* release our exclusive access to the iscsi structures */ UNH_UNLOCK(&host_data_lock, flags); TRACE(TRACE_ENTER_LEAVE, "Leave iscsi_initiator_queuecommand, retval %d\n", retval);/* RDR */#ifndef K26 /* get back midlevel caller's lock */ spin_lock(&io_request_lock);#endif return retval;}/***************************************************************************** * executed by scsi midlevel process and init_recovery thread * host_data_lock and sess->sess_lock MUST be held by the calling process/thread * This function takes the command and data from the scsi buffers, forms a new * iSCSI PDU with the corresponding command and data filled-in and attaches the * command to the end of the pending commands list for the session - SAI * scsi midlevel's SPIN_LOCK io_request_lock must NOT be held*****************************************************************************/intscsi_to_iscsi(struct scsi_cmnd * Cmnd, struct session *current_session){ int retval = 0; /* assume this function succeeds */ __u32 lun; struct iscsi_init_scsi_cmnd *iscsi_cmd; struct command *new_command; struct connection *conn; TRACE(TRACE_ENTER_LEAVE, "Enter scsi_to_iscsi\n");/* Ming Zhang, mingz@ele.uri.edu */#ifdef K26 lun = Cmnd->device->lun;#else lun = Cmnd->lun;#endif if (current_session->nconnections <= 1) conn = current_session->connection_head; else { /* multiple connections usage - SAI */ conn = get_connection(Cmnd, current_session); } if (unlikely(conn == NULL)) { TRACE_ERROR("Session %u has no connections for lun %u\n", current_session->scsi_target_id, lun); retval = -1; goto out; } /* make sure connection is still in FFP */ if (unlikely(conn->connection_state != CONNECTION_FULL_FEATURE_PHASE)) { /* rx_thread gone -- peer probably reset the connection */ Cmnd->result = DID_NO_CONNECT << 16; if (likely(Cmnd->scsi_done != NULL)) { /* can we do this before queuecommand returns?! */ call_back_scsi_done(Cmnd); } goto out; } /* get a new struct command to send SCSI Request PDU to target */ new_command = setup_command(Cmnd, conn); if (unlikely(new_command == NULL)) { retval = -1; goto out; } /* set up the SCSI_Cmnd header that is to be sent to the target */ iscsi_cmd = &new_command->iscsi_cmd; iscsi_cmd->opcode = ISCSI_INIT_SCSI_CMND; /* 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -