static void target_stat(char **msg, char *targ_name, mgmt_type_t type) { iscsi_conn_t *c; msg_t *m; target_queue_t *q = queue_alloc(); mgmt_request_t mgmt_rqst; int msg_sent, i; extern pthread_mutex_t port_mutex; mgmt_rqst.m_q = q; mgmt_rqst.m_u.m_resp = msg; mgmt_rqst.m_time = time(NULL); mgmt_rqst.m_request = type; (void) pthread_mutex_init(&mgmt_rqst.m_resp_mutex, NULL); (void) pthread_mutex_lock(&port_mutex); mgmt_rqst.m_targ_name = targ_name; msg_sent = 0; for (c = conn_head; c; c = c->c_next) { if (c->c_state == S5_LOGGED_IN) { /* * Only send requests for statistics to * connections that are up. Could even * go further and only look at connections * which are S5_LOGGED_IN, but there may * be statistics, such as connection time, * which we'd like to have. */ queue_message_set(c->c_dataq, 0, msg_mgmt_rqst, &mgmt_rqst); msg_sent++; } } (void) pthread_mutex_unlock(&port_mutex); /* * Comment: main.c:list_targets:1 * We wait for the responses without the port_mutex * being held. There is a small window between when the * connection last listens for a message and when the * queue is freed. During that time the connection will * attempt to grab the port_mutex lock so that it * can unlink itself and call queueu_free(). If we sent * the message with the lock held and then wait for a response * it's possible that the connection will deadlock waiting * to get the port_mutex. */ for (i = 0; i < msg_sent; i++) { m = queue_message_get(q); queue_message_free(m); } queue_free(q, NULL); }
static void send_named_msg(iscsi_conn_t *c, msg_type_t t, char *name) { target_queue_t *q = queue_alloc(); msg_t *m; name_request_t n; n.nr_q = q; n.nr_name = name; queue_message_set(c->c_sessq, 0, t, &n); m = queue_message_get(q); queue_message_free(m); queue_free(q, NULL); }
/* * []---- * | sess_process -- handle messages from the connection(s) * []---- */ static void * sess_process(void *v) { iscsi_sess_t *s = (iscsi_sess_t *)v; iscsi_conn_t *c; iscsi_cmd_t *cmd; msg_t *m; Boolean_t process = True; mgmt_request_t *mgmt; name_request_t *nr; t10_cmd_t *t10_cmd; char **buf, local_buf[16]; int lun; extern void dataout_callback(t10_cmd_t *t, char *data, size_t *xfer); (void) pthread_mutex_lock(&s->s_mutex); s->s_state = SS_RUNNING; (void) pthread_mutex_unlock(&s->s_mutex); do { m = queue_message_get(s->s_sessq); switch (m->msg_type) { case msg_cmd_send: cmd = (iscsi_cmd_t *)m->msg_data; if (s->s_t10 == NULL) { /* * The value of 0x960 comes from T10. * See SPC-4, revision 1a, section 6.4.2, * table 87 * * XXX Need to rethink how I should do * the callback. */ s->s_t10 = t10_handle_create(s->s_t_name, T10_TRANS_ISCSI, s->s_conn_head->c_tpgt, s->s_conn_head->c_max_burst_len, s->s_t10q, dataout_callback); } if (t10_cmd_create(s->s_t10, cmd->c_lun, cmd->c_scb, cmd->c_scb_len, (transport_t)cmd, &t10_cmd) == False) { queue_prt(s->s_mgmtq, Q_SESS_ERRS, "SES%x FAILED to create cmd", s->s_num); /* * If the command create failed, the T10 layer * will attempt to create a sense buffer * telling the initiator what went wrong. If * that layer was unable to accomplish that * things are really bad and we need to just * close the connection. */ if (cmd->c_t10_cmd != NULL) { queue_message_set( cmd->c_allegiance->c_dataq, 0, msg_cmd_cmplt, t10_cmd); } else conn_state(cmd->c_allegiance, T11); } else { (void) pthread_mutex_lock( &cmd->c_allegiance->c_mutex); if (cmd->c_state != CmdCanceled) { cmd->c_t10_cmd = t10_cmd; (void) t10_cmd_send(s->s_t10, cmd->c_t10_cmd, cmd->c_data, cmd->c_data_len); } else { t10_cmd_state(t10_cmd, T10_Cmd_Event_Canceled); } (void) pthread_mutex_unlock( &cmd->c_allegiance->c_mutex); } break; case msg_cmd_data_out: cmd = (iscsi_cmd_t *)m->msg_data; if (s->s_t10 != NULL) (void) t10_cmd_data(s->s_t10, cmd->c_t10_cmd, cmd->c_offset_out, cmd->c_data, cmd->c_data_len); break; case msg_targ_inventory_change: if (s->s_t10 != NULL) (void) t10_task_mgmt(s->s_t10, InventoryChange, 0, 0); break; case msg_lu_capacity_change: lun = (int)(uintptr_t)m->msg_data; if (s->s_t10 != NULL) (void) t10_task_mgmt(s->s_t10, CapacityChange, lun, 0); break; case msg_reset_targ: if (s->s_t10 != NULL) (void) t10_task_mgmt(s->s_t10, ResetTarget, 0, 0); break; case msg_reset_lu: if (s->s_t10 != NULL) (void) t10_task_mgmt(s->s_t10, ResetLun, (int)(uintptr_t)m->msg_data, 0); break; case msg_shutdown: (void) pthread_mutex_lock(&s->s_mutex); s->s_state = SS_SHUTDOWN_START; (void) pthread_mutex_unlock(&s->s_mutex); /* * Shutdown rquest comming from a connection. Only * shutdown the STE if this is the last connection * for this session. */ c = (iscsi_conn_t *)m->msg_data; if (session_remove_connection(s, c) == True) { queue_prt(s->s_mgmtq, Q_SESS_NONIO, "SES%x Starting shutdown", s->s_num); /* * If this is the last connection for this * session send a message to the SAM-3 layer to * shutdown. */ if (s->s_t10 != NULL) { t10_handle_disable(s->s_t10); } queue_message_set(s->s_t10q, 0, msg_shutdown_rsp, 0); process = False; } else { /* * Since this isn't the last connection for * the session, acknowledge the connection * request now since it's references from * this session have been removed. */ queue_message_set(c->c_dataq, 0, msg_shutdown_rsp, (void *)False); } break; case msg_initiator_name: nr = (name_request_t *)m->msg_data; s->s_i_name = strdup(nr->nr_name); /* * Acknowledge the request by sending back an empty * message. */ queue_message_set(nr->nr_q, 0, msg_initiator_name, 0); break; case msg_initiator_alias: nr = (name_request_t *)m->msg_data; s->s_i_alias = strdup(nr->nr_name); /* * Acknowledge the request by sending back an empty * message. */ queue_message_set(nr->nr_q, 0, msg_initiator_alias, 0); break; case msg_target_name: nr = (name_request_t *)m->msg_data; s->s_t_name = strdup(nr->nr_name); /* * Acknowledge the request by sending back an empty * message. */ queue_message_set(nr->nr_q, 0, msg_target_name, 0); break; case msg_mgmt_rqst: mgmt = (mgmt_request_t *)m->msg_data; m->msg_data = NULL; (void) pthread_mutex_lock(&mgmt->m_resp_mutex); buf = mgmt->m_u.m_resp; if ((s->s_type == SessionNormal) && (mgmt->m_request == mgmt_full_phase_statistics) && (strcmp(s->s_t_name, mgmt->m_targ_name) == 0)) { buf_add_tag(buf, XML_ELEMENT_CONN, Tag_Start); buf_add_tag(buf, s->s_i_name, Tag_String); if (s->s_i_alias != NULL) { xml_add_tag(buf, XML_ELEMENT_ALIAS, s->s_i_alias); } /* * Need to loop through the connections * and create one time_connected tag for * each. This will be needed once MC/S support * is added. */ (void) snprintf(local_buf, sizeof (local_buf), "%d", mgmt->m_time - s->s_conn_head->c_up_at); xml_add_tag(buf, XML_ELEMENT_TIMECON, local_buf); buf_add_tag(buf, XML_ELEMENT_STATS, Tag_Start); t10_targ_stat(s->s_t10, buf); buf_add_tag(buf, XML_ELEMENT_STATS, Tag_End); buf_add_tag(buf, XML_ELEMENT_CONN, Tag_End); } (void) pthread_mutex_unlock(&mgmt->m_resp_mutex); queue_message_set(mgmt->m_q, 0, msg_mgmt_rply, 0); break; default: queue_prt(s->s_mgmtq, Q_SESS_ERRS, "SES%x Unknown msg type (%d) from Connection", s->s_num, m->msg_type); break; } queue_message_free(m); } while (process == True); return (NULL); }
/* * []---- * | sess_from_t10 -- handle messages from the T10 layer * []---- */ void * sess_from_t10(void *v) { iscsi_sess_t *s = (iscsi_sess_t *)v; msg_t *m; Boolean_t process = True; while (process == True) { m = queue_message_get(s->s_t10q); switch (m->msg_type) { case msg_cmd_data_rqst: queue_message_set(s->s_conn_head->c_dataq, 0, msg_cmd_data_rqst, m->msg_data); break; case msg_cmd_data_in: queue_message_set(s->s_conn_head->c_dataq, 0, msg_cmd_data_in, m->msg_data); break; case msg_cmd_cmplt: queue_message_set(s->s_conn_head->c_dataq, 0, msg_cmd_cmplt, m->msg_data); break; case msg_shutdown_rsp: if (s->s_t10) { t10_handle_destroy(s->s_t10); s->s_t10 = NULL; } (void) pthread_mutex_lock(&s->s_mutex); s->s_state = SS_SHUTDOWN_CMPLT; (void) pthread_mutex_unlock(&s->s_mutex); session_free(s); /* * Let the connection, which is the last, know * about our completion of the shutdown. */ queue_message_set(s->s_conn_head->c_dataq, 0, msg_shutdown_rsp, (void *)True); process = False; s->s_state = SS_FREE; break; default: queue_prt(s->s_mgmtq, Q_SESS_ERRS, "SES%x Unknown msg type (%d) from T10 ", s->s_num, m->msg_type); queue_message_set(s->s_conn_head->c_dataq, 0, m->msg_type, m->msg_data); break; } queue_message_free(m); } queue_free(s->s_t10q, NULL); util_title(s->s_mgmtq, Q_SESS_LOGIN, s->s_num, "End Session"); free(s); return (NULL); }