/*ARGSUSED*/ void list_func(xml_node_t *p, target_queue_t *reply, target_queue_t *mgmt) { xml_node_t *x; char msgbuf[80], *reply_msg = NULL; if (p->x_child == NULL) { xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT); } else { x = p->x_child; if (x->x_name == NULL) { xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT); } else if (strcmp(x->x_name, XML_ELEMENT_TARG) == 0) { reply_msg = list_targets(x); } else if (strcmp(x->x_name, XML_ELEMENT_INIT) == 0) { reply_msg = list_initiator(x); } else if (strcmp(x->x_name, XML_ELEMENT_TPGT) == 0) { reply_msg = list_tpgt(x); } else if (strcmp(x->x_name, XML_ELEMENT_ADMIN) == 0) { reply_msg = list_admin(x); } else { (void) snprintf(msgbuf, sizeof (msgbuf), "Unknown object '%s' for list element", x->x_name); xml_rtn_msg(&reply_msg, ERR_INVALID_OBJECT); } } queue_message_set(reply, 0, msg_mgmt_rply, reply_msg); }
/*ARGSUSED*/ void modify_func(tgt_node_t *p, target_queue_t *reply, target_queue_t *mgmt, ucred_t *cred) { tgt_node_t *x; char *reply_msg = NULL; x = p->x_child; if (p->x_child == NULL) { xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT); } else if (strcmp(x->x_name, XML_ELEMENT_ZFS) == 0) { reply_msg = modify_zfs(x, cred); } else if (check_auth_modify(cred) != True) { xml_rtn_msg(&reply_msg, ERR_NO_PERMISSION); } else { if (x->x_name == NULL) { xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT); } else if (strcmp(x->x_name, XML_ELEMENT_TARG) == 0) { reply_msg = modify_target(x, cred); } else if (strcmp(x->x_name, XML_ELEMENT_INIT) == 0) { reply_msg = modify_initiator(x); } else if (strcmp(x->x_name, XML_ELEMENT_ADMIN) == 0) { reply_msg = modify_admin(x); } else if (strcmp(x->x_name, XML_ELEMENT_TPGT) == 0) { reply_msg = modify_tpgt(x); } else { xml_rtn_msg(&reply_msg, ERR_INVALID_OBJECT); } } queue_message_set(reply, 0, msg_mgmt_rply, reply_msg); }
/* * This thread sit's in a loop and ensures that it keeps checking for * connection to isns_server. Once the connection works it registers * with the isns and bails out. * We expect the isns server to be fault taulerant and has persistence * for the registered entries. */ static void * isns_server_connection_thr(void *arg) { Boolean_t registered_targets = False; char server[MAXHOSTNAMELEN + 1] = {0}; while (isns_shutdown == False && connection_thr_bail_out == False) { /* current server */ (void) strcpy(server, isns_args.server); if (is_isns_server_up(server) == 0) { if (registered_targets == False) { /* * register all targets, what happens if * no targets are created yet? this should * not be a failure, when new target gets * created, update gets call. what if SCN * register fails? */ if (isns_reg_all() == 0) { /* scn register all targets */ if (isns_op_all(ISNS_SCN_REG) != 0) { syslog(LOG_ERR, "SCN registrations" " failed\n"); (void) isns_op_all( ISNS_DEV_DEREG); registered_targets = False; } else { registered_targets = True; break; } } } } else { syslog(LOG_INFO, "isns server %s is not reachable", server); registered_targets = False; } (void) sleep(ISNS_SLEEP_SECS); /* If isns was disabled, deregister and close the thread */ if (isns_enabled() == False) { syslog(LOG_INFO, "isns server is disabled, dergister target"); isns_fini(); break; } } queue_message_set(mgmtq, 0, msg_pthread_join, (void *)(uintptr_t)pthread_self()); return (NULL); }
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); }
/*ARGSUSED*/ void remove_func(tgt_node_t *p, target_queue_t *reply, target_queue_t *mgmt, ucred_t *cred) { tgt_node_t *x; char msgbuf[80]; char *reply_msg = NULL; x = p->x_child; /* * remove_zfs() does not affect SMF data * therefore it is not covered by auth check */ if (x == NULL) { xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT); } else if (strcmp(x->x_name, XML_ELEMENT_ZFS) == 0) { reply_msg = remove_zfs(x, cred); } else if (check_auth_addremove(cred) != True) { xml_rtn_msg(&reply_msg, ERR_NO_PERMISSION); } else { if (x->x_name == NULL) { xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT); } else if (strcmp(x->x_name, XML_ELEMENT_TARG) == 0) { reply_msg = remove_target(x); } else if (strcmp(x->x_name, XML_ELEMENT_INIT) == 0) { reply_msg = remove_initiator(x); } else if (strcmp(x->x_name, XML_ELEMENT_TPGT) == 0) { reply_msg = remove_tpgt(x); } else { (void) snprintf(msgbuf, sizeof (msgbuf), "Unknown object '%s' for delete element", x->x_name); xml_rtn_msg(&reply_msg, ERR_INVALID_OBJECT); } } queue_message_set(reply, 0, msg_mgmt_rply, reply_msg); }
/* * []---- * | 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); }