dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / kernel / comstar / port / iscsit / iscsit_isns.c
blob1b9bba8757a601145fe1c297e69a5ee590d57f06
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
25 #include <sys/cpuvar.h>
26 #include <sys/types.h>
27 #include <sys/conf.h>
28 #include <sys/file.h>
29 #include <sys/ddi.h>
30 #include <sys/sunddi.h>
31 #include <sys/socket.h>
32 #include <inet/tcp.h>
33 #include <sys/sdt.h>
35 #include <sys/stmf.h>
36 #include <sys/stmf_ioctl.h>
37 #include <sys/portif.h>
38 #include <sys/idm/idm.h>
39 #include <sys/idm/idm_so.h>
40 #include <sys/iscsit/iscsit_common.h>
41 #include <sys/iscsit/isns_protocol.h>
42 #include <sys/ksocket.h>
44 #include "iscsit.h"
45 #include "iscsit_isns.h"
48 * iscsit_isns.c -- isns client that is part of the iscsit server
50 * The COMSTAR iSCSI target uses four pieces of iSNS functionality:
51 * - DevAttrReg to notify the iSNS server of our targets and portals.
52 * - DeregDev to notify when a target goes away or we shut down
53 * - DevAttrQry (self-query) to see if iSNS server still knows us.
54 * - Request ESI probes from iSNS server as a keepalive mechanism
56 * We send only two kinds of DevAttrReg messages.
58 * REPLACE-ALL the info the iSNS server knows about us:
59 * Set Flag in PDU header to ISNS_FLAG_REPLACE_REG
60 * Set "source" to same iSCSI target each time
61 * EID (Entity Identifier) == our DNS name
62 * "Delimiter"
63 * Object operated on = EID
64 * "Entity Portals" owned by this "network entity"
65 * List of targets
66 * (Targets with TPGT are followed by PGT and PG portal info)
68 * UPDATE-EXISTING - used to register/change one target at a time
69 * Flag for replace reg not set
70 * Source and EID and Delimiter and Object Operated On as above
71 * Single Target
72 * (Targets with TPGT are followed by PGT and PG portal info)
74 * Interfaces to iscsit
76 * iscsit_isns_init -- called when iscsi/target service goes online
77 * iscsit_isns_fini -- called when iscsi/target service goes offline
78 * iscsit_isns_register -- a new target comes online
79 * iscsit_isns_deregister -- target goes offline
80 * iscsit_isns_target_update -- called when a target is modified
81 * iscsit_isns_portal_online -- called when defining a new portal
82 * iscsit_isns_portal_offline -- no longer using a portal
84 * Copying Data Structures
86 * The above routines copy all the data they need, so iscsit can
87 * proceed without interfering with us. This is moving in the
88 * direction of having this isns_client be a standalone user-mode
89 * program. Specifically, we copy the target name, alias, and
90 * tpgt+portal information.
92 * The iscsit_isns_mutex protects the shadow copies of target and portal
93 * information. The ISNS_GLOBAL_LOCK protects the iSNS run time structures
94 * that the monitor thread uses. The routine isnst_copy_global_status_changes
95 * has to acquire both locks and copy all the required information from the
96 * global structs to the per-server structs. Once it completes, the monitor
97 * thread should run completely off the per-server copies.
99 * Global State vs Per-Server state
100 * There is a global list of targets and portals that is kept updated
101 * by iscsit. Each svr keeps its own list of targets that have been
102 * announced to the iSNS server.
104 * Invariants
106 * 1) If svr->svr_registered, then there is some itarget with
107 * itarget->target_registered.
108 * 2) If itarget->target_delete_needed, then also itarget->target_registered.
109 * (Corollary: Any time you remove the last registered target, you have
110 * to send an unregister-all message.)
111 * 3) If a target has a non-default portal, then the portal goes online
112 * before the target goes online, and comes offline afterwards.
113 * (This is enforced by the iscsit state machines.)
115 /* local defines */
116 #define MAX_XID (2^16)
117 #define ISNS_IDLE_TIME 60
118 #define MAX_RETRY (3)
119 #define ISNS_RCV_TIMER_SECONDS 5
121 #define VALID_NAME(NAME, LEN) \
122 ((LEN) > 0 && (NAME)[0] != 0 && (NAME)[(LEN) - 1] == 0)
125 #define ISNST_LOG if (iscsit_isns_logging) cmn_err
127 static kmutex_t isns_monitor_mutex;
128 volatile kthread_t *isns_monitor_thr_id;
129 static kt_did_t isns_monitor_thr_did;
130 static boolean_t isns_monitor_thr_running;
132 static kcondvar_t isns_idle_cv;
134 static uint16_t xid;
135 #define GET_XID() atomic_inc_16_nv(&xid)
137 static clock_t monitor_idle_interval;
139 /* The ISNS_GLOBAL_LOCK protects the per-server data structures */
140 #define ISNS_GLOBAL_LOCK() \
141 mutex_enter(&iscsit_global.global_isns_cfg.isns_mutex)
143 #define ISNS_GLOBAL_LOCK_HELD() \
144 MUTEX_HELD(&iscsit_global.global_isns_cfg.isns_mutex)
146 #define ISNS_GLOBAL_UNLOCK() \
147 mutex_exit(&iscsit_global.global_isns_cfg.isns_mutex)
150 * "Configurable" parameters (set in /etc/system for now).
152 boolean_t iscsit_isns_logging = B_FALSE;
156 * If fail this many times to send an update to the server, then
157 * declare the server non-responsive and reregister everything with
158 * the server when we next connect.
160 int isns_max_retry = MAX_RETRY;
163 * The use of ESI probes to all active portals is not appropriate in
164 * all network environments, since the iSNS server may not have
165 * connectivity to all portals, so we turn it off by default.
167 boolean_t isns_use_esi = B_FALSE;
170 * Interval to request ESI probes at, in seconds. The server is free
171 * to specify a different frequency in its response.
173 int isns_default_esi_interval = ISNS_DEFAULT_ESI_INTERVAL;
177 * Registration Period -- we guarantee to check in with iSNS server at
178 * least this often. Used when ESI probes are turned off.
180 int isns_registration_period = ISNS_DEFAULT_REGISTRATION_PERIOD;
183 * Socket connect, PDU receive, and PDU send must complete
184 * within this number of microseconds.
186 uint32_t isns_timeout_usec = ISNS_RCV_TIMER_SECONDS * 1000000;
190 * iSNS Message size -- we start with the max that can fit into one PDU.
191 * If the message doesn't fit, we will expand at run time to a higher
192 * value. This parameter could be set in /etc/system if some particular
193 * installation knows it always goes over the standard limit.
195 uint32_t isns_message_buf_size = ISNSP_MAX_PDU_SIZE;
198 * Number of seconds to wait after isnst_monitor thread starts up
199 * before sending first DevAttrReg message.
201 int isns_initial_delay = ISNS_INITIAL_DELAY;
204 * Because of a bug in the Solaris isns server (c 2009), we cannot send a
205 * modify operation that changes the target's TPGTs. So just replace all.
206 * If the iSNS server does not have this bug, clear this flag.
207 * Changes take effect on each modify_target operation
209 boolean_t isns_modify_must_replace = B_TRUE;
211 /* If PDU sizes ever go over the following, we need to rearchitect */
212 #define ISNST_MAX_MSG_SIZE (16 * ISNSP_MAX_PDU_SIZE)
215 * iSNS ESI thread state
217 static isns_esi_tinfo_t esi;
220 * Our list of targets. Kept in lock-step synch with iscsit.
221 * The iscsit_isns_mutex protects the global data structures that are
222 * kept in lock-step with iscsit.
223 * NOTE: Now that isnst runs independently of iscsit, we could remove the
224 * shadow copies of iscsit structures, such as isns_target_list and
225 * isns_tpg_portals, and have isnst_copy_global_status_changes reconcile
226 * isnst directly with the iscsit data structures.
228 static kmutex_t iscsit_isns_mutex;
229 static avl_tree_t isns_target_list;
230 static boolean_t isns_targets_changed;
233 * List of portals from TPGs. Protected by iscsit_isns_mutex.
235 static boolean_t isns_portals_changed;
236 static avl_tree_t isns_tpg_portals;
237 static boolean_t default_portal_online;
239 /* List of all portals. Protected by ISNS_GLOBAL_LOCK */
240 static avl_tree_t isns_all_portals;
241 static int num_default_portals;
242 static int num_tpg_portals;
245 * Our entity identifier (fully-qualified hostname). Passed in from libiscsit.
247 static char *isns_eid = NULL;
250 * in6addr_any is currently all zeroes, but use the macro in case this
251 * ever changes.
253 static const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
255 static void
256 isnst_start();
258 static void
259 isnst_stop();
261 static void
262 iscsit_set_isns(boolean_t state);
264 static void
265 iscsit_add_isns(it_portal_t *cfg_svr);
267 static void
268 isnst_mark_delete_isns(iscsit_isns_svr_t *svr);
270 static void
271 isnst_finish_delete_isns(iscsit_isns_svr_t *svr);
273 static iscsit_isns_svr_t *
274 iscsit_isns_svr_lookup(struct sockaddr_storage *sa);
276 static void
277 isnst_monitor(void *arg);
279 static int
280 isnst_monitor_one_server(iscsit_isns_svr_t *svr, boolean_t enabled);
282 static void
283 isnst_monitor_awaken(void);
285 static boolean_t
286 isnst_update_server_timestamp(struct sockaddr_storage *sa);
288 static void
289 isnst_copy_global_status_changes(void);
291 static void
292 isnst_mark_deleted_targets(iscsit_isns_svr_t *svr);
294 static int
295 isnst_update_one_server(iscsit_isns_svr_t *svr, isns_target_t *target,
296 isns_reg_type_t reg);
298 static boolean_t isnst_retry_registration(int rsp_status_code);
300 static int isnst_register(iscsit_isns_svr_t *svr, isns_target_t *itarget,
301 isns_reg_type_t regtype);
302 static int isnst_deregister(iscsit_isns_svr_t *svr, isns_target_t *itarget);
304 static size_t
305 isnst_make_dereg_pdu(iscsit_isns_svr_t *svr, isns_pdu_t **pdu,
306 isns_target_t *itarge);
308 static int isnst_keepalive(iscsit_isns_svr_t *svr);
309 static size_t
310 isnst_make_keepalive_pdu(iscsit_isns_svr_t *svr, isns_pdu_t **pdu);
312 static isns_target_t *
313 isnst_get_registered_source(iscsit_isns_svr_t *srv);
314 static isns_target_t *
315 isnst_get_registered_source_locked(iscsit_isns_svr_t *srv);
317 static int
318 isnst_verify_rsp(iscsit_isns_svr_t *svr, isns_pdu_t *pdu,
319 isns_pdu_t *rsp, size_t rsp_size);
321 static uint16_t
322 isnst_pdu_get_op(isns_pdu_t *pdu, uint8_t **pp);
324 static size_t
325 isnst_make_reg_pdu(isns_pdu_t **pdu, isns_target_t *target,
326 iscsit_isns_svr_t *svr, isns_reg_type_t regtype);
328 static int
329 isnst_reg_pdu_add_entity_portals(isns_pdu_t *pdu, size_t pdu_size);
331 static int
332 isnst_reg_pdu_add_pg(isns_pdu_t *pdu, size_t pdu_size, isns_target_t *target);
334 static int
335 isnst_add_default_pg(isns_pdu_t *pdu, size_t pdu_size,
336 avl_tree_t *null_portal_list);
338 static int
339 isnst_add_tpg_pg(isns_pdu_t *pdu, size_t pdu_size,
340 isns_tpgt_t *tig, avl_tree_t *null_portal_list);
342 static int
343 isnst_add_null_pg(isns_pdu_t *pdu, size_t pdu_size,
344 avl_tree_t *null_portal_list);
346 static int
347 isnst_add_portal_attr(isns_pdu_t *pdu, size_t pdu_size,
348 uint32_t ip_attr_id, uint32_t port_attr_id,
349 struct sockaddr_storage *ss, boolean_t esi_info);
351 static size_t
352 isnst_create_pdu_header(uint16_t func_id, isns_pdu_t **pdu, uint16_t flags);
354 static int
355 isnst_add_attr(isns_pdu_t *pdu,
356 size_t max_pdu_size,
357 uint32_t attr_id,
358 uint32_t attr_len,
359 void *attr_data,
360 uint32_t attr_numeric_data);
362 static int
363 isnst_send_pdu(void *so, isns_pdu_t *pdu);
365 static size_t
366 isnst_rcv_pdu(void *so, isns_pdu_t **pdu);
368 static void *
369 isnst_open_so(struct sockaddr_storage *sa);
371 static void
372 isnst_close_so(void *);
374 static void
375 isnst_esi_thread(void *arg);
377 static void
378 isnst_handle_esi_req(ksocket_t so, isns_pdu_t *pdu, size_t pl_size);
380 static void isnst_esi_start(void);
381 static void isnst_esi_stop(void);
382 static isns_target_t *isnst_latch_to_target_list(isns_target_t *target,
383 avl_tree_t *list);
384 static void isnst_clear_target_list(iscsit_isns_svr_t *svr);
385 static void isnst_clear_from_target_list(isns_target_t *target,
386 avl_tree_t *target_list);
387 static int isnst_tgt_avl_compare(const void *t1, const void *t2);
388 static void isnst_set_server_status(iscsit_isns_svr_t *svr,
389 boolean_t registered);
390 static void isnst_monitor_start(void);
391 static void isnst_monitor_stop(void);
393 static void
394 isnst_monitor_default_portal_list(void);
396 static int
397 isnst_find_default_portals(idm_addr_list_t *alist);
399 static int
400 isnst_add_default_portals(idm_addr_list_t *alist);
402 static void
403 isnst_clear_default_portals(void);
406 static void
407 isnst_clear_portal_list(avl_tree_t *portal_list);
409 static void
410 isnst_copy_portal_list(avl_tree_t *t1, avl_tree_t *t2);
412 static isns_portal_t *
413 isnst_lookup_portal(struct sockaddr_storage *sa);
415 static isns_portal_t *
416 isnst_add_to_portal_list(struct sockaddr_storage *sa, avl_tree_t *portal_list);
418 static void
419 isnst_remove_from_portal_list(struct sockaddr_storage *sa,
420 avl_tree_t *portal_list);
422 static int
423 isnst_portal_avl_compare(const void *t1, const void *t2);
430 it_cfg_status_t
431 isnst_config_merge(it_config_t *cfg)
433 boolean_t new_isns_state = B_FALSE;
434 iscsit_isns_svr_t *isns_svr, *next_isns_svr;
435 it_portal_t *cfg_isns_svr;
437 ISNS_GLOBAL_LOCK();
440 * Determine whether iSNS is enabled in the new config.
441 * Isns property may not be set up yet.
443 (void) nvlist_lookup_boolean_value(cfg->config_global_properties,
444 PROP_ISNS_ENABLED, &new_isns_state);
446 /* Delete iSNS servers that are no longer part of the config */
447 for (isns_svr = list_head(&iscsit_global.global_isns_cfg.isns_svrs);
448 isns_svr != NULL;
449 isns_svr = next_isns_svr) {
450 next_isns_svr = list_next(
451 &iscsit_global.global_isns_cfg.isns_svrs, isns_svr);
452 if (it_sns_svr_lookup(cfg, &isns_svr->svr_sa) == NULL)
453 isnst_mark_delete_isns(isns_svr);
456 /* Add new iSNS servers */
457 for (cfg_isns_svr = cfg->config_isns_svr_list;
458 cfg_isns_svr != NULL;
459 cfg_isns_svr = cfg_isns_svr->portal_next) {
460 isns_svr = iscsit_isns_svr_lookup(&cfg_isns_svr->portal_addr);
461 if (isns_svr == NULL) {
462 iscsit_add_isns(cfg_isns_svr);
463 } else if (isns_svr->svr_delete_needed) {
465 * If reactivating a server that was being
466 * deleted, turn it into a reset.
468 isns_svr->svr_delete_needed = B_FALSE;
469 isns_svr->svr_reset_needed = B_TRUE;
474 * There is no "modify case" since the user specifies a complete
475 * server list each time. A modify is the same as a remove+add.
478 /* Start/Stop iSNS if necessary */
479 iscsit_set_isns(new_isns_state);
481 ISNS_GLOBAL_UNLOCK();
484 /* Wake up the monitor thread to complete the state change */
485 isnst_monitor_awaken();
487 return (0);
491 iscsit_isns_init(iscsit_hostinfo_t *hostinfo)
493 mutex_init(&iscsit_global.global_isns_cfg.isns_mutex, NULL,
494 MUTEX_DEFAULT, NULL);
496 ISNS_GLOBAL_LOCK();
497 mutex_init(&iscsit_isns_mutex, NULL, MUTEX_DEFAULT, NULL);
499 iscsit_global.global_isns_cfg.isns_state = B_FALSE;
500 list_create(&iscsit_global.global_isns_cfg.isns_svrs,
501 sizeof (iscsit_isns_svr_t), offsetof(iscsit_isns_svr_t, svr_ln));
502 avl_create(&isns_tpg_portals, isnst_portal_avl_compare,
503 sizeof (isns_portal_t), offsetof(isns_portal_t, portal_node));
504 avl_create(&isns_all_portals, isnst_portal_avl_compare,
505 sizeof (isns_portal_t), offsetof(isns_portal_t, portal_node));
506 num_default_portals = 0;
507 if (hostinfo->length > ISCSIT_MAX_HOSTNAME_LEN)
508 hostinfo->length = ISCSIT_MAX_HOSTNAME_LEN;
509 isns_eid = kmem_alloc(hostinfo->length, KM_SLEEP);
510 (void) strlcpy(isns_eid, hostinfo->fqhn, hostinfo->length);
511 avl_create(&isns_target_list, isnst_tgt_avl_compare,
512 sizeof (isns_target_t), offsetof(isns_target_t, target_node));
514 /* initialize isns client */
515 mutex_init(&isns_monitor_mutex, NULL, MUTEX_DEFAULT, NULL);
516 mutex_init(&esi.esi_mutex, NULL, MUTEX_DEFAULT, NULL);
517 isns_monitor_thr_id = NULL;
518 monitor_idle_interval = ISNS_IDLE_TIME * drv_usectohz(1000000);
519 cv_init(&isns_idle_cv, NULL, CV_DEFAULT, NULL);
520 cv_init(&esi.esi_cv, NULL, CV_DEFAULT, NULL);
521 xid = 0;
522 ISNS_GLOBAL_UNLOCK();
524 return (0);
527 void
528 iscsit_isns_fini()
530 ISNS_GLOBAL_LOCK();
533 * The following call to iscsit_set_isns waits until all the
534 * iSNS servers have been fully deactivated and the monitor and esi
535 * threads have stopped.
537 iscsit_set_isns(B_FALSE);
539 /* Clean up data structures */
540 mutex_destroy(&isns_monitor_mutex);
541 cv_destroy(&isns_idle_cv);
542 mutex_destroy(&esi.esi_mutex);
543 cv_destroy(&esi.esi_cv);
544 mutex_destroy(&iscsit_isns_mutex);
547 * Free our EID and target list.
550 if (isns_eid) {
551 kmem_free(isns_eid, strlen(isns_eid) + 1);
552 isns_eid = NULL;
555 iscsit_global.global_isns_cfg.isns_state = B_FALSE;
556 avl_destroy(&isns_target_list);
557 list_destroy(&iscsit_global.global_isns_cfg.isns_svrs);
558 avl_destroy(&isns_tpg_portals);
559 avl_destroy(&isns_all_portals);
560 num_default_portals = 0;
561 ISNS_GLOBAL_UNLOCK();
563 mutex_destroy(&iscsit_global.global_isns_cfg.isns_mutex);
566 static void
567 iscsit_set_isns(boolean_t state)
569 iscsit_isns_svr_t *svr;
571 ASSERT(ISNS_GLOBAL_LOCK_HELD());
574 * Update state and isns stop flag
576 if (iscsit_global.global_isns_cfg.isns_state != state) {
577 /* reset retry count for all servers */
578 for (svr = list_head(&iscsit_global.global_isns_cfg.isns_svrs);
579 svr != NULL;
580 svr = list_next(&iscsit_global.global_isns_cfg.isns_svrs,
581 svr)) {
582 svr->svr_retry_count = 0;
585 iscsit_global.global_isns_cfg.isns_state = state;
587 if (state) {
588 isnst_start();
589 } else {
590 isnst_stop();
595 void
596 iscsit_add_isns(it_portal_t *cfg_svr)
598 iscsit_isns_svr_t *svr;
600 ASSERT(ISNS_GLOBAL_LOCK_HELD());
602 svr = kmem_zalloc(sizeof (iscsit_isns_svr_t), KM_SLEEP);
603 bcopy(&cfg_svr->portal_addr, &svr->svr_sa,
604 sizeof (struct sockaddr_storage));
605 avl_create(&svr->svr_target_list, isnst_tgt_avl_compare,
606 sizeof (isns_target_t), offsetof(isns_target_t, target_node));
607 svr->svr_esi_interval = isns_default_esi_interval;
609 /* put it on the global isns server list */
610 list_insert_tail(&iscsit_global.global_isns_cfg.isns_svrs, svr);
613 void
614 isnst_mark_delete_isns(iscsit_isns_svr_t *svr)
616 ASSERT(ISNS_GLOBAL_LOCK_HELD());
618 /* If monitor thread not running, finish delete here */
619 if (iscsit_global.global_isns_cfg.isns_state == B_FALSE) {
620 isnst_finish_delete_isns(svr);
621 } else {
622 svr->svr_delete_needed = B_TRUE;
627 void
628 isnst_finish_delete_isns(iscsit_isns_svr_t *svr)
631 ASSERT(ISNS_GLOBAL_LOCK_HELD());
632 isnst_clear_target_list(svr);
634 list_remove(&iscsit_global.global_isns_cfg.isns_svrs, svr);
635 /* free the memory */
636 avl_destroy(&svr->svr_target_list);
637 kmem_free(svr, sizeof (*svr));
640 static iscsit_isns_svr_t *
641 iscsit_isns_svr_lookup(struct sockaddr_storage *sa)
643 iscsit_isns_svr_t *svr;
644 it_portal_t portal1;
646 ASSERT(ISNS_GLOBAL_LOCK_HELD());
648 bcopy(sa, &portal1.portal_addr, sizeof (struct sockaddr_storage));
650 for (svr = list_head(&iscsit_global.global_isns_cfg.isns_svrs);
651 svr != NULL;
652 svr = list_next(&iscsit_global.global_isns_cfg.isns_svrs, svr)) {
653 if (it_sa_compare(&svr->svr_sa, sa) == 0)
654 return (svr);
657 return (NULL);
660 static isns_target_info_t *
661 isnst_create_target_info(iscsit_tgt_t *target)
664 isns_target_info_t *ti;
665 isns_tpgt_t *tig;
666 isns_tpgt_addr_t *tip;
667 iscsit_tpgt_t *tpgt;
668 iscsit_tpg_t *tpg;
669 iscsit_portal_t *tp;
670 char *str;
672 /* Cannot hold the iscsit_isns_mutex here! */
673 ASSERT(! mutex_owned(&iscsit_isns_mutex));
675 ti = kmem_zalloc(sizeof (isns_target_info_t), KM_SLEEP);
676 list_create(&ti->ti_tpgt_list,
677 sizeof (isns_tpgt_t), offsetof(isns_tpgt_t, ti_tpgt_ln));
678 idm_refcnt_init(&ti->ti_refcnt, ti);
680 mutex_enter(&target->target_mutex);
681 (void) strncpy(ti->ti_tgt_name, target->target_name,
682 MAX_ISCSI_NODENAMELEN);
685 if (nvlist_lookup_string(target->target_props, PROP_ALIAS,
686 &str) == 0) {
687 (void) strncpy(ti->ti_tgt_alias, str, MAX_ISCSI_NODENAMELEN);
690 tpgt = avl_first(&target->target_tpgt_list);
691 ASSERT(tpgt != NULL);
692 do {
693 tig = kmem_zalloc(sizeof (isns_tpgt_t), KM_SLEEP);
694 list_create(&tig->ti_portal_list, sizeof (isns_tpgt_addr_t),
695 offsetof(isns_tpgt_addr_t, portal_ln));
696 tig->ti_tpgt_tag = tpgt->tpgt_tag;
699 * Only need portal list for non-default portal.
701 if (tpgt->tpgt_tag != ISCSIT_DEFAULT_TPGT) {
702 tpg = tpgt->tpgt_tpg;
704 mutex_enter(&tpg->tpg_mutex);
706 tp = avl_first(&tpg->tpg_portal_list);
707 do {
708 tip = kmem_zalloc(sizeof (isns_tpgt_addr_t),
709 KM_SLEEP);
710 bcopy(&tp->portal_addr, &tip->portal_addr,
711 sizeof (tip->portal_addr));
712 list_insert_tail(&tig->ti_portal_list, tip);
714 tp = AVL_NEXT(&tpg->tpg_portal_list, tp);
715 } while (tp != NULL);
716 mutex_exit(&tpg->tpg_mutex);
718 list_insert_tail(&ti->ti_tpgt_list, tig);
719 tpgt = AVL_NEXT(&target->target_tpgt_list, tpgt);
720 } while (tpgt != NULL);
721 mutex_exit(&target->target_mutex);
723 return (ti);
726 static void
727 isnst_clear_target_info_cb(void *arg)
729 isns_target_info_t *ti = (isns_target_info_t *)arg;
730 isns_tpgt_t *tig;
731 isns_tpgt_addr_t *tip;
733 while ((tig = list_remove_head(&ti->ti_tpgt_list)) != NULL) {
734 while ((tip = list_remove_head(&tig->ti_portal_list)) != NULL) {
735 kmem_free(tip, sizeof (isns_tpgt_addr_t));
737 list_destroy(&tig->ti_portal_list);
738 kmem_free(tig, sizeof (isns_tpgt_t));
740 list_destroy(&ti->ti_tpgt_list);
741 idm_refcnt_destroy(&ti->ti_refcnt);
742 kmem_free(ti, sizeof (isns_target_info_t));
747 * iscsit_isns_register
748 * called by iscsit when a target goes online
751 iscsit_isns_register(iscsit_tgt_t *target)
753 isns_target_t *itarget, tmptgt;
754 avl_index_t where;
755 isns_target_info_t *ti;
757 /* Create TI struct outside of isns_mutex */
758 ti = isnst_create_target_info(target);
760 mutex_enter(&iscsit_isns_mutex);
762 tmptgt.target = target;
763 if ((itarget = (isns_target_t *)avl_find(&isns_target_list,
764 &tmptgt, &where)) == NULL) {
765 itarget = kmem_zalloc(sizeof (isns_target_t), KM_SLEEP);
767 itarget->target = target;
768 avl_insert(&isns_target_list, (void *)itarget, where);
769 } else {
770 ASSERT(0);
773 /* Copy the target info so it will last beyond deregister */
774 itarget->target_info = ti;
775 idm_refcnt_hold(&ti->ti_refcnt);
777 isns_targets_changed = B_TRUE;
779 mutex_exit(&iscsit_isns_mutex);
781 isnst_monitor_awaken();
782 return (0);
786 * iscsit_isns_deregister
787 * called by iscsit when a target goes offline
790 iscsit_isns_deregister(iscsit_tgt_t *target)
792 isns_target_t *itarget, tmptgt;
793 isns_target_info_t *ti;
795 tmptgt.target = target;
797 mutex_enter(&iscsit_isns_mutex);
799 itarget = avl_find(&isns_target_list, &tmptgt, NULL);
800 ASSERT(itarget != NULL);
801 ti = itarget->target_info;
804 * The main thread is done with the target_info object.
805 * Make sure the delete callback is called when
806 * all the svrs are done with it.
808 idm_refcnt_rele(&ti->ti_refcnt);
809 idm_refcnt_async_wait_ref(&ti->ti_refcnt,
810 (idm_refcnt_cb_t *)&isnst_clear_target_info_cb);
812 itarget->target_info = NULL;
813 avl_remove(&isns_target_list, itarget);
814 kmem_free(itarget, sizeof (isns_target_t));
816 isns_targets_changed = B_TRUE;
818 mutex_exit(&iscsit_isns_mutex);
820 isnst_monitor_awaken();
821 return (0);
825 * iscsit_isns_target_update
826 * This function is called by iscsit when a target's configuration
827 * has changed.
830 void
831 iscsit_isns_target_update(iscsit_tgt_t *target)
833 isns_target_t *itarget, tmptgt;
834 isns_target_info_t *ti;
836 /* Create new TI struct outside of isns_mutex */
837 ti = isnst_create_target_info(target);
839 mutex_enter(&iscsit_isns_mutex);
842 * If iscsit calls us to modify a target, that target should
843 * already exist in the isns_svr_list.
845 tmptgt.target = target;
846 itarget = avl_find(&isns_target_list, &tmptgt, NULL);
847 if (itarget == NULL) {
849 * If target-update gets called while the target is still
850 * offline, then there is nothing to do. The target will be
851 * completely registered when it comes online.
853 mutex_exit(&iscsit_isns_mutex);
854 /* Remove the target_info struct -- not needed */
855 isnst_clear_target_info_cb(ti);
856 return;
859 /* Remove the old target_info struct */
860 idm_refcnt_rele(&itarget->target_info->ti_refcnt);
861 idm_refcnt_async_wait_ref(&itarget->target_info->ti_refcnt,
862 (idm_refcnt_cb_t *)&isnst_clear_target_info_cb);
864 /* Link to new target_info struct */
865 itarget->target_info = ti;
866 idm_refcnt_hold(&ti->ti_refcnt);
868 itarget->target_update_needed = B_TRUE;
870 isns_targets_changed = B_TRUE;
872 mutex_exit(&iscsit_isns_mutex);
874 isnst_monitor_awaken();
877 static void
878 isnst_start()
880 ISNST_LOG(CE_NOTE, "**** isnst_start");
882 ASSERT(ISNS_GLOBAL_LOCK_HELD());
885 * Start ESI thread(s)
887 isnst_esi_start();
890 * Create a thread for monitoring server communications
892 isnst_monitor_start();
895 static void
896 isnst_stop()
898 ASSERT(ISNS_GLOBAL_LOCK_HELD());
899 ISNST_LOG(CE_NOTE, "**** isnst_stop");
902 ISNS_GLOBAL_UNLOCK();
903 isnst_esi_stop();
904 isnst_monitor_stop();
905 ISNS_GLOBAL_LOCK();
908 static void
909 isnst_monitor_start(void)
911 ISNST_LOG(CE_NOTE, "isnst_monitor_start");
914 mutex_enter(&isns_monitor_mutex);
915 ASSERT(!isns_monitor_thr_running);
916 isns_monitor_thr_id = thread_create(NULL, 0,
917 isnst_monitor, NULL, 0, &p0, TS_RUN, minclsyspri);
918 while (!isns_monitor_thr_running)
919 cv_wait(&isns_idle_cv, &isns_monitor_mutex);
920 mutex_exit(&isns_monitor_mutex);
923 static void
924 isnst_monitor_stop(void)
926 ISNST_LOG(CE_NOTE, "isnst_monitor_stop");
928 mutex_enter(&isns_monitor_mutex);
929 if (isns_monitor_thr_running) {
930 isns_monitor_thr_running = B_FALSE;
931 cv_signal(&isns_idle_cv);
932 mutex_exit(&isns_monitor_mutex);
934 thread_join(isns_monitor_thr_did);
935 return;
937 mutex_exit(&isns_monitor_mutex);
941 * isnst_update_server_timestamp
943 * When we receive an ESI request, update the timestamp for the server.
944 * If we don't receive one for the specified period of time, we'll attempt
945 * to re-register.
948 static boolean_t
949 isnst_update_server_timestamp(struct sockaddr_storage *ss)
951 iscsit_isns_svr_t *svr;
953 ASSERT(ISNS_GLOBAL_LOCK_HELD());
956 * Find the server and update the timestamp
958 for (svr = list_head(&iscsit_global.global_isns_cfg.isns_svrs);
959 svr != NULL;
960 svr = list_next(&iscsit_global.global_isns_cfg.isns_svrs, svr)) {
962 * Note that the port number in incoming probe will be
963 * different than the iSNS server's port number.
965 if (idm_ss_compare(ss, &svr->svr_sa,
966 B_TRUE /* v4_mapped_as_v4 */,
967 B_FALSE /* don't compare_ports */) == 0) {
968 break;
972 if (svr != NULL) {
973 /* Update the timestamp we keep for this server */
974 svr->svr_last_msg = ddi_get_lbolt();
976 * If we receive ESI probe from a server we are not
977 * registered to, then cause a re-reg attempt.
979 if (!svr->svr_registered) {
980 isnst_monitor_awaken();
982 return (B_TRUE);
985 return (B_FALSE);
990 * isnst_monitor_all_servers -- loop through all servers
994 static void
995 isnst_monitor_all_servers()
997 iscsit_isns_svr_t *svr, *next_svr;
998 boolean_t enabled;
999 list_t *svr_list;
1000 int rc;
1002 svr_list = &iscsit_global.global_isns_cfg.isns_svrs;
1004 ISNS_GLOBAL_LOCK();
1006 isnst_copy_global_status_changes();
1008 enabled = iscsit_global.global_isns_cfg.isns_state;
1009 for (svr = list_head(svr_list); svr != NULL; svr = next_svr) {
1011 svr->svr_monitor_hold = B_TRUE;
1013 * isnst_monitor_one_server can release ISNS_GLOBAL_LOCK
1014 * internally. This allows isnst_config_merge to run
1015 * even when messages to iSNS servers are pending.
1017 rc = isnst_monitor_one_server(svr, enabled);
1018 if (rc != 0) {
1019 svr->svr_retry_count++;
1020 if (svr->svr_registered &&
1021 svr->svr_retry_count > isns_max_retry) {
1022 char server_buf[IDM_SA_NTOP_BUFSIZ];
1024 if (! svr->svr_reset_needed) {
1025 ISNST_LOG(CE_WARN,
1026 "isnst: iSNS server %s"
1027 " not responding (rc=%d).",
1028 idm_sa_ntop(&svr->svr_sa,
1029 server_buf, sizeof (server_buf)),
1030 rc);
1031 svr->svr_reset_needed = B_TRUE;
1034 } else {
1035 svr->svr_retry_count = 0;
1038 * If we have finished unregistering this server,
1039 * it is now OK to delete it.
1041 svr->svr_monitor_hold = B_FALSE;
1042 next_svr = list_next(svr_list, svr);
1043 if (svr->svr_delete_needed == B_TRUE &&
1044 svr->svr_registered == B_FALSE) {
1045 isnst_finish_delete_isns(svr);
1048 ISNS_GLOBAL_UNLOCK();
1051 static void
1052 isnst_monitor_awaken(void)
1054 mutex_enter(&isns_monitor_mutex);
1055 if (isns_monitor_thr_running) {
1056 DTRACE_PROBE(iscsit__isns__monitor__awaken);
1057 cv_signal(&isns_idle_cv);
1059 mutex_exit(&isns_monitor_mutex);
1063 * isnst_monitor -- the monitor thread for iSNS
1065 /*ARGSUSED*/
1066 static void
1067 isnst_monitor(void *arg)
1069 mutex_enter(&isns_monitor_mutex);
1070 isns_monitor_thr_did = curthread->t_did;
1071 isns_monitor_thr_running = B_TRUE;
1072 cv_signal(&isns_idle_cv);
1075 * Start with a short pause (5 sec) to allow all targets
1076 * to be registered before we send register-all. This is
1077 * purely an optimization to cut down on the number of
1078 * messages we send to the iSNS server.
1080 mutex_exit(&isns_monitor_mutex);
1081 ddi_sleep(isns_initial_delay);
1082 mutex_enter(&isns_monitor_mutex);
1084 /* Force an initialization of isns_all_portals */
1085 mutex_enter(&iscsit_isns_mutex);
1086 isns_portals_changed = B_TRUE;
1087 mutex_exit(&iscsit_isns_mutex);
1089 while (isns_monitor_thr_running) {
1091 /* Update servers */
1092 mutex_exit(&isns_monitor_mutex);
1093 isnst_monitor_all_servers();
1094 mutex_enter(&isns_monitor_mutex);
1096 /* If something needs attention, go right to the top */
1097 mutex_enter(&iscsit_isns_mutex);
1098 if (isns_targets_changed || isns_portals_changed) {
1099 DTRACE_PROBE(iscsit__isns__monitor__reenter);
1100 mutex_exit(&iscsit_isns_mutex);
1101 /* isns_monitor_mutex still held */
1102 continue;
1104 mutex_exit(&iscsit_isns_mutex);
1107 * Keep running until isns_monitor_thr_running is set to
1108 * B_FALSE.
1110 if (! isns_monitor_thr_running)
1111 break;
1113 DTRACE_PROBE(iscsit__isns__monitor__sleep);
1114 (void) cv_reltimedwait(&isns_idle_cv, &isns_monitor_mutex,
1115 monitor_idle_interval, TR_CLOCK_TICK);
1116 DTRACE_PROBE1(iscsit__isns__monitor__wakeup,
1117 boolean_t, isns_monitor_thr_running);
1120 mutex_exit(&isns_monitor_mutex);
1122 /* Update the servers one last time for deregistration */
1123 isnst_monitor_all_servers();
1125 /* Clean up the all-portals list */
1126 ISNS_GLOBAL_LOCK();
1127 isnst_clear_default_portals();
1128 ISNS_GLOBAL_UNLOCK();
1130 /* terminate the thread at the last */
1131 thread_exit();
1134 static int
1135 isnst_monitor_one_server(iscsit_isns_svr_t *svr, boolean_t enabled)
1137 int rc = 0;
1138 isns_target_t *itarget;
1140 ASSERT(ISNS_GLOBAL_LOCK_HELD());
1143 * First, take care of the case where iSNS is no longer enabled.
1147 if (enabled == B_FALSE || svr->svr_delete_needed) {
1149 * Just try one time to deregister all from server.
1150 * Doesn't matter if this fails. We're disabled.
1152 (void) isnst_update_one_server(svr, NULL, ISNS_DEREGISTER_ALL);
1153 isnst_set_server_status(svr, B_FALSE);
1154 return (0);
1157 retry_replace_all:
1159 * If the server needs replace-all, check if it should
1160 * be a DevDereg (i.e. if the last target is gone.)
1163 if (svr->svr_registered && svr->svr_reset_needed) {
1164 /* Send DevDereg if last registered target */
1165 isns_target_t *jtarget;
1166 for (jtarget = avl_first(&svr->svr_target_list);
1167 jtarget != NULL;
1168 jtarget = AVL_NEXT(&svr->svr_target_list, jtarget)) {
1169 if (!jtarget->target_delete_needed) {
1170 break;
1174 * jtarget is null IFF all tgts need deletion,
1175 * and there are no new targets to register.
1177 if (jtarget == NULL) {
1178 rc = isnst_update_one_server(svr, NULL,
1179 ISNS_DEREGISTER_ALL);
1180 if (rc != 0) {
1181 return (rc);
1183 isnst_set_server_status(svr, B_FALSE);
1184 return (0);
1189 * If the server is not yet registered, do the registration
1191 if (! svr->svr_registered || svr->svr_reset_needed) {
1193 if (avl_numnodes(&svr->svr_target_list) == 0) {
1194 /* If no targets, nothing to register */
1195 return (0);
1197 if ((rc = isnst_update_one_server(svr, NULL,
1198 ISNS_REGISTER_ALL)) != 0) {
1199 /* Registration failed */
1200 return (rc);
1202 isnst_set_server_status(svr, B_TRUE);
1206 /* The following checks are expensive, so only do them if needed */
1207 if (svr->svr_targets_changed) {
1208 isns_target_t *next_target;
1210 * If there is a target to be deleted, send the
1211 * deletion request for one target at a time.
1213 for (itarget = avl_first(&svr->svr_target_list);
1214 itarget != NULL;
1215 itarget = next_target) {
1216 next_target = AVL_NEXT(&svr->svr_target_list, itarget);
1217 if (itarget->target_delete_needed) {
1218 /* See if last non-deleted target */
1219 isns_target_t *jtarget;
1220 ASSERT(itarget->target_registered);
1221 for (jtarget =
1222 avl_first(&svr->svr_target_list);
1223 jtarget != NULL;
1224 jtarget = AVL_NEXT(&svr->svr_target_list,
1225 jtarget)) {
1226 if (jtarget->target_registered &&
1227 !jtarget->target_delete_needed) {
1228 break;
1231 /* jtarget is null if last registered tgt */
1232 if (jtarget == NULL) {
1234 * Removing last tgt -- deregister all.
1235 * Doesn't matter if this fails.
1236 * We're disabled.
1238 rc = isnst_update_one_server(svr,
1239 NULL, ISNS_DEREGISTER_ALL);
1240 if (rc != 0) {
1241 return (rc);
1243 isnst_set_server_status(svr, B_FALSE);
1244 return (0);
1246 rc = isnst_update_one_server(svr,
1247 itarget, ISNS_DEREGISTER_TARGET);
1248 if (rc != 0 && isnst_retry_registration(rc)) {
1249 /* Retryable code => try replace-all */
1250 svr->svr_reset_needed = B_TRUE;
1251 goto retry_replace_all;
1254 if (rc != 0) {
1255 return (rc);
1257 isnst_clear_from_target_list(itarget,
1258 &svr->svr_target_list);
1262 /* If any target needs a register or an update, do so */
1263 itarget = avl_first(&svr->svr_target_list);
1264 while (itarget) {
1265 if (!itarget->target_registered ||
1266 itarget->target_update_needed) {
1269 * Because of a bug in the isns
1270 * server, we cannot send a modify
1271 * operation that changes the target's
1272 * TPGTs. So just replace all.
1274 if (isns_modify_must_replace) {
1275 svr->svr_reset_needed = B_TRUE;
1276 goto retry_replace_all;
1278 /* Try to update existing info for one tgt */
1279 rc = isnst_update_one_server(svr,
1280 itarget,
1281 ISNS_MODIFY_TARGET);
1282 if (rc != 0 && isnst_retry_registration(rc)) {
1283 /* Retryable code => try replace-all */
1284 svr->svr_reset_needed = B_TRUE;
1285 goto retry_replace_all;
1287 if (rc != 0) {
1288 return (rc);
1290 itarget->target_update_needed =
1291 B_FALSE;
1292 itarget->target_registered = B_TRUE;
1294 itarget = AVL_NEXT(&svr->svr_target_list,
1295 itarget);
1299 * We have gone through all the cases -- this server
1300 * is now up to date.
1302 svr->svr_targets_changed = B_FALSE;
1306 if (isns_use_esi) {
1308 * If using ESI, and no ESI request is received within
1309 * MAX_ESI_INTERVALS (3) number of intervals, we'll
1310 * try to re-register with the server. The server will
1311 * delete our information if we fail to respond for 2
1312 * ESI intervals.
1314 if (ddi_get_lbolt() >= (svr->svr_last_msg +
1315 drv_usectohz(svr->svr_esi_interval * 1000000 *
1316 MAX_ESI_INTERVALS))) {
1317 /* re-register everything */
1318 svr->svr_reset_needed = B_TRUE;
1319 goto retry_replace_all;
1321 } else {
1323 * If not using ESI, make sure to ping server during
1324 * each registration period. Do this at half the
1325 * registration interval, so we won't get timed out.
1327 if (ddi_get_lbolt() >= (svr->svr_last_msg +
1328 drv_usectohz(isns_registration_period * (1000000/3)))) {
1329 /* Send a self-query as a keepalive. */
1330 ISNS_GLOBAL_UNLOCK();
1331 rc = isnst_keepalive(svr);
1332 ISNS_GLOBAL_LOCK();
1333 if (rc != 0 && isnst_retry_registration(rc)) {
1334 /* Retryable code => try replace-all */
1335 svr->svr_reset_needed = B_TRUE;
1336 goto retry_replace_all;
1338 if (rc != 0) {
1339 return (rc);
1343 return (0);
1348 * isnst_mark_deleted_target -- find tgt in svr list but not global list
1350 static void
1351 isnst_mark_deleted_targets(iscsit_isns_svr_t *svr)
1353 isns_target_t *itarget, *nxt_target, tmptgt;
1355 ASSERT(ISNS_GLOBAL_LOCK_HELD());
1356 ASSERT(mutex_owned(&iscsit_isns_mutex));
1358 for (itarget = avl_first(&svr->svr_target_list);
1359 itarget != NULL;
1360 itarget = nxt_target) {
1361 tmptgt.target = itarget->target;
1362 nxt_target = AVL_NEXT(&svr->svr_target_list, itarget);
1363 if (avl_find(&isns_target_list, &tmptgt, NULL) == NULL) {
1364 if (itarget->target_registered) {
1365 itarget->target_delete_needed = B_TRUE;
1366 } else {
1367 isnst_clear_from_target_list(itarget,
1368 &svr->svr_target_list);
1374 static isns_target_t *
1375 isnst_latch_to_target_list(isns_target_t *jtarget, avl_tree_t *target_list)
1377 isns_target_t *itarget, tmptgt;
1378 avl_index_t where;
1380 ASSERT(ISNS_GLOBAL_LOCK_HELD());
1381 ASSERT(mutex_owned(&iscsit_isns_mutex));
1383 * Make sure this target isn't already in our list.
1386 tmptgt.target = jtarget->target;
1387 if ((itarget = (isns_target_t *)avl_find(target_list,
1388 &tmptgt, &where)) == NULL) {
1389 itarget = kmem_zalloc(sizeof (isns_target_t), KM_SLEEP);
1391 itarget->target = jtarget->target;
1392 itarget->target_info = jtarget->target_info;
1393 idm_refcnt_hold(&itarget->target_info->ti_refcnt);
1395 avl_insert(target_list, (void *)itarget, where);
1396 } else {
1397 ASSERT(0);
1400 return (itarget);
1403 static void
1404 isnst_clear_target_list(iscsit_isns_svr_t *svr)
1406 isns_target_t *itarget;
1408 while ((itarget = avl_first(&svr->svr_target_list)) != NULL) {
1409 isnst_clear_from_target_list(itarget,
1410 &svr->svr_target_list);
1414 static void
1415 isnst_clear_from_target_list(isns_target_t *jtarget, avl_tree_t *target_list)
1417 isns_target_t *itarget, tmptgt;
1419 tmptgt.target = jtarget->target;
1421 if ((itarget = avl_find(target_list, &tmptgt, NULL))
1422 != NULL) {
1424 avl_remove(target_list, itarget);
1425 idm_refcnt_rele(&itarget->target_info->ti_refcnt);
1426 kmem_free(itarget, sizeof (isns_target_t));
1427 } else {
1428 ASSERT(0);
1433 * isnst_copy_global_status_changes -- update svrs to match iscsit
1435 * At the end of this routine svr->svr_target_list has all the entries
1436 * in the current isns_target_list plus any targets that are marked
1437 * for deletion.
1439 static void
1440 isnst_copy_global_status_changes(void)
1442 isns_target_t *ttarget, *itarget, tmptgt;
1443 iscsit_isns_svr_t *svr;
1445 ASSERT(ISNS_GLOBAL_LOCK_HELD());
1448 * Copy info about recent transitions from global state to
1449 * per-server state. We use the global state so that iscsit
1450 * functions can proceed without blocking on slow-to-release
1451 * iSNS locks.
1453 mutex_enter(&iscsit_isns_mutex);
1456 * Periodically check for changed IP addresses. This function
1457 * sets isns_all_portals to the current set, and sets
1458 * isns_portals_changed if a portal is added or removed.
1460 isnst_monitor_default_portal_list();
1462 /* Initialize the per-server structs to some basic values */
1463 for (svr = list_head(&iscsit_global.global_isns_cfg.isns_svrs);
1464 svr != NULL;
1465 svr = list_next(&iscsit_global.global_isns_cfg.isns_svrs,
1466 svr)) {
1467 if (isns_portals_changed && svr->svr_registered) {
1469 * Cause re-register, for now, when portals change.
1470 * Eventually, we should add new portals one by one
1472 svr->svr_reset_needed = B_TRUE;
1474 if (!svr->svr_registered) {
1475 /* To re-register, start with empty target list */
1476 isnst_clear_target_list(svr);
1477 /* And set flag to add all current targets, below */
1478 isns_targets_changed = B_TRUE;
1479 } else if (isns_targets_changed || svr->svr_reset_needed) {
1480 /* Mark to look for target changes */
1481 isnst_mark_deleted_targets(svr);
1482 svr->svr_targets_changed = B_TRUE;
1487 * If any target has been modified, tell all the svrs to
1488 * update that target.
1490 if (isns_targets_changed) {
1491 ttarget = avl_first(&isns_target_list);
1492 while (ttarget) {
1493 for (svr = list_head(
1494 &iscsit_global.global_isns_cfg.isns_svrs);
1495 svr != NULL;
1496 svr = list_next(
1497 &iscsit_global.global_isns_cfg.isns_svrs,
1498 svr)) {
1499 tmptgt.target = ttarget->target;
1500 itarget = avl_find(
1501 &svr->svr_target_list,
1502 &tmptgt, NULL);
1504 if (itarget == NULL) {
1505 /* Add a new target */
1506 (void) isnst_latch_to_target_list(
1507 ttarget, &svr->svr_target_list);
1508 } else if (ttarget->target_update_needed) {
1509 /* Modify existing target */
1510 itarget->target_update_needed =
1511 B_TRUE;
1512 /* Remove link to old target_info */
1513 idm_refcnt_rele(
1514 &itarget->target_info->ti_refcnt);
1515 /* Link to new target_info struct */
1516 itarget->target_info =
1517 ttarget->target_info;
1518 idm_refcnt_hold(
1519 &itarget->target_info->ti_refcnt);
1522 ttarget->target_update_needed = B_FALSE;
1523 ttarget = AVL_NEXT(&isns_target_list, ttarget);
1528 * Now we have updated the per-server state for all servers.
1529 * Clear the global state flags
1531 isns_targets_changed = B_FALSE;
1532 isns_portals_changed = B_FALSE;
1533 mutex_exit(&iscsit_isns_mutex);
1537 * isnst_update_one_server releases ISNS_GLOBAL_LOCK internally and
1538 * acquires it again as needed. This allows isnst_config_merge and
1539 * isnst_esi_thread to run even while waiting for a response from the
1540 * iSNS server (or a dead iSNS server).
1542 static int
1543 isnst_update_one_server(iscsit_isns_svr_t *svr, isns_target_t *itarget,
1544 isns_reg_type_t reg)
1546 int rc = 0;
1548 ASSERT(ISNS_GLOBAL_LOCK_HELD());
1549 ISNS_GLOBAL_UNLOCK();
1551 switch (reg) {
1552 case ISNS_DEREGISTER_TARGET:
1553 rc = isnst_deregister(svr, itarget);
1554 break;
1556 case ISNS_DEREGISTER_ALL:
1557 rc = isnst_deregister(svr, NULL);
1558 break;
1560 case ISNS_MODIFY_TARGET:
1561 case ISNS_REGISTER_TARGET:
1562 rc = isnst_register(svr, itarget, reg);
1563 break;
1565 case ISNS_REGISTER_ALL:
1566 rc = isnst_register(svr, NULL, reg);
1567 break;
1569 default:
1570 ASSERT(0);
1571 /* NOTREACHED */
1574 ISNS_GLOBAL_LOCK();
1575 return (rc);
1579 * isnst_retry_registration
1581 * This function checks the return value from a registration pdu and
1582 * determines whether or not we should retry this request. If the
1583 * request is retried, it will do so as an "update", which means we
1584 * re-register everything.
1587 static boolean_t
1588 isnst_retry_registration(int rsp_status_code)
1590 boolean_t retry;
1593 * The following are the error codes that indicate isns-client
1594 * and isns-server are out of synch. E.g. No-Such-Entry can
1595 * occur on a keepalive if the server has timed out our
1596 * connection. If we get one of these messages, we replace-all
1597 * right away to get back in synch faster.
1599 switch (rsp_status_code) {
1600 case ISNS_RSP_INVALID_REGIS:
1601 case ISNS_RSP_SRC_UNAUTHORIZED:
1602 case ISNS_RSP_BUSY:
1603 case ISNS_RSP_INVALID_UPDATE:
1604 case ISNS_RSP_NO_SUCH_ENTRY:
1605 retry = B_TRUE;
1606 break;
1607 default:
1608 retry = B_FALSE;
1609 break;
1612 return (retry);
1617 static int
1618 isnst_register(iscsit_isns_svr_t *svr, isns_target_t *itarget,
1619 isns_reg_type_t regtype)
1621 struct sonode *so;
1622 int rc = 0;
1623 isns_pdu_t *pdu, *rsp;
1624 size_t pdu_size, rsp_size;
1626 /* create TCP connection to the isns server */
1627 so = isnst_open_so(&svr->svr_sa);
1628 if (so == NULL) {
1629 return (-1);
1632 pdu_size = isnst_make_reg_pdu(&pdu, itarget, svr, regtype);
1633 if (pdu_size == 0) {
1634 isnst_close_so(so);
1635 return (-1);
1638 rc = isnst_send_pdu(so, pdu);
1639 if (rc != 0) {
1640 kmem_free(pdu, pdu_size);
1641 isnst_close_so(so);
1642 return (rc);
1645 rsp_size = isnst_rcv_pdu(so, &rsp);
1646 if (rsp_size == 0) {
1647 kmem_free(pdu, pdu_size);
1648 isnst_close_so(so);
1649 return (-1);
1652 rc = isnst_verify_rsp(svr, pdu, rsp, rsp_size);
1654 kmem_free(pdu, pdu_size);
1655 kmem_free(rsp, rsp_size);
1656 isnst_close_so(so);
1658 return (rc);
1662 * isnst_make_reg_pdu:
1663 * Cases:
1664 * initial registration of all targets (replace-all)
1665 * initial registration of a single target (update-existing)
1666 * modify an existing target (update-existing)
1668 static size_t
1669 isnst_make_reg_pdu(isns_pdu_t **pdu, isns_target_t *itarget,
1670 iscsit_isns_svr_t *svr, isns_reg_type_t regtype)
1672 size_t pdu_size;
1673 char *str;
1674 int len;
1675 isns_target_t *src;
1676 boolean_t reg_all = B_FALSE;
1677 uint16_t flags = 0;
1679 ISNS_GLOBAL_LOCK();
1680 ASSERT(svr->svr_monitor_hold);
1682 * svr could have an empty target list if svr was added
1683 * by isnst_config_merge sometime after the last call to
1684 * copy_global_status_changes. Just skip this chance
1685 * to reregister. The next call to copy_global_status_changes
1686 * will sort things out.
1688 if (avl_numnodes(&svr->svr_target_list) == 0) {
1689 /* If no targets, nothing to register */
1690 ISNS_GLOBAL_UNLOCK();
1691 return (0);
1694 * Find a source attribute for this registration.
1696 * If updating a specific target for the first time, use that
1697 * target.
1698 * If already registered, use a registered target
1699 * Otherwise, use the first target we are going to register.
1701 if (itarget != NULL && ! svr->svr_registered) {
1702 src = itarget;
1703 } else if (svr->svr_registered) {
1704 src = isnst_get_registered_source_locked(svr);
1705 } else {
1707 * When registering to a server, and we don't know which
1708 * of our targets the server might already know,
1709 * cycle through each of our targets as source. The server
1710 * does source validation. If the server knows any of our
1711 * targets, it will eventually accept one of our registrations.
1713 int i;
1714 isns_target_t *jtarget;
1716 if (svr->svr_last_target_index >=
1717 avl_numnodes(&svr->svr_target_list) - 1) {
1718 svr->svr_last_target_index = 0;
1719 } else {
1720 svr->svr_last_target_index++;
1722 for (i = 0, jtarget = avl_first(&svr->svr_target_list);
1723 i < svr->svr_last_target_index;
1724 i++, jtarget = AVL_NEXT(&svr->svr_target_list, jtarget)) {
1725 ASSERT(jtarget != NULL);
1727 src = jtarget;
1728 ASSERT(src != NULL);
1732 * Null target means we're replacing everything.
1734 if (itarget == NULL) {
1735 reg_all = B_TRUE;
1736 flags = ISNS_FLAG_REPLACE_REG;
1737 /* Reset itarget to the beginning of our list */
1738 itarget = (isns_target_t *)avl_first(&svr->svr_target_list);
1739 } else if (regtype == ISNS_REGISTER_TARGET) {
1740 flags = ISNS_FLAG_REPLACE_REG;
1741 ASSERT(!itarget->target_delete_needed);
1744 pdu_size = isnst_create_pdu_header(ISNS_DEV_ATTR_REG, pdu, flags);
1745 if (pdu_size == 0) {
1746 ISNS_GLOBAL_UNLOCK();
1747 return (0);
1750 /* Source Attribute */
1752 len = strlen(src->target_info->ti_tgt_name) + 1;
1753 if (isnst_add_attr(*pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
1754 len, src->target_info->ti_tgt_name, 0) != 0) {
1755 goto pdu_error;
1759 * Message Key Attributes - EID
1761 len = strlen(isns_eid) + 1;
1763 if (isnst_add_attr(*pdu, pdu_size, ISNS_EID_ATTR_ID,
1764 len, isns_eid, 0) != 0) {
1765 goto pdu_error;
1768 /* Delimiter */
1769 if (isnst_add_attr(*pdu, pdu_size, ISNS_DELIMITER_ATTR_ID,
1770 0, 0, 0) != 0) {
1771 goto pdu_error;
1775 * Operating Attributes
1777 if (isnst_add_attr(*pdu, pdu_size, ISNS_EID_ATTR_ID, len,
1778 isns_eid, 0) != 0) {
1779 goto pdu_error;
1783 /* ENTITY Protocol - Section 6.2.2 */
1784 if (isnst_add_attr(*pdu, pdu_size,
1785 ISNS_ENTITY_PROTOCOL_ATTR_ID,
1786 4, 0, ISNS_ENTITY_PROTOCOL_ISCSI) != 0) {
1787 goto pdu_error;
1790 if (reg_all) {
1791 /* Registration Period -- use if not using ESI */
1792 if (!isns_use_esi &&
1793 isnst_add_attr(*pdu, pdu_size,
1794 ISNS_ENTITY_REG_PERIOD_ATTR_ID, 4,
1795 0, isns_registration_period) != 0) {
1796 goto pdu_error;
1799 * Network entity portal information - only when
1800 * replacing all. Since targets are only registered
1801 * to iSNS when their portals are already registered
1802 * to iSNS, we can assume entity portals exist.
1804 if (isnst_reg_pdu_add_entity_portals(*pdu, pdu_size) != 0) {
1805 goto pdu_error;
1809 * Skip over delete-pending tgts. There must be at
1810 * least one non-deleted tgt, or it is an error.
1812 while (itarget->target_delete_needed) {
1813 itarget = AVL_NEXT(&svr->svr_target_list,
1814 itarget);
1815 ASSERT(itarget != NULL);
1820 /* Add information about each target or one target */
1821 do {
1823 /* iSCSI Name - Section 6.4.1 */
1824 str = itarget->target_info->ti_tgt_name;
1825 len = strlen(str) + 1;
1826 if (isnst_add_attr(*pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
1827 len, str, 0) != 0) {
1828 goto pdu_error;
1831 /* iSCSI Node Type */
1832 if (isnst_add_attr(*pdu, pdu_size,
1833 ISNS_ISCSI_NODE_TYPE_ATTR_ID, 4, 0,
1834 ISNS_TARGET_NODE_TYPE) != 0) {
1835 goto pdu_error;
1838 /* iSCSI Alias */
1839 str = itarget->target_info->ti_tgt_alias;
1840 len = strnlen(str,
1841 sizeof (itarget->target_info->ti_tgt_alias));
1842 if (len) {
1843 /* Found alias in property list */
1844 if (isnst_add_attr(*pdu, pdu_size,
1845 ISNS_ISCSI_ALIAS_ATTR_ID, len+1, str, 0) != 0) {
1846 goto pdu_error;
1850 if (isnst_reg_pdu_add_pg(*pdu, pdu_size, itarget) != 0) {
1851 goto pdu_error;
1854 /* If registering one target, then we are done. */
1855 if (!reg_all) {
1856 break;
1859 /* Skip over delete-pending tgts */
1860 do {
1861 itarget = AVL_NEXT(&svr->svr_target_list, itarget);
1862 } while (itarget != NULL && itarget->target_delete_needed);
1864 } while (itarget != NULL);
1866 ISNS_GLOBAL_UNLOCK();
1867 return (pdu_size);
1869 pdu_error:
1870 /* packet too large, no memory (or other error) */
1871 len = ntohs((*pdu)->payload_len);
1872 if (len + 1000 > isns_message_buf_size) {
1873 /* Increase the PDU size we will ask for next time */
1874 if (isns_message_buf_size * 2 <= ISNST_MAX_MSG_SIZE) {
1875 isns_message_buf_size *= 2;
1876 ISNST_LOG(CE_NOTE,
1877 "Increasing isns_message_buf_size to %d",
1878 isns_message_buf_size);
1879 } else {
1880 cmn_err(CE_WARN, "iscsit: isns: no space"
1881 " to send required PDU");
1885 kmem_free(*pdu, pdu_size);
1886 *pdu = NULL;
1888 ISNS_GLOBAL_UNLOCK();
1889 return (0);
1892 static int
1893 isnst_reg_pdu_add_entity_portals(isns_pdu_t *pdu, size_t pdu_size)
1895 int rc = 0;
1896 isns_portal_t *iportal;
1898 ASSERT(ISNS_GLOBAL_LOCK_HELD());
1900 iportal = (isns_portal_t *)avl_first(&isns_all_portals);
1901 while (iportal != NULL) {
1902 /* Do not include ESI port if not using ESI */
1903 if (isnst_add_portal_attr(pdu, pdu_size,
1904 ISNS_PORTAL_IP_ADDR_ATTR_ID,
1905 ISNS_PORTAL_PORT_ATTR_ID,
1906 &iportal->portal_addr,
1907 isns_use_esi /* ESI info */) != 0) {
1908 rc = -1;
1909 break;
1911 iportal = AVL_NEXT(&isns_all_portals, iportal);
1914 return (rc);
1919 * isnst_reg_pdu_add_pg -- add the PG and PGT entries for one target.
1921 static int
1922 isnst_reg_pdu_add_pg(isns_pdu_t *pdu, size_t pdu_size, isns_target_t *itarget)
1924 int rval = 0;
1925 avl_tree_t null_portals;
1926 isns_target_info_t *ti;
1927 isns_tpgt_t *tig;
1929 ASSERT(ISNS_GLOBAL_LOCK_HELD());
1931 ti = itarget->target_info;
1934 * If all registered targets only use the default TPGT, then
1935 * we can skip sending PG info to the iSNS server.
1937 if (num_tpg_portals == 0)
1938 return (0);
1941 * For each target, we start with the full portal list,
1942 * and then remove portals as we add them to TPGTs for this target.
1943 * At the end, all the remaining portals go into the "null pg".
1944 * We use the "null_portals" list to track this.
1946 avl_create(&null_portals, isnst_portal_avl_compare,
1947 sizeof (isns_portal_t), offsetof(isns_portal_t, portal_node));
1948 isnst_copy_portal_list(&isns_all_portals, &null_portals);
1950 for (tig = list_head(&ti->ti_tpgt_list);
1951 tig != NULL;
1952 tig = list_next(&ti->ti_tpgt_list, tig)) {
1954 if (tig->ti_tpgt_tag == ISCSIT_DEFAULT_TPGT) {
1955 /* Add portal info from list of default portals */
1956 if (isnst_add_default_pg(pdu, pdu_size,
1957 &null_portals) != 0) {
1958 rval = 1;
1959 break;
1961 } else {
1962 /* Add portal info from this TPGT's entries */
1963 if (isnst_add_tpg_pg(pdu, pdu_size, tig,
1964 &null_portals) != 0) {
1965 rval = 1;
1966 break;
1971 /* Add the remaining portals (if any) to the null PG */
1972 if (rval == 0 &&
1973 isnst_add_null_pg(pdu, pdu_size, &null_portals) != 0) {
1974 rval = 1;
1976 isnst_clear_portal_list(&null_portals);
1977 avl_destroy(&null_portals);
1978 return (rval);
1981 /* Write one TPGT's info into the PDU */
1982 static int
1983 isnst_add_tpg_pg(isns_pdu_t *pdu, size_t pdu_size,
1984 isns_tpgt_t *tig, avl_tree_t *null_portal_list)
1986 isns_tpgt_addr_t *tip;
1987 int rval = 0;
1989 ASSERT(ISNS_GLOBAL_LOCK_HELD());
1990 ASSERT(tig->ti_tpgt_tag != ISCSIT_DEFAULT_TPGT);
1992 /* Portal Group Tag */
1993 if (isnst_add_attr(pdu, pdu_size,
1994 ISNS_PG_TAG_ATTR_ID, 4, 0, tig->ti_tpgt_tag) != 0) {
1995 rval = 1;
1996 goto pg_done;
1999 tip = list_head(&tig->ti_portal_list);
2000 ASSERT(tip != NULL);
2001 do {
2002 /* PG Portal Addr and PG Portal Port */
2003 if (isnst_add_portal_attr(pdu, pdu_size,
2004 ISNS_PG_PORTAL_IP_ADDR_ATTR_ID,
2005 ISNS_PG_PORTAL_PORT_ATTR_ID,
2006 &tip->portal_addr, B_FALSE /* ESI */) != 0) {
2007 rval = 1;
2008 goto pg_done;
2010 isnst_remove_from_portal_list(&tip->portal_addr,
2011 null_portal_list);
2013 tip = list_next(&tig->ti_portal_list, tip);
2014 } while (tip != NULL);
2016 pg_done:
2017 return (rval);
2020 static int
2021 isnst_add_default_pg(isns_pdu_t *pdu, size_t pdu_size,
2022 avl_tree_t *null_portal_list)
2024 isns_portal_t *iportal;
2026 ASSERT(ISNS_GLOBAL_LOCK_HELD());
2028 if (num_default_portals == 0) {
2030 * It is OK for a target with default-portals to be
2031 * online from an STMF perspective and yet all
2032 * default portals are down. if other (non-default)
2033 * portals do exist, we will still announce the target
2034 * to the isns server. In this case, we will specify
2035 * all the active non-default portals as NULL portals.
2036 * This is an OK state.
2038 * There is a corner case if non-default portals have
2039 * been marked online but the targets that use them
2040 * are not fully online yet, AND all the default portals
2041 * are down. In this case, the iSNS server will receive
2042 * a DevAttrReg pdu that announces both non-default
2043 * portals and default-portal-only targets. In other
2044 * words, there may be no target that has an active
2045 * portal. The iSNS spec does not forbid this case.
2047 * Both of the above cases are somewhat theoretical.
2048 * If the default portals are down we probably cannot
2049 * get any messages through to the iSNS server anyway.
2051 return (0);
2054 /* Portal Group Tag */
2055 if (isnst_add_attr(pdu, pdu_size,
2056 ISNS_PG_TAG_ATTR_ID, 4, 0, ISCSIT_DEFAULT_TPGT) != 0) {
2057 return (1);
2060 for (iportal = avl_first(&isns_all_portals);
2061 iportal != NULL;
2062 iportal = AVL_NEXT(&isns_all_portals, iportal)) {
2063 if (iportal->portal_default) {
2064 /* PG Portal Addr and PG Portal Port */
2065 if (isnst_add_portal_attr(pdu, pdu_size,
2066 ISNS_PG_PORTAL_IP_ADDR_ATTR_ID,
2067 ISNS_PG_PORTAL_PORT_ATTR_ID,
2068 &iportal->portal_addr, B_FALSE) != 0) {
2069 return (1);
2071 isnst_remove_from_portal_list(&iportal->portal_addr,
2072 null_portal_list);
2076 return (0);
2079 static int
2080 isnst_add_null_pg(isns_pdu_t *pdu, size_t pdu_size,
2081 avl_tree_t *null_portal_list)
2083 isns_portal_t *iportal;
2085 /* If all portals accounted for, no NULL PG needed */
2086 if (avl_numnodes(null_portal_list) == 0) {
2087 return (0);
2090 /* NULL Portal Group Tag means no access via these portals. */
2091 if (isnst_add_attr(pdu, pdu_size,
2092 ISNS_PG_TAG_ATTR_ID, 0, 0, 0) != 0) {
2093 return (1);
2096 for (iportal = avl_first(null_portal_list);
2097 iportal != NULL;
2098 iportal = AVL_NEXT(null_portal_list, iportal)) {
2099 if (isnst_add_portal_attr(pdu, pdu_size,
2100 ISNS_PG_PORTAL_IP_ADDR_ATTR_ID,
2101 ISNS_PG_PORTAL_PORT_ATTR_ID,
2102 &iportal->portal_addr, B_FALSE) != 0) {
2103 return (1);
2107 return (0);
2110 static int
2111 isnst_add_portal_attr(isns_pdu_t *pdu, size_t pdu_size,
2112 uint32_t ip_attr_id, uint32_t port_attr_id,
2113 struct sockaddr_storage *ss, boolean_t esi_info)
2115 struct sockaddr_in *in;
2116 struct sockaddr_in6 *in6;
2117 uint32_t attr_numeric_data;
2118 void *inaddrp;
2120 in = (struct sockaddr_in *)ss;
2121 in6 = (struct sockaddr_in6 *)ss;
2123 ASSERT((ss->ss_family == AF_INET) || (ss->ss_family == AF_INET6));
2125 if (ss->ss_family == AF_INET) {
2126 attr_numeric_data = sizeof (in_addr_t);
2127 inaddrp = (void *)&in->sin_addr;
2128 } else if (ss->ss_family == AF_INET6) {
2129 attr_numeric_data = sizeof (in6_addr_t);
2130 inaddrp = (void *)&in6->sin6_addr;
2133 /* Portal Group Portal IP Address */
2134 if (isnst_add_attr(pdu, pdu_size, ip_attr_id,
2135 16, inaddrp, attr_numeric_data) != 0) {
2136 return (1);
2139 /* Portal Group Portal Port */
2140 if (isnst_add_attr(pdu, pdu_size, port_attr_id,
2141 4, 0, ntohs(in->sin_port)) != 0) {
2142 return (1);
2145 mutex_enter(&esi.esi_mutex);
2146 if (esi_info && esi.esi_valid) {
2147 /* ESI interval and port */
2148 if (isnst_add_attr(pdu, pdu_size, ISNS_ESI_INTERVAL_ATTR_ID, 4,
2149 NULL, isns_default_esi_interval) != 0) {
2150 return (1);
2153 if (isnst_add_attr(pdu, pdu_size, ISNS_ESI_PORT_ATTR_ID, 4,
2154 NULL, esi.esi_port) != 0) {
2155 return (1);
2158 mutex_exit(&esi.esi_mutex);
2160 return (0);
2163 static int
2164 isnst_deregister(iscsit_isns_svr_t *svr, isns_target_t *itarget)
2166 int rc;
2167 isns_pdu_t *pdu, *rsp;
2168 size_t pdu_size, rsp_size;
2169 struct sonode *so;
2171 so = isnst_open_so(&svr->svr_sa);
2173 if (so == NULL) {
2174 return (-1);
2177 pdu_size = isnst_make_dereg_pdu(svr, &pdu, itarget);
2178 if (pdu_size == 0) {
2179 isnst_close_so(so);
2180 return (-1);
2183 rc = isnst_send_pdu(so, pdu);
2184 if (rc != 0) {
2185 isnst_close_so(so);
2186 kmem_free(pdu, pdu_size);
2187 return (rc);
2190 rsp_size = isnst_rcv_pdu(so, &rsp);
2191 if (rsp_size == 0) {
2192 isnst_close_so(so);
2193 kmem_free(pdu, pdu_size);
2194 return (-1);
2197 rc = isnst_verify_rsp(svr, pdu, rsp, rsp_size);
2199 isnst_close_so(so);
2200 kmem_free(pdu, pdu_size);
2201 kmem_free(rsp, rsp_size);
2203 return (rc);
2206 static int
2207 isnst_keepalive(iscsit_isns_svr_t *svr)
2209 int rc;
2210 isns_pdu_t *pdu, *rsp;
2211 size_t pdu_size, rsp_size;
2212 struct sonode *so;
2214 so = isnst_open_so(&svr->svr_sa);
2216 if (so == NULL) {
2217 return (-1);
2220 pdu_size = isnst_make_keepalive_pdu(svr, &pdu);
2221 if (pdu_size == 0) {
2222 isnst_close_so(so);
2223 return (-1);
2226 rc = isnst_send_pdu(so, pdu);
2227 if (rc != 0) {
2228 isnst_close_so(so);
2229 kmem_free(pdu, pdu_size);
2230 return (rc);
2233 rsp_size = isnst_rcv_pdu(so, &rsp);
2234 if (rsp_size == 0) {
2235 isnst_close_so(so);
2236 kmem_free(pdu, pdu_size);
2237 return (-1);
2240 rc = isnst_verify_rsp(svr, pdu, rsp, rsp_size);
2242 isnst_close_so(so);
2243 kmem_free(pdu, pdu_size);
2244 kmem_free(rsp, rsp_size);
2246 return (rc);
2249 static size_t
2250 isnst_make_dereg_pdu(iscsit_isns_svr_t *svr, isns_pdu_t **pdu,
2251 isns_target_t *itarget)
2253 size_t pdu_size;
2254 int len;
2255 isns_target_t *src;
2258 * create DevDereg Message with all of target nodes
2260 pdu_size = isnst_create_pdu_header(ISNS_DEV_DEREG, pdu, 0);
2261 if (pdu_size == 0) {
2262 return (0);
2266 * Source attribute - Must be a storage node in the same
2267 * network entity.
2269 if (svr->svr_registered) {
2270 src = isnst_get_registered_source(svr);
2271 } else if (itarget != NULL) {
2272 src = itarget;
2273 } else {
2274 goto dereg_pdu_error;
2277 len = strlen(src->target_info->ti_tgt_name) + 1;
2278 if (isnst_add_attr(*pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
2279 len, src->target_info->ti_tgt_name, 0) != 0) {
2280 goto dereg_pdu_error;
2284 /* Delimiter */
2285 if (isnst_add_attr(*pdu, pdu_size, ISNS_DELIMITER_ATTR_ID,
2286 0, 0, 0) != 0) {
2287 goto dereg_pdu_error;
2291 * Operating attributes
2293 if (itarget == NULL) {
2294 /* dereg everything */
2295 len = strlen(isns_eid) + 1;
2296 if (isnst_add_attr(*pdu, pdu_size, ISNS_EID_ATTR_ID,
2297 len, isns_eid, 0) != 0) {
2298 goto dereg_pdu_error;
2300 } else {
2301 /* dereg one target only */
2302 len = strlen(itarget->target_info->ti_tgt_name) + 1;
2303 if (isnst_add_attr(*pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
2304 len, itarget->target_info->ti_tgt_name, 0) != 0) {
2305 goto dereg_pdu_error;
2309 return (pdu_size);
2311 dereg_pdu_error:
2312 kmem_free(*pdu, pdu_size);
2313 *pdu = NULL;
2315 return (0);
2318 static size_t
2319 isnst_make_keepalive_pdu(iscsit_isns_svr_t *svr, isns_pdu_t **pdu)
2321 size_t pdu_size;
2322 int len;
2323 isns_target_t *src;
2325 ASSERT(svr->svr_registered);
2328 * create DevAttrQuery Message
2330 pdu_size = isnst_create_pdu_header(ISNS_DEV_ATTR_QRY, pdu, 0);
2331 if (pdu_size == 0) {
2332 return (0);
2336 * Source attribute - Must be a iscsi target in the same
2337 * network entity.
2339 src = isnst_get_registered_source(svr);
2341 len = strlen(src->target_info->ti_tgt_name) + 1;
2342 if (isnst_add_attr(*pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
2343 len, src->target_info->ti_tgt_name, 0) != 0) {
2344 goto keepalive_pdu_error;
2347 /* EID */
2348 len = strlen(isns_eid) + 1;
2349 if (isnst_add_attr(*pdu, pdu_size, ISNS_EID_ATTR_ID,
2350 len, isns_eid, 0) != 0) {
2351 goto keepalive_pdu_error;
2353 /* Delimiter */
2354 if (isnst_add_attr(*pdu, pdu_size, ISNS_DELIMITER_ATTR_ID,
2355 0, 0, 0) != 0) {
2356 goto keepalive_pdu_error;
2359 /* Values to Fetch -- EID */
2360 if (isnst_add_attr(*pdu, pdu_size, ISNS_EID_ATTR_ID,
2361 0, 0, 0) != 0) {
2362 goto keepalive_pdu_error;
2366 return (pdu_size);
2368 keepalive_pdu_error:
2369 kmem_free(*pdu, pdu_size);
2370 *pdu = NULL;
2372 return (0);
2375 static isns_target_t *
2376 isnst_get_registered_source(iscsit_isns_svr_t *svr)
2378 isns_target_t *itarget;
2381 * If svr is registered, then there must be at least one
2382 * target that is registered to that svr.
2384 ISNS_GLOBAL_LOCK();
2385 ASSERT(svr->svr_monitor_hold);
2386 itarget = isnst_get_registered_source_locked(svr);
2387 ISNS_GLOBAL_UNLOCK();
2388 return (itarget);
2391 static isns_target_t *
2392 isnst_get_registered_source_locked(iscsit_isns_svr_t *svr)
2394 isns_target_t *itarget;
2396 ASSERT(ISNS_GLOBAL_LOCK_HELD());
2397 ASSERT(svr->svr_registered);
2398 ASSERT((avl_numnodes(&svr->svr_target_list) != 0));
2400 itarget = avl_first(&svr->svr_target_list);
2401 do {
2402 if (itarget->target_registered == B_TRUE)
2403 break;
2404 itarget = AVL_NEXT(&svr->svr_target_list, itarget);
2405 } while (itarget != NULL);
2406 ASSERT(itarget != NULL);
2407 return (itarget);
2410 static int
2411 isnst_verify_rsp(iscsit_isns_svr_t *svr, isns_pdu_t *pdu,
2412 isns_pdu_t *rsp, size_t rsp_size)
2414 uint16_t func_id;
2415 int payload_len, rsp_payload_len;
2416 int status;
2417 isns_resp_t *resp;
2418 uint8_t *pp;
2419 isns_tlv_t *attr;
2420 uint32_t attr_len, attr_id, esi_interval;
2423 * Ensure we have at least a valid header (don't count the
2424 * "payload" field.
2426 if (rsp_size < offsetof(isns_pdu_t, payload)) {
2427 ISNST_LOG(CE_WARN, "Invalid iSNS PDU header, %d of %d bytes",
2428 (int)rsp_size, (int)offsetof(isns_pdu_t, payload));
2429 return (-1);
2432 /* Make sure we have the amount of data that the header specifies */
2433 payload_len = ntohs(rsp->payload_len);
2434 if (rsp_size < (payload_len + offsetof(isns_pdu_t, payload))) {
2435 ISNST_LOG(CE_WARN, "Invalid iSNS response, %d of %d bytes",
2436 (int)rsp_size,
2437 (int)(payload_len + offsetof(isns_pdu_t, payload)));
2438 return (-1);
2441 /* Find the start of all operational parameters */
2442 rsp_payload_len = isnst_pdu_get_op(rsp, &pp);
2444 * Make sure isnst_pdu_get_op didn't encounter an error
2445 * in the attributes.
2447 if (pp == NULL) {
2448 return (-1);
2451 /* verify response transaction id */
2452 if (ntohs(rsp->xid) != ntohs(pdu->xid)) {
2453 return (-1);
2456 /* check the error code */
2457 resp = (isns_resp_t *)((void *)&rsp->payload[0]);
2459 status = ntohl(resp->status);
2461 /* validate response function id */
2462 func_id = ntohs(rsp->func_id);
2463 switch (ntohs(pdu->func_id)) {
2464 case ISNS_DEV_ATTR_REG:
2465 if (func_id != ISNS_DEV_ATTR_REG_RSP) {
2466 return (-1);
2469 /* Only look through response if msg status says OK */
2470 if (status != 0) {
2471 break;
2474 * Get the ESI interval returned by the server. It could
2475 * be different than what we asked for. We never know which
2476 * portal a request may come in on, and any server could demand
2477 * any interval. We'll simply keep track of the largest
2478 * interval for use in monitoring.
2481 attr = (isns_tlv_t *)((void *)pp);
2482 while (rsp_payload_len >= 8) {
2483 attr_len = ntohl(attr->attr_len);
2484 attr_id = ntohl(attr->attr_id);
2485 if (attr_id == ISNS_ESI_INTERVAL_ATTR_ID) {
2486 if (attr_len != 4 ||
2487 attr_len > rsp_payload_len - 8) {
2488 /* Mal-formed packet */
2489 return (-1);
2491 esi_interval =
2492 ntohl(*((uint32_t *)
2493 ((void *)(&attr->attr_value))));
2495 ISNS_GLOBAL_LOCK();
2496 ASSERT(svr->svr_monitor_hold);
2497 if (esi_interval > svr->svr_esi_interval)
2498 svr->svr_esi_interval = esi_interval;
2499 ISNS_GLOBAL_UNLOCK();
2501 break;
2503 rsp_payload_len -= (8 + attr_len);
2504 attr = (isns_tlv_t *)
2505 ((void *)((uint8_t *)attr + attr_len + 8));
2508 break;
2509 case ISNS_DEV_DEREG:
2510 if (func_id != ISNS_DEV_DEREG_RSP) {
2511 return (-1);
2513 break;
2514 case ISNS_DEV_ATTR_QRY:
2515 /* Keepalive Response */
2516 if (func_id != ISNS_DEV_ATTR_QRY_RSP) {
2517 return (-1);
2520 if (status == 0) {
2521 boolean_t found_eid = B_FALSE;
2523 /* Scan the operational parameters */
2524 attr = (isns_tlv_t *)((void *)pp);
2525 while (rsp_payload_len >= 8) {
2526 attr_len = ntohl(attr->attr_len);
2527 attr_id = ntohl(attr->attr_id);
2528 if (attr_id == ISNS_EID_ATTR_ID &&
2529 attr_len > 0 &&
2530 attr_len <= rsp_payload_len - 8) {
2532 * If the isns server knows us, the
2533 * response will include our EID in
2534 * the operational parameters, i.e.
2535 * after the delimiter.
2536 * Just receiving this pattern
2537 * is good enough to tell the isns
2538 * server still knows us.
2540 found_eid = B_TRUE;
2541 break;
2544 rsp_payload_len -= (8 + attr_len);
2545 attr = (isns_tlv_t *)
2546 ((void *)((uint8_t *)attr + attr_len + 8));
2548 if (! found_eid) {
2549 status = ISNS_RSP_NO_SUCH_ENTRY;
2552 if (status == ISNS_RSP_NO_SUCH_ENTRY) {
2553 char server_buf[IDM_SA_NTOP_BUFSIZ];
2555 * The iSNS server has forgotten about us.
2556 * We will re-register everything.
2557 * This can happen e.g. if ESI probes time out,
2558 * or if the iSNS server does a factory reset.
2560 ISNST_LOG(CE_WARN, "iscsit: iSNS server %s"
2561 " forgot about us and has to be reminded.",
2562 idm_sa_ntop(&svr->svr_sa,
2563 server_buf, sizeof (server_buf)));
2564 /* isnst_retry_registration will trigger the reset */
2567 break;
2569 default:
2570 ASSERT(0);
2571 break;
2574 /* Update the last time we heard from this server */
2575 if (status == 0) {
2576 ISNS_GLOBAL_LOCK();
2577 ASSERT(svr->svr_monitor_hold);
2578 svr->svr_last_msg = ddi_get_lbolt();
2579 ISNS_GLOBAL_UNLOCK();
2584 return (status);
2587 static uint16_t
2588 isnst_pdu_get_op(isns_pdu_t *pdu, uint8_t **pp)
2590 uint8_t *payload;
2591 uint16_t payload_len;
2592 isns_resp_t *resp;
2593 isns_tlv_t *attr;
2594 uint32_t attr_id;
2595 uint32_t tlv_len;
2597 /* get payload */
2598 payload_len = ntohs(pdu->payload_len);
2599 resp = (isns_resp_t *)((void *)&pdu->payload[0]);
2601 /* find the operating attributes */
2602 if (payload_len < sizeof (resp->status)) {
2603 ISNST_LOG(CE_WARN, "Invalid iSNS response, %d payload bytes",
2604 payload_len);
2605 *pp = NULL;
2606 return (0);
2609 payload_len -= sizeof (resp->status);
2610 payload = &resp->data[0];
2612 while (payload_len >= (sizeof (isns_tlv_t) - 1)) {
2613 attr = (isns_tlv_t *)((void *)payload);
2614 tlv_len = offsetof(isns_tlv_t, attr_value) +
2615 ntohl(attr->attr_len);
2616 if (payload_len >= tlv_len) {
2617 payload += tlv_len;
2618 payload_len -= tlv_len;
2619 attr_id = ntohl(attr->attr_id);
2620 if (attr_id == ISNS_DELIMITER_ATTR_ID) {
2621 break;
2623 } else {
2624 /* mal-formed packet */
2625 payload = NULL;
2626 payload_len = 0;
2630 *pp = payload;
2632 return (payload_len);
2635 static size_t
2636 isnst_create_pdu_header(uint16_t func_id, isns_pdu_t **pdu, uint16_t flags)
2638 size_t pdu_size = isns_message_buf_size;
2640 *pdu = (isns_pdu_t *)kmem_zalloc(pdu_size, KM_NOSLEEP);
2641 if (*pdu != NULL) {
2642 (*pdu)->version = htons((uint16_t)ISNSP_VERSION);
2643 (*pdu)->func_id = htons((uint16_t)func_id);
2644 (*pdu)->payload_len = htons(0);
2645 (*pdu)->flags = htons(flags);
2647 (*pdu)->xid = htons(GET_XID());
2648 (*pdu)->seq = htons(0);
2649 } else {
2650 pdu_size = 0;
2653 return (pdu_size);
2656 static int
2657 isnst_add_attr(isns_pdu_t *pdu,
2658 size_t max_pdu_size,
2659 uint32_t attr_id,
2660 uint32_t attr_len,
2661 void *attr_data,
2662 uint32_t attr_numeric_data)
2664 isns_tlv_t *attr_tlv;
2665 uint8_t *payload_ptr;
2666 uint16_t payload_len;
2667 uint32_t normalized_attr_len;
2668 uint64_t attr_tlv_len;
2670 /* The attribute length must be 4-byte aligned. Section 5.1.3. */
2671 normalized_attr_len = (attr_len % 4) == 0 ?
2672 (attr_len) : (attr_len + (4 - (attr_len % 4)));
2673 attr_tlv_len = ISNS_TLV_ATTR_ID_LEN +
2674 ISNS_TLV_ATTR_LEN_LEN + normalized_attr_len;
2676 /* Check if we are going to exceed the maximum PDU length. */
2677 payload_len = ntohs(pdu->payload_len);
2678 if ((payload_len + attr_tlv_len) > max_pdu_size) {
2679 return (1);
2682 attr_tlv = (isns_tlv_t *)kmem_zalloc(attr_tlv_len, KM_SLEEP);
2684 attr_tlv->attr_id = htonl(attr_id);
2686 switch (attr_id) {
2687 case ISNS_DELIMITER_ATTR_ID:
2688 break;
2690 case ISNS_PORTAL_IP_ADDR_ATTR_ID:
2691 case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID:
2692 if (attr_numeric_data == sizeof (in_addr_t)) {
2693 /* IPv4 */
2694 attr_tlv->attr_value[10] = 0xFF;
2695 attr_tlv->attr_value[11] = 0xFF;
2696 bcopy(attr_data, ((attr_tlv->attr_value) + 12),
2697 sizeof (in_addr_t));
2698 } else if (attr_numeric_data == sizeof (in6_addr_t)) {
2699 /* IPv6 */
2700 bcopy(attr_data, attr_tlv->attr_value,
2701 sizeof (in6_addr_t));
2702 } else if (attr_numeric_data == 0) {
2703 /* EMPTY */
2704 /* Do nothing */
2705 } else {
2706 kmem_free(attr_tlv, attr_tlv_len);
2707 attr_tlv = NULL;
2708 return (1);
2710 break;
2712 case ISNS_EID_ATTR_ID:
2713 case ISNS_ISCSI_NAME_ATTR_ID:
2714 case ISNS_ISCSI_ALIAS_ATTR_ID:
2715 case ISNS_PG_ISCSI_NAME_ATTR_ID:
2716 if (attr_len && attr_data) {
2717 bcopy((char *)attr_data,
2718 attr_tlv->attr_value, attr_len);
2720 break;
2722 default:
2723 if (attr_len == 8) {
2724 *(uint64_t *)((void *)attr_tlv->attr_value) =
2725 BE_64((uint64_t)attr_numeric_data);
2726 } else if (attr_len == 4) {
2727 *(uint32_t *)((void *)attr_tlv->attr_value) =
2728 htonl((uint32_t)attr_numeric_data);
2730 break;
2733 attr_tlv->attr_len = htonl(normalized_attr_len);
2735 * Convert the network byte ordered payload length to host byte
2736 * ordered for local address calculation.
2738 payload_len = ntohs(pdu->payload_len);
2739 payload_ptr = pdu->payload + payload_len;
2740 bcopy(attr_tlv, payload_ptr, attr_tlv_len);
2741 payload_len += attr_tlv_len;
2744 * Convert the host byte ordered payload length back to network
2745 * byte ordered - it's now ready to be sent on the wire.
2747 pdu->payload_len = htons(payload_len);
2749 kmem_free(attr_tlv, attr_tlv_len);
2750 attr_tlv = NULL;
2752 return (0);
2755 static void
2756 isnst_so_timeout(void *so)
2758 /* Wake up any sosend or sorecv blocked on this socket */
2759 idm_soshutdown(so);
2762 static int
2763 isnst_send_pdu(void *so, isns_pdu_t *pdu)
2765 size_t total_len, payload_len, send_len;
2766 uint8_t *payload;
2767 uint16_t flags, seq;
2768 timeout_id_t send_timer;
2769 iovec_t iov[2];
2770 int rc;
2772 ASSERT(! ISNS_GLOBAL_LOCK_HELD());
2774 /* update pdu flags */
2775 flags = ntohs(pdu->flags);
2776 flags |= ISNS_FLAG_CLIENT;
2777 flags |= ISNS_FLAG_FIRST_PDU;
2779 /* initalize sequence number */
2780 seq = 0;
2782 payload = pdu->payload;
2784 /* total payload length */
2785 total_len = ntohs(pdu->payload_len);
2787 /* fill in the pdu header */
2788 iov[0].iov_base = (void *)pdu;
2789 iov[0].iov_len = ISNSP_HEADER_SIZE;
2791 do {
2792 /* split the payload accordingly */
2793 if (total_len > ISNSP_MAX_PAYLOAD_SIZE) {
2794 payload_len = ISNSP_MAX_PAYLOAD_SIZE;
2795 } else {
2796 payload_len = total_len;
2797 /* set the last pdu flag */
2798 flags |= ISNS_FLAG_LAST_PDU;
2801 /* set back the pdu flags */
2802 pdu->flags = htons(flags);
2803 /* set the sequence number */
2804 pdu->seq = htons(seq);
2805 /* set the payload length */
2806 pdu->payload_len = htons(payload_len);
2808 /* fill in the payload */
2809 iov[1].iov_base = (void *)payload;
2810 iov[1].iov_len = payload_len;
2812 DTRACE_PROBE3(isnst__pdu__send, uint16_t, ntohs(pdu->func_id),
2813 uint16_t, ntohs(pdu->payload_len), caddr_t, pdu);
2815 /* send the pdu */
2816 send_len = ISNSP_HEADER_SIZE + payload_len;
2817 send_timer = timeout(isnst_so_timeout, so,
2818 drv_usectohz(isns_timeout_usec));
2819 rc = idm_iov_sosend(so, &iov[0], 2, send_len);
2820 (void) untimeout(send_timer);
2822 flags &= ~ISNS_FLAG_FIRST_PDU;
2823 payload += payload_len;
2824 total_len -= payload_len;
2826 /* increase the sequence number */
2827 seq ++;
2829 } while (rc == 0 && total_len > 0);
2831 return (rc);
2834 static size_t
2835 isnst_rcv_pdu(void *so, isns_pdu_t **pdu)
2837 size_t total_pdu_len;
2838 size_t total_payload_len;
2839 size_t payload_len;
2840 size_t combined_len;
2841 isns_pdu_t tmp_pdu_hdr;
2842 isns_pdu_t *combined_pdu;
2843 uint8_t *payload;
2844 uint8_t *combined_payload;
2845 timeout_id_t rcv_timer;
2846 uint16_t flags;
2847 uint16_t seq;
2849 ASSERT(! ISNS_GLOBAL_LOCK_HELD());
2851 *pdu = NULL;
2852 total_pdu_len = total_payload_len = 0;
2853 payload = NULL;
2854 seq = 0;
2856 do {
2857 /* receive the pdu header */
2858 rcv_timer = timeout(isnst_so_timeout, so,
2859 drv_usectohz(isns_timeout_usec));
2860 if (idm_sorecv(so, &tmp_pdu_hdr, ISNSP_HEADER_SIZE) != 0 ||
2861 ntohs(tmp_pdu_hdr.seq) != seq) {
2862 (void) untimeout(rcv_timer);
2863 goto rcv_error;
2865 (void) untimeout(rcv_timer);
2867 /* receive the payload */
2868 payload_len = ntohs(tmp_pdu_hdr.payload_len);
2869 if (payload_len > ISNST_MAX_MSG_SIZE) {
2870 goto rcv_error;
2872 payload = kmem_alloc(payload_len, KM_NOSLEEP);
2873 if (payload == NULL) {
2874 goto rcv_error;
2876 rcv_timer = timeout(isnst_so_timeout, so,
2877 drv_usectohz(ISNS_RCV_TIMER_SECONDS * 1000000));
2878 if (idm_sorecv(so, payload, payload_len) != 0) {
2879 (void) untimeout(rcv_timer);
2880 goto rcv_error;
2882 (void) untimeout(rcv_timer);
2884 /* combine the pdu if it is not the first one */
2885 if (total_pdu_len > 0) {
2886 combined_len = total_pdu_len + payload_len;
2887 combined_pdu = kmem_alloc(combined_len, KM_SLEEP);
2888 if (combined_pdu == NULL) {
2889 goto rcv_error;
2891 bcopy(*pdu, combined_pdu, total_pdu_len);
2892 combined_payload =
2893 &combined_pdu->payload[total_payload_len];
2894 bcopy(payload, combined_payload, payload_len);
2895 kmem_free(*pdu, total_pdu_len);
2896 kmem_free(payload, payload_len);
2897 *pdu = combined_pdu;
2898 total_payload_len += payload_len;
2899 total_pdu_len += payload_len;
2900 (*pdu)->payload_len = htons(total_payload_len);
2901 } else {
2902 total_payload_len = payload_len;
2903 total_pdu_len = ISNSP_HEADER_SIZE + payload_len;
2904 *pdu = kmem_alloc(total_pdu_len, KM_NOSLEEP);
2905 if (*pdu == NULL) {
2906 goto rcv_error;
2908 bcopy(&tmp_pdu_hdr, *pdu, ISNSP_HEADER_SIZE);
2909 bcopy(payload, &(*pdu)->payload[0], payload_len);
2910 kmem_free(payload, payload_len);
2912 payload = NULL;
2914 /* the flags of pdu which is just received */
2915 flags = ntohs(tmp_pdu_hdr.flags);
2917 /* increase sequence number by one */
2918 seq ++;
2919 } while ((flags & ISNS_FLAG_LAST_PDU) == 0);
2921 DTRACE_PROBE3(isnst__pdu__recv, uint16_t, ntohs((*pdu)->func_id),
2922 size_t, total_payload_len, caddr_t, *pdu);
2924 return (total_pdu_len);
2926 rcv_error:
2927 if (*pdu != NULL) {
2928 kmem_free(*pdu, total_pdu_len);
2929 *pdu = NULL;
2931 if (payload != NULL) {
2932 kmem_free(payload, payload_len);
2934 return (0);
2937 static void *
2938 isnst_open_so(struct sockaddr_storage *sa)
2940 int sa_sz;
2941 ksocket_t so;
2943 ASSERT(! ISNS_GLOBAL_LOCK_HELD());
2945 /* determine local IP address */
2946 if (sa->ss_family == AF_INET) {
2947 /* IPv4 */
2948 sa_sz = sizeof (struct sockaddr_in);
2950 /* Create socket */
2951 so = idm_socreate(AF_INET, SOCK_STREAM, 0);
2952 } else {
2953 /* IPv6 */
2954 sa_sz = sizeof (struct sockaddr_in6);
2956 /* Create socket */
2957 so = idm_socreate(AF_INET6, SOCK_STREAM, 0);
2960 if (so != NULL) {
2961 if (idm_so_timed_socket_connect(so, sa, sa_sz,
2962 isns_timeout_usec) != 0) {
2963 /* not calling isnst_close_so() to */
2964 /* make dtrace output look clear */
2965 idm_soshutdown(so);
2966 idm_sodestroy(so);
2967 so = NULL;
2971 if (so == NULL) {
2972 char server_buf[IDM_SA_NTOP_BUFSIZ];
2973 ISNST_LOG(CE_WARN, "open iSNS Server %s failed",
2974 idm_sa_ntop(sa, server_buf,
2975 sizeof (server_buf)));
2976 DTRACE_PROBE1(isnst__connect__fail,
2977 struct sockaddr_storage *, sa);
2980 return (so);
2983 static void
2984 isnst_close_so(void *so)
2986 idm_soshutdown(so);
2987 idm_sodestroy(so);
2991 * ESI handling
2994 static void
2995 isnst_esi_start(void)
2997 if (isns_use_esi == B_FALSE) {
2998 ISNST_LOG(CE_NOTE, "ESI disabled by isns_use_esi=FALSE");
2999 return;
3002 ISNST_LOG(CE_NOTE, "isnst_esi_start");
3004 mutex_enter(&esi.esi_mutex);
3005 ASSERT(esi.esi_enabled == B_FALSE);
3006 ASSERT(esi.esi_thread_running == B_FALSE);
3008 esi.esi_enabled = B_TRUE;
3009 esi.esi_valid = B_FALSE;
3010 esi.esi_thread = thread_create(NULL, 0, isnst_esi_thread,
3011 (void *)&esi, 0, &p0, TS_RUN, minclsyspri);
3014 * Wait for the thread to start
3016 while (!esi.esi_thread_running) {
3017 cv_wait(&esi.esi_cv, &esi.esi_mutex);
3019 mutex_exit(&esi.esi_mutex);
3022 static void
3023 isnst_esi_stop()
3025 boolean_t need_offline = B_FALSE;
3027 ISNST_LOG(CE_NOTE, "isnst_esi_stop");
3029 /* Shutdown ESI listening socket, wait for thread to terminate */
3030 mutex_enter(&esi.esi_mutex);
3031 if (esi.esi_enabled) {
3032 esi.esi_enabled = B_FALSE;
3033 if (esi.esi_valid) {
3034 need_offline = B_TRUE;
3036 mutex_exit(&esi.esi_mutex);
3037 if (need_offline) {
3038 idm_soshutdown(esi.esi_so);
3039 idm_sodestroy(esi.esi_so);
3041 thread_join(esi.esi_thread_did);
3042 } else {
3043 mutex_exit(&esi.esi_mutex);
3048 * isnst_esi_thread
3050 * This function listens on a socket for incoming connections from an
3051 * iSNS server until told to stop.
3054 /*ARGSUSED*/
3055 static void
3056 isnst_esi_thread(void *arg)
3058 ksocket_t newso;
3059 struct sockaddr_in6 sin6;
3060 socklen_t sin_addrlen;
3061 uint32_t on = 1;
3062 int rc;
3063 isns_pdu_t *pdu;
3064 size_t pl_size;
3066 bzero(&sin6, sizeof (struct sockaddr_in6));
3067 sin_addrlen = sizeof (struct sockaddr_in6);
3069 esi.esi_thread_did = curthread->t_did;
3071 mutex_enter(&esi.esi_mutex);
3074 * Mark the thread as running and the portal as no longer new.
3076 esi.esi_thread_running = B_TRUE;
3077 cv_signal(&esi.esi_cv);
3079 while (esi.esi_enabled) {
3081 * Create a socket to listen for requests from the iSNS server.
3083 if ((esi.esi_so = idm_socreate(PF_INET6, SOCK_STREAM, 0)) ==
3084 NULL) {
3085 ISNST_LOG(CE_WARN,
3086 "isnst_esi_thread: Unable to create socket");
3087 mutex_exit(&esi.esi_mutex);
3088 ddi_sleep(1);
3089 mutex_enter(&esi.esi_mutex);
3090 continue;
3094 * Set options, bind, and listen until we're told to stop
3096 bzero(&sin6, sizeof (sin6));
3097 sin6.sin6_family = AF_INET6;
3098 sin6.sin6_port = htons(0);
3099 sin6.sin6_addr = in6addr_any;
3101 (void) ksocket_setsockopt(esi.esi_so, SOL_SOCKET,
3102 SO_REUSEADDR, (char *)&on, sizeof (on), CRED());
3104 if (ksocket_bind(esi.esi_so, (struct sockaddr *)&sin6,
3105 sizeof (sin6), CRED()) != 0) {
3106 ISNST_LOG(CE_WARN, "Unable to bind socket for ESI");
3107 idm_sodestroy(esi.esi_so);
3108 mutex_exit(&esi.esi_mutex);
3109 ddi_sleep(1);
3110 mutex_enter(&esi.esi_mutex);
3111 continue;
3115 * Get the port (sin6 is meaningless at this point)
3117 (void) ksocket_getsockname(esi.esi_so,
3118 (struct sockaddr *)(&sin6), &sin_addrlen, CRED());
3119 esi.esi_port =
3120 ntohs(((struct sockaddr_in6 *)(&sin6))->sin6_port);
3122 if ((rc = ksocket_listen(esi.esi_so, 5, CRED())) != 0) {
3123 ISNST_LOG(CE_WARN, "isnst_esi_thread: listen "
3124 "failure 0x%x", rc);
3125 idm_sodestroy(esi.esi_so);
3126 mutex_exit(&esi.esi_mutex);
3127 ddi_sleep(1);
3128 mutex_enter(&esi.esi_mutex);
3129 continue;
3132 ksocket_hold(esi.esi_so);
3133 esi.esi_valid = B_TRUE;
3134 while (esi.esi_enabled) {
3135 mutex_exit(&esi.esi_mutex);
3137 DTRACE_PROBE3(iscsit__isns__esi__accept__wait,
3138 boolean_t, esi.esi_enabled,
3139 ksocket_t, esi.esi_so,
3140 struct sockaddr_in6, &sin6);
3141 if ((rc = ksocket_accept(esi.esi_so, NULL, NULL,
3142 &newso, CRED())) != 0) {
3143 mutex_enter(&esi.esi_mutex);
3144 DTRACE_PROBE2(iscsit__isns__esi__accept__fail,
3145 int, rc, boolean_t, esi.esi_enabled);
3147 * If we were interrupted with EINTR
3148 * it's not really a failure.
3150 ISNST_LOG(CE_WARN, "isnst_esi_thread: "
3151 "accept failure (0x%x)", rc);
3153 if (rc == EINTR) {
3154 continue;
3155 } else {
3156 break;
3159 DTRACE_PROBE2(iscsit__isns__esi__accept,
3160 boolean_t, esi.esi_enabled,
3161 ksocket_t, newso);
3163 pl_size = isnst_rcv_pdu(newso, &pdu);
3164 if (pl_size == 0) {
3165 ISNST_LOG(CE_WARN, "isnst_esi_thread: "
3166 "rcv_pdu failure");
3167 idm_soshutdown(newso);
3168 idm_sodestroy(newso);
3170 mutex_enter(&esi.esi_mutex);
3171 continue;
3174 isnst_handle_esi_req(newso, pdu, pl_size);
3176 idm_soshutdown(newso);
3177 idm_sodestroy(newso);
3179 mutex_enter(&esi.esi_mutex);
3182 idm_soshutdown(esi.esi_so);
3183 ksocket_rele(esi.esi_so);
3184 esi.esi_valid = B_FALSE;
3187 * If we're going to try to re-establish the listener then
3188 * destroy this socket. Otherwise isnst_esi_stop already
3189 * destroyed it.
3191 if (esi.esi_enabled)
3192 idm_sodestroy(esi.esi_so);
3195 esi.esi_thread_running = B_FALSE;
3196 cv_signal(&esi.esi_cv);
3197 mutex_exit(&esi.esi_mutex);
3198 esi_thread_exit:
3199 thread_exit();
3203 * Handle an incoming ESI request
3206 static void
3207 isnst_handle_esi_req(ksocket_t ks, isns_pdu_t *pdu, size_t pdu_size)
3209 isns_pdu_t *rsp_pdu;
3210 isns_resp_t *rsp;
3211 isns_tlv_t *attr;
3212 uint32_t attr_len, attr_id;
3213 size_t req_pl_len, rsp_size, tlv_len;
3214 struct sockaddr_storage portal_ss;
3215 struct sockaddr_storage server_ss;
3216 struct sockaddr_in6 *portal_addr6;
3217 boolean_t portal_addr_valid = B_FALSE;
3218 boolean_t portal_port_valid = B_FALSE;
3219 uint32_t esi_response = ISNS_RSP_SUCCESSFUL;
3220 isns_portal_t *iportal;
3221 socklen_t sa_len;
3224 if (ntohs(pdu->func_id) != ISNS_ESI) {
3225 ISNST_LOG(CE_WARN, "isnst_handle_esi_req: Unexpected func 0x%x",
3226 pdu->func_id);
3227 kmem_free(pdu, pdu_size);
3228 return;
3231 req_pl_len = ntohs(pdu->payload_len);
3232 if (req_pl_len + offsetof(isns_pdu_t, payload) > pdu_size) {
3233 ISNST_LOG(CE_WARN, "isnst_handle_esi_req: "
3234 "payload exceeds PDU size (%d > %d)",
3235 (int)(req_pl_len + offsetof(isns_pdu_t, payload)),
3236 (int)pdu_size);
3237 /* Not all data is present -- ignore */
3238 kmem_free(pdu, pdu_size);
3239 return;
3242 if (req_pl_len + sizeof (uint32_t) > ISNSP_MAX_PAYLOAD_SIZE) {
3243 ISNST_LOG(CE_WARN,
3244 "isnst_handle_esi_req: PDU payload exceeds max (%ld bytes)",
3245 req_pl_len + sizeof (uint32_t));
3246 kmem_free(pdu, pdu_size);
3247 return;
3251 * Check portal in ESI request and make sure it is valid. Return
3252 * esi_response of ISNS_RSP_SUCCESSFUL if valid, otherwise don't
3253 * respond at all. Get IP addr and port. Format of ESI
3254 * is:
3256 * ISNS_TIMESTAMP_ATTR_ID,
3257 * ISNS_EID_ATTR_ID,
3258 * ISNS_PORTAL_IP_ADDR_ATTR_ID,
3259 * ISNS_PORTAL_PORT_ATTR_ID
3261 bzero(&portal_ss, sizeof (struct sockaddr_storage));
3262 portal_ss.ss_family = AF_INET6;
3263 portal_addr6 = (struct sockaddr_in6 *)&portal_ss;
3264 attr = (isns_tlv_t *)((void *)&pdu->payload);
3265 attr_len = ntohl(attr->attr_len);
3266 attr_id = ntohl(attr->attr_id);
3267 tlv_len = attr_len + offsetof(isns_tlv_t, attr_value);
3268 while (tlv_len <= req_pl_len) {
3269 switch (attr_id) {
3270 case ISNS_TIMESTAMP_ATTR_ID:
3271 break;
3272 case ISNS_EID_ATTR_ID:
3273 break;
3274 case ISNS_PORTAL_IP_ADDR_ATTR_ID:
3275 if (attr_len > sizeof (struct in6_addr)) {
3276 /* Bad attribute format */
3277 esi_response = ISNS_RSP_MSG_FORMAT_ERROR;
3278 } else {
3279 portal_addr6->sin6_family = AF_INET6;
3280 attr_len = min(attr_len,
3281 sizeof (portal_addr6->sin6_addr));
3282 bcopy(attr->attr_value,
3283 portal_addr6->sin6_addr.s6_addr, attr_len);
3284 portal_addr_valid = B_TRUE;
3286 break;
3287 case ISNS_PORTAL_PORT_ATTR_ID:
3288 if (attr_len > sizeof (uint32_t)) {
3289 /* Bad attribute format */
3290 esi_response = ISNS_RSP_MSG_FORMAT_ERROR;
3291 } else {
3292 portal_addr6->sin6_port =
3293 htons((uint16_t)BE_IN32(attr->attr_value));
3294 portal_port_valid = B_TRUE;
3296 break;
3297 default:
3298 /* Bad request format */
3299 esi_response = ISNS_RSP_MSG_FORMAT_ERROR;
3300 break;
3303 /* If we've set an error then stop processing */
3304 if (esi_response != ISNS_RSP_SUCCESSFUL) {
3305 break;
3308 /* Get next attribute */
3309 req_pl_len -= tlv_len;
3310 attr = (isns_tlv_t *)((void *)((uint8_t *)attr + tlv_len));
3311 attr_len = ntohl(attr->attr_len);
3312 attr_id = ntohl(attr->attr_id);
3313 tlv_len = attr_len + offsetof(isns_tlv_t, attr_value);
3316 if (!portal_port_valid)
3317 portal_addr6->sin6_port = htons(ISCSI_LISTEN_PORT);
3319 if (!portal_addr_valid) {
3320 esi_response = ISNS_RSP_MSG_FORMAT_ERROR;
3324 * If we've detected an error or if the portal does not
3325 * exist then drop the request. The server will eventually
3326 * timeout the portal and eliminate it from the list.
3329 if (esi_response != ISNS_RSP_SUCCESSFUL) {
3330 kmem_free(pdu, pdu_size);
3331 return;
3334 /* Get the remote peer's IP address */
3335 bzero(&server_ss, sizeof (server_ss));
3336 sa_len = sizeof (server_ss);
3337 if (ksocket_getpeername(ks, (struct sockaddr *)&server_ss, &sa_len,
3338 CRED())) {
3339 return;
3342 if (iscsit_isns_logging) {
3343 char server_buf[IDM_SA_NTOP_BUFSIZ];
3344 char portal_buf[IDM_SA_NTOP_BUFSIZ];
3345 ISNST_LOG(CE_NOTE, "ESI: svr %s -> portal %s",
3346 idm_sa_ntop(&server_ss, server_buf,
3347 sizeof (server_buf)),
3348 idm_sa_ntop(&portal_ss, portal_buf,
3349 sizeof (portal_buf)));
3353 ISNS_GLOBAL_LOCK();
3354 if (isnst_lookup_portal(&portal_ss) == NULL) {
3355 ISNST_LOG(CE_WARN, "ESI req to non-active portal");
3356 ISNS_GLOBAL_UNLOCK();
3357 kmem_free(pdu, pdu_size);
3358 return;
3362 * Update the server timestamp of how recently we have
3363 * received an ESI request from this iSNS server.
3364 * We ignore requests from servers we don't know.
3366 if (! isnst_update_server_timestamp(&server_ss)) {
3367 ISNST_LOG(CE_WARN, "ESI req from unknown server");
3368 kmem_free(pdu, pdu_size);
3369 ISNS_GLOBAL_UNLOCK();
3370 return;
3374 * Update ESI timestamps for all portals with same IP address.
3376 for (iportal = avl_first(&isns_all_portals);
3377 iportal != NULL;
3378 iportal = AVL_NEXT(&isns_all_portals, iportal)) {
3379 if (idm_ss_compare(&iportal->portal_addr, &portal_ss,
3380 B_TRUE, B_FALSE)) {
3381 gethrestime(&iportal->portal_esi_timestamp);
3385 ISNS_GLOBAL_UNLOCK();
3389 * Build response validating the portal
3391 rsp_size = isnst_create_pdu_header(ISNS_ESI_RSP, &rsp_pdu, 0);
3393 if (rsp_size == 0) {
3394 ISNST_LOG(CE_WARN, "isnst_handle_esi_req: Can't get rsp pdu");
3395 kmem_free(pdu, pdu_size);
3396 return;
3399 rsp = (isns_resp_t *)((void *)(&rsp_pdu->payload[0]));
3401 /* Use xid from the request pdu */
3402 rsp_pdu->xid = pdu->xid;
3403 rsp->status = htonl(ISNS_RSP_SUCCESSFUL);
3405 /* Copy original data */
3406 req_pl_len = ntohs(pdu->payload_len);
3407 bcopy(pdu->payload, rsp->data, req_pl_len);
3408 rsp_pdu->payload_len = htons(req_pl_len + sizeof (uint32_t));
3410 if (isnst_send_pdu(ks, rsp_pdu) != 0) {
3411 ISNST_LOG(CE_WARN,
3412 "isnst_handle_esi_req: Send response failed");
3415 kmem_free(rsp_pdu, rsp_size);
3416 kmem_free(pdu, pdu_size);
3420 static int
3421 isnst_tgt_avl_compare(const void *t1, const void *t2)
3423 const isns_target_t *tgt1 = t1;
3424 const isns_target_t *tgt2 = t2;
3427 * Sort by target (pointer to iscsit_tgt_t).
3430 if (tgt1->target < tgt2->target) {
3431 return (-1);
3432 } else if (tgt1->target > tgt2->target) {
3433 return (1);
3436 return (0);
3439 static void
3440 isnst_set_server_status(iscsit_isns_svr_t *svr, boolean_t registered)
3442 isns_target_t *itarget;
3444 ASSERT(ISNS_GLOBAL_LOCK_HELD());
3446 svr->svr_reset_needed = B_FALSE;
3447 if (registered == B_TRUE) {
3448 svr->svr_registered = B_TRUE;
3449 svr->svr_last_msg = ddi_get_lbolt();
3450 itarget = avl_first(&svr->svr_target_list);
3451 while (itarget) {
3452 isns_target_t *next_target;
3453 next_target = AVL_NEXT(&svr->svr_target_list, itarget);
3454 if (itarget->target_delete_needed) {
3455 /* All deleted tgts removed */
3456 isnst_clear_from_target_list(itarget,
3457 &svr->svr_target_list);
3458 } else {
3459 /* Other tgts marked registered */
3460 itarget->target_registered = B_TRUE;
3461 /* No updates needed -- clean slate */
3462 itarget->target_update_needed = B_FALSE;
3464 itarget = next_target;
3466 ASSERT(avl_numnodes(&svr->svr_target_list) > 0);
3467 } else {
3468 svr->svr_registered = B_FALSE;
3469 isnst_clear_target_list(svr);
3473 static void
3474 isnst_monitor_default_portal_list(void)
3476 idm_addr_list_t *new_portal_list = NULL;
3477 uint32_t new_portal_list_size = 0;
3479 ASSERT(ISNS_GLOBAL_LOCK_HELD());
3480 ASSERT(mutex_owned(&iscsit_isns_mutex));
3482 if (default_portal_online) {
3483 new_portal_list_size = idm_get_ipaddr(&new_portal_list);
3487 * We compute a new list of portals if
3488 * a) Something in itadm has changed a portal
3489 * b) there are new default portals
3490 * c) the default portal has gone offline
3492 if (isns_portals_changed ||
3493 ((new_portal_list_size != 0) &&
3494 (isnst_find_default_portals(new_portal_list) !=
3495 num_default_portals)) ||
3496 ((new_portal_list_size == 0) && (num_default_portals > 0))) {
3498 isnst_clear_default_portals();
3499 isnst_copy_portal_list(&isns_tpg_portals,
3500 &isns_all_portals);
3501 num_tpg_portals = avl_numnodes(&isns_all_portals);
3502 if (new_portal_list_size != 0) {
3503 num_default_portals =
3504 isnst_add_default_portals(new_portal_list);
3508 /* Catch any case where we miss an update to TPG portals */
3509 ASSERT(num_tpg_portals == avl_numnodes(&isns_tpg_portals));
3511 if (new_portal_list != NULL) {
3512 kmem_free(new_portal_list, new_portal_list_size);
3517 static int
3518 isnst_find_default_portals(idm_addr_list_t *alist)
3520 idm_addr_t *dportal;
3521 isns_portal_t *iportal;
3522 struct sockaddr_storage sa;
3523 int aidx;
3524 int num_portals_found = 0;
3526 for (aidx = 0; aidx < alist->al_out_cnt; aidx++) {
3527 dportal = &alist->al_addrs[aidx];
3528 dportal->a_port = ISCSI_LISTEN_PORT;
3529 idm_addr_to_sa(dportal, &sa);
3530 iportal = isnst_lookup_portal(&sa);
3531 if (iportal == NULL) {
3532 /* Found a non-matching default portal */
3533 return (-1);
3535 if (iportal->portal_default) {
3536 num_portals_found++;
3539 return (num_portals_found);
3542 static void
3543 isnst_clear_default_portals(void)
3545 ASSERT(ISNS_GLOBAL_LOCK_HELD());
3547 isnst_clear_portal_list(&isns_all_portals);
3548 num_tpg_portals = 0;
3549 num_default_portals = 0;
3552 static int
3553 isnst_add_default_portals(idm_addr_list_t *alist)
3555 idm_addr_t *dportal;
3556 isns_portal_t *iportal;
3557 struct sockaddr_storage sa;
3558 int aidx;
3560 for (aidx = 0; aidx < alist->al_out_cnt; aidx++) {
3561 dportal = &alist->al_addrs[aidx];
3562 dportal->a_port = ISCSI_LISTEN_PORT;
3563 idm_addr_to_sa(dportal, &sa);
3564 iportal = isnst_add_to_portal_list(&sa, &isns_all_portals);
3565 iportal->portal_default = B_TRUE;
3567 return (alist->al_out_cnt);
3571 static int
3572 isnst_portal_avl_compare(const void *p1, const void *p2)
3574 const isns_portal_t *portal1 = p1;
3575 const isns_portal_t *portal2 = p2;
3577 return (idm_ss_compare(&portal1->portal_addr, &portal2->portal_addr,
3578 B_TRUE /* v4_mapped_as_v4 */, B_TRUE /* compare_ports */));
3581 static void
3582 isnst_clear_portal_list(avl_tree_t *portal_list)
3584 isns_portal_t *iportal;
3585 void *cookie = NULL;
3587 while ((iportal = avl_destroy_nodes(portal_list, &cookie)) != NULL) {
3588 kmem_free(iportal, sizeof (isns_portal_t));
3591 static void
3592 isnst_copy_portal_list(avl_tree_t *t1, avl_tree_t *t2)
3594 isns_portal_t *iportal, *jportal;
3596 iportal = (isns_portal_t *)avl_first(t1);
3597 while (iportal) {
3598 jportal = isnst_add_to_portal_list(&iportal->portal_addr, t2);
3599 jportal->portal_iscsit = iportal->portal_iscsit;
3600 iportal = AVL_NEXT(t1, iportal);
3605 static isns_portal_t *
3606 isnst_lookup_portal(struct sockaddr_storage *sa)
3608 isns_portal_t *iportal, tmp_portal;
3609 ASSERT(ISNS_GLOBAL_LOCK_HELD());
3611 bcopy(sa, &tmp_portal.portal_addr, sizeof (*sa));
3612 iportal = avl_find(&isns_all_portals, &tmp_portal, NULL);
3613 return (iportal);
3616 static isns_portal_t *
3617 isnst_add_to_portal_list(struct sockaddr_storage *sa, avl_tree_t *portal_list)
3619 isns_portal_t *iportal, tmp_portal;
3620 avl_index_t where;
3622 * Make sure this portal isn't already in our list.
3625 bcopy(sa, &tmp_portal.portal_addr, sizeof (*sa));
3627 if ((iportal = (isns_portal_t *)avl_find(portal_list,
3628 &tmp_portal, &where)) == NULL) {
3629 iportal = kmem_zalloc(sizeof (isns_portal_t), KM_SLEEP);
3630 bcopy(sa, &iportal->portal_addr, sizeof (*sa));
3631 avl_insert(portal_list, (void *)iportal, where);
3634 return (iportal);
3638 static void
3639 isnst_remove_from_portal_list(struct sockaddr_storage *sa,
3640 avl_tree_t *portal_list)
3642 isns_portal_t *iportal, tmp_portal;
3644 bcopy(sa, &tmp_portal.portal_addr, sizeof (*sa));
3646 if ((iportal = avl_find(portal_list, &tmp_portal, NULL))
3647 != NULL) {
3648 avl_remove(portal_list, iportal);
3649 kmem_free(iportal, sizeof (isns_portal_t));
3654 * These functions are called by iscsit proper when a portal comes online
3655 * or goes offline.
3658 void
3659 iscsit_isns_portal_online(iscsit_portal_t *portal)
3661 isns_portal_t *iportal;
3663 mutex_enter(&iscsit_isns_mutex);
3665 if (portal->portal_default) {
3666 /* Portals should only be onlined once */
3667 ASSERT(default_portal_online == B_FALSE);
3668 default_portal_online = B_TRUE;
3669 } else {
3670 iportal = isnst_add_to_portal_list(
3671 &portal->portal_addr, &isns_tpg_portals);
3672 iportal->portal_iscsit = portal;
3674 isns_portals_changed = B_TRUE;
3676 mutex_exit(&iscsit_isns_mutex);
3678 isnst_monitor_awaken();
3681 void
3682 iscsit_isns_portal_offline(iscsit_portal_t *portal)
3684 mutex_enter(&iscsit_isns_mutex);
3686 if (portal->portal_default) {
3687 /* Portals should only be offlined once */
3688 ASSERT(default_portal_online == B_TRUE);
3689 default_portal_online = B_FALSE;
3690 } else {
3691 isnst_remove_from_portal_list(&portal->portal_addr,
3692 &isns_tpg_portals);
3694 isns_portals_changed = B_TRUE;
3696 mutex_exit(&iscsit_isns_mutex);
3698 isnst_monitor_awaken();