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