XXXX introduce drv_sectohz

   1 /*
   2  * CDDL HEADER START
   3  *
   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.
   7  *
   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.
  12  *
  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]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  23  */
  24 
  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>
  34 
  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>
  43 
  44 #include "iscsit.h"
  45 #include "iscsit_isns.h"
  46 
  47 /*
  48  * iscsit_isns.c -- isns client that is part of the iscsit server
  49  *
  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
  55  *
  56  * We send only two kinds of DevAttrReg messages.
  57  *
  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)
  67  *
  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)
  73  *
  74  * Interfaces to iscsit
  75  *
  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
  83  *
  84  * Copying Data Structures
  85  *
  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.
  91  *
  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.
  98  *
  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.
 103  *
 104  * Invariants
 105  *
 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.)
 114  */
 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
 120 
 121 #define VALID_NAME(NAME, LEN)   \
 122 ((LEN) > 0 && (NAME)[0] != 0 && (NAME)[(LEN) - 1] == 0)
 123 
 124 
 125 #define ISNST_LOG if (iscsit_isns_logging) cmn_err
 126 
 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;
 131 
 132 static kcondvar_t       isns_idle_cv;
 133 
 134 static uint16_t         xid;
 135 #define GET_XID()       atomic_inc_16_nv(&xid)
 136 
 137 static clock_t          monitor_idle_interval;
 138 
 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)
 142 
 143 #define ISNS_GLOBAL_LOCK_HELD() \
 144         MUTEX_HELD(&iscsit_global.global_isns_cfg.isns_mutex)
 145 
 146 #define ISNS_GLOBAL_UNLOCK() \
 147         mutex_exit(&iscsit_global.global_isns_cfg.isns_mutex)
 148 
 149 /*
 150  * "Configurable" parameters (set in /etc/system for now).
 151  */
 152 boolean_t iscsit_isns_logging = B_FALSE;
 153 
 154 
 155 /*
 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.
 159  */
 160 int     isns_max_retry = MAX_RETRY;
 161 
 162 /*
 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.
 166  */
 167 boolean_t       isns_use_esi = B_FALSE;
 168 
 169 /*
 170  * Interval to request ESI probes at, in seconds.  The server is free
 171  * to specify a different frequency in its response.
 172  */
 173 int     isns_default_esi_interval = ISNS_DEFAULT_ESI_INTERVAL;
 174 
 175 
 176 /*
 177  * Registration Period -- we guarantee to check in with iSNS server at
 178  * least this often.  Used when ESI probes are turned off.
 179  */
 180 int     isns_registration_period = ISNS_DEFAULT_REGISTRATION_PERIOD;
 181 
 182 /*
 183  * Socket connect, PDU receive, and PDU send must complete
 184  * within this number of microseconds.
 185  */
 186 uint32_t        isns_timeout_usec = ISNS_RCV_TIMER_SECONDS * 1000000;
 187 
 188 
 189 /*
 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.
 194  */
 195 uint32_t        isns_message_buf_size = ISNSP_MAX_PDU_SIZE;
 196 
 197 /*
 198  * Number of seconds to wait after isnst_monitor thread starts up
 199  * before sending first DevAttrReg message.
 200  */
 201 int     isns_initial_delay = ISNS_INITIAL_DELAY;
 202 
 203 /*
 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
 208  */
 209 boolean_t isns_modify_must_replace = B_TRUE;
 210 
 211 /* If PDU sizes ever go over the following, we need to rearchitect */
 212 #define ISNST_MAX_MSG_SIZE (16 * ISNSP_MAX_PDU_SIZE)
 213 
 214 /*
 215  * iSNS ESI thread state
 216  */
 217 static isns_esi_tinfo_t esi;
 218 
 219 /*
 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.
 227  */
 228 static kmutex_t         iscsit_isns_mutex;
 229 static avl_tree_t       isns_target_list;
 230 static boolean_t        isns_targets_changed;
 231 
 232 /*
 233  * List of portals from TPGs.  Protected by iscsit_isns_mutex.
 234  */
 235 static boolean_t        isns_portals_changed;
 236 static avl_tree_t       isns_tpg_portals;
 237 static boolean_t        default_portal_online;
 238 
 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;
 243 
 244 /*
 245  * Our entity identifier (fully-qualified hostname). Passed in from libiscsit.
 246  */
 247 static char             *isns_eid = NULL;
 248 
 249 /*
 250  * in6addr_any is currently all zeroes, but use the macro in case this
 251  * ever changes.
 252  */
 253 static const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
 254 
 255 static void
 256 isnst_start();
 257 
 258 static void
 259 isnst_stop();
 260 
 261 static void
 262 iscsit_set_isns(boolean_t state);
 263 
 264 static void
 265 iscsit_add_isns(it_portal_t *cfg_svr);
 266 
 267 static void
 268 isnst_mark_delete_isns(iscsit_isns_svr_t *svr);
 269 
 270 static void
 271 isnst_finish_delete_isns(iscsit_isns_svr_t *svr);
 272 
 273 static iscsit_isns_svr_t *
 274 iscsit_isns_svr_lookup(struct sockaddr_storage *sa);
 275 
 276 static void
 277 isnst_monitor(void *arg);
 278 
 279 static int
 280 isnst_monitor_one_server(iscsit_isns_svr_t *svr, boolean_t enabled);
 281 
 282 static void
 283 isnst_monitor_awaken(void);
 284 
 285 static boolean_t
 286 isnst_update_server_timestamp(struct sockaddr_storage *sa);
 287 
 288 static void
 289 isnst_copy_global_status_changes(void);
 290 
 291 static void
 292 isnst_mark_deleted_targets(iscsit_isns_svr_t *svr);
 293 
 294 static  int
 295 isnst_update_one_server(iscsit_isns_svr_t *svr, isns_target_t *target,
 296     isns_reg_type_t reg);
 297 
 298 static boolean_t isnst_retry_registration(int rsp_status_code);
 299 
 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);
 303 
 304 static size_t
 305 isnst_make_dereg_pdu(iscsit_isns_svr_t *svr, isns_pdu_t **pdu,
 306     isns_target_t *itarge);
 307 
 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);
 311 
 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);
 316 
 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);
 320 
 321 static uint16_t
 322 isnst_pdu_get_op(isns_pdu_t *pdu, uint8_t **pp);
 323 
 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);
 327 
 328 static int
 329 isnst_reg_pdu_add_entity_portals(isns_pdu_t *pdu, size_t pdu_size);
 330 
 331 static int
 332 isnst_reg_pdu_add_pg(isns_pdu_t *pdu, size_t pdu_size, isns_target_t *target);
 333 
 334 static int
 335 isnst_add_default_pg(isns_pdu_t *pdu, size_t pdu_size,
 336     avl_tree_t *null_portal_list);
 337 
 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);
 341 
 342 static int
 343 isnst_add_null_pg(isns_pdu_t *pdu, size_t pdu_size,
 344     avl_tree_t *null_portal_list);
 345 
 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);
 350 
 351 static size_t
 352 isnst_create_pdu_header(uint16_t func_id, isns_pdu_t **pdu, uint16_t flags);
 353 
 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);
 361 
 362 static int
 363 isnst_send_pdu(void *so, isns_pdu_t *pdu);
 364 
 365 static size_t
 366 isnst_rcv_pdu(void *so, isns_pdu_t **pdu);
 367 
 368 static void *
 369 isnst_open_so(struct sockaddr_storage *sa);
 370 
 371 static void
 372 isnst_close_so(void *);
 373 
 374 static void
 375 isnst_esi_thread(void *arg);
 376 
 377 static void
 378 isnst_handle_esi_req(ksocket_t so, isns_pdu_t *pdu, size_t pl_size);
 379 
 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);
 392 
 393 static void
 394 isnst_monitor_default_portal_list(void);
 395 
 396 static int
 397 isnst_find_default_portals(idm_addr_list_t *alist);
 398 
 399 static int
 400 isnst_add_default_portals(idm_addr_list_t *alist);
 401 
 402 static void
 403 isnst_clear_default_portals(void);
 404 
 405 
 406 static void
 407 isnst_clear_portal_list(avl_tree_t *portal_list);
 408 
 409 static void
 410 isnst_copy_portal_list(avl_tree_t *t1, avl_tree_t *t2);
 411 
 412 static isns_portal_t *
 413 isnst_lookup_portal(struct sockaddr_storage *sa);
 414 
 415 static isns_portal_t *
 416 isnst_add_to_portal_list(struct sockaddr_storage *sa, avl_tree_t *portal_list);
 417 
 418 static void
 419 isnst_remove_from_portal_list(struct sockaddr_storage *sa,
 420     avl_tree_t *portal_list);
 421 
 422 static int
 423 isnst_portal_avl_compare(const void *t1, const void *t2);
 424 
 425 
 426 
 427 
 428 
 429 
 430 it_cfg_status_t
 431 isnst_config_merge(it_config_t *cfg)
 432 {
 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;
 436 
 437         ISNS_GLOBAL_LOCK();
 438 
 439         /*
 440          * Determine whether iSNS is enabled in the new config.
 441          * Isns property may not be set up yet.
 442          */
 443         (void) nvlist_lookup_boolean_value(cfg->config_global_properties,
 444             PROP_ISNS_ENABLED, &new_isns_state);
 445 
 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);
 454         }
 455 
 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) {
 464                         /*
 465                          * If reactivating a server that was being
 466                          * deleted, turn it into a reset.
 467                          */
 468                         isns_svr->svr_delete_needed = B_FALSE;
 469                         isns_svr->svr_reset_needed = B_TRUE;
 470                 }
 471         }
 472 
 473         /*
 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.
 476          */
 477 
 478         /* Start/Stop iSNS if necessary */
 479         iscsit_set_isns(new_isns_state);
 480 
 481         ISNS_GLOBAL_UNLOCK();
 482 
 483 
 484         /* Wake up the monitor thread to complete the state change */
 485         isnst_monitor_awaken();
 486 
 487         return (0);
 488 }
 489 
 490 int
 491 iscsit_isns_init(iscsit_hostinfo_t *hostinfo)
 492 {
 493         mutex_init(&iscsit_global.global_isns_cfg.isns_mutex, NULL,
 494             MUTEX_DEFAULT, NULL);
 495 
 496         ISNS_GLOBAL_LOCK();
 497         mutex_init(&iscsit_isns_mutex, NULL, MUTEX_DEFAULT, NULL);
 498 
 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));
 513 
 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();
 523 
 524         return (0);
 525 }
 526 
 527 void
 528 iscsit_isns_fini()
 529 {
 530         ISNS_GLOBAL_LOCK();
 531 
 532         /*
 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.
 536          */
 537         iscsit_set_isns(B_FALSE);
 538 
 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);
 545 
 546         /*
 547          * Free our EID and target list.
 548          */
 549 
 550         if (isns_eid) {
 551                 kmem_free(isns_eid, strlen(isns_eid) + 1);
 552                 isns_eid = NULL;
 553         }
 554 
 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();
 562 
 563         mutex_destroy(&iscsit_global.global_isns_cfg.isns_mutex);
 564 }
 565 
 566 static void
 567 iscsit_set_isns(boolean_t state)
 568 {
 569         iscsit_isns_svr_t       *svr;
 570 
 571         ASSERT(ISNS_GLOBAL_LOCK_HELD());
 572 
 573         /*
 574          * Update state and isns stop flag
 575          */
 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;
 583                 }
 584 
 585                 iscsit_global.global_isns_cfg.isns_state = state;
 586 
 587                 if (state) {
 588                         isnst_start();
 589                 } else {
 590                         isnst_stop();
 591                 }
 592         }
 593 }
 594 
 595 void
 596 iscsit_add_isns(it_portal_t *cfg_svr)
 597 {
 598         iscsit_isns_svr_t *svr;
 599 
 600         ASSERT(ISNS_GLOBAL_LOCK_HELD());
 601 
 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;
 608 
 609         /* put it on the global isns server list */
 610         list_insert_tail(&iscsit_global.global_isns_cfg.isns_svrs, svr);
 611 }
 612 
 613 void
 614 isnst_mark_delete_isns(iscsit_isns_svr_t *svr)
 615 {
 616         ASSERT(ISNS_GLOBAL_LOCK_HELD());
 617 
 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;
 623         }
 624 
 625 }
 626 
 627 void
 628 isnst_finish_delete_isns(iscsit_isns_svr_t *svr)
 629 {
 630 
 631         ASSERT(ISNS_GLOBAL_LOCK_HELD());
 632         isnst_clear_target_list(svr);
 633 
 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));
 638 }
 639 
 640 static iscsit_isns_svr_t *
 641 iscsit_isns_svr_lookup(struct sockaddr_storage *sa)
 642 {
 643         iscsit_isns_svr_t       *svr;
 644         it_portal_t             portal1;
 645 
 646         ASSERT(ISNS_GLOBAL_LOCK_HELD());
 647 
 648         bcopy(sa, &portal1.portal_addr, sizeof (struct sockaddr_storage));
 649 
 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);
 655         }
 656 
 657         return (NULL);
 658 }
 659 
 660 static isns_target_info_t *
 661 isnst_create_target_info(iscsit_tgt_t *target)
 662 {
 663 
 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;
 671 
 672         /* Cannot hold the iscsit_isns_mutex here! */
 673         ASSERT(! mutex_owned(&iscsit_isns_mutex));
 674 
 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);
 679 
 680         mutex_enter(&target->target_mutex);
 681         (void) strncpy(ti->ti_tgt_name, target->target_name,
 682             MAX_ISCSI_NODENAMELEN);
 683 
 684 
 685         if (nvlist_lookup_string(target->target_props, PROP_ALIAS,
 686             &str) == 0) {
 687                 (void) strncpy(ti->ti_tgt_alias, str, MAX_ISCSI_NODENAMELEN);
 688         }
 689 
 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;
 697 
 698                 /*
 699                  * Only need portal list for non-default portal.
 700                  */
 701                 if (tpgt->tpgt_tag != ISCSIT_DEFAULT_TPGT) {
 702                         tpg = tpgt->tpgt_tpg;
 703 
 704                         mutex_enter(&tpg->tpg_mutex);
 705 
 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);
 713 
 714                                 tp = AVL_NEXT(&tpg->tpg_portal_list, tp);
 715                         } while (tp != NULL);
 716                         mutex_exit(&tpg->tpg_mutex);
 717                 }
 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);
 722 
 723         return (ti);
 724 }
 725 
 726 static void
 727 isnst_clear_target_info_cb(void *arg)
 728 {
 729         isns_target_info_t *ti = (isns_target_info_t *)arg;
 730         isns_tpgt_t     *tig;
 731         isns_tpgt_addr_t *tip;
 732 
 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));
 736                 }
 737                 list_destroy(&tig->ti_portal_list);
 738                 kmem_free(tig, sizeof (isns_tpgt_t));
 739         }
 740         list_destroy(&ti->ti_tpgt_list);
 741         idm_refcnt_destroy(&ti->ti_refcnt);
 742         kmem_free(ti, sizeof (isns_target_info_t));
 743 }
 744 
 745 
 746 /*
 747  * iscsit_isns_register
 748  * called by iscsit when a target goes online
 749  */
 750 int
 751 iscsit_isns_register(iscsit_tgt_t *target)
 752 {
 753         isns_target_t           *itarget, tmptgt;
 754         avl_index_t             where;
 755         isns_target_info_t      *ti;
 756 
 757         /* Create TI struct outside of isns_mutex */
 758         ti = isnst_create_target_info(target);
 759 
 760         mutex_enter(&iscsit_isns_mutex);
 761 
 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);
 766 
 767                 itarget->target = target;
 768                 avl_insert(&isns_target_list, (void *)itarget, where);
 769         } else {
 770                 ASSERT(0);
 771         }
 772 
 773         /* Copy the target info so it will last beyond deregister */
 774         itarget->target_info = ti;
 775         idm_refcnt_hold(&ti->ti_refcnt);
 776 
 777         isns_targets_changed = B_TRUE;
 778 
 779         mutex_exit(&iscsit_isns_mutex);
 780 
 781         isnst_monitor_awaken();
 782         return (0);
 783 }
 784 
 785 /*
 786  * iscsit_isns_deregister
 787  * called by iscsit when a target goes offline
 788  */
 789 int
 790 iscsit_isns_deregister(iscsit_tgt_t *target)
 791 {
 792         isns_target_t           *itarget, tmptgt;
 793         isns_target_info_t      *ti;
 794 
 795         tmptgt.target = target;
 796 
 797         mutex_enter(&iscsit_isns_mutex);
 798 
 799         itarget = avl_find(&isns_target_list, &tmptgt, NULL);
 800         ASSERT(itarget != NULL);
 801         ti = itarget->target_info;
 802 
 803         /*
 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.
 807          */
 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);
 811 
 812         itarget->target_info = NULL;
 813         avl_remove(&isns_target_list, itarget);
 814         kmem_free(itarget, sizeof (isns_target_t));
 815 
 816         isns_targets_changed = B_TRUE;
 817 
 818         mutex_exit(&iscsit_isns_mutex);
 819 
 820         isnst_monitor_awaken();
 821         return (0);
 822 }
 823 
 824 /*
 825  * iscsit_isns_target_update
 826  * This function is called by iscsit when a target's configuration
 827  * has changed.
 828  */
 829 
 830 void
 831 iscsit_isns_target_update(iscsit_tgt_t *target)
 832 {
 833         isns_target_t           *itarget, tmptgt;
 834         isns_target_info_t      *ti;
 835 
 836         /* Create new TI struct outside of isns_mutex */
 837         ti = isnst_create_target_info(target);
 838 
 839         mutex_enter(&iscsit_isns_mutex);
 840 
 841         /*
 842          * If iscsit calls us to modify a target, that target should
 843          * already exist in the isns_svr_list.
 844          */
 845         tmptgt.target = target;
 846         itarget = avl_find(&isns_target_list, &tmptgt, NULL);
 847         if (itarget == NULL) {
 848                 /*
 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.
 852                  */
 853                 mutex_exit(&iscsit_isns_mutex);
 854                 /* Remove the target_info struct -- not needed */
 855                 isnst_clear_target_info_cb(ti);
 856                 return;
 857         }
 858 
 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);
 863 
 864         /* Link to new target_info struct */
 865         itarget->target_info = ti;
 866         idm_refcnt_hold(&ti->ti_refcnt);
 867 
 868         itarget->target_update_needed = B_TRUE;
 869 
 870         isns_targets_changed = B_TRUE;
 871 
 872         mutex_exit(&iscsit_isns_mutex);
 873 
 874         isnst_monitor_awaken();
 875 }
 876 
 877 static void
 878 isnst_start()
 879 {
 880         ISNST_LOG(CE_NOTE, "**** isnst_start");
 881 
 882         ASSERT(ISNS_GLOBAL_LOCK_HELD());
 883 
 884         /*
 885          * Start ESI thread(s)
 886          */
 887         isnst_esi_start();
 888 
 889         /*
 890          * Create a thread for monitoring server communications
 891          */
 892         isnst_monitor_start();
 893 }
 894 
 895 static void
 896 isnst_stop()
 897 {
 898         ASSERT(ISNS_GLOBAL_LOCK_HELD());
 899         ISNST_LOG(CE_NOTE, "**** isnst_stop");
 900 
 901 
 902         ISNS_GLOBAL_UNLOCK();
 903         isnst_esi_stop();
 904         isnst_monitor_stop();
 905         ISNS_GLOBAL_LOCK();
 906 }
 907 
 908 static void
 909 isnst_monitor_start(void)
 910 {
 911         ISNST_LOG(CE_NOTE, "isnst_monitor_start");
 912 
 913 
 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);
 921 }
 922 
 923 static void
 924 isnst_monitor_stop(void)
 925 {
 926         ISNST_LOG(CE_NOTE, "isnst_monitor_stop");
 927 
 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);
 933 
 934                 thread_join(isns_monitor_thr_did);
 935                 return;
 936         }
 937         mutex_exit(&isns_monitor_mutex);
 938 }
 939 
 940 /*
 941  * isnst_update_server_timestamp
 942  *
 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.
 946  *
 947  */
 948 static boolean_t
 949 isnst_update_server_timestamp(struct sockaddr_storage *ss)
 950 {
 951         iscsit_isns_svr_t       *svr;
 952 
 953         ASSERT(ISNS_GLOBAL_LOCK_HELD());
 954 
 955         /*
 956          * Find the server and update the timestamp
 957          */
 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)) {
 961                 /*
 962                  * Note that the port number in incoming probe will be
 963                  * different than the iSNS server's port number.
 964                  */
 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;
 969                 }
 970         }
 971 
 972         if (svr != NULL) {
 973                 /* Update the timestamp we keep for this server */
 974                 svr->svr_last_msg = ddi_get_lbolt();
 975                 /*
 976                  * If we receive ESI probe from a server we are not
 977                  * registered to, then cause a re-reg attempt.
 978                  */
 979                 if (!svr->svr_registered) {
 980                         isnst_monitor_awaken();
 981                 }
 982                 return (B_TRUE);
 983         }
 984 
 985         return (B_FALSE);
 986 }
 987 
 988 
 989 /*
 990  * isnst_monitor_all_servers -- loop through all servers
 991  */
 992 
 993 
 994 static void
 995 isnst_monitor_all_servers()
 996 {
 997         iscsit_isns_svr_t       *svr, *next_svr;
 998         boolean_t               enabled;
 999         list_t                  *svr_list;
1000         int                     rc;
1001 
1002         svr_list = &iscsit_global.global_isns_cfg.isns_svrs;
1003 
1004         ISNS_GLOBAL_LOCK();
1005 
1006         isnst_copy_global_status_changes();
1007 
1008         enabled = iscsit_global.global_isns_cfg.isns_state;
1009         for (svr = list_head(svr_list); svr != NULL; svr = next_svr) {
1010 
1011                 svr->svr_monitor_hold = B_TRUE;
1012                 /*
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.
1016                  */
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];
1023 
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;
1032                                 }
1033                         }
1034                 } else {
1035                         svr->svr_retry_count = 0;
1036                 }
1037                 /*
1038                  * If we have finished unregistering this server,
1039                  * it is now OK to delete it.
1040                  */
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);
1046                 }
1047         }
1048         ISNS_GLOBAL_UNLOCK();
1049 }
1050 
1051 static void
1052 isnst_monitor_awaken(void)
1053 {
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);
1058         }
1059         mutex_exit(&isns_monitor_mutex);
1060 }
1061 
1062 /*
1063  * isnst_monitor -- the monitor thread for iSNS
1064  */
1065 /*ARGSUSED*/
1066 static void
1067 isnst_monitor(void *arg)
1068 {
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);
1073 
1074         /*
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.
1079          */
1080         mutex_exit(&isns_monitor_mutex);
1081         delay(drv_usectohz(isns_initial_delay * 1000000));
1082         mutex_enter(&isns_monitor_mutex);
1083 
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);
1088 
1089         while (isns_monitor_thr_running) {
1090 
1091                 /* Update servers */
1092                 mutex_exit(&isns_monitor_mutex);
1093                 isnst_monitor_all_servers();
1094                 mutex_enter(&isns_monitor_mutex);
1095 
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;
1103                 }
1104                 mutex_exit(&iscsit_isns_mutex);
1105 
1106                 /*
1107                  * Keep running until isns_monitor_thr_running is set to
1108                  * B_FALSE.
1109                  */
1110                 if (! isns_monitor_thr_running)
1111                         break;
1112 
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);
1118         }
1119 
1120         mutex_exit(&isns_monitor_mutex);
1121 
1122         /* Update the servers one last time for deregistration */
1123         isnst_monitor_all_servers();
1124 
1125         /* Clean up the all-portals list */
1126         ISNS_GLOBAL_LOCK();
1127         isnst_clear_default_portals();
1128         ISNS_GLOBAL_UNLOCK();
1129 
1130         /* terminate the thread at the last */
1131         thread_exit();
1132 }
1133 
1134 static int
1135 isnst_monitor_one_server(iscsit_isns_svr_t *svr, boolean_t enabled)
1136 {
1137         int             rc = 0;
1138         isns_target_t   *itarget;
1139 
1140         ASSERT(ISNS_GLOBAL_LOCK_HELD());
1141 
1142         /*
1143          * First, take care of the case where iSNS is no longer enabled.
1144          *
1145          */
1146 
1147         if (enabled == B_FALSE || svr->svr_delete_needed) {
1148                 /*
1149                  * Just try one time to deregister all from server.
1150                  * Doesn't matter if this fails.  We're disabled.
1151                  */
1152                 (void) isnst_update_one_server(svr, NULL, ISNS_DEREGISTER_ALL);
1153                 isnst_set_server_status(svr, B_FALSE);
1154                 return (0);
1155         }
1156 
1157 retry_replace_all:
1158         /*
1159          * If the server needs replace-all, check if it should
1160          * be a DevDereg (i.e. if the last target is gone.)
1161          */
1162 
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;
1171                         }
1172                 }
1173                 /*
1174                  * jtarget is null IFF all tgts need deletion,
1175                  * and there are no new targets to register.
1176                  */
1177                 if (jtarget == NULL) {
1178                         rc = isnst_update_one_server(svr, NULL,
1179                             ISNS_DEREGISTER_ALL);
1180                         if (rc != 0) {
1181                                 return (rc);
1182                         }
1183                         isnst_set_server_status(svr, B_FALSE);
1184                         return (0);
1185                 }
1186         }
1187 
1188         /*
1189          * If the server is not yet registered, do the registration
1190          */
1191         if (! svr->svr_registered || svr->svr_reset_needed) {
1192 
1193                 if (avl_numnodes(&svr->svr_target_list) == 0) {
1194                         /* If no targets, nothing to register */
1195                         return (0);
1196                 }
1197                 if ((rc = isnst_update_one_server(svr, NULL,
1198                     ISNS_REGISTER_ALL)) != 0) {
1199                         /* Registration failed */
1200                         return (rc);
1201                 }
1202                 isnst_set_server_status(svr, B_TRUE);
1203 
1204         }
1205 
1206         /* The following checks are expensive, so only do them if needed */
1207         if (svr->svr_targets_changed) {
1208                 isns_target_t   *next_target;
1209                 /*
1210                  * If there is a target to be deleted, send the
1211                  * deletion request for one target at a time.
1212                  */
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;
1229                                         }
1230                                 }
1231                                 /* jtarget is null if last registered tgt */
1232                                 if (jtarget == NULL) {
1233                                         /*
1234                                          * Removing last tgt -- deregister all.
1235                                          * Doesn't matter if this fails.
1236                                          * We're disabled.
1237                                          */
1238                                         rc = isnst_update_one_server(svr,
1239                                             NULL, ISNS_DEREGISTER_ALL);
1240                                         if (rc != 0) {
1241                                                 return (rc);
1242                                         }
1243                                         isnst_set_server_status(svr, B_FALSE);
1244                                         return (0);
1245                                 }
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;
1252                                 }
1253 
1254                                 if (rc != 0) {
1255                                         return (rc);
1256                                 }
1257                                 isnst_clear_from_target_list(itarget,
1258                                     &svr->svr_target_list);
1259                         }
1260                 }
1261 
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) {
1267 
1268                                 /*
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.
1273                                  */
1274                                 if (isns_modify_must_replace) {
1275                                         svr->svr_reset_needed = B_TRUE;
1276                                         goto retry_replace_all;
1277                                 }
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;
1286                                 }
1287                                 if (rc != 0) {
1288                                         return (rc);
1289                                 }
1290                                 itarget->target_update_needed =
1291                                     B_FALSE;
1292                                 itarget->target_registered = B_TRUE;
1293                         }
1294                         itarget = AVL_NEXT(&svr->svr_target_list,
1295                             itarget);
1296                 }
1297 
1298                 /*
1299                  * We have gone through all the cases -- this server
1300                  * is now up to date.
1301                  */
1302                 svr->svr_targets_changed = B_FALSE;
1303         }
1304 
1305 
1306         if (isns_use_esi) {
1307                 /*
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.
1313                  */
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;
1320                 }
1321         } else {
1322                 /*
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.
1326                  */
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;
1337                         }
1338                         if (rc != 0) {
1339                                 return (rc);
1340                         }
1341                 }
1342         }
1343         return (0);
1344 
1345 }
1346 
1347 /*
1348  * isnst_mark_deleted_target -- find tgt in svr list but not global list
1349  */
1350 static void
1351 isnst_mark_deleted_targets(iscsit_isns_svr_t *svr)
1352 {
1353         isns_target_t *itarget, *nxt_target, tmptgt;
1354 
1355         ASSERT(ISNS_GLOBAL_LOCK_HELD());
1356         ASSERT(mutex_owned(&iscsit_isns_mutex));
1357 
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);
1369                         }
1370                 }
1371         }
1372 }
1373 
1374 static isns_target_t *
1375 isnst_latch_to_target_list(isns_target_t *jtarget, avl_tree_t *target_list)
1376 {
1377         isns_target_t *itarget, tmptgt;
1378         avl_index_t where;
1379 
1380         ASSERT(ISNS_GLOBAL_LOCK_HELD());
1381         ASSERT(mutex_owned(&iscsit_isns_mutex));
1382         /*
1383          * Make sure this target isn't already in our list.
1384          */
1385 
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);
1390 
1391                 itarget->target = jtarget->target;
1392                 itarget->target_info = jtarget->target_info;
1393                 idm_refcnt_hold(&itarget->target_info->ti_refcnt);
1394 
1395                 avl_insert(target_list, (void *)itarget, where);
1396         } else {
1397                 ASSERT(0);
1398         }
1399 
1400         return (itarget);
1401 }
1402 
1403 static void
1404 isnst_clear_target_list(iscsit_isns_svr_t *svr)
1405 {
1406         isns_target_t   *itarget;
1407 
1408         while ((itarget = avl_first(&svr->svr_target_list)) != NULL) {
1409                 isnst_clear_from_target_list(itarget,
1410                     &svr->svr_target_list);
1411         }
1412 }
1413 
1414 static void
1415 isnst_clear_from_target_list(isns_target_t *jtarget, avl_tree_t *target_list)
1416 {
1417         isns_target_t           *itarget, tmptgt;
1418 
1419         tmptgt.target = jtarget->target;
1420 
1421         if ((itarget = avl_find(target_list, &tmptgt, NULL))
1422             != NULL) {
1423 
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);
1429         }
1430 }
1431 
1432 /*
1433  * isnst_copy_global_status_changes -- update svrs to match iscsit
1434  *
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.
1438  */
1439 static void
1440 isnst_copy_global_status_changes(void)
1441 {
1442         isns_target_t           *ttarget, *itarget, tmptgt;
1443         iscsit_isns_svr_t       *svr;
1444 
1445         ASSERT(ISNS_GLOBAL_LOCK_HELD());
1446 
1447         /*
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.
1452          */
1453         mutex_enter(&iscsit_isns_mutex);
1454 
1455         /*
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.
1459          */
1460         isnst_monitor_default_portal_list();
1461 
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) {
1468                         /*
1469                          * Cause re-register, for now, when portals change.
1470                          * Eventually, we should add new portals one by one
1471                          */
1472                         svr->svr_reset_needed = B_TRUE;
1473                 }
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;
1483                 }
1484         }
1485 
1486         /*
1487          * If any target has been modified, tell all the svrs to
1488          * update that target.
1489          */
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);
1503 
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);
1520                                 }
1521                         }
1522                         ttarget->target_update_needed = B_FALSE;
1523                         ttarget = AVL_NEXT(&isns_target_list, ttarget);
1524                 }
1525         }
1526 
1527         /*
1528          * Now we have updated the per-server state for all servers.
1529          * Clear the global state flags
1530          */
1531         isns_targets_changed = B_FALSE;
1532         isns_portals_changed = B_FALSE;
1533         mutex_exit(&iscsit_isns_mutex);
1534 }
1535 
1536 /*
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).
1541  */
1542 static int
1543 isnst_update_one_server(iscsit_isns_svr_t *svr, isns_target_t *itarget,
1544     isns_reg_type_t reg)
1545 {
1546         int rc = 0;
1547 
1548         ASSERT(ISNS_GLOBAL_LOCK_HELD());
1549         ISNS_GLOBAL_UNLOCK();
1550 
1551         switch (reg) {
1552         case ISNS_DEREGISTER_TARGET:
1553                 rc = isnst_deregister(svr, itarget);
1554                 break;
1555 
1556         case ISNS_DEREGISTER_ALL:
1557                 rc = isnst_deregister(svr, NULL);
1558                 break;
1559 
1560         case ISNS_MODIFY_TARGET:
1561         case ISNS_REGISTER_TARGET:
1562                 rc = isnst_register(svr, itarget, reg);
1563                 break;
1564 
1565         case ISNS_REGISTER_ALL:
1566                 rc = isnst_register(svr, NULL, reg);
1567                 break;
1568 
1569         default:
1570                 ASSERT(0);
1571                 /* NOTREACHED */
1572         }
1573 
1574         ISNS_GLOBAL_LOCK();
1575         return (rc);
1576 }
1577 
1578 /*
1579  * isnst_retry_registration
1580  *
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.
1585  */
1586 
1587 static boolean_t
1588 isnst_retry_registration(int rsp_status_code)
1589 {
1590         boolean_t retry;
1591 
1592         /*
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.
1598          */
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;
1610         }
1611 
1612         return (retry);
1613 }
1614 
1615 
1616 
1617 static int
1618 isnst_register(iscsit_isns_svr_t *svr, isns_target_t *itarget,
1619     isns_reg_type_t regtype)
1620 {
1621         struct sonode   *so;
1622         int             rc = 0;
1623         isns_pdu_t      *pdu, *rsp;
1624         size_t          pdu_size, rsp_size;
1625 
1626         /* create TCP connection to the isns server */
1627         so = isnst_open_so(&svr->svr_sa);
1628         if (so == NULL) {
1629                 return (-1);
1630         }
1631 
1632         pdu_size = isnst_make_reg_pdu(&pdu, itarget, svr, regtype);
1633         if (pdu_size == 0) {
1634                 isnst_close_so(so);
1635                 return (-1);
1636         }
1637 
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);
1643         }
1644 
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);
1650         }
1651 
1652         rc = isnst_verify_rsp(svr, pdu, rsp, rsp_size);
1653 
1654         kmem_free(pdu, pdu_size);
1655         kmem_free(rsp, rsp_size);
1656         isnst_close_so(so);
1657 
1658         return (rc);
1659 }
1660 
1661 /*
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)
1667  */
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)
1671 {
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;
1678 
1679         ISNS_GLOBAL_LOCK();
1680         ASSERT(svr->svr_monitor_hold);
1681         /*
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.
1687          */
1688         if (avl_numnodes(&svr->svr_target_list) == 0) {
1689                 /* If no targets, nothing to register */
1690                 ISNS_GLOBAL_UNLOCK();
1691                 return (0);
1692         }
1693         /*
1694          * Find a source attribute for this registration.
1695          *
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.
1700          */
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 {
1706                 /*
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.
1712                  */
1713                 int             i;
1714                 isns_target_t   *jtarget;
1715 
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++;
1721                 }
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);
1726                 }
1727                 src = jtarget;
1728                 ASSERT(src != NULL);
1729         }
1730 
1731         /*
1732          * Null target means we're replacing everything.
1733          */
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);
1742         }
1743 
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);
1748         }
1749 
1750         /* Source Attribute */
1751 
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;
1756         }
1757 
1758         /*
1759          * Message Key Attributes - EID
1760          */
1761         len = strlen(isns_eid) + 1;
1762 
1763         if (isnst_add_attr(*pdu, pdu_size, ISNS_EID_ATTR_ID,
1764             len, isns_eid, 0) != 0) {
1765                 goto pdu_error;
1766         }
1767 
1768         /* Delimiter */
1769         if (isnst_add_attr(*pdu, pdu_size, ISNS_DELIMITER_ATTR_ID,
1770             0, 0, 0) != 0) {
1771                 goto pdu_error;
1772         }
1773 
1774         /*
1775          * Operating Attributes
1776          */
1777         if (isnst_add_attr(*pdu, pdu_size, ISNS_EID_ATTR_ID, len,
1778             isns_eid, 0) != 0) {
1779                 goto pdu_error;
1780         }
1781 
1782 
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;
1788         }
1789 
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;
1797                 }
1798                 /*
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.
1803                  */
1804                 if (isnst_reg_pdu_add_entity_portals(*pdu, pdu_size) != 0) {
1805                         goto pdu_error;
1806                 }
1807 
1808                 /*
1809                  * Skip over delete-pending tgts. There must be at
1810                  * least one non-deleted tgt, or it is an error.
1811                  */
1812                 while (itarget->target_delete_needed) {
1813                         itarget = AVL_NEXT(&svr->svr_target_list,
1814                             itarget);
1815                         ASSERT(itarget != NULL);
1816                 }
1817         }
1818 
1819 
1820         /* Add information about each target or one target */
1821         do {
1822 
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;
1829                 }
1830 
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;
1836                 }
1837 
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;
1847                         }
1848                 }
1849 
1850                 if (isnst_reg_pdu_add_pg(*pdu, pdu_size, itarget) != 0) {
1851                         goto pdu_error;
1852                 }
1853 
1854                 /* If registering one target, then we are done. */
1855                 if (!reg_all) {
1856                         break;
1857                 }
1858 
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);
1863 
1864         } while (itarget != NULL);
1865 
1866         ISNS_GLOBAL_UNLOCK();
1867         return (pdu_size);
1868 
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");
1882                 }
1883         }
1884 
1885         kmem_free(*pdu, pdu_size);
1886         *pdu = NULL;
1887 
1888         ISNS_GLOBAL_UNLOCK();
1889         return (0);
1890 }
1891 
1892 static int
1893 isnst_reg_pdu_add_entity_portals(isns_pdu_t *pdu, size_t pdu_size)
1894 {
1895         int                     rc = 0;
1896         isns_portal_t           *iportal;
1897 
1898         ASSERT(ISNS_GLOBAL_LOCK_HELD());
1899 
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;
1910                 }
1911                 iportal = AVL_NEXT(&isns_all_portals, iportal);
1912         }
1913 
1914         return (rc);
1915 }
1916 
1917 
1918 /*
1919  * isnst_reg_pdu_add_pg -- add the PG and PGT entries for one target.
1920  */
1921 static int
1922 isnst_reg_pdu_add_pg(isns_pdu_t *pdu, size_t pdu_size, isns_target_t *itarget)
1923 {
1924         int                     rval = 0;
1925         avl_tree_t              null_portals;
1926         isns_target_info_t      *ti;
1927         isns_tpgt_t             *tig;
1928 
1929         ASSERT(ISNS_GLOBAL_LOCK_HELD());
1930 
1931         ti = itarget->target_info;
1932 
1933         /*
1934          * If all registered targets only use the default TPGT, then
1935          * we can skip sending PG info to the iSNS server.
1936          */
1937         if (num_tpg_portals == 0)
1938                 return (0);
1939 
1940         /*
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.
1945          */
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);
1949 
1950         for (tig = list_head(&ti->ti_tpgt_list);
1951             tig != NULL;
1952             tig = list_next(&ti->ti_tpgt_list, tig)) {
1953 
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;
1960                         }
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;
1967                         }
1968                 }
1969         }
1970 
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;
1975         }
1976         isnst_clear_portal_list(&null_portals);
1977         avl_destroy(&null_portals);
1978         return (rval);
1979 }
1980 
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)
1985 {
1986         isns_tpgt_addr_t        *tip;
1987         int                     rval = 0;
1988 
1989         ASSERT(ISNS_GLOBAL_LOCK_HELD());
1990         ASSERT(tig->ti_tpgt_tag != ISCSIT_DEFAULT_TPGT);
1991 
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;
1997         }
1998 
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;
2009                 }
2010                 isnst_remove_from_portal_list(&tip->portal_addr,
2011                     null_portal_list);
2012 
2013                 tip = list_next(&tig->ti_portal_list, tip);
2014         } while (tip != NULL);
2015 
2016 pg_done:
2017         return (rval);
2018 }
2019 
2020 static int
2021 isnst_add_default_pg(isns_pdu_t *pdu, size_t pdu_size,
2022     avl_tree_t *null_portal_list)
2023 {
2024         isns_portal_t *iportal;
2025 
2026         ASSERT(ISNS_GLOBAL_LOCK_HELD());
2027 
2028         if (num_default_portals == 0) {
2029                 /*
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.
2037                  *
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.
2046                  *
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.
2050                  */
2051                 return (0);
2052         }
2053 
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);
2058         }
2059 
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);
2070                         }
2071                         isnst_remove_from_portal_list(&iportal->portal_addr,
2072                             null_portal_list);
2073                 }
2074         }
2075 
2076         return (0);
2077 }
2078 
2079 static int
2080 isnst_add_null_pg(isns_pdu_t *pdu, size_t pdu_size,
2081     avl_tree_t *null_portal_list)
2082 {
2083         isns_portal_t *iportal;
2084 
2085         /* If all portals accounted for, no NULL PG needed */
2086         if (avl_numnodes(null_portal_list) == 0) {
2087                 return (0);
2088         }
2089 
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);
2094         }
2095 
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);
2104                 }
2105         }
2106 
2107         return (0);
2108 }
2109 
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)
2114 {
2115         struct sockaddr_in      *in;
2116         struct sockaddr_in6     *in6;
2117         uint32_t                attr_numeric_data;
2118         void                    *inaddrp;
2119 
2120         in = (struct sockaddr_in *)ss;
2121         in6 = (struct sockaddr_in6 *)ss;
2122 
2123         ASSERT((ss->ss_family == AF_INET) || (ss->ss_family == AF_INET6));
2124 
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;
2131         }
2132 
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);
2137         }
2138 
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);
2143         }
2144 
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);
2151                 }
2152 
2153                 if (isnst_add_attr(pdu, pdu_size, ISNS_ESI_PORT_ATTR_ID, 4,
2154                     NULL, esi.esi_port) != 0) {
2155                         return (1);
2156                 }
2157         }
2158         mutex_exit(&esi.esi_mutex);
2159 
2160         return (0);
2161 }
2162 
2163 static int
2164 isnst_deregister(iscsit_isns_svr_t *svr, isns_target_t *itarget)
2165 {
2166         int             rc;
2167         isns_pdu_t      *pdu, *rsp;
2168         size_t          pdu_size, rsp_size;
2169         struct sonode   *so;
2170 
2171         so = isnst_open_so(&svr->svr_sa);
2172 
2173         if (so == NULL) {
2174                 return (-1);
2175         }
2176 
2177         pdu_size = isnst_make_dereg_pdu(svr, &pdu, itarget);
2178         if (pdu_size == 0) {
2179                 isnst_close_so(so);
2180                 return (-1);
2181         }
2182 
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);
2188         }
2189 
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);
2195         }
2196 
2197         rc = isnst_verify_rsp(svr, pdu, rsp, rsp_size);
2198 
2199         isnst_close_so(so);
2200         kmem_free(pdu, pdu_size);
2201         kmem_free(rsp, rsp_size);
2202 
2203         return (rc);
2204 }
2205 
2206 static int
2207 isnst_keepalive(iscsit_isns_svr_t *svr)
2208 {
2209         int             rc;
2210         isns_pdu_t      *pdu, *rsp;
2211         size_t          pdu_size, rsp_size;
2212         struct sonode   *so;
2213 
2214         so = isnst_open_so(&svr->svr_sa);
2215 
2216         if (so == NULL) {
2217                 return (-1);
2218         }
2219 
2220         pdu_size = isnst_make_keepalive_pdu(svr, &pdu);
2221         if (pdu_size == 0) {
2222                 isnst_close_so(so);
2223                 return (-1);
2224         }
2225 
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);
2231         }
2232 
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);
2238         }
2239 
2240         rc = isnst_verify_rsp(svr, pdu, rsp, rsp_size);
2241 
2242         isnst_close_so(so);
2243         kmem_free(pdu, pdu_size);
2244         kmem_free(rsp, rsp_size);
2245 
2246         return (rc);
2247 }
2248 
2249 static size_t
2250 isnst_make_dereg_pdu(iscsit_isns_svr_t *svr, isns_pdu_t **pdu,
2251     isns_target_t *itarget)
2252 {
2253         size_t          pdu_size;
2254         int             len;
2255         isns_target_t   *src;
2256 
2257         /*
2258          * create DevDereg Message with all of target nodes
2259          */
2260         pdu_size = isnst_create_pdu_header(ISNS_DEV_DEREG, pdu, 0);
2261         if (pdu_size == 0) {
2262                 return (0);
2263         }
2264 
2265         /*
2266          * Source attribute - Must be a storage node in the same
2267          * network entity.
2268          */
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;
2275         }
2276 
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;
2281         }
2282 
2283 
2284         /* Delimiter */
2285         if (isnst_add_attr(*pdu, pdu_size, ISNS_DELIMITER_ATTR_ID,
2286             0, 0, 0) != 0) {
2287                 goto dereg_pdu_error;
2288         }
2289 
2290         /*
2291          * Operating attributes
2292          */
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;
2299                 }
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;
2306                 }
2307         }
2308 
2309         return (pdu_size);
2310 
2311 dereg_pdu_error:
2312         kmem_free(*pdu, pdu_size);
2313         *pdu = NULL;
2314 
2315         return (0);
2316 }
2317 
2318 static size_t
2319 isnst_make_keepalive_pdu(iscsit_isns_svr_t *svr, isns_pdu_t **pdu)
2320 {
2321         size_t          pdu_size;
2322         int             len;
2323         isns_target_t   *src;
2324 
2325         ASSERT(svr->svr_registered);
2326 
2327         /*
2328          * create DevAttrQuery Message
2329          */
2330         pdu_size = isnst_create_pdu_header(ISNS_DEV_ATTR_QRY, pdu, 0);
2331         if (pdu_size == 0) {
2332                 return (0);
2333         }
2334 
2335         /*
2336          * Source attribute - Must be a iscsi target in the same
2337          * network entity.
2338          */
2339         src = isnst_get_registered_source(svr);
2340 
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;
2345         }
2346 
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;
2352         }
2353         /* Delimiter */
2354         if (isnst_add_attr(*pdu, pdu_size, ISNS_DELIMITER_ATTR_ID,
2355             0, 0, 0) != 0) {
2356                 goto keepalive_pdu_error;
2357         }
2358 
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;
2363         }
2364 
2365 
2366         return (pdu_size);
2367 
2368 keepalive_pdu_error:
2369         kmem_free(*pdu, pdu_size);
2370         *pdu = NULL;
2371 
2372         return (0);
2373 }
2374 
2375 static isns_target_t *
2376 isnst_get_registered_source(iscsit_isns_svr_t *svr)
2377 {
2378         isns_target_t   *itarget;
2379 
2380         /*
2381          * If svr is registered, then there must be at least one
2382          * target that is registered to that svr.
2383          */
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);
2389 }
2390 
2391 static isns_target_t *
2392 isnst_get_registered_source_locked(iscsit_isns_svr_t *svr)
2393 {
2394         isns_target_t   *itarget;
2395 
2396         ASSERT(ISNS_GLOBAL_LOCK_HELD());
2397         ASSERT(svr->svr_registered);
2398         ASSERT((avl_numnodes(&svr->svr_target_list) != 0));
2399 
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);
2408 }
2409 
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)
2413 {
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;
2421 
2422         /*
2423          * Ensure we have at least a valid header (don't count the
2424          * "payload" field.
2425          */
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);
2430         }
2431 
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);
2439         }
2440 
2441         /* Find the start of all operational parameters */
2442         rsp_payload_len = isnst_pdu_get_op(rsp, &pp);
2443         /*
2444          * Make sure isnst_pdu_get_op didn't encounter an error
2445          * in the attributes.
2446          */
2447         if (pp == NULL) {
2448                 return (-1);
2449         }
2450 
2451         /* verify response transaction id */
2452         if (ntohs(rsp->xid) != ntohs(pdu->xid)) {
2453                 return (-1);
2454         }
2455 
2456         /* check the error code */
2457         resp = (isns_resp_t *)((void *)&rsp->payload[0]);
2458 
2459         status = ntohl(resp->status);
2460 
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);
2467                 }
2468 
2469                 /* Only look through response if msg status says OK */
2470                 if (status != 0) {
2471                         break;
2472                 }
2473                 /*
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.
2479                  */
2480 
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);
2490                                 }
2491                                 esi_interval =
2492                                     ntohl(*((uint32_t *)
2493                                     ((void *)(&attr->attr_value))));
2494 
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();
2500 
2501                                 break;
2502                         }
2503                         rsp_payload_len -= (8 + attr_len);
2504                         attr = (isns_tlv_t *)
2505                             ((void *)((uint8_t *)attr + attr_len + 8));
2506                 }
2507 
2508                 break;
2509         case ISNS_DEV_DEREG:
2510                 if (func_id != ISNS_DEV_DEREG_RSP) {
2511                         return (-1);
2512                 }
2513                 break;
2514         case ISNS_DEV_ATTR_QRY:
2515                 /* Keepalive Response */
2516                 if (func_id != ISNS_DEV_ATTR_QRY_RSP) {
2517                         return (-1);
2518                 }
2519 
2520                 if (status == 0) {
2521                         boolean_t       found_eid = B_FALSE;
2522 
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) {
2531                                         /*
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.
2539                                          */
2540                                         found_eid = B_TRUE;
2541                                         break;
2542                                 }
2543 
2544                                 rsp_payload_len -= (8 + attr_len);
2545                                 attr = (isns_tlv_t *)
2546                                     ((void *)((uint8_t *)attr + attr_len + 8));
2547                         }
2548                         if (! found_eid) {
2549                                 status = ISNS_RSP_NO_SUCH_ENTRY;
2550                         }
2551                 }
2552                 if (status == ISNS_RSP_NO_SUCH_ENTRY) {
2553                         char    server_buf[IDM_SA_NTOP_BUFSIZ];
2554                         /*
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.
2559                          */
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 */
2565                 }
2566 
2567                 break;
2568 
2569         default:
2570                 ASSERT(0);
2571                 break;
2572         }
2573 
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();
2580         }
2581 
2582 
2583 
2584         return (status);
2585 }
2586 
2587 static uint16_t
2588 isnst_pdu_get_op(isns_pdu_t *pdu, uint8_t **pp)
2589 {
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;
2596 
2597         /* get payload */
2598         payload_len = ntohs(pdu->payload_len);
2599         resp = (isns_resp_t *)((void *)&pdu->payload[0]);
2600 
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);
2607         }
2608 
2609         payload_len -= sizeof (resp->status);
2610         payload = &resp->data[0];
2611 
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;
2622                         }
2623                 } else {
2624                         /* mal-formed packet */
2625                         payload = NULL;
2626                         payload_len = 0;
2627                 }
2628         }
2629 
2630         *pp = payload;
2631 
2632         return (payload_len);
2633 }
2634 
2635 static size_t
2636 isnst_create_pdu_header(uint16_t func_id, isns_pdu_t **pdu, uint16_t flags)
2637 {
2638         size_t  pdu_size = isns_message_buf_size;
2639 
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);
2646 
2647                 (*pdu)->xid = htons(GET_XID());
2648                 (*pdu)->seq = htons(0);
2649         } else {
2650                 pdu_size = 0;
2651         }
2652 
2653         return (pdu_size);
2654 }
2655 
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)
2663 {
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;
2669 
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;
2675 
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);
2680         }
2681 
2682         attr_tlv = (isns_tlv_t *)kmem_zalloc(attr_tlv_len, KM_SLEEP);
2683 
2684         attr_tlv->attr_id = htonl(attr_id);
2685 
2686         switch (attr_id) {
2687         case ISNS_DELIMITER_ATTR_ID:
2688                 break;
2689 
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);
2709                 }
2710                 break;
2711 
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);
2719                 }
2720                 break;
2721 
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);
2729                 }
2730                 break;
2731         }
2732 
2733         attr_tlv->attr_len = htonl(normalized_attr_len);
2734         /*
2735          * Convert the network byte ordered payload length to host byte
2736          * ordered for local address calculation.
2737          */
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;
2742 
2743         /*
2744          * Convert the host byte ordered payload length back to network
2745          * byte ordered - it's now ready to be sent on the wire.
2746          */
2747         pdu->payload_len = htons(payload_len);
2748 
2749         kmem_free(attr_tlv, attr_tlv_len);
2750         attr_tlv = NULL;
2751 
2752         return (0);
2753 }
2754 
2755 static void
2756 isnst_so_timeout(void *so)
2757 {
2758         /* Wake up any sosend or sorecv blocked on this socket */
2759         idm_soshutdown(so);
2760 }
2761 
2762 static int
2763 isnst_send_pdu(void *so, isns_pdu_t *pdu)
2764 {
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;
2771 
2772         ASSERT(! ISNS_GLOBAL_LOCK_HELD());
2773 
2774         /* update pdu flags */
2775         flags  = ntohs(pdu->flags);
2776         flags |= ISNS_FLAG_CLIENT;
2777         flags |= ISNS_FLAG_FIRST_PDU;
2778 
2779         /* initalize sequence number */
2780         seq = 0;
2781 
2782         payload = pdu->payload;
2783 
2784         /* total payload length */
2785         total_len = ntohs(pdu->payload_len);
2786 
2787         /* fill in the pdu header */
2788         iov[0].iov_base = (void *)pdu;
2789         iov[0].iov_len = ISNSP_HEADER_SIZE;
2790 
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;
2799                 }
2800 
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);
2807 
2808                 /* fill in the payload */
2809                 iov[1].iov_base = (void *)payload;
2810                 iov[1].iov_len = payload_len;
2811 
2812                 DTRACE_PROBE3(isnst__pdu__send, uint16_t, ntohs(pdu->func_id),
2813                     uint16_t, ntohs(pdu->payload_len), caddr_t, pdu);
2814 
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);
2821 
2822                 flags &= ~ISNS_FLAG_FIRST_PDU;
2823                 payload += payload_len;
2824                 total_len -= payload_len;
2825 
2826                 /* increase the sequence number */
2827                 seq ++;
2828 
2829         } while (rc == 0 && total_len > 0);
2830 
2831         return (rc);
2832 }
2833 
2834 static size_t
2835 isnst_rcv_pdu(void *so, isns_pdu_t **pdu)
2836 {
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;
2848 
2849         ASSERT(! ISNS_GLOBAL_LOCK_HELD());
2850 
2851         *pdu = NULL;
2852         total_pdu_len = total_payload_len = 0;
2853         payload = NULL;
2854         seq = 0;
2855 
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;
2864                 }
2865                 (void) untimeout(rcv_timer);
2866 
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;
2871                 }
2872                 payload = kmem_alloc(payload_len, KM_NOSLEEP);
2873                 if (payload == NULL) {
2874                         goto rcv_error;
2875                 }
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;
2881                 }
2882                 (void) untimeout(rcv_timer);
2883 
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;
2890                         }
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;
2907                         }
2908                         bcopy(&tmp_pdu_hdr, *pdu, ISNSP_HEADER_SIZE);
2909                         bcopy(payload, &(*pdu)->payload[0], payload_len);
2910                         kmem_free(payload, payload_len);
2911                 }
2912                 payload = NULL;
2913 
2914                 /* the flags of pdu which is just received */
2915                 flags = ntohs(tmp_pdu_hdr.flags);
2916 
2917                 /* increase sequence number by one */
2918                 seq ++;
2919         } while ((flags & ISNS_FLAG_LAST_PDU) == 0);
2920 
2921         DTRACE_PROBE3(isnst__pdu__recv, uint16_t, ntohs((*pdu)->func_id),
2922             size_t, total_payload_len, caddr_t, *pdu);
2923 
2924         return (total_pdu_len);
2925 
2926 rcv_error:
2927         if (*pdu != NULL) {
2928                 kmem_free(*pdu, total_pdu_len);
2929                 *pdu = NULL;
2930         }
2931         if (payload != NULL) {
2932                 kmem_free(payload, payload_len);
2933         }
2934         return (0);
2935 }
2936 
2937 static void *
2938 isnst_open_so(struct sockaddr_storage *sa)
2939 {
2940         int sa_sz;
2941         ksocket_t so;
2942 
2943         ASSERT(! ISNS_GLOBAL_LOCK_HELD());
2944 
2945         /* determine local IP address */
2946         if (sa->ss_family == AF_INET) {
2947                 /* IPv4 */
2948                 sa_sz = sizeof (struct sockaddr_in);
2949 
2950                 /* Create socket */
2951                 so = idm_socreate(AF_INET, SOCK_STREAM, 0);
2952         } else {
2953                 /* IPv6 */
2954                 sa_sz = sizeof (struct sockaddr_in6);
2955 
2956                 /* Create socket */
2957                 so = idm_socreate(AF_INET6, SOCK_STREAM, 0);
2958         }
2959 
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;
2968                 }
2969         }
2970 
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);
2978         }
2979 
2980         return (so);
2981 }
2982 
2983 static void
2984 isnst_close_so(void *so)
2985 {
2986         idm_soshutdown(so);
2987         idm_sodestroy(so);
2988 }
2989 
2990 /*
2991  * ESI handling
2992  */
2993 
2994 static void
2995 isnst_esi_start(void)
2996 {
2997         if (isns_use_esi == B_FALSE) {
2998                 ISNST_LOG(CE_NOTE, "ESI disabled by isns_use_esi=FALSE");
2999                 return;
3000         }
3001 
3002         ISNST_LOG(CE_NOTE, "isnst_esi_start");
3003 
3004         mutex_enter(&esi.esi_mutex);
3005         ASSERT(esi.esi_enabled == B_FALSE);
3006         ASSERT(esi.esi_thread_running == B_FALSE);
3007 
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);
3012 
3013         /*
3014          * Wait for the thread to start
3015          */
3016         while (!esi.esi_thread_running) {
3017                 cv_wait(&esi.esi_cv, &esi.esi_mutex);
3018         }
3019         mutex_exit(&esi.esi_mutex);
3020 }
3021 
3022 static void
3023 isnst_esi_stop()
3024 {
3025         boolean_t       need_offline = B_FALSE;
3026 
3027         ISNST_LOG(CE_NOTE, "isnst_esi_stop");
3028 
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;
3035                 }
3036                 mutex_exit(&esi.esi_mutex);
3037                 if (need_offline) {
3038                         idm_soshutdown(esi.esi_so);
3039                         idm_sodestroy(esi.esi_so);
3040                 }
3041                 thread_join(esi.esi_thread_did);
3042         } else {
3043                 mutex_exit(&esi.esi_mutex);
3044         }
3045 }
3046 
3047 /*
3048  * isnst_esi_thread
3049  *
3050  * This function listens on a socket for incoming connections from an
3051  * iSNS server until told to stop.
3052  */
3053 
3054 /*ARGSUSED*/
3055 static void
3056 isnst_esi_thread(void *arg)
3057 {
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;
3065 
3066         bzero(&sin6, sizeof (struct sockaddr_in6));
3067         sin_addrlen = sizeof (struct sockaddr_in6);
3068 
3069         esi.esi_thread_did = curthread->t_did;
3070 
3071         mutex_enter(&esi.esi_mutex);
3072 
3073         /*
3074          * Mark the thread as running and the portal as no longer new.
3075          */
3076         esi.esi_thread_running = B_TRUE;
3077         cv_signal(&esi.esi_cv);
3078 
3079         while (esi.esi_enabled) {
3080                 /*
3081                  * Create a socket to listen for requests from the iSNS server.
3082                  */
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                         delay(drv_usectohz(1000000));
3089                         mutex_enter(&esi.esi_mutex);
3090                         continue;
3091                 }
3092 
3093                 /*
3094                  * Set options, bind, and listen until we're told to stop
3095                  */
3096                 bzero(&sin6, sizeof (sin6));
3097                 sin6.sin6_family = AF_INET6;
3098                 sin6.sin6_port = htons(0);
3099                 sin6.sin6_addr = in6addr_any;
3100 
3101                 (void) ksocket_setsockopt(esi.esi_so, SOL_SOCKET,
3102                     SO_REUSEADDR, (char *)&on, sizeof (on), CRED());
3103 
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                         delay(drv_usectohz(1000000));
3110                         mutex_enter(&esi.esi_mutex);
3111                         continue;
3112                 }
3113 
3114                 /*
3115                  * Get the port (sin6 is meaningless at this point)
3116                  */
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);
3121 
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                         delay(drv_usectohz(1000000));
3128                         mutex_enter(&esi.esi_mutex);
3129                         continue;
3130                 }
3131 
3132                 ksocket_hold(esi.esi_so);
3133                 esi.esi_valid = B_TRUE;
3134                 while (esi.esi_enabled) {
3135                         mutex_exit(&esi.esi_mutex);
3136 
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);
3146                                 /*
3147                                  * If we were interrupted with EINTR
3148                                  * it's not really a failure.
3149                                  */
3150                                 ISNST_LOG(CE_WARN, "isnst_esi_thread: "
3151                                     "accept failure (0x%x)", rc);
3152 
3153                                 if (rc == EINTR) {
3154                                         continue;
3155                                 } else {
3156                                         break;
3157                                 }
3158                         }
3159                         DTRACE_PROBE2(iscsit__isns__esi__accept,
3160                             boolean_t, esi.esi_enabled,
3161                             ksocket_t, newso);
3162 
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);
3169 
3170                                 mutex_enter(&esi.esi_mutex);
3171                                 continue;
3172                         }
3173 
3174                         isnst_handle_esi_req(newso, pdu, pl_size);
3175 
3176                         idm_soshutdown(newso);
3177                         idm_sodestroy(newso);
3178 
3179                         mutex_enter(&esi.esi_mutex);
3180                 }
3181 
3182                 idm_soshutdown(esi.esi_so);
3183                 ksocket_rele(esi.esi_so);
3184                 esi.esi_valid = B_FALSE;
3185 
3186                 /*
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.
3190                  */
3191                 if (esi.esi_enabled)
3192                         idm_sodestroy(esi.esi_so);
3193         }
3194 
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();
3200 }
3201 
3202 /*
3203  * Handle an incoming ESI request
3204  */
3205 
3206 static void
3207 isnst_handle_esi_req(ksocket_t ks, isns_pdu_t *pdu, size_t pdu_size)
3208 {
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;
3222 
3223 
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;
3229         }
3230 
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;
3240         }
3241 
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;
3248         }
3249 
3250         /*
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:
3255          *
3256          * ISNS_TIMESTAMP_ATTR_ID,
3257          * ISNS_EID_ATTR_ID,
3258          * ISNS_PORTAL_IP_ADDR_ATTR_ID,
3259          * ISNS_PORTAL_PORT_ATTR_ID
3260          */
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;
3285                         }
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;
3295                         }
3296                         break;
3297                 default:
3298                         /* Bad request format */
3299                         esi_response = ISNS_RSP_MSG_FORMAT_ERROR;
3300                         break;
3301                 }
3302 
3303                 /* If we've set an error then stop processing */
3304                 if (esi_response != ISNS_RSP_SUCCESSFUL) {
3305                         break;
3306                 }
3307 
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);
3314         }
3315 
3316         if (!portal_port_valid)
3317                 portal_addr6->sin6_port = htons(ISCSI_LISTEN_PORT);
3318 
3319         if (!portal_addr_valid) {
3320                 esi_response = ISNS_RSP_MSG_FORMAT_ERROR;
3321         }
3322 
3323         /*
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.
3327          */
3328 
3329         if (esi_response != ISNS_RSP_SUCCESSFUL) {
3330                 kmem_free(pdu, pdu_size);
3331                 return;
3332         }
3333 
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;
3340         }
3341 
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)));
3350         }
3351 
3352 
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;
3359         }
3360 
3361         /*
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.
3365          */
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;
3371         }
3372 
3373         /*
3374          * Update ESI timestamps for all portals with same IP address.
3375          */
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);
3382                 }
3383         }
3384 
3385         ISNS_GLOBAL_UNLOCK();
3386 
3387 
3388         /*
3389          * Build response validating the portal
3390          */
3391         rsp_size = isnst_create_pdu_header(ISNS_ESI_RSP, &rsp_pdu, 0);
3392 
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;
3397         }
3398 
3399         rsp = (isns_resp_t *)((void *)(&rsp_pdu->payload[0]));
3400 
3401         /* Use xid from the request pdu */
3402         rsp_pdu->xid = pdu->xid;
3403         rsp->status = htonl(ISNS_RSP_SUCCESSFUL);
3404 
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));
3409 
3410         if (isnst_send_pdu(ks, rsp_pdu) != 0) {
3411                 ISNST_LOG(CE_WARN,
3412                     "isnst_handle_esi_req: Send response failed");
3413         }
3414 
3415         kmem_free(rsp_pdu, rsp_size);
3416         kmem_free(pdu, pdu_size);
3417 
3418 }
3419 
3420 static int
3421 isnst_tgt_avl_compare(const void *t1, const void *t2)
3422 {
3423         const isns_target_t     *tgt1 = t1;
3424         const isns_target_t     *tgt2 = t2;
3425 
3426         /*
3427          * Sort by target (pointer to iscsit_tgt_t).
3428          */
3429 
3430         if (tgt1->target < tgt2->target) {
3431                 return (-1);
3432         } else if (tgt1->target > tgt2->target) {
3433                 return (1);
3434         }
3435 
3436         return (0);
3437 }
3438 
3439 static void
3440 isnst_set_server_status(iscsit_isns_svr_t *svr, boolean_t registered)
3441 {
3442         isns_target_t           *itarget;
3443 
3444         ASSERT(ISNS_GLOBAL_LOCK_HELD());
3445 
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;
3463                         }
3464                         itarget = next_target;
3465                 }
3466                 ASSERT(avl_numnodes(&svr->svr_target_list) > 0);
3467         } else {
3468                 svr->svr_registered = B_FALSE;
3469                 isnst_clear_target_list(svr);
3470         }
3471 }
3472 
3473 static void
3474 isnst_monitor_default_portal_list(void)
3475 {
3476         idm_addr_list_t         *new_portal_list = NULL;
3477         uint32_t                new_portal_list_size = 0;
3478 
3479         ASSERT(ISNS_GLOBAL_LOCK_HELD());
3480         ASSERT(mutex_owned(&iscsit_isns_mutex));
3481 
3482         if (default_portal_online) {
3483                 new_portal_list_size = idm_get_ipaddr(&new_portal_list);
3484         }
3485 
3486         /*
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
3491          */
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))) {
3497 
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);
3505                 }
3506         }
3507 
3508         /* Catch any case where we miss an update to TPG portals */
3509         ASSERT(num_tpg_portals == avl_numnodes(&isns_tpg_portals));
3510 
3511         if (new_portal_list != NULL) {
3512                 kmem_free(new_portal_list, new_portal_list_size);
3513         }
3514 }
3515 
3516 
3517 static int
3518 isnst_find_default_portals(idm_addr_list_t *alist)
3519 {
3520         idm_addr_t              *dportal;
3521         isns_portal_t           *iportal;
3522         struct sockaddr_storage sa;
3523         int                     aidx;
3524         int                     num_portals_found = 0;
3525 
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);
3534                 }
3535                 if (iportal->portal_default) {
3536                         num_portals_found++;
3537                 }
3538         }
3539         return (num_portals_found);
3540 }
3541 
3542 static void
3543 isnst_clear_default_portals(void)
3544 {
3545         ASSERT(ISNS_GLOBAL_LOCK_HELD());
3546 
3547         isnst_clear_portal_list(&isns_all_portals);
3548         num_tpg_portals = 0;
3549         num_default_portals = 0;
3550 }
3551 
3552 static int
3553 isnst_add_default_portals(idm_addr_list_t *alist)
3554 {
3555         idm_addr_t              *dportal;
3556         isns_portal_t           *iportal;
3557         struct sockaddr_storage sa;
3558         int                     aidx;
3559 
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;
3566         }
3567         return (alist->al_out_cnt);
3568 }
3569 
3570 
3571 static int
3572 isnst_portal_avl_compare(const void *p1, const void *p2)
3573 {
3574         const isns_portal_t     *portal1 = p1;
3575         const isns_portal_t     *portal2 = p2;
3576 
3577         return (idm_ss_compare(&portal1->portal_addr, &portal2->portal_addr,
3578             B_TRUE /* v4_mapped_as_v4 */, B_TRUE /* compare_ports */));
3579 }
3580 
3581 static void
3582 isnst_clear_portal_list(avl_tree_t *portal_list)
3583 {
3584         isns_portal_t   *iportal;
3585         void *cookie = NULL;
3586 
3587         while ((iportal = avl_destroy_nodes(portal_list, &cookie)) != NULL) {
3588                 kmem_free(iportal, sizeof (isns_portal_t));
3589         }
3590 }
3591 static void
3592 isnst_copy_portal_list(avl_tree_t *t1, avl_tree_t *t2)
3593 {
3594         isns_portal_t           *iportal, *jportal;
3595 
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);
3601         }
3602 }
3603 
3604 
3605 static isns_portal_t *
3606 isnst_lookup_portal(struct sockaddr_storage *sa)
3607 {
3608         isns_portal_t *iportal, tmp_portal;
3609         ASSERT(ISNS_GLOBAL_LOCK_HELD());
3610 
3611         bcopy(sa, &tmp_portal.portal_addr, sizeof (*sa));
3612         iportal = avl_find(&isns_all_portals, &tmp_portal, NULL);
3613         return (iportal);
3614 }
3615 
3616 static isns_portal_t *
3617 isnst_add_to_portal_list(struct sockaddr_storage *sa, avl_tree_t *portal_list)
3618 {
3619         isns_portal_t           *iportal, tmp_portal;
3620         avl_index_t             where;
3621         /*
3622          * Make sure this portal isn't already in our list.
3623          */
3624 
3625         bcopy(sa, &tmp_portal.portal_addr, sizeof (*sa));
3626 
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);
3632         }
3633 
3634         return (iportal);
3635 }
3636 
3637 
3638 static void
3639 isnst_remove_from_portal_list(struct sockaddr_storage *sa,
3640     avl_tree_t *portal_list)
3641 {
3642         isns_portal_t           *iportal, tmp_portal;
3643 
3644         bcopy(sa, &tmp_portal.portal_addr, sizeof (*sa));
3645 
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));
3650         }
3651 }
3652 
3653 /*
3654  * These functions are called by iscsit proper when a portal comes online
3655  * or goes offline.
3656  */
3657 
3658 void
3659 iscsit_isns_portal_online(iscsit_portal_t *portal)
3660 {
3661         isns_portal_t   *iportal;
3662 
3663         mutex_enter(&iscsit_isns_mutex);
3664 
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;
3673         }
3674         isns_portals_changed = B_TRUE;
3675 
3676         mutex_exit(&iscsit_isns_mutex);
3677 
3678         isnst_monitor_awaken();
3679 }
3680 
3681 void
3682 iscsit_isns_portal_offline(iscsit_portal_t *portal)
3683 {
3684         mutex_enter(&iscsit_isns_mutex);
3685 
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);
3693         }
3694         isns_portals_changed = B_TRUE;
3695 
3696         mutex_exit(&iscsit_isns_mutex);
3697 
3698         isnst_monitor_awaken();
3699 }
--- EOF ---