51 #define CMD_Q_TIMER_MS 30
77 iscsi->
sess_mem = ocs_malloc(iscsi->
os,
sizeof(ocs_session_t) *
79 OCS_M_ZERO | OCS_M_NOWAIT);
81 ocs_log_err(iscsi->
os,
"Failed to allocate sessions, num_cxns is %d\n",
83 ocs_log_err(iscsi->
os,
"sizeof(ocs_session_t) is %ld, total alloc is %ld\n",
sizeof(ocs_session_t),
sizeof(ocs_session_t) * iscsi->
num_cxns);
87 for (i = 0; i < iscsi->
num_cxns; i++) {
88 ocs_session_t *session = &iscsi->
sess_mem[i];
93 OCS_M_ZERO | OCS_M_NOWAIT);
95 if (session->cmd_q == NULL) {
96 ocs_log_err(iscsi->
os,
"Failed to allocate memory for cmd queue\n");
100 ocs_lock_init(iscsi->
os, &session->cmd_q_lock,
"cmd_q lock[%d]", i);
102 session->ocs = iscsi->
os;
103 session->iscsi = iscsi;
104 session->instance_index = i;
125 ocs_session_t *session;
131 while (NULL != session) {
137 while (NULL != session) {
150 for (i = 0; i < iscsi->
num_cxns; i++) {
151 ocs_session_t *session = &iscsi->
sess_mem[i];
153 if (session->cmd_q != NULL) {
154 ocs_free(iscsi->
os, session->cmd_q,
157 session->cmd_q = NULL;
159 ocs_lock_free(&session->cmd_q_lock);
195 ocs_t *ocs = cxn->ocs;
197 ocs_session_t *session;
199 uint8_t isid_found = FALSE;
200 uint8_t cxn_found = FALSE;
201 uint8_t create_new_session = FALSE;
202 uint8_t add_cxn = FALSE;
203 uint32_t cxn_cnt = 0;
214 if (isid == session->isid &&
215 !session->is_removed &&
216 ocs_strcmp(tgt_name, session->tgt_name) == 0 &&
217 ocs_strcmp(ini_name, session->ini_name) == 0) {
229 if (cid == cxn_tmp->cid) {
237 ocs_log_debug(ocs,
"Session reinstatement for isid 0x%" PRIx64
", tsih = 0x%x\n",
238 session->isid, session->tsih);
240 create_new_session = TRUE;
242 }
else if (tsih != session->tsih) {
252 if (cxn_cnt >= session->login_options.max_connections) {
263 create_new_session = TRUE;
270 if (rc == 0 && create_new_session) {
274 if (NULL != session) {
278 session->isid = isid;
281 ocs_strcpy(session->tgt_name, tgt_name);
284 ocs_log_test(ocs,
"Tgt name of len %d exceeds max of %d chars\n",
288 ocs_strcpy(session->ini_name, ini_name);
291 ocs_log_test(ocs,
"Ini name of len %d exceeds max of %d chars\n",
294 session->tsih = session->instance_index + 1;
295 session->login_options.initial_r2t = 1;
296 session->login_options.immediate_data = (ocs->enable_immediate_data ? 1 : 0);;
297 session->login_options.data_pdu_in_order = 1;
298 session->login_options.data_sequence_in_order = 1;
299 session->login_options.error_recovery_level = 0;
303 session->login_options.max_r2t = 1;
307 session->cmd_sn = cmd_sn;
308 session->is_discovery_session = FALSE;
309 session->is_removed = FALSE;
310 session->cmd_q_num_queued = 0;
313 ocs_log_debug(ocs,
"Session created for isid 0x%" PRIx64
", tsih = 0x%x\n",
314 session->isid, session->tsih);
321 if (rc == 0 && add_cxn) {
326 cxn->session = session;
327 cxn->is_leading_login = (cxn_cnt == 0);
328 ocs_log_debug(ocs,
"Added connection 0x%x to isid 0x%" PRIx64
", tsih = 0x%x, is leading login = %d\n",
329 cxn->cid, session->isid, session->tsih,
330 cxn->is_leading_login);
346 ocs_session_t *session = cxn->session;
353 ocs_log_debug(iscsi->
os,
"removed connection 0x%x to isid 0x%" PRIx64
", tsih = 0x%x\n",
354 cxn->cid, session->isid, session->tsih);
362 ocs_log_debug(iscsi->
os,
"Session deleted for isid 0x%" PRIx64
" , tsih = 0x%x\n",
363 session->isid, session->tsih);
384 ocs_cxn_t *rc = NULL;
388 if (cxn->cid == cid) {
411 session->is_removed = TRUE;
413 ocs_lock(&session->cmd_q_lock);
422 session->cmd_q_num_queued--;
426 ocs_unlock(&session->cmd_q_lock);
429 if (ocs_timer_pending(&session->cmd_q_timer)) {
430 ocs_del_timer(&session->cmd_q_timer);
451 uint32_t window_size;
460 if (window_size > 2) {
470 max_cmd_sn = (session->exp_cmd_sn + window_size) - 1;
471 if (
GT_WRAPPED(max_cmd_sn, session->max_cmd_sn)) {
473 session->max_cmd_sn = max_cmd_sn;
474 }
else if (max_cmd_sn > session->max_cmd_sn) {
476 session->max_cmd_sn = max_cmd_sn;
489 ocs_session_t *session = arg;
504 ocs_t *ocs = session->ocs;
507 uint8_t cmd_processed = TRUE;
508 uint8_t set_timer = FALSE;
509 uint8_t release_entry;
510 uint8_t free_rx_buffer;
513 uint8_t reject_reason;
516 ocs_lock(&session->cmd_q_lock);
517 while (cmd_processed) {
518 cmd_processed = FALSE;
523 release_entry = FALSE;
524 free_rx_buffer = FALSE;
526 if (unlikely(
before(cmd_q->
cmd_sn, session->exp_cmd_sn))) {
528 release_entry = TRUE;
529 free_rx_buffer = TRUE;
530 ocs_log_test(ocs,
"Dropping cmd_sn 0x%x, exp_cmd_sn 0x%x for session instance %d\n",
533 session->instance_index);
534 }
else if (cmd_q->
cmd_sn == session->exp_cmd_sn) {
546 session->exp_cmd_sn++;
561 release_entry = TRUE;
562 free_rx_buffer = TRUE;
563 cmd_processed = TRUE;
566 release_entry = TRUE;
575 ocs_log_test(ocs,
"PDU handler returned reject\n");
580 cmd_q->
hdr->dma.virt,
585 release_entry = TRUE;
586 free_rx_buffer = TRUE;
594 ocs_log_test(ocs,
"general error on cmdsn %d", cmd_q->
cmd_sn);
596 release_entry = TRUE;
597 free_rx_buffer = TRUE;
598 cmd_processed = TRUE;
604 if (free_rx_buffer) {
608 session->cmd_q_num_queued--;
610 if (decr_cmd_sn && bhs->
immediate == 0) {
611 session->exp_cmd_sn--;
615 ocs_unlock(&session->cmd_q_lock);
618 if (!ocs_timer_pending(&session->cmd_q_timer)) {
619 ocs_setup_timer(ocs, &session->cmd_q_timer,
652 ocs_session_t *session = cxn->session;
657 if (session == NULL) {
660 ocs_lock(&session->cmd_q_lock);
673 session->cmd_q_num_queued++;
675 ocs_log_test(iscsi->
os,
"no room on command queue");
678 ocs_unlock(&session->cmd_q_lock);
707 ocs_session_t *session = cxn->session;
709 uint32_t cmd_sn = ocs_be32toh(bhs->
cmd_sn);
711 uint8_t decr_cmd_sn = FALSE;
712 uint8_t reject_reason;
720 (session != NULL && session->is_removed)) {
736 ocs_log_test(iscsi->
os,
"startup connection rcvd opcode 0x%x instead of logi PDU",
750 ocs_log_test(iscsi->
os,
"connection rcvd opcode 0x%x during login",
753 (cxn, ocs_be32toh(bhs->
itt));
756 ocs_log_test(iscsi->
os,
"Failed sending Invalid login response");
763 ocs_log_test(iscsi->
os,
"%s Non-logout PDU after logout request - reject\n",
770 ocs_log_test(iscsi->
os,
"%s Login PDU after login complete - reject\n",
776 session->is_discovery_session) {
787 ocs_log_test(iscsi->
os,
"%s Only Text and logout allowed on discovery sessions\n",
794 ocs_log_test(iscsi->
os,
"%s Discovery logout with bad reason %d\n",
795 cxn->display_name, reason);
809 ocs_log_test(iscsi->
os,
"Received data digest error");
812 ocs_log_test(iscsi->
os,
"error sending reject for data digest error");
827 (session != NULL && cmd_sn == session->exp_cmd_sn)) {
833 if (session != NULL &&
835 session->exp_cmd_sn++;
863 ocs_log_test(iscsi->
os,
"%s PDU handler returned reject\n",
882 ocs_log_test(iscsi->
os,
"%s general error on cmdsn %d",
883 cxn->display_name, cmd_sn);
892 session->exp_cmd_sn--;
895 if (session != NULL && session->cmd_q_num_queued > 0) {
899 if (session != NULL) {
902 }
else if (session != NULL &&
after(cmd_sn, session->exp_cmd_sn)) {
935 ocs_t *ocs = session->ocs;
939 ocs_lock(&session->cmd_q_lock);
942 uint32_t cmd_itt = ocs_be32toh(bhs->
itt);
943 if (cmd_itt == itt) {
948 ocs_unlock(&session->cmd_q_lock);
950 ocs_log_debug(ocs,
"ITT 0x%x aborted = %s for session instance %d\n",
952 (rc == 0 ?
"Yes" :
"No"),
953 session->instance_index);
968 ocs_t *ocs = session->ocs;
972 ocs_lock(&session->cmd_q_lock);
974 if (cmd_q->
cmd_sn <= cmdsn) {
979 ocs_unlock(&session->cmd_q_lock);
981 ocs_log_debug(ocs,
"cmd_sn 0x%x aborted = %s for session instance %d\n",
983 (rc == 0 ?
"Yes" :
"No"),
984 session->instance_index);
997 ocs_session_t *session;
1056 ocs_ddump_value(textbuf,
"is_discovery_session",
"%d", session->is_discovery_session);
1060 ocs_ddump_value(textbuf,
"initial_r2t",
"%d", session->login_options.initial_r2t);
1061 ocs_ddump_value(textbuf,
"immediate_data",
"%d", session->login_options.immediate_data);
1062 ocs_ddump_value(textbuf,
"data_pdu_in_order",
"%d", session->login_options.data_pdu_in_order);
1063 ocs_ddump_value(textbuf,
"data_sequence_in_order",
"%d", session->login_options.data_sequence_in_order);
1064 ocs_ddump_value(textbuf,
"error_recovery_level",
"%d", session->login_options.error_recovery_level);
1065 ocs_ddump_value(textbuf,
"first_burst",
"%d", session->login_options.first_burst);
1066 ocs_ddump_value(textbuf,
"max_burst",
"%d", session->login_options.max_burst);
1067 ocs_ddump_value(textbuf,
"max_connections",
"%d", session->login_options.max_connections);
1068 ocs_ddump_value(textbuf,
"max_r2t",
"%d", session->login_options.max_r2t);
1069 ocs_ddump_value(textbuf,
"def_time_to_wait",
"%d", session->login_options.def_time_to_wait);
1070 ocs_ddump_value(textbuf,
"def_time_to_retain",
"%d", session->login_options.def_time_to_retain);
1073 ocs_lock(&session->cmd_q_lock);
1074 ocs_ddump_value(textbuf,
"cmd_q_num_queued",
"%d", session->cmd_q_num_queued);
1078 ocs_unlock(&session->cmd_q_lock);
1097 ocs_session_t *session;
#define OCS_ISCSI_LOGIN_DEFAULT_TIME_2_WAIT
static void ocs_ddump_cmd_q(ocs_textbuf_t *textbuf, ocs_session_q_unsol_t *cmd_q)
Generate node ddump data.
#define OCS_ISCSI_LOGIN_MAX_BURST_LEN
ocs_pdu_process_rtn_e
iSCSI PDU processing return codes
static void ocs_session_cmd_q_timeout(void *arg)
This function is called to process commands on a session command queue.
static void * ocs_list_get_head(ocs_list_t *list)
Return the first item in the list.
static int32_t ocs_session_queue_command(ocs_cxn_t *cxn, ocs_hal_rq_buffer_t *hdr, uint32_t hdr_len, ocs_hal_rq_buffer_t *data, uint32_t data_len, uint8_t code, uint32_t cmd_sn)
Adds a command to the command queue.
void ocs_session_max_cmd_sn_upd(ocs_session_t *session)
Updates the max_cmd_sn based on the number IOs available.
#define ISCSI_REJECT_REASON_WAITING_FOR_LOGOUT
#define OCS_HAL_RQ_SIZE_DATA
ocs_pdu_process_rtn_e ocs_iscsi_tgt_process_cmd_sn(ocs_iscsi_t *iscsi, ocs_cxn_t *cxn, ocs_hal_rq_buffer_t *hdr, uint32_t hdr_len, ocs_hal_rq_buffer_t *data, uint32_t data_len, uint8_t code, uint8_t *reject_reason)
Function to process unsolicited PDUs for a target.
#define CONN_STATE_LOGIN_PROGRESS
Defines the iSCSI logout PDU header.
void ocs_ddump_section(ocs_textbuf_t *textbuf, const char *name, uint32_t instance)
Generate driver dump section start data.
#define CONN_STATE_NEW_CONN
int32_t ocs_iscsi_send_reject(ocs_cxn_t *cxn, void *hdr, uint32_t hdr_len, uint8_t reason)
Sends a reject PDU for the supplied PDU header.
int32_t ocs_session_initialize(ocs_iscsi_t *iscsi)
Initialize the session management by allocating objects for sessions.
static void * ocs_list_remove(ocs_list_t *list, void *item)
Remove an item from the list.
struct ocs_hal_rq_buffer_s * hdr
int32_t ocs_session_cxn_del(ocs_cxn_t *cxn)
Removes a connection from its session.
#define ocs_list_init(head, type, link)
void ocs_ddump_sessions(ocs_textbuf_t *textbuf, ocs_iscsi_t *iscsi)
Generate node ddump data.
#define ocs_list_foreach_safe(list, item, nxt)
Iterate a linked list safely.
Defines the parameters passed to the target unsolicted PDU handler.
int32_t ocs_session_tgt_unsol_pdu_recv(ocs_cxn_t *cxn, ocs_hal_rq_buffer_t *hdr, uint32_t hdr_len, ocs_hal_rq_buffer_t *data, uint32_t data_len, uint8_t code)
Function to handle unsolicited PDUs on a target.
#define CONN_STATE_LOGOUT_REQUESTED
Defines a wrapper for the RQ payload buffers so that we can place it back on the proper queue...
#define LOGOUT_REASON_CLOSE_CONN_FOR_RECOVERY
void ocs_session_close(ocs_session_t *session, uint8_t reset)
Closes all connections on a session.
uint32_t ocs_instance(void *os)
Return the instance index of an opaque ocs structure.
#define ISCSI_REJECT_REASON_PROTOCOL_ERR
void ocs_ddump_endsection(ocs_textbuf_t *textbuf, const char *name, uint32_t instance)
Generate driver dump section end data.
void ocs_iscsi_rx_buffers_free(ocs_iscsi_t *iscsi, ocs_hal_rq_buffer_t *header, ocs_hal_rq_buffer_t *payload)
Add a receive buffer pair to the Receive Queue, if an error is received, then queue the buffer...
static void ocs_session_check_queued_commands(ocs_session_t *session)
Checks the queued command to see if any can start.
int32_t ocs_iscsi_send_login_rsp_invalid_during_login(ocs_cxn_t *cxn, uint32_t itt)
Function to send an login Response PDU (invalid during login).
#define OCS_ISCSI_MAX_QUEUED_CMDSN
void ocs_session_all_abort_cmdsn(ocs_iscsi_t *iscsi, uint32_t cmdsn)
Abort a specific IO based on the cmdSN of the abort request.
static void ocs_list_add_tail(ocs_list_t *list, void *item)
Add an item to the tail of the list.
static void ocs_ddump_session(ocs_textbuf_t *textbuf, ocs_session_t *session)
Generate node ddump data.
#define ocs_list_remove_head(list)
Remove and return an item from the head of the list.
struct ocs_hal_rq_buffer_s * data
#define LOGOUT_REASON_CLOSE_SESS
#define ISCSI_REJECT_REASON_DATA_DIGEST_ERR
ocs_lock_t sess_queue_lock
int32_t ocs_session_cxn_new(ocs_cxn_t *cxn, char *tgt_name, char *ini_name, uint64_t isid, uint16_t tsih, uint16_t cid, uint32_t cmd_sn)
Find an existing session or create a new one based on the login parameters.
static bool before(uint32_t seq1, uint32_t seq2)
#define OCS_MAX_ISCSI_NAME
#define CONN_STATE_FULL_FEATURE
void ocs_session_teardown(ocs_iscsi_t *iscsi)
Releases the session objects used within the login module.
#define OCS_LOGIN_REQUEST_QUEUED
uint32_t ocs_iscsi_get_max_cxns(ocs_t *ocs, char *tgt_name, char *ini_name)
Returns the maximum number of connections allowed per session.
#define ocs_list_foreach(list, item)
Iterate a linked list.
#define after(seq2, seq1)
#define OCS_ISCSI_LOGIN_DEFAULT_TIME_2_RETAIN
#define GT_WRAPPED(a_cmd_sn, b_cmd_sn)
int32_t ocs_cxn_close(ocs_cxn_t *cxn, uint8_t sendRst)
Issues a request to the HAL to close the connection.
int32_t ocs_session_abort_itt(ocs_session_t *session, uint32_t itt)
Abort a specific IO based on the ITT.
ocs_cxn_t * ocs_session_cxn_find(ocs_session_t *session, uint16_t cid)
Locate a connection within a session based on the cid.
void ocs_ddump_value(ocs_textbuf_t *textbuf, const char *name, const char *fmt,...)
Generate driver dump data for a given value.
void ocs_session_abort_cmdsn(ocs_session_t *session, uint32_t cmdsn)
Abort a specific IO based on the cmdSN of the abort request.
Defines the iSCSI login PDU header.