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 /*
  23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
  25  */
  26 
  27 /*
  28  * ISCSID --
  29  *
  30  * Discovery of targets and access to the persistent storage starts here.
  31  */
  32 
  33 #include <sys/thread.h>
  34 #include <sys/types.h>
  35 #include <sys/proc.h>             /* declares:    p0 */
  36 #include <sys/cmn_err.h>
  37 #include <sys/scsi/adapters/iscsi_if.h>
  38 #include <netinet/in.h>
  39 #include "iscsi_targetparam.h"
  40 #include "isns_client.h"
  41 #include "isns_protocol.h"
  42 #include "persistent.h"
  43 #include "iscsi.h"
  44 #include <sys/ethernet.h>
  45 #include <sys/bootprops.h>
  46 
  47 /*
  48  * local function prototypes
  49  */
  50 static boolean_t iscsid_init_config(iscsi_hba_t *ihp);
  51 static boolean_t iscsid_init_targets(iscsi_hba_t *ihp);
  52 static void iscsid_thread_static(iscsi_thread_t *thread, void *p);
  53 static void iscsid_thread_sendtgts(iscsi_thread_t *thread, void *p);
  54 static void iscsid_thread_isns(iscsi_thread_t *thread, void *p);
  55 static void iscsid_thread_slp(iscsi_thread_t *thread, void *p);
  56 static void iscsid_thread_boot_wd(iscsi_thread_t *thread, void *p);
  57 static void iscsid_threads_create(iscsi_hba_t *ihp);
  58 static void iscsid_threads_destroy(void);
  59 static int iscsid_copyto_param_set(uint32_t param_id,
  60     iscsi_login_params_t *params, iscsi_param_set_t *ipsp);
  61 static void iscsid_add_pg_list_to_cache(iscsi_hba_t *ihp,
  62     isns_portal_group_list_t *pg_list);
  63 static void iscsid_remove_target_param(char *name);
  64 static boolean_t iscsid_add(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t method,
  65     struct sockaddr *addr_dsc, char *target_name, int tpgt,
  66     struct sockaddr *addr_tgt);
  67 static void iscsi_discovery_event(iscsi_hba_t *ihp,
  68     iSCSIDiscoveryMethod_t m, boolean_t start);
  69 static boolean_t iscsid_boot_init_config(iscsi_hba_t *ihp);
  70 static iscsi_sess_t *iscsi_add_boot_sess(iscsi_hba_t *ihp, int isid);
  71 static boolean_t iscsid_make_entry(ib_boot_prop_t *boot_prop_entry,
  72     entry_t *entry);
  73 static boolean_t iscsid_check_active_boot_conn(iscsi_hba_t *ihp);
  74 
  75 extern int modrootloaded;
  76 int iscsi_configroot_retry = 20;
  77 static boolean_t iscsi_configroot_printed = FALSE;
  78 static int iscsi_net_up = 0;
  79 extern ib_boot_prop_t   *iscsiboot_prop;
  80 
  81 #define ISCSI_CONFIGROOT_DELAY  1
  82 
  83 /*
  84  * iSCSI target discovery thread table
  85  */
  86 typedef struct iscsid_thr_table {
  87         void                    (*func_start)(iscsi_thread_t *, void *);
  88         iscsi_thread_t          *thr_id;
  89         iSCSIDiscoveryMethod_t  method;
  90         char                    *name;
  91 } iscsid_thr_table;
  92 
  93 static iscsid_thr_table iscsid_thr[] = {
  94         { iscsid_thread_static, NULL,
  95             iSCSIDiscoveryMethodStatic,
  96             "Static" },
  97         { iscsid_thread_sendtgts, NULL,
  98             iSCSIDiscoveryMethodSendTargets,
  99             "SendTarget" },
 100         { iscsid_thread_slp, NULL,
 101             iSCSIDiscoveryMethodSLP,
 102             "SLP" },
 103         { iscsid_thread_isns, NULL,
 104             iSCSIDiscoveryMethodISNS,
 105             "iSNS" },
 106         { NULL, NULL,
 107             iSCSIDiscoveryMethodUnknown,
 108             NULL }
 109 };
 110 
 111 /*
 112  * discovery method event table
 113  */
 114 iSCSIDiscoveryMethod_t  for_failure[] = {
 115         iSCSIDiscoveryMethodStatic,
 116         iSCSIDiscoveryMethodSLP,
 117         iSCSIDiscoveryMethodISNS,
 118         iSCSIDiscoveryMethodSendTargets,
 119         iSCSIDiscoveryMethodUnknown /* terminating value */
 120 };
 121 
 122 /*
 123  * The following private tunable, set in /etc/system, e.g.,
 124  *      set iscsi:iscsi_boot_max_delay = 360
 125  * , provides with customer a max wait time in
 126  * seconds to wait for boot lun online during iscsi boot.
 127  * Defaults to 180s.
 128  */
 129 int iscsi_boot_max_delay = ISCSI_BOOT_DEFAULT_MAX_DELAY;
 130 
 131 /*
 132  * discovery configuration semaphore
 133  */
 134 ksema_t iscsid_config_semaphore;
 135 
 136 static iscsi_thread_t   *iscsi_boot_wd_handle = NULL;
 137 
 138 #define CHECK_METHOD(v) ((dm & v) ? B_TRUE : B_FALSE)
 139 
 140 /*
 141  * Check if IP is valid
 142  */
 143 static boolean_t
 144 iscsid_ip_check(char *ip)
 145 {
 146         int     i       = 0;
 147 
 148         if (!ip)
 149                 return (B_FALSE);
 150         for (; (ip[i] == 0) && (i < IB_IP_BUFLEN); i++) {}
 151         if (i == IB_IP_BUFLEN) {
 152                 /* invalid IP address */
 153                 return (B_FALSE);
 154         }
 155         return (B_TRUE);
 156 }
 157 
 158 /*
 159  * Make an entry for the boot target.
 160  * return B_TRUE upon success
 161  *        B_FALSE if fail
 162  */
 163 static boolean_t
 164 iscsid_make_entry(ib_boot_prop_t *boot_prop_entry, entry_t *entry)
 165 {
 166         if (entry == NULL || boot_prop_entry == NULL) {
 167                 return (B_FALSE);
 168         }
 169 
 170         if (!iscsid_ip_check(
 171             (char *)&boot_prop_entry->boot_tgt.tgt_ip_u))
 172                 return (B_FALSE);
 173 
 174         if (boot_prop_entry->boot_tgt.sin_family != AF_INET &&
 175             boot_prop_entry->boot_tgt.sin_family != AF_INET6)
 176                 return (B_FALSE);
 177 
 178         entry->e_vers = ISCSI_INTERFACE_VERSION;
 179 
 180         mutex_enter(&iscsi_oid_mutex);
 181         entry->e_oid = iscsi_oid++;
 182         mutex_exit(&iscsi_oid_mutex);
 183 
 184         entry->e_tpgt = ISCSI_DEFAULT_TPGT;
 185 
 186         if (boot_prop_entry->boot_tgt.sin_family == AF_INET) {
 187                 entry->e_u.u_in4.s_addr =
 188                     boot_prop_entry->boot_tgt.tgt_ip_u.u_in4.s_addr;
 189                 entry->e_insize = sizeof (struct in_addr);
 190         } else {
 191                 (void) bcopy(
 192                     &boot_prop_entry->boot_tgt.tgt_ip_u.u_in6.s6_addr,
 193                     entry->e_u.u_in6.s6_addr, 16);
 194                 entry->e_insize = sizeof (struct in6_addr);
 195         }
 196 
 197         entry->e_port = boot_prop_entry->boot_tgt.tgt_port;
 198         entry->e_boot = B_TRUE;
 199         return (B_TRUE);
 200 }
 201 
 202 /*
 203  * Create the boot session
 204  */
 205 static void
 206 iscsi_boot_session_create(iscsi_hba_t *ihp,
 207     ib_boot_prop_t      *boot_prop_table)
 208 {
 209         iSCSIDiscoveryMethod_t  dm;
 210         entry_t                 e;
 211         iscsi_sockaddr_t        addr_dsc;
 212 
 213         if (ihp == NULL || boot_prop_table == NULL) {
 214                 return;
 215         }
 216 
 217         if (!iscsid_ip_check(
 218             (char *)&boot_prop_table->boot_tgt.tgt_ip_u)) {
 219                 return;
 220         }
 221 
 222         if (boot_prop_table->boot_tgt.tgt_name != NULL) {
 223                 dm = iSCSIDiscoveryMethodStatic |
 224                     iSCSIDiscoveryMethodBoot;
 225                 if (!iscsid_make_entry(boot_prop_table, &e))
 226                         return;
 227                 iscsid_addr_to_sockaddr(e.e_insize, &e.e_u,
 228                     e.e_port, &addr_dsc.sin);
 229 
 230                 (void) iscsid_add(ihp, dm, &addr_dsc.sin,
 231                     (char *)boot_prop_table->boot_tgt.tgt_name,
 232                     e.e_tpgt, &addr_dsc.sin);
 233         } else {
 234                 dm = iSCSIDiscoveryMethodSendTargets |
 235                     iSCSIDiscoveryMethodBoot;
 236                 if (!iscsid_make_entry(boot_prop_table, &e))
 237                         return;
 238                 iscsid_addr_to_sockaddr(e.e_insize, &e.e_u,
 239                     e.e_port, &addr_dsc.sin);
 240                 iscsid_do_sendtgts(&e);
 241                 (void) iscsid_login_tgt(ihp, NULL, dm,
 242                     &addr_dsc.sin);
 243         }
 244 }
 245 
 246 /*
 247  * iscsid_init -- to initialize stuffs related to iscsi daemon,
 248  * and to create boot session if needed
 249  */
 250 boolean_t
 251 iscsid_init(iscsi_hba_t *ihp)
 252 {
 253         boolean_t               rval = B_TRUE;
 254 
 255         sema_init(&iscsid_config_semaphore, 1, NULL,
 256             SEMA_DRIVER, NULL);
 257         persistent_init();
 258         iscsid_threads_create(ihp);
 259 
 260         if (modrootloaded == 1) {
 261                 /* normal case, load the persistent store */
 262                 if (persistent_load() == B_TRUE) {
 263                         ihp->hba_persistent_loaded = B_TRUE;
 264                 } else {
 265                         return (B_FALSE);
 266                 }
 267         }
 268 
 269         if ((modrootloaded == 0) && (iscsiboot_prop != NULL)) {
 270                 if (!iscsid_boot_init_config(ihp)) {
 271                         rval = B_FALSE;
 272                 } else {
 273                         iscsi_boot_session_create(ihp, iscsiboot_prop);
 274                         iscsi_boot_wd_handle =
 275                             iscsi_thread_create(ihp->hba_dip,
 276                             "BootWD", iscsid_thread_boot_wd, ihp);
 277                         if (iscsi_boot_wd_handle) {
 278                                 rval = iscsi_thread_start(
 279                                     iscsi_boot_wd_handle);
 280                         } else {
 281                                 rval = B_FALSE;
 282                         }
 283                 }
 284                 if (rval == B_FALSE) {
 285                         cmn_err(CE_NOTE, "Initializaton of iscsi boot session"
 286                             " partially failed");
 287                 }
 288         }
 289 
 290         return (rval);
 291 }
 292 
 293 /*
 294  * iscsid_start -- start the iscsi initiator daemon, actually this code
 295  * is just to enable discovery methods which are set enabled in
 296  * persistent store, as an economic way to present the 'daemon' funtionality
 297  */
 298 boolean_t
 299 iscsid_start(iscsi_hba_t *ihp) {
 300         boolean_t               rval = B_FALSE;
 301         iSCSIDiscoveryMethod_t  dm;
 302         iSCSIDiscoveryMethod_t  *fdm;
 303 
 304         rval = iscsid_init_config(ihp);
 305         if (rval == B_TRUE) {
 306                 rval = iscsid_init_targets(ihp);
 307         }
 308 
 309         if (rval == B_TRUE) {
 310                 dm = persistent_disc_meth_get();
 311                 rval = iscsid_enable_discovery(ihp, dm, B_TRUE);
 312                 if (rval == B_TRUE) {
 313                         iscsid_poke_discovery(ihp,
 314                             iSCSIDiscoveryMethodUnknown);
 315                         (void) iscsid_login_tgt(ihp, NULL,
 316                             iSCSIDiscoveryMethodUnknown, NULL);
 317                 }
 318         }
 319 
 320         if (rval == B_FALSE) {
 321                 /*
 322                  * In case of failure the events still need to be sent
 323                  * because the door daemon will pause until all these
 324                  * events have occurred.
 325                  */
 326                 for (fdm = &for_failure[0]; *fdm !=
 327                     iSCSIDiscoveryMethodUnknown; fdm++) {
 328                         /* ---- Send both start and end events ---- */
 329                         iscsi_discovery_event(ihp, *fdm, B_TRUE);
 330                         iscsi_discovery_event(ihp, *fdm, B_FALSE);
 331                 }
 332         }
 333 
 334         return (rval);
 335 }
 336 
 337 /*
 338  * iscsid_stop -- stop the iscsi initiator daemon, by disabling
 339  * all the discovery methods first, and then try to stop all
 340  * related threads. This is a try-best effort, leave any 'busy' device
 341  * (and therefore session) there and just return.
 342  */
 343 boolean_t
 344 iscsid_stop(iscsi_hba_t *ihp) {
 345         boolean_t               rval = B_FALSE;
 346         iscsi_sess_t            *isp = NULL;
 347 
 348         (void) iscsid_disable_discovery(ihp, ISCSI_ALL_DISCOVERY_METHODS);
 349 
 350         /* final check */
 351         rw_enter(&ihp->hba_sess_list_rwlock, RW_READER);
 352         if (ihp->hba_sess_list == NULL) {
 353                 rval = B_TRUE;
 354         } else {
 355                 /*
 356                  * If only boot session is left, that is OK.
 357                  * Otherwise, we should report that some sessions are left.
 358                  */
 359                 rval = B_TRUE;
 360                 for (isp = ihp->hba_sess_list; isp != NULL;
 361                     isp = isp->sess_next) {
 362                         if (isp->sess_boot == B_FALSE) {
 363                                 rval = B_FALSE;
 364                                 break;
 365                         }
 366                 }
 367         }
 368         rw_exit(&ihp->hba_sess_list_rwlock);
 369 
 370         return (rval);
 371 }
 372 
 373 /*
 374  * iscsid_fini -- do whatever is required to clean up
 375  */
 376 /* ARGSUSED */
 377 void
 378 iscsid_fini()
 379 {
 380         if (iscsi_boot_wd_handle != NULL) {
 381                 iscsi_thread_destroy(iscsi_boot_wd_handle);
 382                 iscsi_boot_wd_handle = NULL;
 383         }
 384         iscsid_threads_destroy();
 385         persistent_fini();
 386         sema_destroy(&iscsid_config_semaphore);
 387 }
 388 
 389 /*
 390  * iscsid_props -- returns discovery thread information, used by ioctl code
 391  */
 392 void
 393 iscsid_props(iSCSIDiscoveryProperties_t *props)
 394 {
 395         iSCSIDiscoveryMethod_t  dm;
 396 
 397         dm = persistent_disc_meth_get();
 398 
 399         props->vers = ISCSI_INTERFACE_VERSION;
 400 
 401         /* ---- change once thread is implemented ---- */
 402         props->iSNSDiscoverySettable         = B_FALSE;
 403         props->SLPDiscoverySettable          = B_FALSE;
 404         props->StaticDiscoverySettable               = B_TRUE;
 405         props->SendTargetsDiscoverySettable  = B_TRUE;
 406         props->iSNSDiscoveryMethod           = iSNSDiscoveryMethodStatic;
 407 
 408         props->iSNSDiscoveryEnabled = CHECK_METHOD(iSCSIDiscoveryMethodISNS);
 409         props->StaticDiscoveryEnabled =
 410             CHECK_METHOD(iSCSIDiscoveryMethodStatic);
 411         props->SendTargetsDiscoveryEnabled =
 412             CHECK_METHOD(iSCSIDiscoveryMethodSendTargets);
 413         props->SLPDiscoveryEnabled = CHECK_METHOD(iSCSIDiscoveryMethodSLP);
 414 }
 415 
 416 /*
 417  * iscsid_enable_discovery - start specified discovery methods
 418  */
 419 /* ARGSUSED */
 420 boolean_t
 421 iscsid_enable_discovery(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t idm,
 422     boolean_t poke)
 423 {
 424         boolean_t               rval = B_TRUE;
 425         iscsid_thr_table        *dt;
 426 
 427         /*
 428          * start the specified discovery method(s)
 429          */
 430         for (dt = &iscsid_thr[0]; dt->method != iSCSIDiscoveryMethodUnknown;
 431             dt++) {
 432                 if (idm & dt->method) {
 433                         if (dt->thr_id != NULL) {
 434                                 rval = iscsi_thread_start(dt->thr_id);
 435                                 if (rval == B_FALSE) {
 436                                         break;
 437                                 }
 438                                 if (poke == B_TRUE) {
 439                                         (void) iscsi_thread_send_wakeup(
 440                                             dt->thr_id);
 441                                 }
 442                         } else {
 443                                 /*
 444                                  * unexpected condition.  The threads for each
 445                                  * discovery method should have started at
 446                                  * initialization
 447                                  */
 448                                 ASSERT(B_FALSE);
 449                         }
 450                 }
 451         } /* END for() */
 452 
 453         return (rval);
 454 }
 455 
 456 
 457 /*
 458  * iscsid_disable_discovery - stop specified discovery methods
 459  */
 460 boolean_t
 461 iscsid_disable_discovery(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t idm)
 462 {
 463         boolean_t               rval = B_TRUE;
 464         iscsid_thr_table        *dt;
 465 
 466         /*
 467          * stop the specified discovery method(s)
 468          */
 469         for (dt = &iscsid_thr[0]; dt->method != iSCSIDiscoveryMethodUnknown;
 470             dt++) {
 471                 if (idm & dt->method) {
 472 
 473                         /* signal discovery event change - begin */
 474                         iscsi_discovery_event(ihp, dt->method, B_TRUE);
 475 
 476                         /* Attempt to logout of all associated targets */
 477                         rval = iscsid_del(ihp, NULL, dt->method, NULL);
 478                         if (rval == B_TRUE) {
 479                                 /* Successfully logged out of targets */
 480                                 if (dt->thr_id != NULL) {
 481                                         rval = iscsi_thread_stop(dt->thr_id);
 482                                         if (rval == B_FALSE) {
 483                                                 /*
 484                                                  * signal discovery
 485                                                  * event change - end
 486                                                  */
 487                                                 iscsi_discovery_event(ihp,
 488                                                     dt->method, B_FALSE);
 489                                                 break;
 490                                         }
 491 
 492                                 } else {
 493                                         /*
 494                                          * unexpected condition.  The threads
 495                                          * for each discovery method should
 496                                          * have started at initialization
 497                                          */
 498                                         ASSERT(B_FALSE);
 499                                 }
 500                         }
 501 
 502                         /* signal discovery event change - end */
 503                         iscsi_discovery_event(ihp, dt->method, B_FALSE);
 504 
 505                 }
 506         } /* END for() */
 507 
 508         return (rval);
 509 }
 510 
 511 /*
 512  * iscsid_poke_discovery - wakeup discovery methods to find any new targets
 513  * and wait for all discovery processes to complete.
 514  */
 515 void
 516 iscsid_poke_discovery(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t method)
 517 {
 518 #define ISCSI_DISCOVERY_DELAY   1
 519 
 520         iSCSIDiscoveryMethod_t  dm;
 521         iscsid_thr_table        *dt;
 522         boolean_t               send_wakeup;
 523 
 524         ASSERT(ihp != NULL);
 525 
 526         /* reset discovery flags */
 527         mutex_enter(&ihp->hba_discovery_events_mutex);
 528         ihp->hba_discovery_in_progress = B_TRUE;
 529         ihp->hba_discovery_events = iSCSIDiscoveryMethodUnknown;
 530         mutex_exit(&ihp->hba_discovery_events_mutex);
 531 
 532         /* start all enabled discovery methods */
 533         dm = persistent_disc_meth_get();
 534         for (dt = &iscsid_thr[0]; dt->method != iSCSIDiscoveryMethodUnknown;
 535             dt++) {
 536                 send_wakeup = B_FALSE;
 537 
 538                 if ((method == iSCSIDiscoveryMethodUnknown) ||
 539                     (method == dt->method)) {
 540                         if ((dm & dt->method) && (dt->thr_id != NULL)) {
 541                                 if (iscsi_thread_send_wakeup(dt->thr_id) ==
 542                                     B_TRUE) {
 543                                         send_wakeup = B_TRUE;
 544                                 }
 545                         }
 546                 }
 547 
 548                 if (send_wakeup == B_FALSE) {
 549                         iscsi_discovery_event(ihp, dt->method, B_TRUE);
 550                         iscsi_discovery_event(ihp, dt->method, B_FALSE);
 551                 }
 552         }
 553 
 554         mutex_enter(&ihp->hba_discovery_events_mutex);
 555         while (ihp->hba_discovery_events != ISCSI_ALL_DISCOVERY_METHODS) {
 556                 mutex_exit(&ihp->hba_discovery_events_mutex);
 557                 delay(SEC_TO_TICK(ISCSI_DISCOVERY_DELAY));
 558                 mutex_enter(&ihp->hba_discovery_events_mutex);
 559         }
 560         ihp->hba_discovery_in_progress = B_FALSE;
 561         mutex_exit(&ihp->hba_discovery_events_mutex);
 562 
 563 }
 564 
 565 /*
 566  * iscsid_do_sendtgts - issue send targets command to the given discovery
 567  * address and then add the discovered targets to the discovery queue
 568  */
 569 void
 570 iscsid_do_sendtgts(entry_t *disc_addr)
 571 {
 572 
 573 #define SENDTGTS_DEFAULT_NUM_TARGETS    10
 574 
 575         int                     stl_sz;
 576         int                     stl_num_tgts = SENDTGTS_DEFAULT_NUM_TARGETS;
 577         iscsi_sendtgts_list_t   *stl_hdr = NULL;
 578         boolean_t               retry = B_TRUE;
 579         char                    inp_buf[INET6_ADDRSTRLEN];
 580         const char              *ip;
 581         int                     ctr;
 582         int                     rc;
 583         iscsi_hba_t             *ihp;
 584         iSCSIDiscoveryMethod_t  dm = iSCSIDiscoveryMethodSendTargets;
 585 
 586         /* allocate and initialize sendtargets list header */
 587         stl_sz = sizeof (*stl_hdr) + ((stl_num_tgts - 1) *
 588             sizeof (iscsi_sendtgts_entry_t));
 589         stl_hdr = kmem_zalloc(stl_sz, KM_SLEEP);
 590 
 591 retry_sendtgts:
 592         stl_hdr->stl_in_cnt = stl_num_tgts;
 593         bcopy(disc_addr, &(stl_hdr->stl_entry),
 594             sizeof (stl_hdr->stl_entry));
 595         stl_hdr->stl_entry.e_vers = ISCSI_INTERFACE_VERSION;
 596 
 597         /* lock interface so only one SendTargets operation occurs */
 598         if ((ihp = (iscsi_hba_t *)ddi_get_soft_state(iscsi_state, 0)) == NULL) {
 599                 cmn_err(CE_NOTE, "!iscsi discovery failure - SendTargets. "
 600                     "failure to get soft state");
 601                 kmem_free(stl_hdr, stl_sz);
 602                 return;
 603         }
 604         sema_p(&ihp->hba_sendtgts_semaphore);
 605         rc = iscsi_ioctl_sendtgts_get(ihp, stl_hdr);
 606         sema_v(&ihp->hba_sendtgts_semaphore);
 607         if (rc) {
 608                 ip = inet_ntop((disc_addr->e_insize ==
 609                     sizeof (struct in_addr) ? AF_INET : AF_INET6),
 610                     &disc_addr->e_u, inp_buf, sizeof (inp_buf));
 611                 cmn_err(CE_NOTE,
 612                     "iscsi discovery failure - SendTargets (%s)\n", ip);
 613                 kmem_free(stl_hdr, stl_sz);
 614                 return;
 615         }
 616 
 617         /* check if all targets received */
 618         if (stl_hdr->stl_in_cnt < stl_hdr->stl_out_cnt) {
 619                 if (retry == B_TRUE) {
 620                         stl_num_tgts = stl_hdr->stl_out_cnt;
 621                         kmem_free(stl_hdr, stl_sz);
 622                         stl_sz = sizeof (*stl_hdr) +
 623                             ((stl_num_tgts - 1) *
 624                             sizeof (iscsi_sendtgts_entry_t));
 625                         stl_hdr = kmem_zalloc(stl_sz, KM_SLEEP);
 626                         retry = B_FALSE;
 627                         goto retry_sendtgts;
 628                 } else {
 629                         ip = inet_ntop((disc_addr->e_insize ==
 630                             sizeof (struct in_addr) ?
 631                             AF_INET : AF_INET6), &disc_addr->e_u,
 632                             inp_buf, sizeof (inp_buf));
 633                         cmn_err(CE_NOTE, "iscsi discovery failure - "
 634                             "SendTargets overflow (%s)\n", ip);
 635                         kmem_free(stl_hdr, stl_sz);
 636                         return;
 637                 }
 638         }
 639 
 640         for (ctr = 0; ctr < stl_hdr->stl_out_cnt; ctr++) {
 641                 iscsi_sockaddr_t addr_dsc;
 642                 iscsi_sockaddr_t addr_tgt;
 643 
 644                 iscsid_addr_to_sockaddr(disc_addr->e_insize,
 645                     &disc_addr->e_u, disc_addr->e_port, &addr_dsc.sin);
 646                 iscsid_addr_to_sockaddr(
 647                     stl_hdr->stl_list[ctr].ste_ipaddr.a_addr.i_insize,
 648                     &(stl_hdr->stl_list[ctr].ste_ipaddr.a_addr.i_addr),
 649                     stl_hdr->stl_list[ctr].ste_ipaddr.a_port,
 650                     &addr_tgt.sin);
 651                 if (disc_addr->e_boot == B_TRUE) {
 652                         dm = dm | iSCSIDiscoveryMethodBoot;
 653                 }
 654                 (void) iscsid_add(ihp, dm,
 655                     &addr_dsc.sin, (char *)stl_hdr->stl_list[ctr].ste_name,
 656                     stl_hdr->stl_list[ctr].ste_tpgt,
 657                     &addr_tgt.sin);
 658         }
 659         kmem_free(stl_hdr, stl_sz);
 660 }
 661 
 662 void
 663 iscsid_do_isns_query_one_server(iscsi_hba_t *ihp, entry_t *isns_server)
 664 {
 665         int pg_sz, query_status;
 666         iscsi_addr_t *ap;
 667         isns_portal_group_list_t *pg_list;
 668 
 669         ap = (iscsi_addr_t *)kmem_zalloc(sizeof (iscsi_addr_t), KM_SLEEP);
 670         ap->a_port = isns_server->e_port;
 671         ap->a_addr.i_insize = isns_server->e_insize;
 672 
 673         if (isns_server->e_insize == sizeof (struct in_addr)) {
 674                 ap->a_addr.i_addr.in4.s_addr = (isns_server->e_u.u_in4.s_addr);
 675         } else if (isns_server->e_insize == sizeof (struct in6_addr)) {
 676                 bcopy(&(isns_server->e_u.u_in6.s6_addr),
 677                     ap->a_addr.i_addr.in6.s6_addr, 16);
 678         } else {
 679                 kmem_free(ap, sizeof (iscsi_addr_t));
 680                 return;
 681         }
 682 
 683         pg_list = NULL;
 684         query_status = isns_query_one_server(
 685             ap, ihp->hba_isid,
 686             ihp->hba_name, ihp->hba_alias,
 687             ISNS_INITIATOR_NODE_TYPE, &pg_list);
 688         kmem_free(ap, sizeof (iscsi_addr_t));
 689         if (query_status != isns_ok || pg_list == NULL) {
 690                 DTRACE_PROBE1(iscsid_do_isns_query_one_server_status,
 691                     int, query_status);
 692                 return;
 693         }
 694 
 695         iscsid_add_pg_list_to_cache(ihp, pg_list);
 696         pg_sz = sizeof (isns_portal_group_list_t);
 697         if (pg_list->pg_out_cnt > 0) {
 698                 pg_sz += (pg_list->pg_out_cnt - 1) *
 699                     sizeof (isns_portal_group_t);
 700         }
 701         kmem_free(pg_list, pg_sz);
 702 }
 703 
 704 void
 705 iscsid_do_isns_query(iscsi_hba_t *ihp)
 706 {
 707         int pg_sz, query_status;
 708         isns_portal_group_list_t *pg_list;
 709 
 710         pg_list = NULL;
 711         query_status = isns_query(ihp->hba_isid,
 712             ihp->hba_name,
 713             ihp->hba_alias,
 714             ISNS_INITIATOR_NODE_TYPE,
 715             &pg_list);
 716 
 717         if (pg_list == NULL) {
 718                 DTRACE_PROBE1(iscsid_do_isns_query_status,
 719                     int, query_status);
 720                 return;
 721         }
 722 
 723         if ((query_status != isns_ok &&
 724             query_status != isns_op_partially_failed)) {
 725                 DTRACE_PROBE1(iscsid_do_isns_query_status,
 726                     int, query_status);
 727                 pg_sz = sizeof (isns_portal_group_list_t);
 728                 if (pg_list->pg_out_cnt > 0) {
 729                         pg_sz += (pg_list->pg_out_cnt - 1) *
 730                             sizeof (isns_portal_group_t);
 731                 }
 732                 kmem_free(pg_list, pg_sz);
 733                 return;
 734         }
 735 
 736         iscsid_add_pg_list_to_cache(ihp, pg_list);
 737 
 738         pg_sz = sizeof (isns_portal_group_list_t);
 739         if (pg_list->pg_out_cnt > 0) {
 740                 pg_sz += (pg_list->pg_out_cnt - 1) *
 741                     sizeof (isns_portal_group_t);
 742         }
 743         kmem_free(pg_list, pg_sz);
 744 }
 745 
 746 /*
 747  * iscsid_config_one - for the given target name, attempt
 748  * to login to all targets associated with name.  If target
 749  * name is not found in discovery queue, reset the discovery
 750  * queue, kick the discovery processes, and then retry.
 751  *
 752  * NOTE: The caller of this function must hold the
 753  *      iscsid_config_semaphore across this call.
 754  */
 755 void
 756 iscsid_config_one(iscsi_hba_t *ihp, char *name, boolean_t protect)
 757 {
 758         boolean_t       rc          =   B_FALSE;
 759         int             retry       =   0;
 760         int             lun_online  =   0;
 761         int             cur_sec     =   0;
 762 
 763         if (!modrootloaded && (iscsiboot_prop != NULL)) {
 764                 if (!iscsi_configroot_printed) {
 765                         cmn_err(CE_NOTE, "Configuring"
 766                             " iSCSI boot session...");
 767                         iscsi_configroot_printed = B_TRUE;
 768                 }
 769                 if (iscsi_net_up == 0) {
 770                         if (iscsi_net_interface(B_FALSE) ==
 771                             ISCSI_STATUS_SUCCESS) {
 772                                 iscsi_net_up = 1;
 773                         } else {
 774                                 cmn_err(CE_WARN, "Failed to configure interface"
 775                                     " for iSCSI boot session");
 776                                 return;
 777                         }
 778                 }
 779                 while (rc == B_FALSE && retry <
 780                     iscsi_configroot_retry) {
 781                         rc = iscsid_login_tgt(ihp, name,
 782                             iSCSIDiscoveryMethodBoot, NULL);
 783                         if (rc == B_FALSE) {
 784                                 /*
 785                                  * create boot session
 786                                  */
 787                                 iscsi_boot_session_create(ihp,
 788                                     iscsiboot_prop);
 789                                 retry++;
 790                                 continue;
 791                         }
 792                         rc = iscsid_check_active_boot_conn(ihp);
 793                         if (rc == B_FALSE) {
 794                                 /*
 795                                  * no active connection for the boot
 796                                  * session, retry the login until
 797                                  * one is found or the retry count
 798                                  * is exceeded
 799                                  */
 800                                 delay(SEC_TO_TICK(ISCSI_CONFIGROOT_DELAY));
 801                                 retry++;
 802                                 continue;
 803                         }
 804                         /*
 805                          * The boot session has been created with active
 806                          * connection. If the target lun has not been online,
 807                          * we should wait here for a while
 808                          */
 809                         do {
 810                                 lun_online =
 811                                     iscsiboot_prop->boot_tgt.lun_online;
 812                                 if (lun_online == 0) {
 813                                         delay(SEC_TO_TICK(
 814                                             ISCSI_CONFIGROOT_DELAY));
 815                                         cur_sec++;
 816                                 }
 817                         } while ((lun_online == 0) &&
 818                             (cur_sec < iscsi_boot_max_delay));
 819                         retry++;
 820                 }
 821                 if (!rc) {
 822                         cmn_err(CE_WARN, "Failed to configure iSCSI"
 823                             " boot session");
 824                 }
 825         } else {
 826                 rc = iscsid_login_tgt(ihp, name, iSCSIDiscoveryMethodUnknown,
 827                     NULL);
 828                 /*
 829                  * If we didn't login to the device we might have
 830                  * to update our discovery information and attempt
 831                  * the login again.
 832                  */
 833                 if (rc == B_FALSE) {
 834                         /*
 835                          * Stale /dev links can cause us to get floods
 836                          * of config requests.  Prevent these repeated
 837                          * requests from causing unneeded discovery updates
 838                          * if ISCSI_CONFIG_STORM_PROTECT is set.
 839                          */
 840                         if ((protect == B_FALSE) ||
 841                             (ddi_get_lbolt() > ihp->hba_config_lbolt +
 842                             SEC_TO_TICK(ihp->hba_config_storm_delay))) {
 843                                 ihp->hba_config_lbolt = ddi_get_lbolt();
 844                                 iscsid_poke_discovery(ihp,
 845                                     iSCSIDiscoveryMethodUnknown);
 846                                 (void) iscsid_login_tgt(ihp, name,
 847                                     iSCSIDiscoveryMethodUnknown, NULL);
 848                         }
 849                 }
 850         }
 851 }
 852 
 853 /*
 854  * iscsid_config_all - reset the discovery queue, kick the
 855  * discovery processes, and login to all targets found
 856  *
 857  * NOTE: The caller of this function must hold the
 858  *      iscsid_config_semaphore across this call.
 859  */
 860 void
 861 iscsid_config_all(iscsi_hba_t *ihp, boolean_t protect)
 862 {
 863         boolean_t       rc              = B_FALSE;
 864         int             retry   = 0;
 865         int             lun_online  = 0;
 866         int             cur_sec = 0;
 867 
 868         if (!modrootloaded && iscsiboot_prop != NULL) {
 869                 if (!iscsi_configroot_printed) {
 870                         cmn_err(CE_NOTE, "Configuring"
 871                             " iSCSI boot session...");
 872                         iscsi_configroot_printed = B_TRUE;
 873                 }
 874                 if (iscsi_net_up == 0) {
 875                         if (iscsi_net_interface(B_FALSE) ==
 876                             ISCSI_STATUS_SUCCESS) {
 877                                 iscsi_net_up = 1;
 878                         }
 879                 }
 880                 while (rc == B_FALSE && retry <
 881                     iscsi_configroot_retry) {
 882                         rc = iscsid_login_tgt(ihp, NULL,
 883                             iSCSIDiscoveryMethodBoot, NULL);
 884                         if (rc == B_FALSE) {
 885                                 /*
 886                                  * No boot session has been created.
 887                                  * We would like to create the boot
 888                                  * Session first.
 889                                  */
 890                                 iscsi_boot_session_create(ihp,
 891                                     iscsiboot_prop);
 892                                 retry++;
 893                                 continue;
 894                         }
 895                         rc = iscsid_check_active_boot_conn(ihp);
 896                         if (rc == B_FALSE) {
 897                                 /*
 898                                  * no active connection for the boot
 899                                  * session, retry the login until
 900                                  * one is found or the retry count
 901                                  * is exceeded
 902                                  */
 903                                 delay(SEC_TO_TICK(ISCSI_CONFIGROOT_DELAY));
 904                                 retry++;
 905                                 continue;
 906                         }
 907                         /*
 908                          * The boot session has been created with active
 909                          * connection. If the target lun has not been online,
 910                          * we should wait here for a while
 911                          */
 912                         do {
 913                                 lun_online =
 914                                     iscsiboot_prop->boot_tgt.lun_online;
 915                                 if (lun_online == 0) {
 916                                         delay(SEC_TO_TICK(
 917                                             ISCSI_CONFIGROOT_DELAY));
 918                                         cur_sec++;
 919                                 }
 920                         } while ((lun_online == 0) &&
 921                             (cur_sec < iscsi_boot_max_delay));
 922                         retry++;
 923                 }
 924                 if (!rc) {
 925                         cmn_err(CE_WARN, "Failed to configure"
 926                             " boot session");
 927                 }
 928         } else {
 929                 /*
 930                  * Stale /dev links can cause us to get floods
 931                  * of config requests.  Prevent these repeated
 932                  * requests from causing unneeded discovery updates
 933                  * if ISCSI_CONFIG_STORM_PROTECT is set.
 934                  */
 935                 if ((protect == B_FALSE) ||
 936                     (ddi_get_lbolt() > ihp->hba_config_lbolt +
 937                     SEC_TO_TICK(ihp->hba_config_storm_delay))) {
 938                         ihp->hba_config_lbolt = ddi_get_lbolt();
 939                         iscsid_poke_discovery(ihp,
 940                             iSCSIDiscoveryMethodUnknown);
 941                 }
 942                 (void) iscsid_login_tgt(ihp, NULL,
 943                     iSCSIDiscoveryMethodUnknown, NULL);
 944         }
 945 }
 946 
 947 /*
 948  * isns_scn_callback - iSNS client received an SCN
 949  *
 950  * This code processes the iSNS client SCN events.  These
 951  * could relate to the addition, removal, or update of a
 952  * logical unit.
 953  */
 954 void
 955 isns_scn_callback(void *arg)
 956 {
 957         int                             i, pg_sz;
 958         int                             qry_status;
 959         isns_portal_group_list_t        *pg_list;
 960         uint32_t                        scn_type;
 961         iscsi_hba_t                     *ihp;
 962 
 963         if (arg == NULL) {
 964                 /* No argument */
 965                 return;
 966         }
 967 
 968         if ((ihp = (iscsi_hba_t *)ddi_get_soft_state(iscsi_state, 0)) == NULL) {
 969                 kmem_free(arg, sizeof (isns_scn_callback_arg_t));
 970                 return;
 971         }
 972 
 973         /*
 974          * All isns callbacks are from a standalone taskq
 975          * therefore the blocking here doesn't affect the enable/disable
 976          * of isns discovery method
 977          */
 978         if (iscsi_client_request_service(ihp) == B_FALSE) {
 979                 kmem_free(arg, sizeof (isns_scn_callback_arg_t));
 980                 return;
 981         }
 982 
 983         scn_type = ((isns_scn_callback_arg_t *)arg)->scn_type;
 984         DTRACE_PROBE1(isns_scn_callback_scn_type, int, scn_type);
 985         switch (scn_type) {
 986         /*
 987          * ISNS_OBJ_ADDED - An object has been added.
 988          */
 989         case ISNS_OBJ_ADDED:
 990                 /* Query iSNS server for contact information */
 991                 pg_list = NULL;
 992                 qry_status = isns_query_one_node(
 993                     ((isns_scn_callback_arg_t *)arg)->source_key_attr,
 994                     ihp->hba_isid,
 995                     ihp->hba_name,
 996                     (uint8_t *)"",
 997                     ISNS_INITIATOR_NODE_TYPE,
 998                     &pg_list);
 999 
1000                 /* Verify portal group is found */
1001                 if ((qry_status != isns_ok &&
1002                     qry_status != isns_op_partially_failed) ||
1003                     pg_list == NULL) {
1004                         break;
1005                 }
1006 
1007                 DTRACE_PROBE1(pg_list,
1008                     isns_portal_group_list_t *, pg_list);
1009 
1010                 /* Add all portals for logical unit to discovery cache */
1011                 for (i = 0; i < pg_list->pg_out_cnt; i++) {
1012                         iscsi_sockaddr_t addr_dsc;
1013                         iscsi_sockaddr_t addr_tgt;
1014 
1015                         iscsid_addr_to_sockaddr(
1016                             pg_list->pg_list[i].isns_server_ip.i_insize,
1017                             &pg_list->pg_list[i].isns_server_ip.i_addr,
1018                             pg_list->pg_list[i].isns_server_port,
1019                             &addr_dsc.sin);
1020                         iscsid_addr_to_sockaddr(pg_list->pg_list[i].insize,
1021                             &pg_list->pg_list[i].pg_ip_addr,
1022                             pg_list->pg_list[i].pg_port, &addr_tgt.sin);
1023 
1024                         (void) iscsid_add(ihp, iSCSIDiscoveryMethodISNS,
1025                             &addr_dsc.sin, (char *)pg_list->pg_list[i].
1026                             pg_iscsi_name, pg_list->pg_list[i].pg_tag,
1027                             &addr_tgt.sin);
1028 
1029                         /* Force target to login */
1030                         (void) iscsid_login_tgt(ihp, (char *)pg_list->
1031                             pg_list[i].pg_iscsi_name, iSCSIDiscoveryMethodISNS,
1032                             NULL);
1033                 }
1034 
1035                 if (pg_list != NULL) {
1036                         pg_sz = sizeof (isns_portal_group_list_t);
1037                         if (pg_list->pg_out_cnt > 0) {
1038                                 pg_sz += (pg_list->pg_out_cnt - 1) *
1039                                     sizeof (isns_portal_group_t);
1040                         }
1041                         kmem_free(pg_list, pg_sz);
1042                 }
1043                 break;
1044 
1045         /*
1046          * ISNS_OBJ_REMOVED - logical unit has been removed
1047          */
1048         case ISNS_OBJ_REMOVED:
1049                 if (iscsid_del(ihp,
1050                     (char *)((isns_scn_callback_arg_t *)arg)->
1051                     source_key_attr, iSCSIDiscoveryMethodISNS, NULL) !=
1052                     B_TRUE) {
1053                         cmn_err(CE_NOTE, "iscsi initiator - "
1054                             "isns remove scn failed for target %s\n",
1055                             (char *)((isns_scn_callback_arg_t *)arg)->
1056                             source_key_attr);
1057 
1058                 }
1059                 break;
1060 
1061         /*
1062          * ISNS_OBJ_UPDATED - logical unit has changed
1063          */
1064         case ISNS_OBJ_UPDATED:
1065                 cmn_err(CE_NOTE, "iscsi initiator - "
1066                     "received iSNS update SCN for %s\n",
1067                     (char *)((isns_scn_callback_arg_t *)arg)->
1068                     source_key_attr);
1069                 break;
1070 
1071         /*
1072          * ISNS_OBJ_UNKNOWN -
1073          */
1074         default:
1075                 cmn_err(CE_NOTE, "iscsi initiator - "
1076                     "received unknown iSNS SCN type 0x%x\n", scn_type);
1077                 break;
1078         }
1079 
1080         iscsi_client_release_service(ihp);
1081         kmem_free(arg, sizeof (isns_scn_callback_arg_t));
1082 }
1083 
1084 
1085 /*
1086  * iscsid_add - Creates discovered session and connection
1087  */
1088 static boolean_t
1089 iscsid_add(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t method,
1090     struct sockaddr *addr_dsc, char *target_name, int tpgt,
1091     struct sockaddr *addr_tgt)
1092 {
1093         boolean_t           rtn = B_TRUE;
1094         iscsi_sess_t        *isp;
1095         iscsi_conn_t        *icp;
1096         uint_t              oid;
1097         int                 idx;
1098         int                 isid;
1099         iscsi_config_sess_t *ics;
1100         int                 size;
1101         char                *tmp;
1102 
1103         ASSERT(ihp != NULL);
1104         ASSERT(addr_dsc != NULL);
1105         ASSERT(target_name != NULL);
1106         ASSERT(addr_tgt != NULL);
1107 
1108         /* setup initial buffer for configured session information */
1109         size = sizeof (*ics);
1110         ics = kmem_zalloc(size, KM_SLEEP);
1111         ics->ics_in = 1;
1112 
1113         /* get configured sessions information */
1114         tmp = target_name;
1115         if (persistent_get_config_session(tmp, ics) == B_FALSE) {
1116                 /*
1117                  * No target information available check for
1118                  * initiator information.
1119                  */
1120                 tmp = (char *)ihp->hba_name;
1121                 if (persistent_get_config_session(tmp, ics) == B_FALSE) {
1122                         /*
1123                          * No hba information is
1124                          * found.  So assume default
1125                          * one session unbound behavior.
1126                          */
1127                         ics->ics_out = 1;
1128                         ics->ics_bound = B_TRUE;
1129                 }
1130         }
1131 
1132         if (iscsiboot_prop && (ics->ics_out > 1) &&
1133             !iscsi_chk_bootlun_mpxio(ihp)) {
1134                 /*
1135                  * iscsi boot with mpxio disabled
1136                  * no need to search configured boot session
1137                  */
1138 
1139                 if (iscsi_cmp_boot_ini_name(tmp) ||
1140                     iscsi_cmp_boot_tgt_name(tmp)) {
1141                         ics->ics_out = 1;
1142                         ics->ics_bound = B_FALSE;
1143                 }
1144         }
1145         /* Check to see if we need to get more information */
1146         if (ics->ics_out > 1) {
1147                 /* record new size and free last buffer */
1148                 idx = ics->ics_out;
1149                 size = ISCSI_SESSION_CONFIG_SIZE(ics->ics_out);
1150                 kmem_free(ics, sizeof (*ics));
1151 
1152                 /* allocate new buffer */
1153                 ics = kmem_zalloc(size, KM_SLEEP);
1154                 ics->ics_in = idx;
1155 
1156                 /* get configured sessions information */
1157                 if (persistent_get_config_session(tmp, ics) != B_TRUE) {
1158                         cmn_err(CE_NOTE, "iscsi session(%s) - "
1159                             "unable to get configured session information\n",
1160                             target_name);
1161                         kmem_free(ics, size);
1162                         return (B_FALSE);
1163                 }
1164         }
1165 
1166         /* loop for all configured sessions */
1167         rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER);
1168         for (isid = 0; isid < ics->ics_out; isid++) {
1169                 /* create or find matching session */
1170                 isp = iscsi_sess_create(ihp, method, addr_dsc, target_name,
1171                     tpgt, isid, ISCSI_SESS_TYPE_NORMAL, &oid);
1172                 if (isp == NULL) {
1173                         rtn = B_FALSE;
1174                         break;
1175                 }
1176 
1177                 /* create or find matching connection */
1178                 if (!ISCSI_SUCCESS(iscsi_conn_create(addr_tgt, isp, &icp))) {
1179                         /*
1180                          * Teardown the session we just created.  It can't
1181                          * have any luns or connections associated with it
1182                          * so this should always succeed (luckily since what
1183                          * would we do if it failed?)
1184                          */
1185                         (void) iscsi_sess_destroy(isp);
1186                         rtn = B_FALSE;
1187                         break;
1188                 }
1189         }
1190         rw_exit(&ihp->hba_sess_list_rwlock);
1191         kmem_free(ics, size);
1192         return (rtn);
1193 }
1194 
1195 /*
1196  * iscsid_del - Attempts to delete all associated sessions
1197  */
1198 boolean_t
1199 iscsid_del(iscsi_hba_t *ihp, char *target_name,
1200     iSCSIDiscoveryMethod_t method, struct sockaddr *addr_dsc)
1201 {
1202         boolean_t       rtn = B_TRUE;
1203         iscsi_status_t  status;
1204         iscsi_sess_t    *isp;
1205         char            name[ISCSI_MAX_NAME_LEN];
1206 
1207         ASSERT(ihp != NULL);
1208         /* target name can be NULL or !NULL */
1209         /* addr_dsc can be NULL or !NULL */
1210 
1211         rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER);
1212         isp = ihp->hba_sess_list;
1213         while (isp != NULL) {
1214                 /*
1215                  * If no target_name is listed (meaning all targets)
1216                  * or this specific target was listed. And the same
1217                  * discovery method discovered this target then
1218                  * continue evaulation.  Otherwise fail.
1219                  */
1220                 if (((target_name == NULL) ||
1221                     (strcmp((char *)isp->sess_name, target_name) == 0)) &&
1222                     (isp->sess_discovered_by == method)) {
1223                         boolean_t try_destroy;
1224 
1225                         /*
1226                          * If iSNS, SendTargets, or Static then special
1227                          * handling for disc_addr.
1228                          */
1229                         if ((method == iSCSIDiscoveryMethodISNS) ||
1230                             (method == iSCSIDiscoveryMethodSendTargets)) {
1231                                 /*
1232                                  * If NULL addr_dsc (meaning all disc_addr)
1233                                  * or matching discovered addr.
1234                                  */
1235                                 if ((addr_dsc == NULL) ||
1236                                     (bcmp(addr_dsc, &isp->sess_discovered_addr,
1237                                     SIZEOF_SOCKADDR(
1238                                     &isp->sess_discovered_addr.sin)) == 0)) {
1239                                         try_destroy = B_TRUE;
1240                                 } else {
1241                                         try_destroy = B_FALSE;
1242                                 }
1243                         } else if (method == iSCSIDiscoveryMethodStatic) {
1244                                 /*
1245                                  * If NULL addr_dsc (meaning all disc_addr)
1246                                  * or matching active connection.
1247                                  */
1248                                 if ((addr_dsc == NULL) ||
1249                                     ((isp->sess_conn_act != NULL) &&
1250                                     (bcmp(addr_dsc,
1251                                     &isp->sess_conn_act->conn_base_addr.sin,
1252                                     SIZEOF_SOCKADDR(
1253                                     &isp->sess_conn_act->conn_base_addr.sin))
1254                                     == 0))) {
1255                                         try_destroy = B_TRUE;
1256                                 } else {
1257                                         try_destroy = B_FALSE;
1258                                 }
1259                         } else {
1260                                 /* Unknown discovery specified */
1261                                 try_destroy = B_TRUE;
1262                         }
1263 
1264                         if (try_destroy == B_TRUE &&
1265                             isp->sess_boot == B_FALSE) {
1266                                 (void) strcpy(name, (char *)isp->sess_name);
1267                                 status = iscsi_sess_destroy(isp);
1268                                 if (ISCSI_SUCCESS(status)) {
1269                                         iscsid_remove_target_param(name);
1270                                         isp = ihp->hba_sess_list;
1271                                 } else if (status == ISCSI_STATUS_BUSY) {
1272                                         /*
1273                                          * The most likely destroy failure
1274                                          * is that ndi/mdi offline failed.
1275                                          * This means that the resource is
1276                                          * in_use/busy.
1277                                          */
1278                                         cmn_err(CE_NOTE, "iscsi session(%d) - "
1279                                             "resource is in use\n",
1280                                             isp->sess_oid);
1281                                         isp = isp->sess_next;
1282                                         rtn = B_FALSE;
1283                                 } else {
1284                                         cmn_err(CE_NOTE, "iscsi session(%d) - "
1285                                             "session logout failed (%d)\n",
1286                                             isp->sess_oid, status);
1287                                         isp = isp->sess_next;
1288                                         rtn = B_FALSE;
1289                                 }
1290                         } else {
1291                                 isp = isp->sess_next;
1292                         }
1293                 } else {
1294                         isp = isp->sess_next;
1295                 }
1296         }
1297         rw_exit(&ihp->hba_sess_list_rwlock);
1298         return (rtn);
1299 }
1300 
1301 
1302 /*
1303  * iscsid_login_tgt - request target(s) to login
1304  */
1305 boolean_t
1306 iscsid_login_tgt(iscsi_hba_t *ihp, char *target_name,
1307     iSCSIDiscoveryMethod_t method, struct sockaddr *addr_dsc)
1308 {
1309         boolean_t               rtn             = B_FALSE;
1310         iscsi_sess_t            *isp            = NULL;
1311         iscsi_sess_list_t       *isp_list       = NULL;
1312         iscsi_sess_list_t       *last_sess      = NULL;
1313         iscsi_sess_list_t       *cur_sess       = NULL;
1314         int                     total           = 0;
1315         ddi_taskq_t             *login_taskq    = NULL;
1316         char                    taskq_name[ISCSI_TH_MAX_NAME_LEN] = {0};
1317         time_t                  time_stamp;
1318 
1319         ASSERT(ihp != NULL);
1320 
1321         rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER);
1322         /* Loop thru sessions */
1323         isp = ihp->hba_sess_list;
1324         while (isp != NULL) {
1325                 boolean_t try_online;
1326                 if (!(method & iSCSIDiscoveryMethodBoot)) {
1327                         if (target_name == NULL) {
1328                                 if (method == iSCSIDiscoveryMethodUnknown) {
1329                                         /* unknown method mean login to all */
1330                                         try_online = B_TRUE;
1331                                 } else if (isp->sess_discovered_by & method) {
1332                                         if ((method ==
1333                                             iSCSIDiscoveryMethodISNS) ||
1334                                             (method ==
1335                                             iSCSIDiscoveryMethodSendTargets)) {
1336 #define SESS_DISC_ADDR  isp->sess_discovered_addr.sin
1337                                                 if ((addr_dsc == NULL) ||
1338                                                     (bcmp(
1339                                                     &isp->sess_discovered_addr,
1340                                                     addr_dsc, SIZEOF_SOCKADDR(
1341                                                     &SESS_DISC_ADDR))
1342                                                     == 0)) {
1343                                                         /*
1344                                                          * iSNS or sendtarget
1345                                                          * discovery and
1346                                                          * discovery address
1347                                                          * is NULL or match
1348                                                          */
1349                                                         try_online = B_TRUE;
1350                                                 } else {
1351                                                 /* addr_dsc not a match */
1352                                                         try_online = B_FALSE;
1353                                                 }
1354 #undef SESS_DISC_ADDR
1355                                         } else {
1356                                                 /* static configuration */
1357                                                 try_online = B_TRUE;
1358                                         }
1359                                 } else {
1360                                         /* method not a match */
1361                                         try_online = B_FALSE;
1362                                 }
1363                         } else if (strcmp(target_name,
1364                             (char *)isp->sess_name) == 0) {
1365                                 /* target_name match */
1366                                 try_online = B_TRUE;
1367                         } else {
1368                                 /* target_name not a match */
1369                                 try_online = B_FALSE;
1370                         }
1371                 } else {
1372                         /*
1373                          * online the boot session.
1374                          */
1375                         if (isp->sess_boot == B_TRUE) {
1376                                 try_online = B_TRUE;
1377                         }
1378                 }
1379 
1380                 if (try_online == B_TRUE &&
1381                     isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
1382                         total++;
1383                         /* Copy these sessions to the list. */
1384                         if (isp_list == NULL) {
1385                                 isp_list =
1386                                     (iscsi_sess_list_t *)kmem_zalloc(
1387                                     sizeof (iscsi_sess_list_t), KM_SLEEP);
1388                                 last_sess = isp_list;
1389                                 last_sess->session = isp;
1390                                 last_sess->next = NULL;
1391                         } else {
1392                                 last_sess->next =
1393                                     (iscsi_sess_list_t *)kmem_zalloc(
1394                                     sizeof (iscsi_sess_list_t), KM_SLEEP);
1395                                 last_sess->next->session = isp;
1396                                 last_sess->next->next = NULL;
1397                                 last_sess = last_sess->next;
1398                         }
1399                         rtn = B_TRUE;
1400                 }
1401 
1402                 isp = isp->sess_next;
1403         }
1404 
1405         if (total > 0) {
1406                 time_stamp = ddi_get_time();
1407                 (void) snprintf(taskq_name, (ISCSI_TH_MAX_NAME_LEN - 1),
1408                     "login_queue.%lx", time_stamp);
1409 
1410                 login_taskq = ddi_taskq_create(ihp->hba_dip,
1411                     taskq_name, total, TASKQ_DEFAULTPRI, 0);
1412                 if (login_taskq == NULL) {
1413                         while (isp_list != NULL) {
1414                                 cur_sess = isp_list;
1415                                 isp_list = isp_list->next;
1416                                 kmem_free(cur_sess, sizeof (iscsi_sess_list_t));
1417                         }
1418                         rtn = B_FALSE;
1419                         rw_exit(&ihp->hba_sess_list_rwlock);
1420                         return (rtn);
1421                 }
1422 
1423                 for (cur_sess = isp_list; cur_sess != NULL;
1424                     cur_sess = cur_sess->next) {
1425                         if (ddi_taskq_dispatch(login_taskq,
1426                             iscsi_sess_online, (void *)cur_sess->session,
1427                             DDI_SLEEP) != DDI_SUCCESS) {
1428                                 cmn_err(CE_NOTE, "Can't dispatch the task "
1429                                     "for login to the target: %s",
1430                                     cur_sess->session->sess_name);
1431                         }
1432                 }
1433 
1434                 ddi_taskq_wait(login_taskq);
1435                 ddi_taskq_destroy(login_taskq);
1436                 while (isp_list != NULL) {
1437                         cur_sess = isp_list;
1438                         isp_list = isp_list->next;
1439                         kmem_free(cur_sess, sizeof (iscsi_sess_list_t));
1440                 }
1441 
1442         }
1443 
1444         rw_exit(&ihp->hba_sess_list_rwlock);
1445         return (rtn);
1446 }
1447 
1448 /*
1449  * +--------------------------------------------------------------------+
1450  * | Local Helper Functions                                             |
1451  * +--------------------------------------------------------------------+
1452  */
1453 
1454 /*
1455  * iscsid_init_config -- initialize configuration parameters of iSCSI initiator
1456  */
1457 static boolean_t
1458 iscsid_init_config(iscsi_hba_t *ihp)
1459 {
1460         iscsi_param_set_t       ips;
1461         void *v = NULL;
1462         char *name;
1463         char *initiatorName;
1464         persistent_param_t      pp;
1465         persistent_tunable_param_t pparam;
1466         uint32_t                param_id;
1467         int                     rc;
1468 
1469         /* allocate memory to hold initiator names */
1470         initiatorName = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP);
1471 
1472         /*
1473          * initialize iSCSI initiator name
1474          */
1475         bzero(&ips, sizeof (ips));
1476         if (persistent_initiator_name_get(initiatorName,
1477             ISCSI_MAX_NAME_LEN) == B_TRUE) {
1478                 ips.s_vers      = ISCSI_INTERFACE_VERSION;
1479                 ips.s_param     = ISCSI_LOGIN_PARAM_INITIATOR_NAME;
1480 
1481                 if (iscsiboot_prop && !iscsi_cmp_boot_ini_name(initiatorName)) {
1482                         (void) strncpy(initiatorName,
1483                             (const char *)iscsiboot_prop->boot_init.ini_name,
1484                             ISCSI_MAX_NAME_LEN);
1485                         (void) strncpy((char *)ips.s_value.v_name,
1486                             (const char *)iscsiboot_prop->boot_init.ini_name,
1487                             sizeof (ips.s_value.v_name));
1488                         (void) iscsi_set_params(&ips, ihp, B_TRUE);
1489                         /* use default tunable value */
1490                         ihp->hba_tunable_params.recv_login_rsp_timeout =
1491                             ISCSI_DEFAULT_RX_TIMEOUT_VALUE;
1492                         ihp->hba_tunable_params.polling_login_delay =
1493                             ISCSI_DEFAULT_LOGIN_POLLING_DELAY;
1494                         ihp->hba_tunable_params.conn_login_max =
1495                             ISCSI_DEFAULT_CONN_DEFAULT_LOGIN_MAX;
1496                         cmn_err(CE_NOTE, "Set initiator's name"
1497                             " from firmware");
1498                 } else {
1499                         (void) strncpy((char *)ips.s_value.v_name,
1500                             initiatorName, sizeof (ips.s_value.v_name));
1501 
1502                         (void) iscsi_set_params(&ips, ihp, B_FALSE);
1503                         if (persistent_get_tunable_param(initiatorName,
1504                             &pparam) == B_FALSE) {
1505                                 /* use default value */
1506                                 pparam.p_params.recv_login_rsp_timeout =
1507                                     ISCSI_DEFAULT_RX_TIMEOUT_VALUE;
1508                                 pparam.p_params.polling_login_delay =
1509                                     ISCSI_DEFAULT_LOGIN_POLLING_DELAY;
1510                                 pparam.p_params.conn_login_max =
1511                                     ISCSI_DEFAULT_CONN_DEFAULT_LOGIN_MAX;
1512                         }
1513                         bcopy(&pparam.p_params, &ihp->hba_tunable_params,
1514                             sizeof (iscsi_tunable_params_t));
1515                 }
1516         } else {
1517                 /*
1518                  * if no initiator-node name available it is most
1519                  * likely due to a fresh install, or the persistent
1520                  * store is not working correctly. Set
1521                  * a default initiator name so that the initiator can
1522                  * be brought up properly.
1523                  */
1524                 iscsid_set_default_initiator_node_settings(ihp, B_FALSE);
1525                 (void) strncpy(initiatorName, (const char *)ihp->hba_name,
1526                     ISCSI_MAX_NAME_LEN);
1527         }
1528 
1529         /*
1530          * initialize iSCSI initiator alias (if any)
1531          */
1532         bzero(&ips, sizeof (ips));
1533         if (persistent_alias_name_get((char *)ips.s_value.v_name,
1534             sizeof (ips.s_value.v_name)) == B_TRUE) {
1535                 ips.s_param     = ISCSI_LOGIN_PARAM_INITIATOR_ALIAS;
1536                 (void) iscsi_set_params(&ips, ihp, B_FALSE);
1537         } else {
1538                 /* EMPTY */
1539                 /* No alias defined - not a problem. */
1540         }
1541 
1542         /*
1543          * load up the overriden iSCSI initiator parameters
1544          */
1545         name = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP);
1546         persistent_param_lock();
1547         v = NULL;
1548         while (persistent_param_next(&v, name, &pp) == B_TRUE) {
1549                 if (strncmp(name, initiatorName, ISCSI_MAX_NAME_LEN) == 0) {
1550                         ips.s_oid = ihp->hba_oid;
1551                         ips.s_vers = ISCSI_INTERFACE_VERSION;
1552                         for (param_id = 0; param_id < ISCSI_NUM_LOGIN_PARAM;
1553                             param_id++) {
1554                                 if (pp.p_bitmap & (1 << param_id)) {
1555                                         rc = iscsid_copyto_param_set(param_id,
1556                                             &pp.p_params, &ips);
1557                                         if (rc == 0) {
1558                                                 rc = iscsi_set_params(&ips,
1559                                                     ihp, B_FALSE);
1560                                         }
1561                                         if (rc != 0) {
1562                                                 /* note error but continue  */
1563                                                 cmn_err(CE_NOTE,
1564                                                     "Failed to set "
1565                                                     "param %d for OID %d",
1566                                                     ips.s_param, ips.s_oid);
1567                                         }
1568                                 }
1569                         } /* END for() */
1570                         if (iscsiboot_prop &&
1571                             iscsi_chk_bootlun_mpxio(ihp)) {
1572                                 (void) iscsi_reconfig_boot_sess(ihp);
1573                         }
1574                         break;
1575                 }
1576         } /* END while() */
1577         persistent_param_unlock();
1578 
1579         kmem_free(initiatorName, ISCSI_MAX_NAME_LEN);
1580         kmem_free(name, ISCSI_MAX_NAME_LEN);
1581         return (B_TRUE);
1582 }
1583 
1584 
1585 /*
1586  * iscsid_init_targets -- Load up the driver with known static targets and
1587  * targets whose parameters have been modified.
1588  *
1589  * This is done so that the CLI can find a list of targets the driver
1590  * currently knows about.
1591  *
1592  * The driver doesn't need to log into these targets.  Log in is done based
1593  * upon the enabled discovery methods.
1594  */
1595 static boolean_t
1596 iscsid_init_targets(iscsi_hba_t *ihp)
1597 {
1598         void                    *v = NULL;
1599         char                    *name;
1600         iscsi_param_set_t       ips;
1601         persistent_param_t      pp;
1602         char                    *iname;
1603         uint32_t                param_id;
1604         int                     rc;
1605 
1606         ASSERT(ihp != NULL);
1607 
1608         /* allocate memory to hold target names */
1609         name = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP);
1610 
1611         /*
1612          * load up targets whose parameters have been overriden
1613          */
1614 
1615         /* ---- only need to be set once ---- */
1616         bzero(&ips, sizeof (ips));
1617         ips.s_vers = ISCSI_INTERFACE_VERSION;
1618 
1619         /* allocate memory to hold initiator name */
1620         iname = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP);
1621         (void) persistent_initiator_name_get(iname, ISCSI_MAX_NAME_LEN);
1622 
1623         persistent_param_lock();
1624         v = NULL;
1625         while (persistent_param_next(&v, name, &pp) == B_TRUE) {
1626 
1627                 if (strncmp(iname, name, ISCSI_MAX_NAME_LEN) == 0) {
1628                         /*
1629                          * target name matched initiator's name so,
1630                          * continue to next target.  Initiator's
1631                          * parmeters have already been set.
1632                          */
1633                         continue;
1634                 }
1635 
1636                 if (iscsiboot_prop && iscsi_cmp_boot_tgt_name(name) &&
1637                     !iscsi_chk_bootlun_mpxio(ihp)) {
1638                         /*
1639                          * boot target is not mpxio enabled
1640                          * simply ignore these overriden parameters
1641                          */
1642                         continue;
1643                 }
1644 
1645                 ips.s_oid = iscsi_targetparam_get_oid((unsigned char *)name);
1646 
1647                 for (param_id = 0; param_id < ISCSI_NUM_LOGIN_PARAM;
1648                     param_id++) {
1649                         if (pp.p_bitmap & (1 << param_id)) {
1650                                 rc = iscsid_copyto_param_set(param_id,
1651                                     &pp.p_params, &ips);
1652                                 if (rc == 0) {
1653                                         rc = iscsi_set_params(&ips,
1654                                             ihp, B_FALSE);
1655                                 }
1656                                 if (rc != 0) {
1657                                         /* note error but continue  ---- */
1658                                         cmn_err(CE_NOTE, "Failed to set "
1659                                             "param %d for OID %d",
1660                                             ips.s_param, ips.s_oid);
1661                                 }
1662                         }
1663                 } /* END for() */
1664                 if (iscsiboot_prop && iscsi_cmp_boot_tgt_name(name) &&
1665                     iscsi_chk_bootlun_mpxio(ihp)) {
1666                         (void) iscsi_reconfig_boot_sess(ihp);
1667                 }
1668         } /* END while() */
1669         persistent_param_unlock();
1670 
1671         kmem_free(iname, ISCSI_MAX_NAME_LEN);
1672         kmem_free(name, ISCSI_MAX_NAME_LEN);
1673 
1674         return (B_TRUE);
1675 }
1676 
1677 
1678 /*
1679  * iscsid_thread_static -- If static discovery is enabled, this routine obtains
1680  * all statically configured targets from the peristent store and issues a
1681  * login request to the driver.
1682  */
1683 /* ARGSUSED */
1684 static void
1685 iscsid_thread_static(iscsi_thread_t *thread, void *p)
1686 {
1687         iSCSIDiscoveryMethod_t  dm;
1688         entry_t                 entry;
1689         char                    name[ISCSI_MAX_NAME_LEN];
1690         void                    *v = NULL;
1691         iscsi_hba_t             *ihp = (iscsi_hba_t *)p;
1692 
1693         while (iscsi_thread_wait(thread, -1) != 0) {
1694                 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodStatic, B_TRUE);
1695 
1696                 /* ---- ensure static target discovery is enabled ---- */
1697                 dm = persistent_disc_meth_get();
1698                 if ((dm & iSCSIDiscoveryMethodStatic) == 0) {
1699                         cmn_err(CE_NOTE,
1700                             "iscsi discovery failure - "
1701                             "StaticTargets method is not enabled");
1702                         iscsi_discovery_event(ihp,
1703                             iSCSIDiscoveryMethodStatic, B_FALSE);
1704                         continue;
1705                 }
1706 
1707                 /*
1708                  * walk list of the statically configured targets from the
1709                  * persistent store
1710                  */
1711                 v = NULL;
1712                 persistent_static_addr_lock();
1713                 while (persistent_static_addr_next(&v, name, &entry) ==
1714                     B_TRUE) {
1715                         iscsi_sockaddr_t addr;
1716 
1717                         iscsid_addr_to_sockaddr(entry.e_insize,
1718                             &(entry.e_u), entry.e_port, &addr.sin);
1719 
1720                         (void) iscsid_add(ihp, iSCSIDiscoveryMethodStatic,
1721                             &addr.sin, name, entry.e_tpgt, &addr.sin);
1722                 }
1723                 persistent_static_addr_unlock();
1724                 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodStatic, B_FALSE);
1725         }
1726 }
1727 
1728 
1729 /*
1730  * iscsid_thread_sendtgts -- If SendTargets discovery is enabled, this routine
1731  * obtains all target discovery addresses configured from the peristent store
1732  * and probe the IP/port addresses for possible targets.  It will then issue
1733  * a login request to the driver for all discoveryed targets.
1734  */
1735 static void
1736 iscsid_thread_sendtgts(iscsi_thread_t *thread, void *p)
1737 {
1738         iscsi_hba_t             *ihp = (iscsi_hba_t *)p;
1739         iSCSIDiscoveryMethod_t  dm;
1740         entry_t                 entry;
1741         void                    *v = NULL;
1742 
1743         while (iscsi_thread_wait(thread, -1) != 0) {
1744                 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodSendTargets,
1745                     B_TRUE);
1746 
1747                 /* ---- ensure SendTargets discovery is enabled ---- */
1748                 dm = persistent_disc_meth_get();
1749                 if ((dm & iSCSIDiscoveryMethodSendTargets) == 0) {
1750                         cmn_err(CE_NOTE,
1751                             "iscsi discovery failure - "
1752                             "SendTargets method is not enabled");
1753                         iscsi_discovery_event(ihp,
1754                             iSCSIDiscoveryMethodSendTargets, B_FALSE);
1755                         continue;
1756                 }
1757                 /*
1758                  * walk list of the SendTarget discovery addresses from the
1759                  * persistent store
1760                  */
1761                 v = NULL;
1762                 persistent_disc_addr_lock();
1763                 while (persistent_disc_addr_next(&v, &entry) == B_TRUE) {
1764                         iscsid_do_sendtgts(&entry);
1765                 }
1766                 persistent_disc_addr_unlock();
1767 
1768                 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodSendTargets,
1769                     B_FALSE);
1770         }
1771 }
1772 
1773 /*
1774  * iscsid_thread_slp -- If SLP discovery is enabled,  this routine provides
1775  * the SLP discovery service.
1776  */
1777 static void
1778 iscsid_thread_slp(iscsi_thread_t *thread, void *p)
1779 {
1780         iscsi_hba_t  *ihp = (iscsi_hba_t *)p;
1781 
1782         do {
1783                 /*
1784                  * Even though we don't have support for SLP at this point
1785                  * we'll send the events if someone has enabled this thread.
1786                  * If this is not done the daemon waiting for discovery to
1787                  * complete will pause forever holding up the boot process.
1788                  */
1789                 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodSLP, B_TRUE);
1790                 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodSLP, B_FALSE);
1791         } while (iscsi_thread_wait(thread, -1) != 0);
1792 }
1793 
1794 /*
1795  * iscsid_thread_isns --
1796  */
1797 static void
1798 iscsid_thread_isns(iscsi_thread_t *thread, void *ptr)
1799 {
1800         iscsi_hba_t             *ihp = (iscsi_hba_t *)ptr;
1801         iSCSIDiscoveryMethod_t  dm;
1802 
1803         while (iscsi_thread_wait(thread, -1) != 0) {
1804                 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodISNS, B_TRUE);
1805 
1806                 /* ---- ensure iSNS discovery is enabled ---- */
1807                 dm = persistent_disc_meth_get();
1808                 if ((dm & iSCSIDiscoveryMethodISNS) == 0) {
1809                         cmn_err(CE_NOTE,
1810                             "iscsi discovery failure - "
1811                             "iSNS method is not enabled");
1812                         iscsi_discovery_event(ihp,
1813                             iSCSIDiscoveryMethodISNS, B_FALSE);
1814                         continue;
1815                 }
1816 
1817                 (void) isns_reg(ihp->hba_isid,
1818                     ihp->hba_name,
1819                     ISCSI_MAX_NAME_LEN,
1820                     ihp->hba_alias,
1821                     ISCSI_MAX_NAME_LEN,
1822                     ISNS_INITIATOR_NODE_TYPE,
1823                     isns_scn_callback);
1824                 iscsid_do_isns_query(ihp);
1825                 iscsi_discovery_event(ihp, iSCSIDiscoveryMethodISNS, B_FALSE);
1826         }
1827 
1828         /* Thread stopped. Deregister from iSNS servers(s). */
1829         (void) isns_dereg(ihp->hba_isid, ihp->hba_name);
1830 }
1831 
1832 
1833 /*
1834  * iscsid_threads_create -- Creates all the discovery threads.
1835  */
1836 static void
1837 iscsid_threads_create(iscsi_hba_t *ihp)
1838 {
1839         iscsid_thr_table        *t;
1840 
1841         /*
1842          * start a thread for each discovery method
1843          */
1844         for (t = &iscsid_thr[0]; t->method != iSCSIDiscoveryMethodUnknown;
1845             t++) {
1846                 if (t->thr_id == NULL) {
1847                         t->thr_id = iscsi_thread_create(ihp->hba_dip, t->name,
1848                             t->func_start, ihp);
1849                 }
1850         }
1851 }
1852 
1853 /*
1854  * iscsid_threads_destroy -- Destroys all the discovery threads.
1855  */
1856 static void
1857 iscsid_threads_destroy(void)
1858 {
1859         iscsid_thr_table        *t;
1860 
1861         for (t = &iscsid_thr[0]; t->method != iSCSIDiscoveryMethodUnknown;
1862             t++) {
1863                 if (t->thr_id != NULL) {
1864                         iscsi_thread_destroy(t->thr_id);
1865                         t->thr_id = NULL;
1866                 }
1867         }
1868 }
1869 
1870 /*
1871  * iscsid_copyto_param_set - helper function for iscsid_init_params.
1872  */
1873 static int
1874 iscsid_copyto_param_set(uint32_t param_id, iscsi_login_params_t *params,
1875     iscsi_param_set_t *ipsp)
1876 {
1877         int rtn = 0;
1878 
1879         if (param_id >= ISCSI_NUM_LOGIN_PARAM) {
1880                 return (EINVAL);
1881         }
1882 
1883         switch (param_id) {
1884 
1885         /*
1886          * Boolean parameters
1887          */
1888         case ISCSI_LOGIN_PARAM_DATA_SEQUENCE_IN_ORDER:
1889                 ipsp->s_value.v_bool = params->data_pdu_in_order;
1890                 break;
1891         case ISCSI_LOGIN_PARAM_IMMEDIATE_DATA:
1892                 ipsp->s_value.v_bool = params->immediate_data;
1893                 break;
1894         case ISCSI_LOGIN_PARAM_INITIAL_R2T:
1895                 ipsp->s_value.v_bool = params->initial_r2t;
1896                 break;
1897         case ISCSI_LOGIN_PARAM_DATA_PDU_IN_ORDER:
1898                 ipsp->s_value.v_bool = params->data_pdu_in_order;
1899                 break;
1900 
1901         /*
1902          * Integer parameters
1903          */
1904         case ISCSI_LOGIN_PARAM_HEADER_DIGEST:
1905                 ipsp->s_value.v_integer = params->header_digest;
1906                 break;
1907         case ISCSI_LOGIN_PARAM_DATA_DIGEST:
1908                 ipsp->s_value.v_integer = params->data_digest;
1909                 break;
1910         case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_RETAIN:
1911                 ipsp->s_value.v_integer = params->default_time_to_retain;
1912                 break;
1913         case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_WAIT:
1914                 ipsp->s_value.v_integer = params->default_time_to_wait;
1915                 break;
1916         case ISCSI_LOGIN_PARAM_MAX_RECV_DATA_SEGMENT_LENGTH:
1917                 ipsp->s_value.v_integer = params->max_recv_data_seg_len;
1918                 break;
1919         case ISCSI_LOGIN_PARAM_FIRST_BURST_LENGTH:
1920                 ipsp->s_value.v_integer = params->first_burst_length;
1921                 break;
1922         case ISCSI_LOGIN_PARAM_MAX_BURST_LENGTH:
1923                 ipsp->s_value.v_integer =  params->max_burst_length;
1924                 break;
1925 
1926         /*
1927          * Integer parameters which currently are unsettable
1928          */
1929         case ISCSI_LOGIN_PARAM_MAX_CONNECTIONS:
1930         case ISCSI_LOGIN_PARAM_OUTSTANDING_R2T:
1931         case ISCSI_LOGIN_PARAM_ERROR_RECOVERY_LEVEL:
1932         /* ---- drop through to default case ---- */
1933         default:
1934                 rtn = EINVAL;
1935                 break;
1936         }
1937 
1938         /* if all is well, set the parameter identifier */
1939         if (rtn == 0) {
1940                 ipsp->s_param = param_id;
1941         }
1942 
1943         return (rtn);
1944 }
1945 
1946 /*
1947  * iscsid_add_pg_list_to_cache - Add portal groups in the list to the
1948  * discovery cache.
1949  */
1950 static void
1951 iscsid_add_pg_list_to_cache(iscsi_hba_t *ihp,
1952     isns_portal_group_list_t *pg_list)
1953 {
1954         int                 i;
1955 
1956         for (i = 0; i < pg_list->pg_out_cnt; i++) {
1957                 iscsi_sockaddr_t addr_dsc;
1958                 iscsi_sockaddr_t addr_tgt;
1959 
1960                 iscsid_addr_to_sockaddr(
1961                     pg_list->pg_list[i].isns_server_ip.i_insize,
1962                     &pg_list->pg_list[i].isns_server_ip.i_addr,
1963                     pg_list->pg_list[i].isns_server_port,
1964                     &addr_dsc.sin);
1965                 iscsid_addr_to_sockaddr(
1966                     pg_list->pg_list[i].insize,
1967                     &pg_list->pg_list[i].pg_ip_addr,
1968                     pg_list->pg_list[i].pg_port,
1969                     &addr_tgt.sin);
1970 
1971                 (void) iscsid_add(ihp, iSCSIDiscoveryMethodISNS, &addr_dsc.sin,
1972                     (char *)pg_list->pg_list[i].pg_iscsi_name,
1973                     pg_list->pg_list[i].pg_tag, &addr_tgt.sin);
1974         }
1975 }
1976 
1977 /*
1978  * set_initiator_name - set default initiator name and alias.
1979  *
1980  * This sets the default initiator name and alias.  The
1981  * initiator name is composed of vendor's reverse domain name
1982  * and registration date followed by a unique classifier.
1983  * This classifier is the mac address of the first NIC in the
1984  * host and a timestamp to make sure the classifier is
1985  * unique if the NIC is moved between hosts.  The alias
1986  * is just the hostname.
1987  */
1988 void
1989 iscsid_set_default_initiator_node_settings(iscsi_hba_t *ihp, boolean_t minimal)
1990 {
1991         int                 i;
1992         time_t              x;
1993         struct ether_addr   eaddr;
1994         char                val[10];
1995         iscsi_chap_props_t  *chap = NULL;
1996 
1997         /* Set default initiator-node name */
1998         if (iscsiboot_prop && iscsiboot_prop->boot_init.ini_name != NULL) {
1999                 (void) strncpy((char *)ihp->hba_name,
2000                     (const char *)iscsiboot_prop->boot_init.ini_name,
2001                     ISCSI_MAX_NAME_LEN);
2002         } else {
2003                 (void) snprintf((char *)ihp->hba_name, ISCSI_MAX_NAME_LEN,
2004                     "iqn.2005-07.com.nexenta:01:");
2005 
2006                 (void) localetheraddr(NULL, &eaddr);
2007                 for (i = 0; i <  ETHERADDRL; i++) {
2008                         (void) snprintf(val, sizeof (val), "%02x",
2009                             eaddr.ether_addr_octet[i]);
2010                         (void) strncat((char *)ihp->hba_name, val,
2011                             ISCSI_MAX_NAME_LEN);
2012                 }
2013 
2014                 /* Set default initiator-node alias */
2015                 x = ddi_get_time();
2016                 (void) snprintf(val, sizeof (val), ".%lx", x);
2017                 (void) strncat((char *)ihp->hba_name, val, ISCSI_MAX_NAME_LEN);
2018 
2019                 if (ihp->hba_alias[0] == '\0') {
2020                         (void) strncpy((char *)ihp->hba_alias,
2021                             utsname.nodename, ISCSI_MAX_NAME_LEN);
2022                         ihp->hba_alias_length = strlen((char *)ihp->hba_alias);
2023                         if (minimal == B_FALSE) {
2024                                 (void) persistent_alias_name_set(
2025                                     (char *)ihp->hba_alias);
2026                         }
2027                 }
2028         }
2029 
2030         if (minimal == B_TRUE) {
2031                 return;
2032         }
2033 
2034         (void) persistent_initiator_name_set((char *)ihp->hba_name);
2035 
2036         /* Set default initiator-node CHAP settings */
2037         if (persistent_initiator_name_get((char *)ihp->hba_name,
2038             ISCSI_MAX_NAME_LEN) == B_TRUE) {
2039                 chap = (iscsi_chap_props_t *)kmem_zalloc(sizeof (*chap),
2040                     KM_SLEEP);
2041                 if (persistent_chap_get((char *)ihp->hba_name, chap) ==
2042                     B_FALSE) {
2043                         bcopy((char *)ihp->hba_name, chap->c_user,
2044                             strlen((char *)ihp->hba_name));
2045                         chap->c_user_len = strlen((char *)ihp->hba_name);
2046                         (void) persistent_chap_set((char *)ihp->hba_name, chap);
2047                 }
2048                 kmem_free(chap, sizeof (*chap));
2049         }
2050 }
2051 
2052 static void
2053 iscsid_remove_target_param(char *name)
2054 {
2055         persistent_param_t  *pparam;
2056         uint32_t            t_oid;
2057         iscsi_config_sess_t *ics;
2058 
2059         ASSERT(name != NULL);
2060 
2061         /*
2062          * Remove target-param <-> target mapping.
2063          * Only remove if there is not any overridden
2064          * parameters in the persistent store
2065          */
2066         pparam = (persistent_param_t *)kmem_zalloc(sizeof (*pparam), KM_SLEEP);
2067 
2068         /*
2069          * setup initial buffer for configured session
2070          * information
2071          */
2072         ics = (iscsi_config_sess_t *)kmem_zalloc(sizeof (*ics), KM_SLEEP);
2073         ics->ics_in = 1;
2074 
2075         if ((persistent_param_get(name, pparam) == B_FALSE) &&
2076             (persistent_get_config_session(name, ics) == B_FALSE))  {
2077                 t_oid = iscsi_targetparam_get_oid((uchar_t *)name);
2078                 (void) iscsi_targetparam_remove_target(t_oid);
2079         }
2080 
2081         kmem_free(pparam, sizeof (*pparam));
2082         pparam = NULL;
2083         kmem_free(ics, sizeof (*ics));
2084         ics = NULL;
2085 }
2086 
2087 /*
2088  * iscsid_addr_to_sockaddr - convert other types to struct sockaddr
2089  */
2090 void
2091 iscsid_addr_to_sockaddr(int src_insize, void *src_addr, int src_port,
2092     struct sockaddr *dst_addr)
2093 {
2094         ASSERT((src_insize == sizeof (struct in_addr)) ||
2095             (src_insize == sizeof (struct in6_addr)));
2096         ASSERT(src_addr != NULL);
2097         ASSERT(dst_addr != NULL);
2098 
2099         bzero(dst_addr, sizeof (*dst_addr));
2100 
2101         /* translate discovery information */
2102         if (src_insize == sizeof (struct in_addr)) {
2103                 struct sockaddr_in *addr_in =
2104                     (struct sockaddr_in *)dst_addr;
2105                 addr_in->sin_family = AF_INET;
2106                 bcopy(src_addr, &addr_in->sin_addr.s_addr,
2107                     sizeof (struct in_addr));
2108                 addr_in->sin_port = htons(src_port);
2109         } else {
2110                 struct sockaddr_in6 *addr_in6 =
2111                     (struct sockaddr_in6 *)dst_addr;
2112                 addr_in6->sin6_family = AF_INET6;
2113                 bcopy(src_addr, &addr_in6->sin6_addr.s6_addr,
2114                     sizeof (struct in6_addr));
2115                 addr_in6->sin6_port = htons(src_port);
2116         }
2117 }
2118 
2119 /*
2120  * iscsi_discovery_event -- send event associated with discovery operations
2121  *
2122  * Each discovery event has a start and end event. Which is sent is based
2123  * on the boolean argument start with the obvious results.
2124  */
2125 static void
2126 iscsi_discovery_event(iscsi_hba_t *ihp, iSCSIDiscoveryMethod_t m,
2127     boolean_t start)
2128 {
2129         char    *subclass = NULL;
2130 
2131         mutex_enter(&ihp->hba_discovery_events_mutex);
2132         switch (m) {
2133         case iSCSIDiscoveryMethodStatic:
2134                 if (start == B_TRUE) {
2135                         subclass = ESC_ISCSI_STATIC_START;
2136                 } else {
2137                         ihp->hba_discovery_events |= iSCSIDiscoveryMethodStatic;
2138                         subclass = ESC_ISCSI_STATIC_END;
2139                 }
2140                 break;
2141 
2142         case iSCSIDiscoveryMethodSendTargets:
2143                 if (start == B_TRUE) {
2144                         subclass = ESC_ISCSI_SEND_TARGETS_START;
2145                 } else {
2146                         ihp->hba_discovery_events |=
2147                             iSCSIDiscoveryMethodSendTargets;
2148                         subclass = ESC_ISCSI_SEND_TARGETS_END;
2149                 }
2150                 break;
2151 
2152         case iSCSIDiscoveryMethodSLP:
2153                 if (start == B_TRUE) {
2154                         subclass = ESC_ISCSI_SLP_START;
2155                 } else {
2156                         ihp->hba_discovery_events |= iSCSIDiscoveryMethodSLP;
2157                         subclass = ESC_ISCSI_SLP_END;
2158                 }
2159                 break;
2160 
2161         case iSCSIDiscoveryMethodISNS:
2162                 if (start == B_TRUE) {
2163                         subclass = ESC_ISCSI_ISNS_START;
2164                 } else {
2165                         ihp->hba_discovery_events |= iSCSIDiscoveryMethodISNS;
2166                         subclass = ESC_ISCSI_ISNS_END;
2167                 }
2168                 break;
2169         }
2170         mutex_exit(&ihp->hba_discovery_events_mutex);
2171         iscsi_send_sysevent(ihp, EC_ISCSI, subclass, NULL);
2172 }
2173 
2174 /*
2175  * iscsi_send_sysevent -- send sysevent using specified class
2176  */
2177 void
2178 iscsi_send_sysevent(
2179     iscsi_hba_t *ihp,
2180     char        *eventclass,
2181     char        *subclass,
2182     nvlist_t    *np)
2183 {
2184         (void) ddi_log_sysevent(ihp->hba_dip, DDI_VENDOR_SUNW, eventclass,
2185             subclass, np, NULL, DDI_SLEEP);
2186 }
2187 
2188 static boolean_t
2189 iscsid_boot_init_config(iscsi_hba_t *ihp)
2190 {
2191         if (strlen((const char *)iscsiboot_prop->boot_init.ini_name) != 0) {
2192                 bcopy(iscsiboot_prop->boot_init.ini_name,
2193                     ihp->hba_name,
2194                     strlen((const char *)iscsiboot_prop->boot_init.ini_name));
2195         }
2196         /* or using default login param for boot session */
2197         return (B_TRUE);
2198 }
2199 
2200 boolean_t
2201 iscsi_reconfig_boot_sess(iscsi_hba_t *ihp)
2202 {
2203         iscsi_config_sess_t     *ics;
2204         int                     idx;
2205         iscsi_sess_t            *isp, *t_isp;
2206         int                     isid, size;
2207         char                    *name;
2208         boolean_t               rtn = B_TRUE;
2209         uint32_t                event_count;
2210 
2211         if (iscsiboot_prop == NULL) {
2212                 return (B_FALSE);
2213         }
2214         size = sizeof (*ics);
2215         ics = kmem_zalloc(size, KM_SLEEP);
2216         ics->ics_in = 1;
2217 
2218         /* get information of number of sessions to be configured */
2219         name = (char *)iscsiboot_prop->boot_tgt.tgt_name;
2220         if (persistent_get_config_session(name, ics) == B_FALSE) {
2221                 /*
2222                  * No target information available to check
2223                  * initiator information. Assume one session
2224                  * by default.
2225                  */
2226                 name = (char *)iscsiboot_prop->boot_init.ini_name;
2227                 if (persistent_get_config_session(name, ics) == B_FALSE) {
2228                         ics->ics_out = 1;
2229                         ics->ics_bound = B_TRUE;
2230                 }
2231         }
2232 
2233         /* get necessary information */
2234         if (ics->ics_out > 1) {
2235                 idx = ics->ics_out;
2236                 size = ISCSI_SESSION_CONFIG_SIZE(ics->ics_out);
2237                 kmem_free(ics, sizeof (*ics));
2238 
2239                 ics = kmem_zalloc(size, KM_SLEEP);
2240                 ics->ics_in = idx;
2241 
2242                 /* get configured sessions information */
2243                 if (persistent_get_config_session((char *)name,
2244                     ics) != B_TRUE) {
2245                         cmn_err(CE_NOTE, "session(%s) - "
2246                             "failed to setup multiple sessions",
2247                             name);
2248                         kmem_free(ics, size);
2249                         return (B_FALSE);
2250                 }
2251         }
2252 
2253         /* create a temporary session to keep boot session connective */
2254         t_isp = iscsi_add_boot_sess(ihp, ISCSI_MAX_CONFIG_SESSIONS);
2255         if (t_isp == NULL) {
2256                 cmn_err(CE_NOTE, "session(%s) - "
2257                     "failed to setup multiple sessions", name);
2258                 rw_exit(&ihp->hba_sess_list_rwlock);
2259                 kmem_free(ics, size);
2260                 return (B_FALSE);
2261         }
2262 
2263         /* destroy all old boot sessions */
2264         rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER);
2265         isp = ihp->hba_sess_list;
2266         while (isp != NULL) {
2267                 if (iscsi_chk_bootlun_mpxio(ihp) && isp->sess_boot) {
2268                         if (isp->sess_isid[5] != ISCSI_MAX_CONFIG_SESSIONS) {
2269                                 /*
2270                                  * destroy all stale sessions
2271                                  * except temporary boot session
2272                                  */
2273                                 if (ISCSI_SUCCESS(iscsi_sess_destroy(
2274                                     isp))) {
2275                                         isp = ihp->hba_sess_list;
2276                                 } else {
2277                                         /*
2278                                          * couldn't destroy stale sessions
2279                                          * at least poke it to disconnect
2280                                          */
2281                                         event_count = atomic_inc_32_nv(
2282                                             &isp->sess_state_event_count);
2283                                         iscsi_sess_enter_state_zone(isp);
2284                                         iscsi_sess_state_machine(isp,
2285                                             ISCSI_SESS_EVENT_N7, event_count);
2286                                         iscsi_sess_exit_state_zone(isp);
2287 
2288                                         isp = isp->sess_next;
2289                                         cmn_err(CE_NOTE, "session(%s) - "
2290                                             "failed to setup multiple"
2291                                             " sessions", name);
2292                                 }
2293                         } else {
2294                                 isp = isp->sess_next;
2295                         }
2296                 } else {
2297                         isp = isp->sess_next;
2298                 }
2299         }
2300         rw_exit(&ihp->hba_sess_list_rwlock);
2301 
2302         for (isid = 0; isid < ics->ics_out; isid++) {
2303                 isp = iscsi_add_boot_sess(ihp, isid);
2304                 if (isp == NULL) {
2305                         cmn_err(CE_NOTE, "session(%s) - failed to setup"
2306                             " multiple sessions", name);
2307                         rtn = B_FALSE;
2308                         break;
2309                 }
2310         }
2311         if (!rtn && (isid == 0)) {
2312                 /*
2313                  * fail to create any new boot session
2314                  * so only the temporary session is alive
2315                  * quit without destroying it
2316                  */
2317                 kmem_free(ics, size);
2318                 return (rtn);
2319         }
2320 
2321         rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER);
2322         if (!ISCSI_SUCCESS(iscsi_sess_destroy(t_isp))) {
2323                 /* couldn't destroy temp boot session */
2324                 cmn_err(CE_NOTE, "session(%s) - "
2325                     "failed to setup multiple sessions", name);
2326                 rw_exit(&ihp->hba_sess_list_rwlock);
2327                 rtn = B_FALSE;
2328         }
2329         rw_exit(&ihp->hba_sess_list_rwlock);
2330 
2331         kmem_free(ics, size);
2332         return (rtn);
2333 }
2334 
2335 static iscsi_sess_t *
2336 iscsi_add_boot_sess(iscsi_hba_t *ihp, int isid)
2337 {
2338         iscsi_sess_t    *isp;
2339         iscsi_conn_t    *icp;
2340         uint_t          oid;
2341 
2342         iscsi_sockaddr_t        addr_dst;
2343 
2344         addr_dst.sin.sa_family = iscsiboot_prop->boot_tgt.sin_family;
2345         if (addr_dst.sin.sa_family == AF_INET) {
2346                 bcopy(&iscsiboot_prop->boot_tgt.tgt_ip_u.u_in4.s_addr,
2347                     &addr_dst.sin4.sin_addr.s_addr, sizeof (struct in_addr));
2348                 addr_dst.sin4.sin_port =
2349                     htons(iscsiboot_prop->boot_tgt.tgt_port);
2350         } else {
2351                 bcopy(&iscsiboot_prop->boot_tgt.tgt_ip_u.u_in6.s6_addr,
2352                     &addr_dst.sin6.sin6_addr.s6_addr,
2353                     sizeof (struct in6_addr));
2354                 addr_dst.sin6.sin6_port =
2355                     htons(iscsiboot_prop->boot_tgt.tgt_port);
2356         }
2357 
2358         rw_enter(&ihp->hba_sess_list_rwlock, RW_WRITER);
2359         isp = iscsi_sess_create(ihp,
2360             iSCSIDiscoveryMethodBoot|iSCSIDiscoveryMethodStatic,
2361             (struct sockaddr *)&addr_dst,
2362             (char *)iscsiboot_prop->boot_tgt.tgt_name,
2363             ISCSI_DEFAULT_TPGT, isid, ISCSI_SESS_TYPE_NORMAL, &oid);
2364         if (isp == NULL) {
2365                 /* create temp booting session failed */
2366                 rw_exit(&ihp->hba_sess_list_rwlock);
2367                 return (NULL);
2368         }
2369         isp->sess_boot = B_TRUE;
2370 
2371         if (!ISCSI_SUCCESS(iscsi_conn_create((struct sockaddr *)&addr_dst,
2372             isp, &icp))) {
2373                 rw_exit(&ihp->hba_sess_list_rwlock);
2374                 return (NULL);
2375         }
2376 
2377         rw_exit(&ihp->hba_sess_list_rwlock);
2378         /* now online created session */
2379         if (iscsid_login_tgt(ihp, (char *)iscsiboot_prop->boot_tgt.tgt_name,
2380             iSCSIDiscoveryMethodBoot|iSCSIDiscoveryMethodStatic,
2381             (struct sockaddr *)&addr_dst) == B_FALSE) {
2382                 return (NULL);
2383         }
2384 
2385         return (isp);
2386 }
2387 
2388 static void
2389 iscsid_thread_boot_wd(iscsi_thread_t *thread, void *p)
2390 {
2391         int                     rc = 1;
2392         iscsi_hba_t             *ihp = (iscsi_hba_t *)p;
2393         boolean_t               reconfigured = B_FALSE;
2394 
2395         while (rc != 0) {
2396                 if (iscsiboot_prop && (modrootloaded == 1)) {
2397                         if (ihp->hba_persistent_loaded == B_FALSE) {
2398                                 if (persistent_load() == B_TRUE) {
2399                                         ihp->hba_persistent_loaded = B_TRUE;
2400                                 }
2401                         }
2402                         if ((ihp->hba_persistent_loaded == B_TRUE) &&
2403                             (reconfigured == B_FALSE)) {
2404                                 if (iscsi_chk_bootlun_mpxio(ihp) == B_TRUE) {
2405                                         (void) iscsi_reconfig_boot_sess(ihp);
2406                                         iscsid_poke_discovery(ihp,
2407                                             iSCSIDiscoveryMethodUnknown);
2408                                         (void) iscsid_login_tgt(ihp, NULL,
2409                                             iSCSIDiscoveryMethodUnknown, NULL);
2410                                 }
2411                                 reconfigured = B_TRUE;
2412                         }
2413                         break;
2414                 }
2415                 rc = iscsi_thread_wait(thread, SEC_TO_TICK(1));
2416         }
2417 }
2418 
2419 boolean_t
2420 iscsi_cmp_boot_tgt_name(char *name)
2421 {
2422         if (iscsiboot_prop && (strncmp((const char *)name,
2423             (const char *)iscsiboot_prop->boot_tgt.tgt_name,
2424             ISCSI_MAX_NAME_LEN) == 0)) {
2425                 return (B_TRUE);
2426         } else {
2427                 return (B_FALSE);
2428         }
2429 }
2430 
2431 boolean_t
2432 iscsi_cmp_boot_ini_name(char *name)
2433 {
2434         if (iscsiboot_prop && (strncmp((const char *)name,
2435             (const char *)iscsiboot_prop->boot_init.ini_name,
2436             ISCSI_MAX_NAME_LEN) == 0)) {
2437                 return (B_TRUE);
2438         } else {
2439                 return (B_FALSE);
2440         }
2441 }
2442 
2443 boolean_t
2444 iscsi_chk_bootlun_mpxio(iscsi_hba_t *ihp)
2445 {
2446         iscsi_sess_t    *isp;
2447         iscsi_lun_t     *ilp;
2448         isp = ihp->hba_sess_list;
2449         boolean_t       tgt_mpxio_enabled = B_FALSE;
2450         boolean_t       bootlun_found = B_FALSE;
2451         uint16_t    lun_num;
2452 
2453         if (iscsiboot_prop == NULL) {
2454                 return (B_FALSE);
2455         }
2456 
2457         if (!ihp->hba_mpxio_enabled) {
2458                 return (B_FALSE);
2459         }
2460 
2461         lun_num = *((uint64_t *)(iscsiboot_prop->boot_tgt.tgt_boot_lun));
2462 
2463         while (isp != NULL) {
2464                 if ((strncmp((char *)isp->sess_name,
2465                     (const char *)iscsiboot_prop->boot_tgt.tgt_name,
2466                     ISCSI_MAX_NAME_LEN) == 0) &&
2467                     (isp->sess_boot == B_TRUE)) {
2468                         /*
2469                          * found boot session.
2470                          * check its mdi path info is null or not
2471                          */
2472                         ilp = isp->sess_lun_list;
2473                         while (ilp != NULL) {
2474                                 if (lun_num == ilp->lun_num) {
2475                                         if (ilp->lun_pip) {
2476                                                 tgt_mpxio_enabled = B_TRUE;
2477                                         }
2478                                         bootlun_found = B_TRUE;
2479                                 }
2480                                 ilp = ilp->lun_next;
2481                         }
2482                 }
2483                 isp = isp->sess_next;
2484         }
2485         if (bootlun_found) {
2486                 return (tgt_mpxio_enabled);
2487         } else {
2488                 /*
2489                  * iscsiboot_prop not NULL while no boot lun found
2490                  * in most cases this is none iscsi boot while iscsiboot_prop
2491                  * is not NULL, in this scenario return iscsi HBA's mpxio config
2492                  */
2493                 return (ihp->hba_mpxio_enabled);
2494         }
2495 }
2496 
2497 static boolean_t
2498 iscsid_check_active_boot_conn(iscsi_hba_t *ihp)
2499 {
2500         iscsi_sess_t    *isp = NULL;
2501         iscsi_conn_t    *icp = NULL;
2502 
2503         rw_enter(&ihp->hba_sess_list_rwlock, RW_READER);
2504         isp = ihp->hba_sess_list;
2505         while (isp != NULL) {
2506                 if (isp->sess_boot == B_TRUE) {
2507                         rw_enter(&isp->sess_conn_list_rwlock, RW_READER);
2508                         icp = isp->sess_conn_list;
2509                         while (icp != NULL) {
2510                                 if (icp->conn_state ==
2511                                     ISCSI_CONN_STATE_LOGGED_IN) {
2512                                         rw_exit(&isp->sess_conn_list_rwlock);
2513                                         rw_exit(&ihp->hba_sess_list_rwlock);
2514                                         return (B_TRUE);
2515                                 }
2516                                 icp = icp->conn_next;
2517                         }
2518                         rw_exit(&isp->sess_conn_list_rwlock);
2519                 }
2520                 isp = isp->sess_next;
2521         }
2522         rw_exit(&ihp->hba_sess_list_rwlock);
2523 
2524         return (B_FALSE);
2525 }