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 2000 by Cisco Systems, Inc.  All rights reserved.
  23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  25  *
  26  * iSCSI Software Initiator
  27  */
  28 
  29 /*
  30  * Framework interface routines for iSCSI
  31  */
  32 
  33 #include "iscsi.h"                              /* main header */
  34 #include <sys/iscsi_protocol.h>   /* protocol structs */
  35 #include <sys/scsi/adapters/iscsi_if.h>           /* ioctl interfaces */
  36 #include "iscsi_targetparam.h"
  37 #include "persistent.h"
  38 #include <sys/scsi/adapters/iscsi_door.h>
  39 #include <sys/dlpi.h>
  40 #include <sys/utsname.h>
  41 #include "isns_client.h"
  42 #include "isns_protocol.h"
  43 #include <sys/bootprops.h>
  44 #include <sys/types.h>
  45 #include <sys/bootconf.h>
  46 
  47 #define ISCSI_NAME_VERSION      "iSCSI Initiator v-1.55"
  48 
  49 #define MAX_GET_NAME_SIZE       1024
  50 #define MAX_NAME_PROP_SIZE      256
  51 #define UNDEFINED               -1
  52 #define ISCSI_DISC_DELAY        2       /* seconds */
  53 
  54 /*
  55  * +--------------------------------------------------------------------+
  56  * | iscsi globals                                                      |
  57  * +--------------------------------------------------------------------+
  58  */
  59 void            *iscsi_state;
  60 kmutex_t        iscsi_oid_mutex;
  61 uint32_t        iscsi_oid;
  62 int             iscsi_nop_delay         = ISCSI_DEFAULT_NOP_DELAY;
  63 int             iscsi_rx_window         = ISCSI_DEFAULT_RX_WINDOW;
  64 int             iscsi_rx_max_window     = ISCSI_DEFAULT_RX_MAX_WINDOW;
  65 boolean_t       iscsi_logging           = B_FALSE;
  66 
  67 extern ib_boot_prop_t   *iscsiboot_prop;
  68 extern int              modrootloaded;
  69 extern struct bootobj   rootfs;
  70 
  71 /*
  72  * +--------------------------------------------------------------------+
  73  * | iscsi.c prototypes                                                 |
  74  * +--------------------------------------------------------------------+
  75  */
  76 static int iscsi_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd,
  77     void *arg, void **result);
  78 static int iscsi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
  79 static int iscsi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
  80 
  81 /* scsi_tran prototypes */
  82 static int iscsi_tran_lun_init(dev_info_t *hba_dip, dev_info_t *lun_dip,
  83     scsi_hba_tran_t *hba_tran, struct scsi_device *sd);
  84 static int iscsi_tran_lun_probe(struct scsi_device *sd, int (*callback) ());
  85 static struct scsi_pkt *iscsi_tran_init_pkt(struct scsi_address *ap,
  86     struct scsi_pkt *pkt, struct buf *bp, int cmdlen, int statuslen,
  87     int tgtlen, int flags, int (*callback) (), caddr_t arg);
  88 static void iscsi_tran_lun_free(dev_info_t *hba_dip, dev_info_t *lun_dip,
  89     scsi_hba_tran_t *hba_tran, struct scsi_device *sd);
  90 static int iscsi_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt);
  91 static int iscsi_tran_abort(struct scsi_address *ap, struct scsi_pkt *pkt);
  92 static int iscsi_tran_reset(struct scsi_address *ap, int level);
  93 static int iscsi_tran_getcap(struct scsi_address *ap, char *cap, int whom);
  94 static int iscsi_tran_setcap(struct scsi_address *ap, char *cap,
  95     int value, int whom);
  96 static void iscsi_tran_destroy_pkt(struct scsi_address *ap,
  97     struct scsi_pkt *pkt);
  98 static void iscsi_tran_dmafree(struct scsi_address *ap,
  99     struct scsi_pkt *pkt);
 100 static void iscsi_tran_sync_pkt(struct scsi_address *ap,
 101     struct scsi_pkt *pkt);
 102 static void iscsi_tran_sync_pkt(struct scsi_address *ap,
 103     struct scsi_pkt *pkt);
 104 static int iscsi_tran_reset_notify(struct scsi_address *ap, int flag,
 105     void (*callback) (caddr_t), caddr_t arg);
 106 static int iscsi_tran_bus_config(dev_info_t *parent, uint_t flags,
 107     ddi_bus_config_op_t op, void *arg, dev_info_t **childp);
 108 static int iscsi_tran_bus_unconfig(dev_info_t *parent, uint_t flags,
 109     ddi_bus_config_op_t op, void *arg);
 110 static int iscsi_tran_get_name(struct scsi_device *sd, char *name, int len);
 111 static int iscsi_tran_get_bus_addr(struct scsi_device *sd, char *name, int len);
 112 
 113 /* bus_ops prototypes */
 114 /* LINTED E_STATIC_UNUSED */
 115 static ddi_intrspec_t iscsi_get_intrspec(dev_info_t *dip, dev_info_t *rdip,
 116     uint_t inumber);
 117 /* LINTED E_STATIC_UNUSED */
 118 static int iscsi_add_intrspec(dev_info_t *dip, dev_info_t *rdip,
 119     ddi_intrspec_t intrspec, ddi_iblock_cookie_t *iblock_cookiep,
 120     ddi_idevice_cookie_t *idevice_cookiep, uint_t (*int_handler)(caddr_t
 121     int_handler_arg), caddr_t int_handler_arg, int kind);
 122 /* LINTED E_STATIC_UNUSED */
 123 static void iscsi_remove_intrspec(dev_info_t *dip, dev_info_t *rdip,
 124     ddi_intrspec_t intrspec, ddi_iblock_cookie_t iblock_cookie);
 125 /* LINTED E_STATIC_UNUSED */
 126 static int iscsi_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
 127     void *arg, void *result);
 128 
 129 /* cb_ops prototypes */
 130 static int iscsi_open(dev_t *devp, int flags, int otyp, cred_t *credp);
 131 static int iscsi_close(dev_t dev, int flag, int otyp, cred_t *credp);
 132 static int iscsi_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
 133     cred_t *credp, int *rvalp);
 134 
 135 int iscsi_get_persisted_param(uchar_t *name,
 136     iscsi_param_get_t *ipgp,
 137     iscsi_login_params_t *params);
 138 static void iscsi_override_target_default(iscsi_hba_t *ihp,
 139     iscsi_param_get_t *ipg);
 140 
 141 /* scsi_tran helpers */
 142 static int iscsi_virt_lun_init(dev_info_t *hba_dip, dev_info_t *lun_dip,
 143     scsi_hba_tran_t *hba_tran, struct scsi_device *sd);
 144 static int iscsi_phys_lun_init(dev_info_t *hba_dip, dev_info_t *lun_dip,
 145     scsi_hba_tran_t *hba_tran, struct scsi_device *sd);
 146 static int iscsi_i_commoncap(struct scsi_address *ap, char *cap,
 147     int val, int lunonly, int doset);
 148 static void iscsi_get_name_to_iqn(char *name, int name_max_len);
 149 static void iscsi_get_name_from_iqn(char *name, int name_max_len);
 150 static boolean_t iscsi_cmp_boot_sess_oid(iscsi_hba_t *ihp, uint32_t oid);
 151 
 152 /* iscsi initiator service helpers */
 153 static boolean_t iscsi_enter_service_zone(iscsi_hba_t *ihp, uint32_t status);
 154 static void iscsi_exit_service_zone(iscsi_hba_t *ihp, uint32_t status);
 155 static void iscsi_check_miniroot(iscsi_hba_t *ihp);
 156 static void iscsi_get_tunable_default(iscsi_tunable_object_t *param);
 157 static int iscsi_get_persisted_tunable_param(uchar_t *name,
 158     iscsi_tunable_object_t *tpsg);
 159 static void iscsi_set_default_tunable_params(iscsi_tunable_params_t *params);
 160 
 161 /* struct helpers prototypes */
 162 
 163 /*
 164  * At this point this driver doesn't need this structure because nothing
 165  * is done during the open, close or ioctl. Code put in place because
 166  * some admin related work might be done in the ioctl routine.
 167  */
 168 static struct cb_ops iscsi_cb_ops = {
 169         iscsi_open,                     /* open */
 170         iscsi_close,                    /* close */
 171         nodev,                          /* strategy */
 172         nodev,                          /* print */
 173         nodev,                          /* dump */
 174         nodev,                          /* read */
 175         nodev,                          /* write */
 176         iscsi_ioctl,                    /* ioctl */
 177         nodev,                          /* devmap */
 178         nodev,                          /* mmap */
 179         nodev,                          /* segmap */
 180         nochpoll,                       /* poll */
 181         ddi_prop_op,                    /* prop_op */
 182         NULL,                           /* streamtab */
 183         D_NEW | D_MP | D_HOTPLUG,       /* flags */
 184         CB_REV,                         /* cb_rev */
 185         nodev,                          /* aread */
 186         nodev,                          /* awrite */
 187 };
 188 
 189 static struct dev_ops iscsi_dev_ops = {
 190         DEVO_REV,               /* devo_rev */
 191         0,                      /* refcnt */
 192         iscsi_getinfo,          /* getinfo */
 193         nulldev,                /* identify */
 194         nulldev,                /* probe */
 195         iscsi_attach,           /* attach */
 196         iscsi_detach,           /* detach */
 197         nodev,                  /* reset */
 198         &iscsi_cb_ops,              /* driver operations */
 199         NULL,                   /* bus ops */
 200         NULL,                   /* power management */
 201         ddi_quiesce_not_needed, /* quiesce */
 202 };
 203 
 204 static struct modldrv modldrv = {
 205         &mod_driverops,             /* drv_modops */
 206         ISCSI_NAME_VERSION,     /* drv_linkinfo */
 207         &iscsi_dev_ops              /* drv_dev_ops */
 208 };
 209 
 210 static struct modlinkage modlinkage = {
 211         MODREV_1,               /* ml_rev */
 212         &modldrv,           /* ml_linkage[] */
 213         NULL                    /* NULL termination */
 214 };
 215 
 216 /*
 217  * This structure is bogus. scsi_hba_attach_setup() requires, as in the kernel
 218  * will panic if you don't pass this in to the routine, this information.
 219  * Need to determine what the actual impact to the system is by providing
 220  * this information if any. Since dma allocation is done in pkt_init it may
 221  * not have any impact. These values are straight from the Writing Device
 222  * Driver manual.
 223  */
 224 static ddi_dma_attr_t iscsi_dma_attr = {
 225         DMA_ATTR_V0,    /* ddi_dma_attr version */
 226         0,              /* low address */
 227         0xffffffff,     /* high address */
 228         0x00ffffff,     /* counter upper bound */
 229         1,              /* alignment requirements */
 230         0x3f,           /* burst sizes */
 231         1,              /* minimum DMA access */
 232         0xffffffff,     /* maximum DMA access */
 233         (1 << 24) - 1,    /* segment boundary restrictions */
 234         1,              /* scater/gather list length */
 235         512,            /* device granularity */
 236         0               /* DMA flags */
 237 };
 238 
 239 /*
 240  * _init - General driver init entry
 241  */
 242 int
 243 _init(void)
 244 {
 245         int rval = 0;
 246 
 247         iscsi_net_init();
 248 
 249         mutex_init(&iscsi_oid_mutex, NULL, MUTEX_DRIVER, NULL);
 250         iscsi_oid = ISCSI_INITIATOR_OID;
 251 
 252         /*
 253          * Set up the soft state structures. If this driver is actually
 254          * being attached to the system then we'll have at least one
 255          * HBA/NIC used.
 256          */
 257         rval = ddi_soft_state_init(&iscsi_state,
 258             sizeof (iscsi_hba_t), 1);
 259         if (rval != 0) {
 260                 iscsi_net_fini();
 261                 goto init_done;
 262         }
 263 
 264         rval = scsi_hba_init(&modlinkage);
 265         if (rval != 0) {
 266                 ddi_soft_state_fini(&iscsi_state);
 267                 iscsi_net_fini();
 268                 goto init_done;
 269         }
 270 
 271         rval = mod_install(&modlinkage);
 272         if (rval != 0) {
 273                 ddi_soft_state_fini(&iscsi_state);
 274                 scsi_hba_fini(&modlinkage);
 275                 iscsi_net_fini();
 276                 goto init_done;
 277         }
 278         (void) iscsi_door_ini();
 279 
 280 init_done:
 281         return (rval);
 282 }
 283 
 284 /*
 285  * _fini - General driver destructor entry
 286  */
 287 int
 288 _fini(void)
 289 {
 290         int rval = 0;
 291 
 292         rval = mod_remove(&modlinkage);
 293         if (rval == 0) {
 294                 scsi_hba_fini(&modlinkage);
 295                 ddi_soft_state_fini(&iscsi_state);
 296                 mutex_destroy(&iscsi_oid_mutex);
 297                 (void) iscsi_door_term();
 298                 iscsi_net_fini();
 299         }
 300         return (rval);
 301 }
 302 
 303 /*
 304  * _info - General driver info entry
 305  */
 306 int
 307 _info(struct modinfo *mp)
 308 {
 309         int rval = 0;
 310 
 311         rval = mod_info(&modlinkage, mp);
 312 
 313         return (rval);
 314 }
 315 
 316 
 317 /*
 318  * +--------------------------------------------------------------------+
 319  * | Start of dev_ops routines                                    |
 320  * +--------------------------------------------------------------------+
 321  */
 322 
 323 /*
 324  * iscsi_getinfo - returns general driver information
 325  */
 326 /* ARGSUSED */
 327 static int
 328 iscsi_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd,
 329     void *arg, void **result)
 330 {
 331         int             rval            = DDI_SUCCESS;
 332         int             instance        = getminor((dev_t)arg);
 333         iscsi_hba_t     *ip;
 334 
 335         switch (infocmd) {
 336         case DDI_INFO_DEVT2DEVINFO:
 337                 if ((ip = ddi_get_soft_state(iscsi_state, instance)) == NULL) {
 338                         return (DDI_FAILURE);
 339                 }
 340                 *result = ip->hba_dip;
 341                 if (ip->hba_dip == NULL)
 342                         rval = DDI_FAILURE;
 343                 else
 344                         rval = DDI_SUCCESS;
 345                 break;
 346 
 347         case DDI_INFO_DEVT2INSTANCE:
 348                 *result = (void *)(uintptr_t)instance;
 349                 rval = DDI_SUCCESS;
 350                 break;
 351 
 352         default:
 353                 rval = DDI_FAILURE;
 354                 break;
 355         }
 356         return (rval);
 357 }
 358 
 359 
 360 /*
 361  * iscsi_attach -- Attach instance of an iSCSI HBA.  We
 362  * will attempt to create our HBA and register it with
 363  * scsi_vhci.  If it's not possible to create the HBA
 364  * or register with vhci we will fail the attach.
 365  */
 366 static int
 367 iscsi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 368 {
 369         int                     rval            = DDI_SUCCESS;
 370         int                     instance        = ddi_get_instance(dip);
 371         iscsi_hba_t             *ihp            = NULL;
 372         scsi_hba_tran_t         *tran           = NULL;
 373         char                    init_port_name[MAX_NAME_PROP_SIZE];
 374 
 375         switch (cmd) {
 376         case DDI_ATTACH:
 377                 /* create iSCSH HBA devctl device node */
 378                 if (ddi_create_minor_node(dip, ISCSI_DEVCTL, S_IFCHR, 0,
 379                     DDI_PSEUDO, 0) == DDI_SUCCESS) {
 380 
 381                         /* allocate HBA soft state */
 382                         if (ddi_soft_state_zalloc(iscsi_state, instance) !=
 383                             DDI_SUCCESS) {
 384                                 ddi_remove_minor_node(dip, NULL);
 385                                 rval = DDI_FAILURE;
 386                                 break;
 387                         }
 388 
 389                         /* get reference to soft state */
 390                         if ((ihp = (iscsi_hba_t *)ddi_get_soft_state(
 391                             iscsi_state, instance)) == NULL) {
 392                                 ddi_remove_minor_node(dip, NULL);
 393                                 ddi_soft_state_free(iscsi_state, instance);
 394                                 rval = DDI_FAILURE;
 395                                 break;
 396                         }
 397 
 398                         /* init HBA mutex used to protect discovery events */
 399                         mutex_init(&ihp->hba_discovery_events_mutex, NULL,
 400                             MUTEX_DRIVER, NULL);
 401 
 402                         /* Get LDI ident */
 403                         rval = ldi_ident_from_dip(dip, &ihp->hba_li);
 404                         ASSERT(rval == 0); /* Failure indicates invalid arg */
 405 
 406                         /* init HBA mutex used to protect service status */
 407                         mutex_init(&ihp->hba_service_lock, NULL,
 408                             MUTEX_DRIVER, NULL);
 409                         cv_init(&ihp->hba_service_cv, NULL, CV_DRIVER, NULL);
 410 
 411                         /*
 412                          * init SendTargets semaphore that is used to allow
 413                          * only one operation at a time
 414                          */
 415                         sema_init(&ihp->hba_sendtgts_semaphore, 1, NULL,
 416                             SEMA_DRIVER, NULL);
 417 
 418                         ihp->hba_sess_list = NULL;
 419                         rw_init(&ihp->hba_sess_list_rwlock, NULL,
 420                             RW_DRIVER, NULL);
 421 
 422                         /* allocate scsi_hba_tran */
 423                         if ((tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP))
 424                             == NULL) {
 425                                 ddi_remove_minor_node(dip, NULL);
 426                                 goto iscsi_attach_failed2;
 427                         }
 428 
 429                         /* soft state setup */
 430                         ihp->hba_sig = ISCSI_SIG_HBA;
 431                         ihp->hba_tran        = tran;
 432                         ihp->hba_dip = dip;
 433                         if (iscsiboot_prop == NULL) {
 434                                 ihp->hba_service_status =
 435                                     ISCSI_SERVICE_DISABLED;
 436                                 ihp->hba_service_status_overwrite = B_FALSE;
 437                         } else {
 438                                 ihp->hba_service_status =
 439                                     ISCSI_SERVICE_ENABLED;
 440                                 ihp->hba_service_status_overwrite = B_TRUE;
 441                         }
 442                         ihp->hba_service_client_count = 0;
 443 
 444                         mutex_enter(&iscsi_oid_mutex);
 445                         ihp->hba_oid           = iscsi_oid++;
 446                         mutex_exit(&iscsi_oid_mutex);
 447 
 448                         ihp->hba_name[0]       = '\0';
 449                         ihp->hba_name_length   = 0;
 450                         ihp->hba_alias_length          = 0;
 451                         ihp->hba_alias[0]      = '\0';
 452 
 453                         iscsi_net->tweaks.rcvbuf = ddi_prop_get_int(
 454                             DDI_DEV_T_ANY, ihp->hba_dip, 0, "so-rcvbuf",
 455                             ISCSI_SOCKET_RCVBUF_SIZE);
 456 
 457                         iscsi_net->tweaks.sndbuf = ddi_prop_get_int(
 458                             DDI_DEV_T_ANY, ihp->hba_dip, 0, "so-sndbuf",
 459                             ISCSI_SOCKET_SNDBUF_SIZE);
 460 
 461                         iscsi_net->tweaks.nodelay = ddi_prop_get_int(
 462                             DDI_DEV_T_ANY, ihp->hba_dip, 0, "tcp-nodelay",
 463                             ISCSI_TCP_NODELAY_DEFAULT);
 464 
 465                         iscsi_net->tweaks.conn_notify_threshold =
 466                             ddi_prop_get_int(DDI_DEV_T_ANY,
 467                             ihp->hba_dip, 0, "tcp-conn-notify-threshold",
 468                             ISCSI_TCP_CNOTIFY_THRESHOLD_DEFAULT);
 469 
 470                         iscsi_net->tweaks.conn_abort_threshold =
 471                             ddi_prop_get_int(DDI_DEV_T_ANY, ihp->hba_dip,
 472                             0, "tcp-conn-abort-threshold",
 473                             ISCSI_TCP_CABORT_THRESHOLD_DEFAULT);
 474 
 475                         iscsi_net->tweaks.abort_threshold = ddi_prop_get_int(
 476                             DDI_DEV_T_ANY, ihp->hba_dip, 0,
 477                             "tcp-abort-threshold",
 478                             ISCSI_TCP_ABORT_THRESHOLD_DEFAULT);
 479 
 480                         ihp->hba_config_storm_delay = ddi_prop_get_int(
 481                             DDI_DEV_T_ANY, ihp->hba_dip, 0,
 482                             "config-storm-delay",
 483                             ISCSI_CONFIG_STORM_DELAY_DEFAULT);
 484 
 485                         (void) ddi_prop_update_int(DDI_DEV_T_NONE, ihp->hba_dip,
 486                             "so-rcvbuf", iscsi_net->tweaks.rcvbuf);
 487 
 488                         (void) ddi_prop_update_int(DDI_DEV_T_NONE, ihp->hba_dip,
 489                             "so-sndbuf", iscsi_net->tweaks.sndbuf);
 490 
 491                         (void) ddi_prop_update_int(DDI_DEV_T_NONE, ihp->hba_dip,
 492                             "tcp-nodelay", iscsi_net->tweaks.nodelay);
 493 
 494                         (void) ddi_prop_update_int(DDI_DEV_T_NONE, ihp->hba_dip,
 495                             "tcp-conn-notify-threshold",
 496                             iscsi_net->tweaks.conn_notify_threshold);
 497 
 498                         (void) ddi_prop_update_int(DDI_DEV_T_NONE, ihp->hba_dip,
 499                             "tcp-conn-abort-threshold",
 500                             iscsi_net->tweaks.conn_abort_threshold);
 501 
 502                         (void) ddi_prop_update_int(DDI_DEV_T_NONE, ihp->hba_dip,
 503                             "tcp-abort-threshold",
 504                             iscsi_net->tweaks.abort_threshold);
 505 
 506                         (void) ddi_prop_update_int(DDI_DEV_T_NONE, ihp->hba_dip,
 507                             "config-storm-delay",
 508                             ihp->hba_config_storm_delay);
 509 
 510                         /* setup hba defaults */
 511                         iscsi_set_default_login_params(&ihp->hba_params);
 512                         iscsi_set_default_tunable_params(
 513                             &ihp->hba_tunable_params);
 514 
 515                         /* setup minimal initiator params */
 516                         iscsid_set_default_initiator_node_settings(ihp, B_TRUE);
 517 
 518                         /* hba set up */
 519                         tran->tran_hba_private  = ihp;
 520                         tran->tran_tgt_private  = NULL;
 521                         tran->tran_tgt_init  = iscsi_tran_lun_init;
 522                         tran->tran_tgt_probe = iscsi_tran_lun_probe;
 523                         tran->tran_tgt_free  = iscsi_tran_lun_free;
 524                         tran->tran_start     = iscsi_tran_start;
 525                         tran->tran_abort     = iscsi_tran_abort;
 526                         tran->tran_reset     = iscsi_tran_reset;
 527                         tran->tran_getcap    = iscsi_tran_getcap;
 528                         tran->tran_setcap    = iscsi_tran_setcap;
 529                         tran->tran_init_pkt  = iscsi_tran_init_pkt;
 530                         tran->tran_destroy_pkt       = iscsi_tran_destroy_pkt;
 531                         tran->tran_dmafree   = iscsi_tran_dmafree;
 532                         tran->tran_sync_pkt  = iscsi_tran_sync_pkt;
 533                         tran->tran_reset_notify      = iscsi_tran_reset_notify;
 534                         tran->tran_bus_config        = iscsi_tran_bus_config;
 535                         tran->tran_bus_unconfig      = iscsi_tran_bus_unconfig;
 536 
 537                         tran->tran_get_name  = iscsi_tran_get_name;
 538                         tran->tran_get_bus_addr      = iscsi_tran_get_bus_addr;
 539                         tran->tran_interconnect_type = INTERCONNECT_ISCSI;
 540 
 541                         /* register scsi hba with scsa */
 542                         if (scsi_hba_attach_setup(dip, &iscsi_dma_attr,
 543                             tran, SCSI_HBA_TRAN_CLONE) != DDI_SUCCESS) {
 544                                 goto iscsi_attach_failed1;
 545                         }
 546 
 547                         /* register scsi hba with mdi (MPxIO/vhci) */
 548                         if (mdi_phci_register(MDI_HCI_CLASS_SCSI, dip, 0) !=
 549                             MDI_SUCCESS) {
 550                                 ihp->hba_mpxio_enabled = B_FALSE;
 551                         } else {
 552                                 ihp->hba_mpxio_enabled = B_TRUE;
 553                         }
 554 
 555                         (void) iscsi_hba_kstat_init(ihp);
 556 
 557                         /* Initialize targetparam list */
 558                         iscsi_targetparam_init();
 559 
 560                         /* Initialize ISID */
 561                         ihp->hba_isid[0] = ISCSI_SUN_ISID_0;
 562                         ihp->hba_isid[1] = ISCSI_SUN_ISID_1;
 563                         ihp->hba_isid[2] = ISCSI_SUN_ISID_2;
 564                         ihp->hba_isid[3] = ISCSI_SUN_ISID_3;
 565                         ihp->hba_isid[4] = ISCSI_SUN_ISID_4;
 566                         ihp->hba_isid[5] = ISCSI_SUN_ISID_5;
 567 
 568                         /* Setup iSNS transport services and client */
 569                         isns_client_init();
 570 
 571                         /*
 572                          * initialize persistent store,
 573                          * or boot target info in case of iscsi boot
 574                          */
 575                         ihp->hba_persistent_loaded = B_FALSE;
 576                         if (iscsid_init(ihp) == B_FALSE) {
 577                                 goto iscsi_attach_failed0;
 578                         }
 579 
 580                         /* Setup init_port_name for MPAPI */
 581                         (void) snprintf(init_port_name, MAX_NAME_PROP_SIZE,
 582                             "%s,%02x%02x%02x%02x%02x%02x",
 583                             (char *)ihp->hba_name, ihp->hba_isid[0],
 584                             ihp->hba_isid[1], ihp->hba_isid[2],
 585                             ihp->hba_isid[3], ihp->hba_isid[4],
 586                             ihp->hba_isid[5]);
 587 
 588                         if (ddi_prop_update_string(DDI_DEV_T_NONE, dip,
 589                             SCSI_ADDR_PROP_INITIATOR_PORT, init_port_name) !=
 590                             DDI_PROP_SUCCESS) {
 591                                 cmn_err(CE_WARN, "iscsi_attach: Creating "
 592                                     SCSI_ADDR_PROP_INITIATOR_PORT
 593                                     " property on iSCSI "
 594                                     "HBA(%s) with dip(%d) Failed",
 595                                     (char *)ihp->hba_name,
 596                                     ddi_get_instance(dip));
 597                         }
 598 
 599                         ddi_report_dev(dip);
 600                 } else {
 601                         rval = DDI_FAILURE;
 602                 }
 603                 break;
 604 
 605 iscsi_attach_failed0:
 606                 isns_client_cleanup();
 607                 if (ihp->stats.ks) {
 608                         (void) iscsi_hba_kstat_term(ihp);
 609                 }
 610                 if (ihp->hba_mpxio_enabled == B_TRUE) {
 611                         (void) mdi_phci_unregister(dip, 0);
 612                 }
 613                 (void) scsi_hba_detach(ihp->hba_dip);
 614 iscsi_attach_failed1:
 615                 ddi_remove_minor_node(dip, NULL);
 616                 ddi_prop_remove_all(ihp->hba_dip);
 617                 scsi_hba_tran_free(tran);
 618 iscsi_attach_failed2:
 619                 cv_destroy(&ihp->hba_service_cv);
 620                 mutex_destroy(&ihp->hba_service_lock);
 621                 mutex_destroy(&ihp->hba_discovery_events_mutex);
 622                 sema_destroy(&ihp->hba_sendtgts_semaphore);
 623                 rw_destroy(&ihp->hba_sess_list_rwlock);
 624                 ddi_soft_state_free(iscsi_state, instance);
 625                 rval = DDI_FAILURE;
 626                 break;
 627 
 628         case DDI_RESUME:
 629                 break;
 630 
 631         default:
 632                 rval = DDI_FAILURE;
 633         }
 634 
 635         if (rval != DDI_SUCCESS) {
 636                 cmn_err(CE_WARN, "iscsi driver unable to attach "
 637                     "hba instance %d", instance);
 638         }
 639 
 640         return (rval);
 641 }
 642 
 643 /*
 644  * iscsi_detach - called on unload of hba instance
 645  */
 646 static int
 647 iscsi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 648 {
 649         int                     rval            = DDI_SUCCESS;
 650         scsi_hba_tran_t         *tran           = NULL;
 651         iscsi_hba_t             *ihp            = NULL;
 652         iscsi_hba_t             *ihp_check      = NULL;
 653         int                     instance;
 654         char                    *init_node_name;
 655 
 656         instance = ddi_get_instance(dip);
 657 
 658         switch (cmd) {
 659         case DDI_DETACH:
 660                 if (!(tran = (scsi_hba_tran_t *)ddi_get_driver_private(dip))) {
 661                         rval = DDI_SUCCESS;
 662                         break;
 663                 }
 664 
 665                 if ((ihp = (iscsi_hba_t *)tran->tran_hba_private) == NULL) {
 666                         rval =  DDI_FAILURE;
 667                         break;
 668                 }
 669 
 670                 /*
 671                  * Validate that what is stored by the DDI framework is still
 672                  * the same state structure referenced by the SCSI framework
 673                  */
 674                 ihp_check = ddi_get_soft_state(iscsi_state, instance);
 675                 if (ihp_check != ihp) {
 676                         rval = DDI_FAILURE;
 677                         break;
 678                 }
 679 
 680                 /* If a session exists we can't safely detach */
 681                 rw_enter(&ihp->hba_sess_list_rwlock, RW_READER);
 682                 if (ihp->hba_sess_list != NULL) {
 683                         rw_exit(&ihp->hba_sess_list_rwlock);
 684                         rval = DDI_FAILURE;
 685                         break;
 686                 }
 687                 rw_exit(&ihp->hba_sess_list_rwlock);
 688 
 689                 /* Disable all discovery services */
 690                 if (iscsid_disable_discovery(ihp,
 691                     ISCSI_ALL_DISCOVERY_METHODS) == B_FALSE) {
 692                         /* Disable failed.  Fail detach */
 693                         rval = DDI_FAILURE;
 694                         break;
 695                 }
 696 
 697                 /* Deregister from iSNS server(s). */
 698                 init_node_name = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP);
 699                 if (persistent_initiator_name_get(init_node_name,
 700                     ISCSI_MAX_NAME_LEN) == B_TRUE) {
 701                         if (strlen(init_node_name) > 0) {
 702                                 (void) isns_dereg(ihp->hba_isid,
 703                                     (uint8_t *)init_node_name);
 704                         }
 705                 }
 706                 kmem_free(init_node_name, ISCSI_MAX_NAME_LEN);
 707                 init_node_name = NULL;
 708 
 709                 /* Cleanup iSNS Client */
 710                 isns_client_cleanup();
 711 
 712                 iscsi_targetparam_cleanup();
 713 
 714                 /* Cleanup iscsid resources */
 715                 iscsid_fini();
 716 
 717                 if (rval != DDI_SUCCESS) {
 718                         break;
 719                 }
 720                 /* kstat hba. destroy */
 721                 KSTAT_DEC_HBA_CNTR_SESS(ihp);
 722 
 723                 if (ihp->hba_mpxio_enabled == B_TRUE) {
 724                         (void) mdi_phci_unregister(dip, 0);
 725                 }
 726                 ddi_remove_minor_node(dip, NULL);
 727 
 728                 ddi_prop_remove_all(ihp->hba_dip);
 729 
 730                 ldi_ident_release(ihp->hba_li);
 731 
 732                 cv_destroy(&ihp->hba_service_cv);
 733                 mutex_destroy(&ihp->hba_service_lock);
 734                 mutex_destroy(&ihp->hba_discovery_events_mutex);
 735                 rw_destroy(&ihp->hba_sess_list_rwlock);
 736                 (void) iscsi_hba_kstat_term(ihp);
 737 
 738                 (void) scsi_hba_detach(dip);
 739                 if (tran != NULL) {
 740                         scsi_hba_tran_free(tran);
 741                 }
 742                 ddi_soft_state_free(iscsi_state, instance);
 743                 break;
 744         default:
 745                 break;
 746         }
 747 
 748         if (rval != DDI_SUCCESS) {
 749                 cmn_err(CE_WARN, "iscsi driver unable to "
 750                     "detach hba instance %d", instance);
 751         }
 752 
 753         return (rval);
 754 }
 755 
 756 /*
 757  * +--------------------------------------------------------------------+
 758  * | End of dev_ops routines                                            |
 759  * +--------------------------------------------------------------------+
 760  */
 761 
 762 /*
 763  * +--------------------------------------------------------------------+
 764  * | scsi_tran(9E) routines                                             |
 765  * +--------------------------------------------------------------------+
 766  */
 767 
 768 /*
 769  * iscsi_tran_lun_init - Find target device based on SCSI device
 770  * Based on the information given (SCSI device, target dev_info) find
 771  * the target iSCSI device and put a pointer to that information in
 772  * the scsi_hba_tran_t structure.
 773  */
 774 static int
 775 iscsi_tran_lun_init(dev_info_t *hba_dip, dev_info_t *lun_dip,
 776     scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
 777 {
 778         int             rval    = 0;
 779         int             type    = 0;
 780 
 781         ASSERT(hba_tran->tran_hba_private != NULL);
 782 
 783         /*
 784          * Child node is getting initialized.  Look at the mpxio component
 785          * type on the child device to see if this device is mpxio managed
 786          * or not.
 787          */
 788         type = mdi_get_component_type(lun_dip);
 789         if (type != MDI_COMPONENT_CLIENT) {
 790                 rval = iscsi_phys_lun_init(hba_dip, lun_dip, hba_tran, sd);
 791         } else {
 792                 rval = iscsi_virt_lun_init(hba_dip, lun_dip, hba_tran, sd);
 793         }
 794 
 795         return (rval);
 796 }
 797 
 798 /*
 799  * iscsi_tran_lun_probe - This function didn't need to be implemented.
 800  * We could have left NULL in the tran table.  Since this isn't a
 801  * performance path this seems safe.  We are just wrappering the
 802  * function so we can see the call go through if we have debugging
 803  * enabled.
 804  */
 805 static int
 806 iscsi_tran_lun_probe(struct scsi_device *sd, int (*callback) ())
 807 {
 808         int rval = 0;
 809 
 810         rval = scsi_hba_probe(sd, callback);
 811 
 812         return (rval);
 813 }
 814 
 815 /*
 816  * iscsi_init_pkt - Allocate SCSI packet and fill in required info.
 817  */
 818 /* ARGSUSED */
 819 static struct scsi_pkt *
 820 iscsi_tran_init_pkt(struct scsi_address *ap, struct scsi_pkt *pkt,
 821     struct buf *bp, int cmdlen, int statuslen, int tgtlen, int flags,
 822     int (*callback) (), caddr_t arg)
 823 {
 824         iscsi_lun_t *ilp;
 825         iscsi_cmd_t *icmdp;
 826 
 827         ASSERT(ap != NULL);
 828         ASSERT(callback == NULL_FUNC || callback == SLEEP_FUNC);
 829 
 830         /*
 831          * The software stack doesn't have DMA which means the iSCSI
 832          * protocol layer will be doing a bcopy from bp to outgoing
 833          * streams buffers. Make sure that the buffer is mapped in
 834          * so that the copy won't panic the system.
 835          */
 836         if (bp && (bp->b_bcount != 0) &&
 837             bp_mapin_common(bp, (callback == NULL_FUNC) ?
 838             VM_NOSLEEP : VM_SLEEP) == NULL) {
 839                 return (NULL);
 840         }
 841 
 842         ilp = (iscsi_lun_t *)ap->a_hba_tran->tran_tgt_private;
 843         ASSERT(ilp != NULL);
 844 
 845         if (pkt == NULL) {
 846                 pkt = scsi_hba_pkt_alloc(ilp->lun_sess->sess_hba->hba_dip,
 847                     ap, cmdlen, statuslen, tgtlen, sizeof (iscsi_cmd_t),
 848                     callback, arg);
 849                 if (pkt == NULL) {
 850                         return (NULL);
 851                 }
 852                 icmdp = (iscsi_cmd_t *)pkt->pkt_ha_private;
 853                 icmdp->cmd_sig                       = ISCSI_SIG_CMD;
 854                 icmdp->cmd_state             = ISCSI_CMD_STATE_FREE;
 855                 icmdp->cmd_lun                       = ilp;
 856                 iscsi_lun_hold(ilp);
 857                 icmdp->cmd_type                      = ISCSI_CMD_TYPE_SCSI;
 858                 /* add the report lun addressing type on to the lun */
 859                 icmdp->cmd_un.scsi.lun               = ilp->lun_addr_type << 14;
 860                 icmdp->cmd_un.scsi.lun               = icmdp->cmd_un.scsi.lun |
 861                     ilp->lun_num;
 862                 icmdp->cmd_un.scsi.pkt               = pkt;
 863                 icmdp->cmd_un.scsi.bp                = bp;
 864                 icmdp->cmd_un.scsi.cmdlen    = cmdlen;
 865                 icmdp->cmd_un.scsi.statuslen = statuslen;
 866                 icmdp->cmd_crc_error_seen    = B_FALSE;
 867                 icmdp->cmd_misc_flags                = 0;
 868                 if (flags & PKT_XARQ) {
 869                         icmdp->cmd_misc_flags |= ISCSI_CMD_MISCFLAG_XARQ;
 870                 }
 871 
 872 
 873                 idm_sm_audit_init(&icmdp->cmd_state_audit);
 874 
 875                 mutex_init(&icmdp->cmd_mutex, NULL, MUTEX_DRIVER, NULL);
 876                 cv_init(&icmdp->cmd_completion, NULL, CV_DRIVER, NULL);
 877 
 878                 pkt->pkt_address             = *ap;
 879                 pkt->pkt_comp                        = (void (*)())NULL;
 880                 pkt->pkt_flags                       = 0;
 881                 pkt->pkt_time                        = 0;
 882                 pkt->pkt_resid                       = 0;
 883                 pkt->pkt_statistics          = 0;
 884                 pkt->pkt_reason                      = 0;
 885         }
 886         return (pkt);
 887 }
 888 
 889 /*
 890  * iscsi_tran_lun_free - Free a SCSI LUN
 891  */
 892 static void
 893 iscsi_tran_lun_free(dev_info_t *hba_dip, dev_info_t *lun_dip,
 894     scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
 895 {
 896         iscsi_lun_t *ilp = NULL;
 897 
 898         ASSERT(hba_dip != NULL);
 899         ASSERT(lun_dip != NULL);
 900         ASSERT(hba_tran != NULL);
 901         ASSERT(sd != NULL);
 902         ilp = (iscsi_lun_t *)hba_tran->tran_tgt_private;
 903         ASSERT(ilp != NULL);
 904 
 905         (void) mdi_prop_remove(ilp->lun_pip, NULL);
 906 }
 907 
 908 /*
 909  * iscsi_start -- Start a SCSI transaction based on the packet
 910  * This will attempt to add the icmdp to the pending queue
 911  * for the connection and kick the queue.  If the enqueue
 912  * fails that means the queue is full.
 913  */
 914 static int
 915 iscsi_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt)
 916 {
 917         iscsi_lun_t     *ilp            = NULL;
 918         iscsi_sess_t    *isp            = NULL;
 919         iscsi_cmd_t     *icmdp          = NULL;
 920         uint_t          flags;
 921 
 922         ASSERT(ap != NULL);
 923         ASSERT(pkt != NULL);
 924         ilp = (iscsi_lun_t *)ap->a_hba_tran->tran_tgt_private;
 925         isp = (iscsi_sess_t *)ilp->lun_sess;
 926         icmdp = (iscsi_cmd_t *)pkt->pkt_ha_private;
 927         flags = pkt->pkt_flags;
 928         ASSERT(ilp != NULL);
 929         ASSERT(isp != NULL);
 930         ASSERT(icmdp != NULL);
 931 
 932         /*
 933          * If the session is in the FREE state then
 934          * all connections are down and retries have
 935          * been exhausted.  Fail command with fatal error.
 936          */
 937         rw_enter(&isp->sess_state_rwlock, RW_READER);
 938         if (isp->sess_state == ISCSI_SESS_STATE_FREE) {
 939                 rw_exit(&isp->sess_state_rwlock);
 940                 return (TRAN_FATAL_ERROR);
 941         }
 942 
 943         /*
 944          * If we haven't received data from the target in the
 945          * max specified period something is wrong with the
 946          * transport.  Fail IO with FATAL_ERROR.
 947          */
 948         if (isp->sess_rx_lbolt + SEC_TO_TICK(iscsi_rx_max_window) <
 949             ddi_get_lbolt()) {
 950                 rw_exit(&isp->sess_state_rwlock);
 951                 return (TRAN_FATAL_ERROR);
 952         }
 953 
 954         /*
 955          * If the session is not in LOGGED_IN then we have
 956          * no connections LOGGED_IN, but we haven't exhuasted
 957          * our retries.  Fail the command with busy so the
 958          * caller might try again later.  Once retries are
 959          * exhausted the state machine will move us to FREE.
 960          */
 961         if (isp->sess_state != ISCSI_SESS_STATE_LOGGED_IN) {
 962                 rw_exit(&isp->sess_state_rwlock);
 963                 return (TRAN_BUSY);
 964         }
 965 
 966         /*
 967          * If we haven't received data from the target in the
 968          * specified period something is probably wrong with
 969          * the transport.  Just return back BUSY until either
 970          * the problem is resolved of the transport fails.
 971          */
 972         if (isp->sess_rx_lbolt + SEC_TO_TICK(iscsi_rx_window) <
 973             ddi_get_lbolt()) {
 974                 rw_exit(&isp->sess_state_rwlock);
 975                 return (TRAN_BUSY);
 976         }
 977 
 978 
 979         /* reset cmd values in case upper level driver is retrying cmd */
 980         icmdp->cmd_prev = icmdp->cmd_next = NULL;
 981         icmdp->cmd_crc_error_seen = B_FALSE;
 982         icmdp->cmd_lbolt_pending = icmdp->cmd_lbolt_active =
 983             icmdp->cmd_lbolt_aborting = icmdp->cmd_lbolt_timeout =
 984             (clock_t)NULL;
 985         icmdp->cmd_itt = icmdp->cmd_ttt = 0;
 986         icmdp->cmd_un.scsi.abort_icmdp = NULL;
 987 
 988         mutex_enter(&isp->sess_queue_pending.mutex);
 989         iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E1, isp);
 990         mutex_exit(&isp->sess_queue_pending.mutex);
 991         rw_exit(&isp->sess_state_rwlock);
 992 
 993         /*
 994          * If this packet doesn't have FLAG_NOINTR set, it could have
 995          * already run to completion (and the memory freed) at this
 996          * point, so check our local copy of pkt_flags.  Otherwise we
 997          * have to wait for completion before returning to the caller.
 998          */
 999         if (flags & FLAG_NOINTR) {
1000                 mutex_enter(&icmdp->cmd_mutex);
1001                 while ((icmdp->cmd_state != ISCSI_CMD_STATE_COMPLETED) ||
1002                     (icmdp->cmd_un.scsi.r2t_icmdp != NULL) ||
1003                     (icmdp->cmd_un.scsi.abort_icmdp != NULL) ||
1004                     (icmdp->cmd_un.scsi.r2t_more == B_TRUE)) {
1005                         cv_wait(&icmdp->cmd_completion, &icmdp->cmd_mutex);
1006                 }
1007                 icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
1008                 mutex_exit(&icmdp->cmd_mutex);
1009         }
1010 
1011         return (TRAN_ACCEPT);
1012 }
1013 
1014 /*
1015  * iscsi_tran_abort - Called when an upper level application
1016  * or driver wants to kill a scsi_pkt that was already sent to
1017  * this driver.
1018  */
1019 /* ARGSUSED */
1020 static int
1021 iscsi_tran_abort(struct scsi_address *ap, struct scsi_pkt *pkt)
1022 {
1023         return (0);
1024 }
1025 
1026 /*
1027  * iscsi_tran_reset - Reset target at either BUS, TARGET, or LUN
1028  * level.  This will require the issuing of a task management
1029  * command down to the target/lun.
1030  */
1031 static int
1032 iscsi_tran_reset(struct scsi_address *ap, int level)
1033 {
1034         int             rval    = ISCSI_STATUS_INTERNAL_ERROR;
1035         iscsi_sess_t    *isp    = NULL;
1036         iscsi_lun_t     *ilp    = NULL;
1037 
1038         ilp = (iscsi_lun_t *)ap->a_hba_tran->tran_tgt_private;
1039         ASSERT(ilp != NULL);
1040         isp = ilp->lun_sess;
1041         ASSERT(isp != NULL);
1042 
1043         switch (level) {
1044         case RESET_LUN:
1045                 /* reset attempt will block until attempt is complete */
1046                 rval = iscsi_handle_reset(isp, level, ilp);
1047                 break;
1048         case RESET_BUS:
1049                 /*
1050                  * What are we going to realy reset the ethernet
1051                  * network!?  Just fall through to a target reset.
1052                  */
1053         case RESET_TARGET:
1054                 /* reset attempt will block until attempt is complete */
1055                 rval = iscsi_handle_reset(isp, level, NULL);
1056                 break;
1057         case RESET_ALL:
1058         default:
1059                 break;
1060         }
1061 
1062         return (ISCSI_SUCCESS(rval) ? 1 : 0);
1063 }
1064 
1065 /*
1066  * iscsi_tran_getcap - Get target/lun capabilities.
1067  */
1068 static int
1069 iscsi_tran_getcap(struct scsi_address *ap, char *cap, int whom)
1070 {
1071         return (iscsi_i_commoncap(ap, cap, 0, whom, 0));
1072 }
1073 
1074 
1075 /*
1076  * iscsi_tran_setcap - Set target/lun capabilities.
1077  */
1078 /* ARGSUSED */
1079 static int
1080 iscsi_tran_setcap(struct scsi_address *ap, char *cap, int value, int whom)
1081 {
1082         return (iscsi_i_commoncap(ap, cap, value, whom, 1));
1083 }
1084 
1085 
1086 /*
1087  * iscsi_tran_destroy_pkt - Clean up packet
1088  */
1089 static void
1090 iscsi_tran_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
1091 {
1092         iscsi_cmd_t     *icmdp;
1093 
1094         icmdp = (iscsi_cmd_t *)pkt->pkt_ha_private;
1095 
1096         ASSERT(icmdp != NULL);
1097         ASSERT(icmdp->cmd_sig == ISCSI_SIG_CMD);
1098         ASSERT(icmdp->cmd_state == ISCSI_CMD_STATE_FREE);
1099 
1100         iscsi_lun_rele(icmdp->cmd_lun);
1101         mutex_destroy(&icmdp->cmd_mutex);
1102         cv_destroy(&icmdp->cmd_completion);
1103         scsi_hba_pkt_free(ap, pkt);
1104 }
1105 
1106 /*
1107  * iscsi_tran_dmafree - This is a software driver, NO DMA
1108  */
1109 /* ARGSUSED */
1110 static void
1111 iscsi_tran_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt)
1112 {
1113         /*
1114          * The iSCSI interface doesn't deal with DMA
1115          */
1116 }
1117 
1118 /*
1119  * iscsi_tran_sync_pkt - This is a software driver, NO DMA
1120  */
1121 /* ARGSUSED */
1122 static void
1123 iscsi_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
1124 {
1125         /*
1126          * The iSCSI interface doesn't deal with DMA
1127          */
1128 }
1129 
1130 /*
1131  * iscsi_tran_reset_notify - We don't support BUS_RESET so there
1132  * is no point in support callback.
1133  */
1134 /* ARGSUSED */
1135 static int
1136 iscsi_tran_reset_notify(struct scsi_address *ap, int flag,
1137     void (*callback) (caddr_t), caddr_t arg)
1138 {
1139 
1140         /*
1141          * We never do BUS_RESETS so allowing this call
1142          * back to register has no point?
1143          */
1144         return (DDI_SUCCESS);
1145 }
1146 
1147 
1148 /*
1149  * iscsi_tran_bus_config - on demand device configuration
1150  *
1151  * iscsi_tran_bus_config is called by the NDI layer at the completion
1152  * of a dev_node creation.  There are two primary cases defined in this
1153  * function.  The first is BUS_CONFIG_ALL.  In this case the NDI is trying
1154  * to identify that targets/luns are available configured at that point
1155  * in time.  It is safe to just complete the process succcessfully.  The
1156  * second case is a new case that was defined in S10 for devfs.  BUS_CONFIG_ONE
1157  * this is to help driver the top down discovery instead of bottom up.  If
1158  * we receive a BUS_CONFIG_ONE we should check to see if the <addr> exists
1159  * if so complete successfull processing.  Otherwise we should call the
1160  * deamon and see if we can plumb the <addr>.  If it is possible to plumb the
1161  * <addr> block until plumbing is complete.  In both cases of being able to
1162  * plumb <addr> or not continue with successfull processing.
1163  */
1164 static int
1165 iscsi_tran_bus_config(dev_info_t *parent, uint_t flags,
1166     ddi_bus_config_op_t op, void *arg, dev_info_t **childp)
1167 {
1168         int             rval    = NDI_SUCCESS;
1169         iscsi_hba_t     *ihp    = NULL;
1170         int             iflags  = flags;
1171         char            *name   = NULL;
1172         char            *ptr    = NULL;
1173         boolean_t       config_root = B_FALSE;
1174 
1175         /* get reference to soft state */
1176         ihp = (iscsi_hba_t *)ddi_get_soft_state(iscsi_state,
1177             ddi_get_instance(parent));
1178         if (ihp == NULL) {
1179                 return (NDI_FAILURE);
1180         }
1181 
1182         iscsi_check_miniroot(ihp);
1183         if ((modrootloaded == 0) && (iscsiboot_prop != NULL)) {
1184                 config_root = B_TRUE;
1185         }
1186 
1187         if (config_root == B_FALSE) {
1188                 if (iscsi_client_request_service(ihp) == B_FALSE) {
1189                         return (NDI_FAILURE);
1190                 }
1191         }
1192 
1193         /* lock so only one config operation occrs */
1194         sema_p(&iscsid_config_semaphore);
1195 
1196         switch (op) {
1197         case BUS_CONFIG_ONE:
1198                 /* parse target name out of name given */
1199                 if ((ptr = strchr((char *)arg, '@')) == NULL) {
1200                         rval = NDI_FAILURE;
1201                         break;
1202                 }
1203                 ptr++;          /* move past '@' */
1204                 name = kmem_zalloc(MAX_GET_NAME_SIZE, KM_SLEEP);
1205                 (void) strncpy(name, ptr, MAX_GET_NAME_SIZE);
1206                 /* We need to strip the LUN */
1207                 if ((ptr = strchr(name, ',')) == NULL) {
1208                         rval = NDI_FAILURE;
1209                         kmem_free(name, MAX_GET_NAME_SIZE);
1210                         name = NULL;
1211                         break;
1212                 }
1213                 /* We also need to strip the 4 bytes of hex TPGT */
1214                 ptr -= 4;
1215                 if (ptr <= name) {
1216                         rval = NDI_FAILURE;
1217                         kmem_free(name, MAX_GET_NAME_SIZE);
1218                         name = NULL;
1219                         break;
1220                 }
1221                 *ptr = '\0';            /* NULL terminate */
1222 
1223                 /* translate name back to original iSCSI name */
1224                 iscsi_get_name_to_iqn(name, MAX_GET_NAME_SIZE);
1225 
1226                 /* configure target, skip 4 byte ISID */
1227                 iscsid_config_one(ihp, (name+4), B_TRUE);
1228 
1229                 kmem_free(name, MAX_GET_NAME_SIZE);
1230                 name = NULL;
1231 
1232                 /*
1233                  * DDI group instructed us to use this flag.
1234                  */
1235                 iflags |= NDI_MDI_FALLBACK;
1236                 break;
1237         case BUS_CONFIG_DRIVER:
1238                 /* FALLTHRU */
1239         case BUS_CONFIG_ALL:
1240                 iscsid_config_all(ihp, B_TRUE);
1241                 break;
1242         default:
1243                 rval = NDI_FAILURE;
1244                 break;
1245         }
1246 
1247         if (rval == NDI_SUCCESS) {
1248                 rval = ndi_busop_bus_config(parent, iflags,
1249                     op, arg, childp, 0);
1250         }
1251         sema_v(&iscsid_config_semaphore);
1252 
1253         if (config_root == B_FALSE) {
1254                 iscsi_client_release_service(ihp);
1255         }
1256 
1257         return (rval);
1258 }
1259 
1260 /*
1261  * iscsi_tran_bus_unconfig - on demand device unconfiguration
1262  *
1263  * Called by the os framework under low resource situations.
1264  * It will attempt to unload our minor nodes (logical units
1265  * ndi/mdi nodes).
1266  */
1267 static int
1268 iscsi_tran_bus_unconfig(dev_info_t *parent, uint_t flag,
1269     ddi_bus_config_op_t op, void *arg)
1270 {
1271         int             rval = NDI_SUCCESS;
1272         iscsi_hba_t     *ihp = NULL;
1273 
1274         /* get reference to soft state */
1275         ihp = (iscsi_hba_t *)ddi_get_soft_state(iscsi_state,
1276             ddi_get_instance(parent));
1277         if (ihp == NULL) {
1278                 return (NDI_FAILURE);
1279         }
1280 
1281         if (iscsi_client_request_service(ihp) == B_FALSE) {
1282                 rw_enter(&ihp->hba_sess_list_rwlock, RW_READER);
1283                 if (ihp->hba_sess_list != NULL) {
1284                         rval = NDI_FAILURE;
1285                 }
1286                 rw_exit(&ihp->hba_sess_list_rwlock);
1287                 return (rval);
1288         }
1289 
1290         rval = ndi_busop_bus_unconfig(parent, flag, op, arg);
1291 
1292         iscsi_client_release_service(ihp);
1293 
1294         return (rval);
1295 }
1296 
1297 
1298 /*
1299  * iscsi_tran_get_name - create private /devices name for LUN
1300  *
1301  * This creates the <addr> in /devices/iscsi/<driver>@<addr>
1302  * path.  For this <addr> we return the <session/target_name>,<lun num>
1303  * Where <target_name> is an <iqn/eui/...> as defined by the iSCSI
1304  * specification.  We do modify the name slightly so that it still
1305  * complies with the IEEE <addr> naming scheme.  This means that we
1306  * will substitute out the ':', '@', ... and other reserved characters
1307  * defined in the IEEE definition with '%<hex value of special char>'
1308  * This routine is indirectly called by iscsi_lun_create_xxx.  These
1309  * calling routines must prevent the session and lun lists from changing
1310  * during this routine.
1311  */
1312 static int
1313 iscsi_tran_get_name(struct scsi_device *sd, char *name, int len)
1314 {
1315         int             target          = 0;
1316         int             lun             = 0;
1317         iscsi_hba_t     *ihp            = NULL;
1318         iscsi_sess_t    *isp            = NULL;
1319         iscsi_lun_t     *ilp            = NULL;
1320         dev_info_t      *lun_dip        = NULL;
1321 
1322         ASSERT(sd != NULL);
1323         ASSERT(name != NULL);
1324         lun_dip = sd->sd_dev;
1325         ASSERT(lun_dip != NULL);
1326 
1327         /* get reference to soft state */
1328         ihp = (iscsi_hba_t *)ddi_get_soft_state(iscsi_state,
1329             ddi_get_instance(ddi_get_parent(lun_dip)));
1330         if (ihp == NULL) {
1331                 name[0] = '\0';
1332                 return (0);
1333         }
1334 
1335         /* Get the target num */
1336         target = ddi_prop_get_int(DDI_DEV_T_ANY, sd->sd_dev,
1337             DDI_PROP_DONTPASS, TARGET_PROP, 0);
1338 
1339         /* Get the target num */
1340         lun = ddi_prop_get_int(DDI_DEV_T_ANY, sd->sd_dev,
1341             DDI_PROP_DONTPASS, LUN_PROP, 0);
1342 
1343         /*
1344          * Now we need to find our ilp by walking the lists
1345          * off the ihp and isp.
1346          */
1347         /* See if we already created this session */
1348 
1349         /* Walk the HBA's session list */
1350         for (isp = ihp->hba_sess_list; isp; isp = isp->sess_next) {
1351                 /* compare target name as the unique identifier */
1352                 if (target == isp->sess_oid) {
1353                         /* found match */
1354                         break;
1355                 }
1356         }
1357 
1358         /* If we found matching session continue searching for tgt */
1359         if (isp == NULL) {
1360                 /* sess not found */
1361                 name[0] = '\0';
1362                 return (0);
1363         }
1364 
1365         /*
1366          * Search for the matching iscsi lun structure.  We don't
1367          * need to hold the READER for the lun list at this point.
1368          * because the tran_get_name is being called from the online
1369          * function which is already holding a reader on the lun
1370          * list.
1371          */
1372         for (ilp = isp->sess_lun_list; ilp; ilp = ilp->lun_next) {
1373                 if (lun == ilp->lun_num) {
1374                         /* found match */
1375                         break;
1376                 }
1377         }
1378 
1379         if (ilp == NULL) {
1380                 /* tgt not found */
1381                 name[0] = '\0';
1382                 return (0);
1383         }
1384 
1385         /* Ensure enough space for lun_addr is available */
1386         ASSERT(ilp->lun_addr != NULL);
1387         if ((strlen(ilp->lun_addr) + 1) > len) {
1388                 return (0);
1389         }
1390 
1391         /* copy lun_addr name */
1392         (void) strcpy(name, ilp->lun_addr);
1393 
1394         /*
1395          * Based on IEEE-1275 we can't have any ':', ' ', '@', or '/'
1396          * characters in our naming.  So replace all those characters
1397          * with '-'
1398          */
1399         iscsi_get_name_from_iqn(name, len);
1400 
1401         return (1);
1402 }
1403 
1404 /*
1405  * iscsi_tran_get_bus_addr - This returns a human readable string
1406  * for the bus address.  Examining most other drivers fcp, etc.  They
1407  * all just return the same string as tran_get_name.  In our case
1408  * our tran get name is already some what usable so leave alone.
1409  */
1410 static int
1411 iscsi_tran_get_bus_addr(struct scsi_device *sd, char *name, int len)
1412 {
1413         return (iscsi_tran_get_name(sd, name, len));
1414 }
1415 
1416 
1417 /*
1418  * +--------------------------------------------------------------------+
1419  * | End of scsi_tran routines                                    |
1420  * +--------------------------------------------------------------------+
1421  */
1422 
1423 /*
1424  * +--------------------------------------------------------------------+
1425  * | Start of cb_ops routines                                      |
1426  * +--------------------------------------------------------------------+
1427  */
1428 
1429 /*
1430  * iscsi_open - Driver should be made IOCTL MT safe.  Otherwise
1431  * this function needs updated.
1432  */
1433 /* ARGSUSED */
1434 static int
1435 iscsi_open(dev_t *devp, int flags, int otyp, cred_t *credp)
1436 {
1437         return (0);
1438 }
1439 
1440 /*
1441  * iscsi_close -
1442  */
1443 /* ARGSUSED */
1444 static int
1445 iscsi_close(dev_t dev, int flags, int otyp, cred_t *credp)
1446 {
1447         return (0);
1448 }
1449 
1450 /*
1451  * iscsi_ioctl -
1452  */
1453 /* ARGSUSED */
1454 static int
1455 iscsi_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
1456     cred_t *credp, int *rvalp)
1457 {
1458         int                     rtn             = 0;
1459         int                     instance        = 0;
1460         int                     list_space      = 0;
1461         int                     lun_sz          = 0;
1462         int                     did;
1463         int                     retry;
1464         iscsi_hba_t             *ihp            = NULL;
1465         iscsi_sess_t            *isp            = NULL;
1466         iscsi_conn_t            *icp            = NULL;
1467         iscsi_login_params_t    *params         = NULL;
1468         iscsi_login_params_t    *tmpParams      = NULL;
1469         uchar_t                 *name           = NULL;
1470         dev_info_t              *lun_dip        = NULL;
1471 
1472         entry_t                     e;
1473         iscsi_oid_t                 oid;
1474         iscsi_property_t            *ipp;
1475         iscsi_static_property_t     *ispp;
1476         iscsi_param_get_t           *ilg;
1477         iscsi_param_set_t           *ils;
1478         iscsi_target_list_t         idl, *idlp          = NULL;
1479         iscsi_addr_list_t           ial, *ialp          = NULL;
1480         iscsi_chap_props_t          *chap               = NULL;
1481         iscsi_radius_props_t        *radius             = NULL;
1482         iscsi_auth_props_t          *auth               = NULL;
1483         iscsi_lun_list_t            *ll, *llp           = NULL;
1484         iscsi_lun_props_t           *lun                = NULL;
1485         iscsi_lun_t                 *ilp                = NULL;
1486         iSCSIDiscoveryMethod_t      method;
1487         iSCSIDiscoveryProperties_t  discovery_props;
1488         iscsi_uscsi_t               iu;
1489         iscsi_uscsi_t               iu_caller;
1490 #ifdef _MULTI_DATAMODEL
1491         /* For use when a 32 bit app makes a call into a 64 bit ioctl */
1492         iscsi_uscsi32_t             iu32_caller;
1493         model_t                     model;
1494 #endif /* _MULTI_DATAMODEL */
1495         void                        *void_p;
1496         iscsi_sendtgts_list_t   *stl_hdr;
1497         iscsi_sendtgts_list_t   *istl;
1498         int                     stl_sz;
1499         iscsi_target_entry_t    *target;
1500         uint32_t                old_oid;
1501         uint32_t                target_oid;
1502         iscsi_targetparam_entry_t *curr_entry;
1503         char                    *initiator_node_name;
1504         char                    *initiator_node_alias;
1505         isns_portal_group_list_t    *pg_list = NULL;
1506         isns_server_portal_group_list_t    *server_pg_list_hdr = NULL;
1507         isns_server_portal_group_list_t    *server_pg_list = NULL;
1508         int                     pg_list_sz, pg_sz_copy_out, server_pg_list_sz;
1509         iscsi_config_sess_t     *ics;
1510         int                     size;
1511         boolean_t               rval;
1512         char                    init_port_name[MAX_NAME_PROP_SIZE];
1513         iscsi_sockaddr_t        addr_dsc;
1514         iscsi_boot_property_t   *bootProp;
1515         boolean_t               discovered = B_TRUE;
1516         iscsi_tunable_object_t  *tpsg;
1517         iscsi_tunable_object_t  *tpss;
1518         iscsi_reen_t    *reenum;
1519 
1520         instance = getminor(dev);
1521         ihp = (iscsi_hba_t *)ddi_get_soft_state(iscsi_state, instance);
1522         if (ihp == NULL)
1523                 return (EFAULT);
1524 
1525         iscsi_check_miniroot(ihp);
1526         if ((cmd != ISCSI_SMF_ONLINE) && (cmd != ISCSI_SMF_OFFLINE) &&
1527             (cmd != ISCSI_SMF_GET)) {
1528                 /* other cmd needs to acquire the service */
1529                 if (iscsi_client_request_service(ihp) == B_FALSE) {
1530                         return (EFAULT);
1531                 }
1532         }
1533 
1534         switch (cmd) {
1535         /*
1536          * ISCSI_CREATE_OID - Create a Object IDentifier for a TargetName
1537          */
1538         case ISCSI_CREATE_OID:
1539                 if (ddi_copyin((caddr_t)arg, &oid, sizeof (oid), mode)) {
1540                         rtn = EFAULT;
1541                         break;
1542                 }
1543                 if (oid.o_vers != ISCSI_INTERFACE_VERSION) {
1544                         rtn = EINVAL;
1545                         break;
1546                 }
1547 
1548                 /* Set the target that this session is associated with */
1549                 oid.o_oid = iscsi_targetparam_get_oid(oid.o_name);
1550 
1551                 if (ddi_copyout(&oid, (caddr_t)arg, sizeof (oid), mode)) {
1552                         rtn = EFAULT;
1553                         break;
1554                 }
1555                 break;
1556         /*
1557          * ISCSI_PARAM_GET - Get param for specified
1558          * connection/session.
1559          */
1560         case ISCSI_PARAM_GET:
1561                 /* copyin user args */
1562                 ilg = (iscsi_param_get_t *)kmem_alloc(sizeof (*ilg), KM_SLEEP);
1563                 if (ddi_copyin((caddr_t)arg, ilg, sizeof (*ilg), mode)) {
1564                         rtn = EFAULT;
1565                         kmem_free(ilg, sizeof (*ilg));
1566                         break;
1567                 }
1568 
1569                 if (ilg->g_vers != ISCSI_INTERFACE_VERSION) {
1570                         rtn = EINVAL;
1571                         kmem_free(ilg, sizeof (*ilg));
1572                         break;
1573                 }
1574 
1575                 /* handle special case for Initiator name */
1576                 if (ilg->g_param == ISCSI_LOGIN_PARAM_INITIATOR_NAME) {
1577                         (void) strlcpy((char *)ilg->g_value.v_name,
1578                             (char *)ihp->hba_name, ISCSI_MAX_NAME_LEN);
1579                 } else if (ilg->g_param == ISCSI_LOGIN_PARAM_INITIATOR_ALIAS) {
1580                         if (ihp->hba_alias_length == 0) {
1581                                 rtn = EINVAL;
1582                         } else {
1583                                 (void) strlcpy((char *)ilg->g_value.v_name,
1584                                     (char *)ihp->hba_alias, ISCSI_MAX_NAME_LEN);
1585                         }
1586                 } else {
1587                         /* To describe the validity of the requested param */
1588                         boolean_t valid_flag = B_TRUE;
1589 
1590                         name = NULL;
1591 
1592                         /*
1593                          * switch login based if looking for initiator
1594                          * params
1595                          */
1596                         rw_enter(&ihp->hba_sess_list_rwlock, RW_READER);
1597                         if (ilg->g_oid == ihp->hba_oid) {
1598                                 /* initiator */
1599                                 params = &ihp->hba_params;
1600                                 name = ihp->hba_name;
1601                                 if (iscsi_get_persisted_param(name,
1602                                     ilg, params) != 0) {
1603                                         valid_flag = B_FALSE;
1604                                 }
1605                         } else {
1606                                 /*
1607                                  * If the oid does represent a session check
1608                                  * to see if it is a target oid.  If so,
1609                                  * return the target's associated session.
1610                                  */
1611                                 rtn = iscsi_sess_get(ilg->g_oid, ihp, &isp);
1612                                 if (rtn != 0) {
1613                                         rtn = iscsi_sess_get_by_target(
1614                                             ilg->g_oid, ihp, &isp);
1615                                 }
1616 
1617                                 /*
1618                                  * If rtn is zero then we have found an
1619                                  * existing session.  Use the session name to
1620                                  * do param lookup.  If rtn is non-zero then
1621                                  * create a targetparam object and use its name
1622                                  * for param lookup.
1623                                  */
1624                                 if (rtn == 0) {
1625                                         name = isp->sess_name;
1626                                         params = &isp->sess_params;
1627                                 } else {
1628                                         name =
1629                                             iscsi_targetparam_get_name(
1630                                             ilg->g_oid);
1631                                         if (ilg->g_param_type ==
1632                                             ISCSI_SESS_PARAM) {
1633                                                 tmpParams =
1634                                                     (iscsi_login_params_t *)
1635                                                     kmem_alloc(
1636                                                     sizeof (*tmpParams),
1637                                                     KM_SLEEP);
1638                                                 params = tmpParams;
1639                                         }
1640                                         rtn = 0;
1641                                 }
1642 
1643                                 if (name == NULL) {
1644                                         rw_exit(
1645                                             &ihp->hba_sess_list_rwlock);
1646                                         rtn = EFAULT;
1647                                         kmem_free(ilg, sizeof (*ilg));
1648                                         if (tmpParams != NULL)
1649                                                 kmem_free(tmpParams,
1650                                                     sizeof (*tmpParams));
1651 
1652                                         break;
1653                                 }
1654 
1655                                 if (ilg->g_param_type == ISCSI_SESS_PARAM) {
1656                                         /* session */
1657                                         /*
1658                                          * Update sess_params with the
1659                                          * latest params from the
1660                                          * persistent store.
1661                                          */
1662                                         if (iscsi_get_persisted_param(name,
1663                                             ilg, params) != 0) {
1664                                                 /*
1665                                                  * If the parameter in
1666                                                  * question is not
1667                                                  * overriden, no effect
1668                                                  * on existing session
1669                                                  * parameters. However,
1670                                                  * the parameter is
1671                                                  * marked invalid
1672                                                  * (from the standpoint
1673                                                  * of whether it is
1674                                                  * overriden).
1675                                                  */
1676                                                 valid_flag = B_FALSE;
1677                                         }
1678                                 } else if (ilg->g_param_type ==
1679                                     ISCSI_CONN_PARAM && isp != NULL) {
1680                                         /* connection */
1681                                         rw_enter(&isp->sess_conn_list_rwlock,
1682                                             RW_READER);
1683                                         /* Assuming 1 conn per sess. */
1684                                         /*
1685                                          * MC/S - Need to be modified to
1686                                          * take g_conn_cid into account when
1687                                          * we go multi-connection.
1688                                          */
1689                                         if ((isp->sess_conn_act != NULL) &&
1690                                             (isp->sess_conn_act->conn_state ==
1691                                             ISCSI_CONN_STATE_LOGGED_IN)) {
1692                                                 params = &(isp->
1693                                                     sess_conn_act->
1694                                                     conn_params);
1695                                         } else {
1696                                                 valid_flag = B_FALSE;
1697                                         }
1698                                         rw_exit(&isp->sess_conn_list_rwlock);
1699                                 }
1700                         }
1701 
1702                         /* make sure we have params to get info from */
1703                         if (params) {
1704                                 rtn = iscsi_get_param(params, valid_flag, ilg);
1705 
1706                                 /*
1707                                  * for target parameters, check if any
1708                                  * parameters were overridden at the initiator
1709                                  * level. If so, then change the default value
1710                                  * to the initiator's overridden value
1711                                  */
1712                                 if ((rtn == 0) &&
1713                                     (ilg->g_oid != ihp->hba_oid)) {
1714                                         iscsi_override_target_default(ihp,
1715                                             ilg);
1716                                 }
1717                         }
1718                         rw_exit(&ihp->hba_sess_list_rwlock);
1719                 }
1720 
1721                 if (rtn == 0) {
1722                         rtn = ddi_copyout(ilg, (caddr_t)arg,
1723                             sizeof (iscsi_param_get_t), mode);
1724                 }
1725                 kmem_free(ilg, sizeof (*ilg));
1726                 if (tmpParams != NULL)
1727                         kmem_free(tmpParams, sizeof (*tmpParams));
1728                 break;
1729 
1730         /*
1731          * ISCSI_INIT_NODE_NAME_SET - Change the initiator-node name for
1732          * the specified connection/session.
1733          */
1734         case ISCSI_INIT_NODE_NAME_SET:
1735                 /* copyin user args */
1736                 ils = (iscsi_param_set_t *)kmem_alloc(sizeof (*ils), KM_SLEEP);
1737                 if (ddi_copyin((caddr_t)arg, ils, sizeof (*ils), mode)) {
1738                         rtn = EFAULT;
1739                         kmem_free(ils, sizeof (*ils));
1740                         break;
1741                 }
1742 
1743                 if (ils->s_vers != ISCSI_INTERFACE_VERSION) {
1744                         rtn = EINVAL;
1745                         kmem_free(ils, sizeof (*ils));
1746                         break;
1747                 }
1748 
1749                 /* saving off the old initiator-node name */
1750                 initiator_node_name = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP);
1751                 rval = persistent_initiator_name_get(initiator_node_name,
1752                     ISCSI_MAX_NAME_LEN);
1753 
1754                 rtn = iscsi_set_params(ils, ihp, B_TRUE);
1755                 kmem_free(ils, sizeof (*ils));
1756                 if (rtn != 0) {
1757                         kmem_free(initiator_node_name, ISCSI_MAX_NAME_LEN);
1758                         initiator_node_name = NULL;
1759                         break;
1760                 }
1761 
1762                 (void) snprintf(init_port_name, MAX_NAME_PROP_SIZE,
1763                     "%s,%02x%02x%02x%02x%02x%02x",
1764                     (char *)ihp->hba_name, ihp->hba_isid[0],
1765                     ihp->hba_isid[1], ihp->hba_isid[2],
1766                     ihp->hba_isid[3], ihp->hba_isid[4],
1767                     ihp->hba_isid[5]);
1768 
1769                 if (ddi_prop_update_string(DDI_DEV_T_NONE,
1770                     ihp->hba_dip, SCSI_ADDR_PROP_INITIATOR_PORT,
1771                     init_port_name) != DDI_PROP_SUCCESS) {
1772                         cmn_err(CE_WARN, "iscsi_ioctl: Updating "
1773                             SCSI_ADDR_PROP_INITIATOR_PORT " property on iSCSI "
1774                             "HBA(%s) with dip(%d) Failed",
1775                             (char *)ihp->hba_name,
1776                             ddi_get_instance(ihp->hba_dip));
1777                 }
1778 
1779                 /*
1780                  * Deregister the old initiator-node name from the iSNS
1781                  * server
1782                  * Register the new initiator-node name with the iSNS server
1783                  */
1784                 method = persistent_disc_meth_get();
1785                 if (method & iSCSIDiscoveryMethodISNS) {
1786                         if (rval == B_TRUE) {
1787                                 if (strlen(initiator_node_name) > 0) {
1788                                 /*
1789                                  * we will attempt to offline the targets.
1790                                  * if logouts fail, we will still continue
1791                                  */
1792 #define STRING_INNO "initiator-node name - Offline "
1793 #define STRING_FFOMD "failed for one or more devices"
1794                                         if ((iscsid_del(
1795                                             ihp, NULL, method, NULL))
1796                                             != B_TRUE) {
1797                                                 cmn_err(CE_NOTE,
1798                                                     "Attempting to change "
1799                                                     STRING_INNO
1800                                                     STRING_FFOMD);
1801                                         }
1802                                         (void) isns_dereg(ihp->hba_isid,
1803                                             (uint8_t *)initiator_node_name);
1804 #undef STRING_INNO
1805 #undef STRING_FFOMD
1806                                 }
1807                         }
1808                         if (persistent_initiator_name_get(initiator_node_name,
1809                             ISCSI_MAX_NAME_LEN) != B_TRUE) {
1810                                 kmem_free(initiator_node_name,
1811                                     ISCSI_MAX_NAME_LEN);
1812                                 initiator_node_name = NULL;
1813                                 rtn = EIO;
1814                                 break;
1815                         }
1816                         if (strlen(initiator_node_name) == 0) {
1817                                 kmem_free(initiator_node_name,
1818                                     ISCSI_MAX_NAME_LEN);
1819                                 initiator_node_name = NULL;
1820                                 rtn = EIO;
1821                                 break;
1822                         }
1823 
1824                         initiator_node_alias = kmem_zalloc(ISCSI_MAX_NAME_LEN,
1825                             KM_SLEEP);
1826                         if (persistent_alias_name_get(initiator_node_alias,
1827                             ISCSI_MAX_NAME_LEN) != B_TRUE) {
1828                                 initiator_node_alias[0] = '\0';
1829                         }
1830 
1831                         (void) isns_reg(ihp->hba_isid,
1832                             (uint8_t *)initiator_node_name,
1833                             ISCSI_MAX_NAME_LEN,
1834                             (uint8_t *)initiator_node_alias,
1835                             ISCSI_MAX_NAME_LEN,
1836                             ISNS_INITIATOR_NODE_TYPE,
1837                             isns_scn_callback);
1838                         iscsid_do_isns_query(ihp);
1839 
1840                         kmem_free(initiator_node_alias, ISCSI_MAX_NAME_LEN);
1841                         initiator_node_alias = NULL;
1842                 }
1843 
1844                 kmem_free(initiator_node_name, ISCSI_MAX_NAME_LEN);
1845                 initiator_node_name = NULL;
1846                 break;
1847 
1848         /*
1849          * ISCSI_PARAM_SET - Set param for specified connection/session.
1850          */
1851         case ISCSI_PARAM_SET:
1852                 /* copyin user args */
1853                 ils = (iscsi_param_set_t *)kmem_alloc(sizeof (*ils), KM_SLEEP);
1854                 if (ddi_copyin((caddr_t)arg, ils, sizeof (*ils), mode)) {
1855                         rtn = EFAULT;
1856                         kmem_free(ils, sizeof (*ils));
1857                         break;
1858                 }
1859 
1860                 if (ils->s_vers != ISCSI_INTERFACE_VERSION) {
1861                         rtn = EINVAL;
1862                         kmem_free(ils, sizeof (*ils));
1863                         break;
1864                 }
1865                 rtn = iscsi_set_params(ils, ihp, B_TRUE);
1866                 if (iscsiboot_prop) {
1867                         if (iscsi_cmp_boot_sess_oid(ihp, ils->s_oid)) {
1868                                 /*
1869                                  * found active session for this object
1870                                  * or this is initiator's object
1871                                  * with mpxio enabled
1872                                  */
1873                                 if (!iscsi_reconfig_boot_sess(ihp)) {
1874                                         rtn = EINVAL;
1875                                         kmem_free(ils, sizeof (*ils));
1876                                         break;
1877                                 }
1878                         }
1879                 }
1880                 kmem_free(ils, sizeof (*ils));
1881                 break;
1882 
1883         /*
1884          * ISCSI_TARGET_PARAM_CLEAR
1885          * - remove custom parameter settings for a target.
1886          */
1887         case ISCSI_TARGET_PARAM_CLEAR:
1888                 if (ddi_copyin((caddr_t)arg, &e, sizeof (e), mode)) {
1889                         rtn = EFAULT;
1890                         break;
1891                 } else if (e.e_vers != ISCSI_INTERFACE_VERSION) {
1892                         rtn = EINVAL;
1893                         break;
1894                 }
1895 
1896                 if ((e.e_oid != ihp->hba_oid) &&
1897                     (e.e_oid != ISCSI_OID_NOTSET)) {
1898                         boolean_t rval1, rval2, rval3;
1899                         uchar_t     *t_name;
1900                         iscsi_sess_t *t_isp;
1901                         boolean_t    t_rtn = B_TRUE;
1902                         persistent_param_t  t_param;
1903                         iscsi_config_sess_t t_ics;
1904                         persistent_tunable_param_t t_tpsg;
1905 
1906                         rw_enter(&ihp->hba_sess_list_rwlock, RW_READER);
1907                         /*
1908                          * If the oid does represent a session check to see
1909                          * if it is a target oid.  If so, return the target's
1910                          * associated session.
1911                          */
1912                         rtn = iscsi_sess_get(e.e_oid, ihp, &isp);
1913                         if (rtn != 0) {
1914                                 rtn = iscsi_sess_get_by_target(e.e_oid, ihp,
1915                                     &isp);
1916                         }
1917 
1918                         /*
1919                          * If rtn is zero then we have found an
1920                          * existing session.  Use the session name to
1921                          * do param lookup.  If rtn is non-zero then
1922                          * create a targetparam object and use its name
1923                          * for param lookup.
1924                          */
1925                         if (rtn == 0) {
1926                                 t_name = isp->sess_name;
1927                         } else {
1928                                 t_name = iscsi_targetparam_get_name(e.e_oid);
1929                                 rtn = 0;
1930                         }
1931 
1932                         if (t_name == NULL) {
1933                                 rw_exit(&ihp->hba_sess_list_rwlock);
1934                                 rtn = EFAULT;
1935                                 break;
1936                         }
1937 
1938                         name = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP);
1939                         (void) strncpy((char *)name, (char *)t_name,
1940                             ISCSI_MAX_NAME_LEN);
1941 
1942                         t_ics.ics_in = 1;
1943                         rval1 = persistent_param_get((char *)name, &t_param);
1944                         rval2 = persistent_get_config_session((char *)name,
1945                             &t_ics);
1946                         rval3 = persistent_get_tunable_param((char *)name,
1947                             &t_tpsg);
1948 
1949                         if ((rval1 == B_FALSE) && (rval2 == B_FALSE) &&
1950                             (rval3 == B_FALSE)) {
1951                                 /* no any target parameters get */
1952                                 kmem_free(name, ISCSI_MAX_NAME_LEN);
1953                                 rw_exit(&ihp->hba_sess_list_rwlock);
1954                                 rtn = EIO;
1955                                 break;
1956                         }
1957 
1958                         if (persistent_param_clear((char *)name) == B_FALSE) {
1959                                 kmem_free(name, ISCSI_MAX_NAME_LEN);
1960                                 rw_exit(&ihp->hba_sess_list_rwlock);
1961                                 rtn = EIO;
1962                                 break;
1963                         }
1964 
1965                         ics = kmem_zalloc(sizeof (*ics), KM_SLEEP);
1966                         ics->ics_ver = ISCSI_INTERFACE_VERSION;
1967                         ics->ics_oid = ISCSI_INITIATOR_OID;
1968                         ics->ics_in  = 1;
1969 
1970                         /*
1971                          * We may have multiple sessions with different
1972                          * tpgt values.  So we need to loop through
1973                          * the sessions and update all sessions.
1974                          */
1975                         for (isp = ihp->hba_sess_list; isp;
1976                             isp = t_isp) {
1977                                 t_isp = isp->sess_next;
1978 
1979                                 if (strncmp((char *)isp->sess_name,
1980                                     (char *)name, ISCSI_MAX_NAME_LEN) == 0) {
1981                                         /*
1982                                          * When removing target-params we need
1983                                          * slightly different actions depending
1984                                          * on if the session should still exist.
1985                                          * Get the initiator-node value for
1986                                          * MS/T.  If there is no initiator
1987                                          * value then assume the default value
1988                                          * of 1.  If the initiator value is
1989                                          * less than this ISID then we need to
1990                                          * destroy the session.  Otherwise
1991                                          * update the session information and
1992                                          * resync (N7 event).
1993                                          */
1994                                         rtn = iscsi_ioctl_get_config_sess(
1995                                             ihp, ics);
1996                                         if (((rtn != 0) &&
1997                                             (isp->sess_isid[5] > 0)) ||
1998                                             ((rtn == 0) &&
1999                                             (ics->ics_out <=
2000                                             isp->sess_isid[5]))) {
2001 
2002                                                 /*
2003                                                  * This session should no
2004                                                  * longer exist.  Remove
2005                                                  * session.
2006                                                  */
2007                                                 if (!ISCSI_SUCCESS(
2008                                                     iscsi_sess_destroy(isp))) {
2009                                                         t_rtn = B_FALSE;
2010                                                         continue;
2011                                                 }
2012                                                 isp = ihp->hba_sess_list;
2013                                         } else {
2014                                                 uint32_t event_count;
2015                                                 /*
2016                                                  * Reset the session
2017                                                  * parameters.
2018                                                  */
2019                                                 bcopy(&(isp->sess_hba->
2020                                                     hba_params),
2021                                                     &(isp->sess_params),
2022                                                     sizeof (isp->sess_params));
2023                                                 if (iscsiboot_prop &&
2024                                                     isp->sess_boot) {
2025                                                         /*
2026                                                          * reconfig boot
2027                                                          * session later
2028                                                          */
2029                                                         continue;
2030                                                 }
2031                                                 /*
2032                                                  * Notify the session that the
2033                                                  * login parameters have
2034                                                  * changed.
2035                                                  */
2036                                                 event_count = atomic_inc_32_nv(
2037                                                     &isp->
2038                                                     sess_state_event_count);
2039                                                 iscsi_sess_enter_state_zone(
2040                                                     isp);
2041 
2042                                                 iscsi_sess_state_machine(isp,
2043                                                     ISCSI_SESS_EVENT_N7,
2044                                                     event_count);
2045 
2046                                                 iscsi_sess_exit_state_zone(
2047                                                     isp);
2048                                         }
2049                                 }
2050                         }
2051                         if (t_rtn == B_FALSE) {
2052                                 boolean_t t_rval = B_TRUE;
2053                                 /* Failure!, restore target's parameters */
2054                                 if (rval1 == B_TRUE) {
2055                                         rval1 = persistent_param_set(
2056                                             (char *)name, &t_param);
2057                                         if (rval1 == B_FALSE) {
2058                                                 t_rval = B_FALSE;
2059                                         }
2060                                 }
2061                                 if (rval2 == B_TRUE) {
2062                                         rval2 = persistent_set_config_session(
2063                                             (char *)name, &t_ics);
2064                                         if (rval2 == B_FALSE) {
2065                                                 t_rval = B_FALSE;
2066                                         }
2067                                 }
2068                                 if (rval3 == B_TRUE) {
2069                                         rval3 = persistent_set_tunable_param(
2070                                             (char *)name, &t_tpsg);
2071                                         if (rval3 == B_FALSE) {
2072                                                 t_rval = B_FALSE;
2073                                         }
2074                                 }
2075                                 if (t_rval == B_FALSE) {
2076                                         cmn_err(CE_WARN, "Failed to restore "
2077                                             "target's parameters after remove "
2078                                             "session related to target "
2079                                             "parameters failure.");
2080                                 }
2081                                 rtn = EBUSY;
2082                         }
2083                         kmem_free(ics, sizeof (*ics));
2084                         kmem_free(name, ISCSI_MAX_NAME_LEN);
2085                         rw_exit(&ihp->hba_sess_list_rwlock);
2086                         if (iscsiboot_prop) {
2087                                 if (iscsi_cmp_boot_sess_oid(ihp, e.e_oid)) {
2088                                         /*
2089                                          * found active session for this object
2090                                          * or this is initiator object
2091                                          * with mpxio enabled
2092                                          */
2093                                         if (!iscsi_reconfig_boot_sess(ihp)) {
2094                                                 rtn = EINVAL;
2095                                                 break;
2096                                         }
2097                                 }
2098                         }
2099                 }
2100                 break;
2101 
2102         /*
2103          * ISCSI_TARGET_OID_LIST_GET -
2104          */
2105         case ISCSI_TARGET_OID_LIST_GET:
2106                 /* copyin user args */
2107                 if (ddi_copyin((caddr_t)arg, &idl,
2108                     sizeof (idl), mode)) {
2109                         rtn = EFAULT;
2110                         break;
2111                 }
2112 
2113                 if (idl.tl_vers != ISCSI_INTERFACE_VERSION) {
2114                         rtn = EINVAL;
2115                         break;
2116                 }
2117 
2118                 list_space = sizeof (iscsi_target_list_t);
2119                 if (idl.tl_in_cnt != 0)
2120                         list_space += (sizeof (uint32_t) *
2121                             (idl.tl_in_cnt - 1));
2122 
2123                 idlp = kmem_zalloc(list_space, KM_SLEEP);
2124                 bcopy(&idl, idlp, sizeof (idl));
2125                 idlp->tl_out_cnt = 0;
2126 
2127                 /*
2128                  * If target list type is ISCSI_TGT_OID_LIST and discovery
2129                  * has not been completed or in progress, poke the discovery
2130                  * methods so target information is returned
2131                  */
2132                 mutex_enter(&ihp->hba_discovery_events_mutex);
2133                 method = ihp->hba_discovery_events;
2134                 if ((idl.tl_tgt_list_type == ISCSI_TGT_OID_LIST) &&
2135                     (method != ISCSI_ALL_DISCOVERY_METHODS) &&
2136                     (ihp->hba_discovery_in_progress == B_FALSE)) {
2137                         ihp->hba_discovery_in_progress = B_TRUE;
2138                         mutex_exit(&ihp->hba_discovery_events_mutex);
2139                         iscsid_poke_discovery(ihp, iSCSIDiscoveryMethodUnknown);
2140                         mutex_enter(&ihp->hba_discovery_events_mutex);
2141                         ihp->hba_discovery_in_progress = B_FALSE;
2142                 }
2143                 mutex_exit(&ihp->hba_discovery_events_mutex);
2144 
2145                 /*
2146                  * Return the correct list information based on the type
2147                  */
2148                 switch (idl.tl_tgt_list_type) {
2149                 /* ISCSI_TGT_PARAM_OID_LIST - iscsiadm list target-params */
2150                 case ISCSI_TGT_PARAM_OID_LIST:
2151                         /* get params from persistent store */
2152                         iscsi_targetparam_lock_list(RW_READER);
2153                         curr_entry = iscsi_targetparam_get_next_entry(NULL);
2154                         while (curr_entry != NULL) {
2155                                 if (idlp->tl_out_cnt < idlp->tl_in_cnt) {
2156                                         idlp->tl_oid_list[idlp->tl_out_cnt] =
2157                                             curr_entry->target_oid;
2158                                 }
2159                                 idlp->tl_out_cnt++;
2160                                 curr_entry = iscsi_targetparam_get_next_entry(
2161                                     curr_entry);
2162                         }
2163                         iscsi_targetparam_unlock_list();
2164                         break;
2165 
2166                 /* ISCSI_STATIC_TGT_OID_LIST - iscsiadm list static-config */
2167                 case ISCSI_STATIC_TGT_OID_LIST:
2168                 {
2169                         char *target_name = NULL;
2170                         void *v = NULL;
2171 
2172                         /* get static-config from persistent store */
2173                         target_name = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP);
2174                         persistent_static_addr_lock();
2175                         while (persistent_static_addr_next(&v,
2176                             (char *)target_name, &e) == B_TRUE) {
2177 
2178                                 if (idlp->tl_out_cnt < idlp->tl_in_cnt) {
2179                                         idlp->tl_oid_list[idlp->tl_out_cnt] =
2180                                             e.e_oid;
2181                                 }
2182                                 idlp->tl_out_cnt++;
2183 
2184                         }
2185 
2186                         persistent_static_addr_unlock();
2187                         kmem_free(target_name, ISCSI_MAX_NAME_LEN);
2188                         break;
2189                 }
2190 
2191                 /* ISCSI_TGT_OID_LIST - iscsiadm list target */
2192                 case ISCSI_TGT_OID_LIST:
2193 
2194                         /* get sessions from hba's session list */
2195                         rw_enter(&ihp->hba_sess_list_rwlock, RW_READER);
2196                         for (isp = ihp->hba_sess_list; isp;
2197                             isp = isp->sess_next) {
2198 
2199                                 if (((isp->sess_state !=
2200                                     ISCSI_SESS_STATE_FREE) ||
2201                                     (isp->sess_discovered_by !=
2202                                     iSCSIDiscoveryMethodUnknown)) &&
2203                                     (isp->sess_type ==
2204                                     ISCSI_SESS_TYPE_NORMAL)) {
2205                                         if (idlp->tl_out_cnt <
2206                                             idlp->tl_in_cnt) {
2207                                                 idlp->tl_oid_list[
2208                                                     idlp->tl_out_cnt] =
2209                                                     isp->sess_oid;
2210                                         }
2211                                         idlp->tl_out_cnt++;
2212                                 }
2213 
2214                         }
2215                         rw_exit(&ihp->hba_sess_list_rwlock);
2216                         break;
2217 
2218                 default:
2219                         ASSERT(FALSE);
2220                 }
2221 
2222                 rtn = ddi_copyout(idlp, (caddr_t)arg, list_space, mode);
2223                 kmem_free(idlp, list_space);
2224                 break;
2225 
2226         /*
2227          * ISCSI_TARGET_PROPS_GET -
2228          */
2229         case ISCSI_TARGET_PROPS_GET:
2230                 /* ---- fall through sense the code is almost the same ---- */
2231 
2232         /*
2233          * ISCSI_TARGET_PROPS_SET -
2234          */
2235         case ISCSI_TARGET_PROPS_SET:
2236                 /* copyin user args */
2237                 ipp = (iscsi_property_t *)kmem_alloc(sizeof (*ipp),
2238                     KM_SLEEP);
2239                 if (ddi_copyin((caddr_t)arg, ipp, sizeof (*ipp), mode)) {
2240                         rtn = EFAULT;
2241                         kmem_free(ipp, sizeof (*ipp));
2242                         break;
2243                 }
2244 
2245                 if (ipp->p_vers != ISCSI_INTERFACE_VERSION) {
2246                         rtn = EINVAL;
2247                         kmem_free(ipp, sizeof (*ipp));
2248                         break;
2249                 }
2250 
2251                 rtn = iscsi_target_prop_mod(ihp, ipp, cmd);
2252                 if (rtn == 0)
2253                         rtn = ddi_copyout(ipp, (caddr_t)arg,
2254                             sizeof (*ipp), mode);
2255                 kmem_free(ipp, sizeof (*ipp));
2256                 break;
2257 
2258         /*
2259          * ISCSI_TARGET_ADDRESS_GET -
2260          */
2261         case ISCSI_TARGET_ADDRESS_GET:
2262                 if (ddi_copyin((caddr_t)arg, &ial, sizeof (ial), mode)) {
2263                         rtn = EFAULT;
2264                         break;
2265                 }
2266 
2267                 if (ial.al_vers != ISCSI_INTERFACE_VERSION) {
2268                         rtn = EINVAL;
2269                         break;
2270                 }
2271 
2272                 /*
2273                  * Find out how much space we need to malloc for the users
2274                  * request.
2275                  */
2276                 list_space = sizeof (iscsi_addr_list_t);
2277                 if (ial.al_in_cnt != 0) {
2278                         list_space += (sizeof (iscsi_addr_t) *
2279                             (ial.al_in_cnt - 1));
2280                 }
2281                 ialp = (iscsi_addr_list_t *)kmem_zalloc(list_space, KM_SLEEP);
2282 
2283                 /* Copy in the header portion */
2284                 bcopy(&ial, ialp, sizeof (ial));
2285 
2286                 /* session */
2287                 rw_enter(&ihp->hba_sess_list_rwlock, RW_READER);
2288                 rtn = iscsi_sess_get(ialp->al_oid, ihp, &isp);
2289                 if (rtn != 0) {
2290                         rw_exit(&ihp->hba_sess_list_rwlock);
2291                         rtn = EFAULT;
2292                         break;
2293                 }
2294 
2295                 ialp->al_out_cnt     = 0;
2296                 ialp->al_tpgt                = isp->sess_tpgt_conf;
2297                 rw_enter(&isp->sess_conn_list_rwlock, RW_READER);
2298                 for (icp = isp->sess_conn_list; icp; icp = icp->conn_next) {
2299                         if (icp->conn_state != ISCSI_CONN_STATE_LOGGED_IN) {
2300                                 continue;
2301                         }
2302                         if (ialp->al_out_cnt < ialp->al_in_cnt) {
2303                                 iscsi_addr_t            *ap;
2304 
2305                                 ap = &ialp->al_addrs[ialp->al_out_cnt];
2306                                 if (icp->conn_base_addr.sin.sa_family
2307                                     == AF_INET) {
2308 
2309                                         struct sockaddr_in *addr_in =
2310                                             (struct sockaddr_in *)&icp->
2311                                             conn_base_addr.sin4;
2312                                         ap->a_addr.i_insize =
2313                                             sizeof (struct in_addr);
2314                                         bcopy(&addr_in->sin_addr.s_addr,
2315                                             &ap->a_addr.i_addr.in4.s_addr,
2316                                             sizeof (struct in_addr));
2317                                         ap->a_port = addr_in->sin_port;
2318 
2319                                 } else {
2320 
2321                                         struct sockaddr_in6 *addr_in6 =
2322                                             (struct sockaddr_in6 *)&icp->
2323                                             conn_base_addr.sin6;
2324                                         ap->a_addr.i_insize =
2325                                             sizeof (struct in6_addr);
2326                                         bcopy(&addr_in6->sin6_addr.s6_addr,
2327                                             &ap->a_addr.i_addr.in6.s6_addr,
2328                                             sizeof (struct in6_addr));
2329                                         ap->a_port = addr_in6->sin6_port;
2330 
2331                                 }
2332                         }
2333                         ialp->al_out_cnt++;
2334                 }
2335                 rw_exit(&isp->sess_conn_list_rwlock);
2336                 rw_exit(&ihp->hba_sess_list_rwlock);
2337 
2338                 rtn = ddi_copyout(ialp, (caddr_t)arg, list_space, mode);
2339                 kmem_free(ialp, list_space);
2340                 break;
2341 
2342         /*
2343          * ISCSI_CHAP_SET -
2344          */
2345         case ISCSI_CHAP_SET:
2346                 chap = (iscsi_chap_props_t *)kmem_zalloc(sizeof (*chap),
2347                     KM_SLEEP);
2348                 if (ddi_copyin((caddr_t)arg, chap, sizeof (*chap), mode)) {
2349                         rtn = EFAULT;
2350                         kmem_free(chap, sizeof (*chap));
2351                         break;
2352                 } else if (chap->c_vers != ISCSI_INTERFACE_VERSION) {
2353                         rtn = EINVAL;
2354                         kmem_free(chap, sizeof (*chap));
2355                         break;
2356                 }
2357 
2358                 rw_enter(&ihp->hba_sess_list_rwlock, RW_READER);
2359                 if (chap->c_oid == ihp->hba_oid)
2360                         name = ihp->hba_name;
2361                 else {
2362                         rtn = iscsi_sess_get(chap->c_oid, ihp, &isp);
2363                         if (rtn != 0) {
2364                                 rtn = iscsi_sess_get_by_target(
2365                                     chap->c_oid, ihp, &isp);
2366                         }
2367 
2368                         /*
2369                          * If rtn is zero then we have found an
2370                          * existing session.  Use the session name to
2371                          * do param lookup.  If rtn is non-zero then
2372                          * create a targetparam object and use its name
2373                          * for param lookup.
2374                          */
2375                         if (rtn == 0) {
2376                                 name = isp->sess_name;
2377                         } else {
2378                                 name =
2379                                     iscsi_targetparam_get_name(chap->c_oid);
2380                                 rtn = 0;
2381                         }
2382                 }
2383 
2384                 if (name == NULL) {
2385                         rw_exit(
2386                             &ihp->hba_sess_list_rwlock);
2387                         rtn = EFAULT;
2388                         kmem_free(chap, sizeof (*chap));
2389                         break;
2390                 }
2391 
2392                 if (persistent_chap_set((char *)name, chap) ==
2393                     B_FALSE) {
2394                         rtn = EIO;
2395                 }
2396                 rw_exit(&ihp->hba_sess_list_rwlock);
2397                 kmem_free(chap, sizeof (*chap));
2398                 break;
2399 
2400         /*
2401          * ISCSI_CHAP_GET -
2402          */
2403         case ISCSI_CHAP_GET:
2404                 chap = (iscsi_chap_props_t *)kmem_zalloc(sizeof (*chap),
2405                     KM_SLEEP);
2406                 if (ddi_copyin((caddr_t)arg, chap, sizeof (*chap), mode)) {
2407                         kmem_free(chap, sizeof (*chap));
2408                         rtn = EFAULT;
2409                         break;
2410                 } else if (chap->c_vers != ISCSI_INTERFACE_VERSION) {
2411                         kmem_free(chap, sizeof (*chap));
2412                         rtn = EINVAL;
2413                         break;
2414                 }
2415 
2416                 rw_enter(&ihp->hba_sess_list_rwlock, RW_READER);
2417                 if (chap->c_oid == ihp->hba_oid)
2418                         name = ihp->hba_name;
2419                 else {
2420                         rtn = iscsi_sess_get(chap->c_oid, ihp, &isp);
2421                         if (rtn != 0) {
2422                                 rtn = iscsi_sess_get_by_target(
2423                                     chap->c_oid, ihp, &isp);
2424                         }
2425 
2426                         /*
2427                          * If rtn is zero then we have found an
2428                          * existing session.  Use the session name to
2429                          * do param lookup.  If rtn is non-zero then
2430                          * create a targetparam object and use its name
2431                          * for param lookup.
2432                          */
2433                         if (rtn == 0) {
2434                                 name = isp->sess_name;
2435                         } else {
2436                                 rtn = 0;
2437                                 name =
2438                                     iscsi_targetparam_get_name(chap->c_oid);
2439                         }
2440 
2441                         if (name == NULL) {
2442                                 rw_exit(&ihp->hba_sess_list_rwlock);
2443                                 rtn = EFAULT;
2444                                 break;
2445                         }
2446                         /*
2447                          * Initialize the target-side chap name to the
2448                          * session name if no chap settings have been
2449                          * saved for the current session.
2450                          */
2451                         if (persistent_chap_get((char *)name,
2452                             chap) == B_FALSE) {
2453                                 int name_len = strlen((char *)name);
2454                                 iscsi_chap_props_t *chap = NULL;
2455                                 chap = (iscsi_chap_props_t *)kmem_zalloc
2456                                     (sizeof (iscsi_chap_props_t), KM_SLEEP);
2457                                 bcopy((char *)name, chap->c_user, name_len);
2458                                 chap->c_user_len = name_len;
2459                                 (void) (persistent_chap_set((char *)name,
2460                                     chap));
2461                                 kmem_free(chap, sizeof (*chap));
2462                         }
2463                 }
2464 
2465                 if (name == NULL) {
2466                         rw_exit(
2467                             &ihp->hba_sess_list_rwlock);
2468                         rtn = EFAULT;
2469                         break;
2470                 }
2471 
2472                 if (persistent_chap_get((char *)name, chap) == B_FALSE) {
2473                         rw_exit(&ihp->hba_sess_list_rwlock);
2474                         rtn = EIO;
2475                         break;
2476                 }
2477                 rw_exit(&ihp->hba_sess_list_rwlock);
2478 
2479                 rtn = ddi_copyout(chap, (caddr_t)arg, sizeof (*chap), mode);
2480                 kmem_free(chap, sizeof (*chap));
2481                 break;
2482 
2483         /*
2484          * ISCSI_CHAP_CLEAR -
2485          */
2486         case ISCSI_CHAP_CLEAR:
2487                 chap = (iscsi_chap_props_t *)kmem_zalloc(sizeof (*chap),
2488                     KM_SLEEP);
2489                 if (ddi_copyin((caddr_t)arg, chap, sizeof (*chap), mode)) {
2490                         rtn = EFAULT;
2491                         kmem_free(chap, sizeof (*chap));
2492                         break;
2493                 } else if (chap->c_vers != ISCSI_INTERFACE_VERSION) {
2494                         rtn = EINVAL;
2495                         kmem_free(chap, sizeof (*chap));
2496                         break;
2497                 }
2498 
2499                 if (chap->c_oid == ihp->hba_oid) {
2500                         iscsi_sess_t *sessp;
2501 
2502                         name = ihp->hba_name;
2503 
2504                         if (persistent_chap_clear(
2505                             (char *)name) == B_FALSE) {
2506                                 rtn = EIO;
2507                         }
2508 
2509                         /*
2510                          * Loop through all sessions and memset their
2511                          * (initiator's) passwords
2512                          */
2513                         rw_enter(&ihp->hba_sess_list_rwlock, RW_READER);
2514                         for (sessp = ihp->hba_sess_list; sessp;
2515                             sessp = sessp->sess_next) {
2516                                 (void) memset(sessp->sess_auth.password,
2517                                     0, iscsiAuthStringMaxLength);
2518                                 sessp->sess_auth.password_length = 0;
2519                         }
2520                         rw_exit(&ihp->hba_sess_list_rwlock);
2521 
2522                 } else {
2523                         rw_enter(&ihp->hba_sess_list_rwlock, RW_READER);
2524                         /*
2525                          * If the oid does represent a session check to see
2526                          * if it is a target oid.  If so, return the target's
2527                          * associated session.
2528                          */
2529                         rtn = iscsi_sess_get(chap->c_oid, ihp, &isp);
2530                         if (rtn != 0) {
2531                                 rtn = iscsi_sess_get_by_target(chap->c_oid,
2532                                     ihp, &isp);
2533                         }
2534 
2535                         rw_exit(&ihp->hba_sess_list_rwlock);
2536 
2537                         /*
2538                          * If rtn is zero then we have found an
2539                          * existing session.  Use the session name to
2540                          * do param lookup.  If rtn is non-zero then
2541                          * create a targetparam object and use its name
2542                          * for param lookup.
2543                          */
2544                         if (rtn == 0) {
2545                                 name = isp->sess_name;
2546                         } else {
2547                                 name =
2548                                     iscsi_targetparam_get_name(chap->c_oid);
2549                                 rtn = 0;
2550                         }
2551 
2552                         if (name == NULL) {
2553                                 rtn = EFAULT;
2554                                 break;
2555                         }
2556 
2557                         if (persistent_chap_clear(
2558                             (char *)name) == B_FALSE) {
2559                                 rtn = EIO;
2560                         }
2561 
2562                         /*
2563                          * Clear out session chap password if we found a
2564                          * session above.
2565                          */
2566                         if (isp != NULL) {
2567                                 (void) memset(isp->sess_auth.password_in,
2568                                     0, iscsiAuthStringMaxLength);
2569                                 isp->sess_auth.password_length_in = 0;
2570                         }
2571 
2572                 }
2573 
2574                 kmem_free(chap, sizeof (*chap));
2575                 break;
2576 
2577         /*
2578          * ISCSI_STATIC_GET -
2579          */
2580         case ISCSI_STATIC_GET:
2581                 ispp = (iscsi_static_property_t *)kmem_alloc(
2582                     sizeof (*ispp), KM_SLEEP);
2583 
2584                 if (ddi_copyin((caddr_t)arg, ispp, sizeof (*ispp), mode)) {
2585                         rtn = EFAULT;
2586                         kmem_free(ispp, sizeof (*ispp));
2587                         break;
2588                 }
2589 
2590                 if (ispp->p_vers != ISCSI_INTERFACE_VERSION) {
2591                         rtn = EINVAL;
2592                         kmem_free(ispp, sizeof (*ispp));
2593                         break;
2594                 }
2595 
2596                 {
2597                         void *v = NULL;
2598                         boolean_t found = B_FALSE;
2599 
2600                         persistent_static_addr_lock();
2601                         while (persistent_static_addr_next(&v,
2602                             (char *)ispp->p_name, &e) == B_TRUE) {
2603 
2604                                 if (ispp->p_oid == e.e_oid) {
2605                                         /*
2606                                          * In case there are multiple
2607                                          * addresses associated with the
2608                                          * given target OID, pick the first
2609                                          * one.
2610                                          */
2611                                         iscsi_addr_t *ap;
2612 
2613                                         ap = &(ispp->p_addr_list.al_addrs[0]);
2614                                         ap->a_port = e.e_port;
2615                                         ap->a_addr.i_insize = e.e_insize;
2616                                         bcopy(e.e_u.u_in6.s6_addr,
2617                                             ap->a_addr.i_addr.in6.s6_addr,
2618                                             e.e_insize);
2619                                         ispp->p_name_len =
2620                                             strlen((char *)ispp->p_name);
2621                                         ispp->p_addr_list.al_tpgt = e.e_tpgt;
2622                                         ispp->p_addr_list.al_out_cnt = 1;
2623 
2624                                         found = B_TRUE;
2625                                         break;
2626                                 }
2627                         }
2628                         persistent_static_addr_unlock();
2629 
2630                         if (found == B_TRUE) {
2631                                 rtn = ddi_copyout(ispp, (caddr_t)arg,
2632                                     sizeof (*ispp), mode);
2633                         } else {
2634                                 rtn = ENOENT;
2635                         }
2636                 }
2637                 kmem_free(ispp, sizeof (*ispp));
2638 
2639                 break;
2640 
2641         /*
2642          * ISCSI_STATIC_SET -
2643          */
2644         case ISCSI_STATIC_SET:
2645                 target = iscsi_ioctl_copyin((caddr_t)arg, mode,
2646                     sizeof (*target));
2647                 if (target == NULL) {
2648                         rtn = EFAULT;
2649                         break;
2650                 }
2651 
2652                 if ((target->te_entry.e_vers != ISCSI_INTERFACE_VERSION) ||
2653                     (target->te_entry.e_insize == 0)) {
2654                         kmem_free(target, sizeof (*target));
2655                         rtn = EINVAL;
2656                         break;
2657                 }
2658 
2659                 /* Check if the target's already been added */
2660                 {
2661                         boolean_t static_target_found = B_FALSE;
2662                         void *v = NULL;
2663 
2664                         name = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP);
2665                         persistent_static_addr_lock();
2666                         while (persistent_static_addr_next(&v, (char *)name,
2667                             &e) == B_TRUE) {
2668                                 /*
2669                                  * MC/S - Need to check IP address and port
2670                                  * number as well when we support MC/S.
2671                                  */
2672                                 if ((strncmp((char *)name,
2673                                     (char *)target->te_name,
2674                                     ISCSI_MAX_NAME_LEN) == 0) &&
2675                                     (target->te_entry.e_tpgt == e.e_tpgt) &&
2676                                     (target->te_entry.e_insize == e.e_insize) &&
2677                                     (bcmp(&target->te_entry.e_u, &e.e_u,
2678                                     e.e_insize) == 0)) {
2679                                         /*
2680                                          * We don't allow MC/S for now but
2681                                          * we do allow adding the same target
2682                                          * with different TPGTs (hence,
2683                                          * different sessions).
2684                                          */
2685                                         static_target_found = B_TRUE;
2686                                         break;
2687                                 }
2688                         }
2689                         persistent_static_addr_unlock();
2690                         kmem_free(name, ISCSI_MAX_NAME_LEN);
2691 
2692                         if (static_target_found == B_TRUE) {
2693                                 /* Duplicate entry */
2694                                 kmem_free(target, sizeof (*target));
2695                                 rtn = EEXIST;
2696                                 break;
2697                         }
2698                 }
2699 
2700                 if (target->te_entry.e_oid == ISCSI_OID_NOTSET) {
2701                         mutex_enter(&iscsi_oid_mutex);
2702                         target->te_entry.e_oid = iscsi_oid++;
2703                         mutex_exit(&iscsi_oid_mutex);
2704                 }
2705 
2706                 persistent_static_addr_lock();
2707                 if (persistent_static_addr_set((char *)target->te_name,
2708                     &target->te_entry) == B_FALSE) {
2709                         persistent_static_addr_unlock();
2710                         kmem_free(target, sizeof (*target));
2711                         rtn = EIO;
2712                         break;
2713                 }
2714                 persistent_static_addr_unlock();
2715 
2716                 /*
2717                  * If Static Targets discovery is enabled, then add
2718                  * target to discovery queue. Otherwise, just create
2719                  * the session for potential future use.
2720                  */
2721                 method = persistent_disc_meth_get();
2722                 if (method & iSCSIDiscoveryMethodStatic) {
2723                         iscsid_poke_discovery(ihp, iSCSIDiscoveryMethodStatic);
2724                         (void) iscsid_login_tgt(ihp, (char *)target->te_name,
2725                             iSCSIDiscoveryMethodStatic, NULL);
2726                 }
2727 
2728                 rtn = iscsi_ioctl_copyout(target, sizeof (*target),
2729                     (caddr_t)arg, mode);
2730                 break;
2731 
2732         /*
2733          * ISCSI_STATIC_CLEAR -
2734          */
2735         case ISCSI_STATIC_CLEAR:
2736                 if (ddi_copyin((caddr_t)arg, &e, sizeof (e), mode)) {
2737                         rtn = EFAULT;
2738                         break;
2739                 } else if (e.e_vers != ISCSI_INTERFACE_VERSION) {
2740                         rtn = EINVAL;
2741                         break;
2742                 }
2743 
2744                 {
2745                         boolean_t       found = B_FALSE;
2746                         void            *v = NULL;
2747                         entry_t         tmp_e;
2748                         char            *name = NULL;
2749 
2750                         name = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP);
2751 
2752                         /* Find name for matching static_tgt oid */
2753                         persistent_static_addr_lock();
2754                         while (persistent_static_addr_next(&v,
2755                             (char *)name, &tmp_e) == B_TRUE) {
2756                                 if (e.e_oid == tmp_e.e_oid) {
2757                                         found = B_TRUE;
2758                                         break;
2759                                 }
2760                         }
2761 
2762                         /* If static_tgt found logout and remove it */
2763                         if (found == B_TRUE) {
2764 
2765                                 iscsid_addr_to_sockaddr(tmp_e.e_insize,
2766                                     &tmp_e.e_u, tmp_e.e_port, &addr_dsc.sin);
2767 
2768                                 persistent_static_addr_unlock();
2769 
2770                                 /*
2771                                  * If discovery in progress, try few times
2772                                  * before return busy
2773                                  */
2774                                 retry = 0;
2775                                 mutex_enter(&ihp->hba_discovery_events_mutex);
2776                                 while (ihp->hba_discovery_in_progress ==
2777                                     B_TRUE) {
2778                                         if (++retry == 5) {
2779                                                 rtn = EBUSY;
2780                                                 break;
2781                                         }
2782                                         mutex_exit(
2783                                             &ihp->hba_discovery_events_mutex);
2784                                         delay(SEC_TO_TICK(
2785                                             ISCSI_DISC_DELAY));
2786                                         mutex_enter(
2787                                             &ihp->hba_discovery_events_mutex);
2788                                 }
2789                                 /* remove from persistent store */
2790                                 if (rtn == 0 && persistent_static_addr_clear(
2791                                     e.e_oid) == B_FALSE) {
2792                                         rtn = EIO;
2793                                 }
2794                                 mutex_exit(&ihp->hba_discovery_events_mutex);
2795 
2796                                 if (rtn != 0) {
2797                                         kmem_free(name, ISCSI_MAX_NAME_LEN);
2798                                         break;
2799                                 }
2800 
2801                                 /* Attempt to logout of target */
2802                                 if (iscsid_del(ihp, (char *)name,
2803                                     iSCSIDiscoveryMethodStatic, &addr_dsc.sin)
2804                                     == B_FALSE) {
2805                                         persistent_static_addr_lock();
2806 
2807                                         /*
2808                                          * Restore static_tgt to
2809                                          * persistent store
2810                                          */
2811                                         if (persistent_static_addr_set(
2812                                             (char *)name,
2813                                             &tmp_e) == B_FALSE) {
2814                                                 cmn_err(CE_WARN, "Failed to "
2815                                                     "restore static target "
2816                                                     "address after logout "
2817                                                     "target failure.");
2818                                         }
2819                                         persistent_static_addr_unlock();
2820                                         rtn = EBUSY;
2821                                 } else {
2822                                         iscsid_poke_discovery(ihp,
2823                                             iSCSIDiscoveryMethodStatic);
2824                                         (void) iscsid_login_tgt(ihp,
2825                                             (char *)name,
2826                                             iSCSIDiscoveryMethodStatic,
2827                                             NULL);
2828 
2829                                 }
2830                         } else {
2831                                 persistent_static_addr_unlock();
2832                                 rtn = EIO;
2833                         }
2834                         kmem_free(name, ISCSI_MAX_NAME_LEN);
2835                 }
2836                 break;
2837 
2838         /*
2839          * ISCSI_ISNS_SERVER_ADDR_SET:
2840          */
2841         case ISCSI_ISNS_SERVER_ADDR_SET:
2842                 if (ddi_copyin((caddr_t)arg, &e, sizeof (e), mode)) {
2843                         rtn = EFAULT;
2844                         break;
2845                 } else if (e.e_vers != ISCSI_INTERFACE_VERSION) {
2846                         rtn = EINVAL;
2847                         break;
2848                 }
2849 
2850                 if (persistent_isns_addr_set(&e) == B_FALSE) {
2851                         rtn = EIO;
2852                         break;
2853                 }
2854 
2855                 /*
2856                  * If iSNS server discovery is enabled, then kickoff
2857                  * discovery of the targets advertised by the recently
2858                  * added iSNS server address.
2859                  */
2860                 method = persistent_disc_meth_get();
2861                 if (method & iSCSIDiscoveryMethodISNS) {
2862                         initiator_node_name = kmem_zalloc(ISCSI_MAX_NAME_LEN,
2863                             KM_SLEEP);
2864                         if (persistent_initiator_name_get(initiator_node_name,
2865                             ISCSI_MAX_NAME_LEN) != B_TRUE) {
2866                                 kmem_free(initiator_node_name,
2867                                     ISCSI_MAX_NAME_LEN);
2868                                 initiator_node_name = NULL;
2869                                 rtn = EIO;
2870                                 break;
2871                         }
2872                         if (strlen(initiator_node_name) == 0) {
2873                                 kmem_free(initiator_node_name,
2874                                     ISCSI_MAX_NAME_LEN);
2875                                 initiator_node_name = NULL;
2876                                 rtn = EIO;
2877                                 break;
2878                         }
2879 
2880                         initiator_node_alias = kmem_zalloc(ISCSI_MAX_NAME_LEN,
2881                             KM_SLEEP);
2882                         if (persistent_alias_name_get(initiator_node_alias,
2883                             ISCSI_MAX_NAME_LEN) != B_TRUE) {
2884                                 initiator_node_alias[0] = '\0';
2885                         }
2886 
2887                         /*
2888                          * Register this initiator node against this iSNS
2889                          * server.
2890                          */
2891                         (void) isns_reg_one_server(&e, ihp->hba_isid,
2892                             (uint8_t *)initiator_node_name,
2893                             ISCSI_MAX_NAME_LEN,
2894                             (uint8_t *)initiator_node_alias,
2895                             ISCSI_MAX_NAME_LEN,
2896                             ISNS_INITIATOR_NODE_TYPE,
2897                             isns_scn_callback);
2898 
2899                         iscsid_do_isns_query_one_server(ihp, &e);
2900 
2901                         iscsid_addr_to_sockaddr(e.e_insize,
2902                             &e.e_u, e.e_port, &addr_dsc.sin);
2903 
2904                         (void) iscsid_login_tgt(ihp, NULL,
2905                             iSCSIDiscoveryMethodISNS,
2906                             &addr_dsc.sin);
2907 
2908                         /* Done using the name and alias - free them. */
2909                         kmem_free(initiator_node_name, ISCSI_MAX_NAME_LEN);
2910                         initiator_node_name = NULL;
2911                         kmem_free(initiator_node_alias, ISCSI_MAX_NAME_LEN);
2912                         initiator_node_alias = NULL;
2913                 }
2914                 break;
2915 
2916         /*
2917          * ISCSI_DISCOVERY_ADDR_SET:
2918          */
2919         case ISCSI_DISCOVERY_ADDR_SET:
2920                 if (ddi_copyin((caddr_t)arg, &e, sizeof (e), mode)) {
2921                         rtn = EFAULT;
2922                         break;
2923                 } else if (e.e_vers != ISCSI_INTERFACE_VERSION) {
2924                         rtn = EINVAL;
2925                         break;
2926                 }
2927 
2928                 if (e.e_oid == ISCSI_OID_NOTSET) {
2929                         mutex_enter(&iscsi_oid_mutex);
2930                         e.e_oid = iscsi_oid++;
2931                         mutex_exit(&iscsi_oid_mutex);
2932                 }
2933 
2934                 if (persistent_disc_addr_set(&e) == B_FALSE) {
2935                         rtn = EIO;
2936                         break;
2937                 }
2938 
2939                 /*
2940                  * If Send Targets discovery is enabled, then kickoff
2941                  * discovery of the targets advertised by the recently
2942                  * added discovery address.
2943                  */
2944                 method = persistent_disc_meth_get();
2945                 if (method & iSCSIDiscoveryMethodSendTargets) {
2946 
2947                         iscsid_addr_to_sockaddr(e.e_insize,
2948                             &e.e_u, e.e_port, &addr_dsc.sin);
2949                         iscsid_do_sendtgts(&e);
2950                         (void) iscsid_login_tgt(ihp, NULL,
2951                             iSCSIDiscoveryMethodSendTargets,
2952                             &addr_dsc.sin);
2953 
2954                 }
2955                 break;
2956 
2957         /*
2958          * ISCSI_DISCOVERY_ADDR_LIST_GET
2959          */
2960         case ISCSI_DISCOVERY_ADDR_LIST_GET:
2961                 /* copyin user args */
2962                 if (ddi_copyin((caddr_t)arg, &ial, sizeof (ial), mode)) {
2963                         rtn = EFAULT;
2964                         break;
2965                 }
2966 
2967                 if (ial.al_vers != ISCSI_INTERFACE_VERSION) {
2968                         rtn = EINVAL;
2969                         break;
2970                 }
2971 
2972                 list_space = sizeof (iscsi_addr_list_t);
2973                 if (ial.al_in_cnt != 0) {
2974                         list_space += (sizeof (iscsi_addr_t) *
2975                             (ial.al_in_cnt - 1));
2976                 }
2977 
2978                 ialp = kmem_zalloc(list_space, KM_SLEEP);
2979                 bcopy(&ial, ialp, sizeof (iscsi_addr_list_t));
2980 
2981                 void_p = NULL;
2982                 ialp->al_out_cnt = 0;
2983                 persistent_disc_addr_lock();
2984                 while (persistent_disc_addr_next(&void_p, &e) == B_TRUE) {
2985                         if (ialp->al_out_cnt < ialp->al_in_cnt) {
2986                                 int             i = ialp->al_out_cnt;
2987                                 iscsi_addr_t    *addr = &ialp->al_addrs[i];
2988 
2989                                 addr->a_port = e.e_port;
2990                                 addr->a_addr.i_insize = e.e_insize;
2991                                 addr->a_oid = e.e_oid;
2992 
2993                                 if (e.e_insize == sizeof (struct in_addr)) {
2994                                         /* IPv4 */
2995                                         addr->a_addr.i_addr.in4.s_addr =
2996                                             e.e_u.u_in4.s_addr;
2997                                 } else if (e.e_insize ==
2998                                             sizeof (struct in6_addr)) {
2999                                         /* IPv6 */
3000                                         bcopy(e.e_u.u_in6.s6_addr,
3001                                             addr->a_addr.i_addr.in6.s6_addr,
3002                                             16);
3003                                 }
3004                         }
3005                         ialp->al_out_cnt++;
3006                 }
3007                 persistent_disc_addr_unlock();
3008 
3009                 rtn = ddi_copyout(ialp, (caddr_t)arg, list_space, mode);
3010                 kmem_free(ialp, list_space);
3011                 break;
3012 
3013         /*
3014          * ISCSI_ISNS_SERVER_ADDR_LIST_GET
3015          */
3016         case ISCSI_ISNS_SERVER_ADDR_LIST_GET:
3017                 /* copyin user args */
3018                 if (ddi_copyin((caddr_t)arg, &ial, sizeof (ial), mode)) {
3019                         rtn = EFAULT;
3020                         break;
3021                 }
3022 
3023                 if (ial.al_vers != ISCSI_INTERFACE_VERSION) {
3024                         rtn = EINVAL;
3025                         break;
3026                 }
3027 
3028                 list_space = sizeof (iscsi_addr_list_t);
3029                 if (ial.al_in_cnt != 0) {
3030                         list_space += (sizeof (iscsi_addr_t) *
3031                             (ial.al_in_cnt - 1));
3032                 }
3033 
3034                 ialp = kmem_zalloc(list_space, KM_SLEEP);
3035                 bcopy(&ial, ialp, sizeof (iscsi_addr_list_t));
3036 
3037                 void_p = NULL;
3038                 ialp->al_out_cnt = 0;
3039                 persistent_isns_addr_lock();
3040                 while (persistent_isns_addr_next(&void_p, &e) == B_TRUE) {
3041                         if (ialp->al_out_cnt < ialp->al_in_cnt) {
3042                                 int             i = ialp->al_out_cnt;
3043                                 iscsi_addr_t    *addr = &ialp->al_addrs[i];
3044 
3045                                 addr->a_port = e.e_port;
3046                                 addr->a_addr.i_insize = e.e_insize;
3047                                 if (e.e_insize == sizeof (struct in_addr)) {
3048                                         /* IPv4 */
3049                                         addr->a_addr.i_addr.in4.s_addr =
3050                                             e.e_u.u_in4.s_addr;
3051                                 } else if (e.e_insize ==
3052                                             sizeof (struct in6_addr)) {
3053                                         /* IPv6 */
3054                                         bcopy(e.e_u.u_in6.s6_addr,
3055                                             addr->a_addr.i_addr.in6.s6_addr,
3056                                             16);
3057                                 }
3058                         }
3059                         ialp->al_out_cnt++;
3060                 }
3061                 persistent_isns_addr_unlock();
3062 
3063                 rtn = ddi_copyout(ialp, (caddr_t)arg, list_space, mode);
3064                 kmem_free(ialp, list_space);
3065                 break;
3066 
3067         /*
3068          * ISCSI_DISCOVERY_ADDR_CLEAR:
3069          */
3070         case ISCSI_DISCOVERY_ADDR_CLEAR:
3071                 if (ddi_copyin((caddr_t)arg, &e, sizeof (e), mode)) {
3072                         rtn = EFAULT;
3073                         break;
3074                 } else if (e.e_vers != ISCSI_INTERFACE_VERSION) {
3075                         rtn = EINVAL;
3076                         break;
3077                 }
3078 
3079                 iscsid_addr_to_sockaddr(e.e_insize,
3080                     &e.e_u, e.e_port, &addr_dsc.sin);
3081 
3082                 /* If discovery in progress, try few times before return busy */
3083                 retry = 0;
3084                 mutex_enter(&ihp->hba_discovery_events_mutex);
3085                 while (ihp->hba_discovery_in_progress == B_TRUE) {
3086                         if (++retry == 5) {
3087                                 rtn = EBUSY;
3088                                 break;
3089                         }
3090                         mutex_exit(&ihp->hba_discovery_events_mutex);
3091                         delay(SEC_TO_TICK(ISCSI_DISC_DELAY));
3092                         mutex_enter(&ihp->hba_discovery_events_mutex);
3093                 }
3094 
3095                 /*
3096                  * Clear discovery address first, so that any bus config
3097                  * will ignore this discovery address
3098                  */
3099                 if (rtn == 0 && persistent_disc_addr_clear(&e) == B_FALSE) {
3100                         rtn = EIO;
3101                 }
3102                 mutex_exit(&ihp->hba_discovery_events_mutex);
3103 
3104                 if (rtn != 0) {
3105                         break;
3106                 }
3107                 /* Attempt to logout of associated targets */
3108                 if (iscsid_del(ihp, NULL,
3109                     iSCSIDiscoveryMethodSendTargets, &addr_dsc.sin) ==
3110                     B_FALSE) {
3111                         /* Failure!, restore the discovery addr. */
3112                         if (persistent_disc_addr_set(&e) == B_FALSE) {
3113                                 cmn_err(CE_WARN, "Failed to restore sendtgt "
3114                                     "discovery address after logout associated "
3115                                     "targets failures.");
3116                         }
3117                         rtn = EBUSY;
3118                 }
3119                 break;
3120 
3121         /*
3122          * ISCSI_ISNS_SERVER_CLEAR:
3123          */
3124         case ISCSI_ISNS_SERVER_ADDR_CLEAR:
3125                 if (ddi_copyin((caddr_t)arg, &e, sizeof (e), mode)) {
3126                         rtn = EFAULT;
3127                         break;
3128                 } else if (e.e_vers != ISCSI_INTERFACE_VERSION) {
3129                         rtn = EINVAL;
3130                         break;
3131                 }
3132 
3133                 iscsid_addr_to_sockaddr(e.e_insize,
3134                     &e.e_u, e.e_port, &addr_dsc.sin);
3135 
3136                 /* If discovery in progress, try few times before return busy */
3137                 retry = 0;
3138                 mutex_enter(&ihp->hba_discovery_events_mutex);
3139                 while (ihp->hba_discovery_in_progress == B_TRUE) {
3140                         if (++retry == 5) {
3141                                 rtn = EBUSY;
3142                                 break;
3143                         }
3144                         mutex_exit(&ihp->hba_discovery_events_mutex);
3145                         delay(SEC_TO_TICK(ISCSI_DISC_DELAY));
3146                         mutex_enter(&ihp->hba_discovery_events_mutex);
3147                 }
3148 
3149                 /*
3150                  * Clear isns server address first, so that any bus config
3151                  * will ignore any target registerd on this isns server
3152                  */
3153                 if (rtn == 0 && persistent_isns_addr_clear(&e) == B_FALSE) {
3154                         rtn = EIO;
3155                 }
3156                 mutex_exit(&ihp->hba_discovery_events_mutex);
3157 
3158                 if (rtn != 0) {
3159                         break;
3160                 }
3161 
3162                 /* Attempt logout of associated targets */
3163                 if (iscsid_del(ihp, NULL, iSCSIDiscoveryMethodISNS,
3164                     &addr_dsc.sin) == B_FALSE) {
3165                         /* Failure!, restore the isns server addr. */
3166 
3167                         if (persistent_isns_addr_set(&e) == B_FALSE) {
3168                                 cmn_err(CE_WARN, "Failed to restore isns server"
3169                                     " address after logout associated targets"
3170                                     " failures.");
3171                         }
3172                         rtn = EBUSY;
3173                 } else {
3174                         method = persistent_disc_meth_get();
3175                         if (method & iSCSIDiscoveryMethodISNS) {
3176                                 boolean_t is_last_isns_server_b =
3177                                     B_FALSE;
3178                                 int isns_server_count = 0;
3179                                 void *void_p = NULL;
3180 
3181                                 /*
3182                                  * Check if the last iSNS server's been
3183                                  * removed.
3184                                  */
3185                                 {
3186                                         entry_t tmp_e;
3187                                         persistent_isns_addr_lock();
3188                                         while (persistent_isns_addr_next(
3189                                             &void_p, &tmp_e) == B_TRUE) {
3190                                                 isns_server_count++;
3191                                         }
3192                                 }
3193                                 persistent_isns_addr_unlock();
3194                                 if (isns_server_count == 0) {
3195                                         is_last_isns_server_b = B_TRUE;
3196                                 }
3197 
3198                                 /*
3199                                  * Deregister this node from this iSNS
3200                                  * server.
3201                                  */
3202                                 initiator_node_name = kmem_zalloc(
3203                                     ISCSI_MAX_NAME_LEN, KM_SLEEP);
3204                                 if (persistent_initiator_name_get(
3205                                     initiator_node_name,
3206                                     ISCSI_MAX_NAME_LEN) == B_TRUE) {
3207 
3208                                         if (strlen(initiator_node_name) > 0) {
3209                                                 (void) isns_dereg_one_server(
3210                                                     &e, (uint8_t *)
3211                                                     initiator_node_name,
3212                                                     is_last_isns_server_b);
3213                                         }
3214                                 }
3215                                 kmem_free(initiator_node_name,
3216                                     ISCSI_MAX_NAME_LEN);
3217                                 initiator_node_name = NULL;
3218                         }
3219                 }
3220                 break;
3221 
3222         /*
3223          * ISCSI_DISCOVERY_SET -
3224          */
3225         case ISCSI_DISCOVERY_SET:
3226                 if (ddi_copyin((caddr_t)arg, &method, sizeof (method), mode)) {
3227                         rtn = EFAULT;
3228                         break;
3229                 }
3230 
3231                 if (persistent_disc_meth_set(method) == B_FALSE) {
3232                         rtn = EIO;
3233                 } else {
3234                         (void) iscsid_enable_discovery(ihp, method, B_FALSE);
3235                         iscsid_poke_discovery(ihp, method);
3236                         (void) iscsid_login_tgt(ihp, NULL, method, NULL);
3237                 }
3238                 break;
3239 
3240         /*
3241          * ISCSI_DISCOVERY_GET -
3242          */
3243         case ISCSI_DISCOVERY_GET:
3244                 method = persistent_disc_meth_get();
3245                 rtn = ddi_copyout(&method, (caddr_t)arg,
3246                     sizeof (method), mode);
3247                 break;
3248 
3249         /*
3250          * ISCSI_DISCOVERY_CLEAR -
3251          */
3252         case ISCSI_DISCOVERY_CLEAR:
3253                 if (ddi_copyin((caddr_t)arg, &method, sizeof (method), mode)) {
3254                         rtn = EFAULT;
3255                         break;
3256                 }
3257 
3258                 /* If discovery in progress, try few times before return busy */
3259                 retry = 0;
3260                 mutex_enter(&ihp->hba_discovery_events_mutex);
3261                 while (ihp->hba_discovery_in_progress == B_TRUE) {
3262                         if (++retry == 5) {
3263                                 rtn = EBUSY;
3264                                 break;
3265                         }
3266                         mutex_exit(&ihp->hba_discovery_events_mutex);
3267                         delay(SEC_TO_TICK(ISCSI_DISC_DELAY));
3268                         mutex_enter(&ihp->hba_discovery_events_mutex);
3269                 }
3270 
3271                 /*
3272                  * Clear discovery first, so that any bus config or
3273                  * discovery requests will ignore this discovery method
3274                  */
3275                 if (rtn == 0 && persistent_disc_meth_clear(method) == B_FALSE) {
3276                         rtn = EIO;
3277                 }
3278                 mutex_exit(&ihp->hba_discovery_events_mutex);
3279 
3280                 if (rtn != 0) {
3281                         break;
3282                 }
3283 
3284                 /* Attempt to logout from all associated targets */
3285                 if (iscsid_disable_discovery(ihp, method) == B_FALSE) {
3286                         /* Failure!, reset the discovery */
3287                         if (persistent_disc_meth_set(method) == B_FALSE) {
3288                                 cmn_err(CE_WARN, "Failed to reset discovery "
3289                                     "method after discovery disable failure.");
3290                         }
3291                         rtn = EBUSY;
3292                 }
3293                 break;
3294 
3295         /*
3296          * ISCSI_DISCOVERY_PROPS -
3297          */
3298         case ISCSI_DISCOVERY_PROPS:
3299                 iscsid_props(&discovery_props);
3300                 if (ddi_copyout(&discovery_props, (caddr_t)arg,
3301                     sizeof (discovery_props), mode))
3302                         rtn = EFAULT;
3303                 break;
3304 
3305         /*
3306          * ISCSI_LUN_OID_LIST --
3307          */
3308         case ISCSI_LUN_OID_LIST_GET:
3309                 ll = (iscsi_lun_list_t *)kmem_alloc(sizeof (*ll), KM_SLEEP);
3310                 if (ddi_copyin((caddr_t)arg, ll, sizeof (*ll), mode)) {
3311                         rtn = EFAULT;
3312                         kmem_free(ll, sizeof (*ll));
3313                         break;
3314                 }
3315 
3316                 if (ll->ll_vers != ISCSI_INTERFACE_VERSION) {
3317                         rtn = EINVAL;
3318                         kmem_free(ll, sizeof (*ll));
3319                         break;
3320                 }
3321 
3322                 /*
3323                  * Find out how much space the user has allocated in their
3324                  * structure. Match the same space for our structure.
3325                  */
3326                 lun_sz = sizeof (iscsi_lun_list_t);
3327                 if (ll->ll_in_cnt > 0) {
3328                         lun_sz += (ll->ll_in_cnt - 1) * sizeof (iscsi_if_lun_t);
3329                 }
3330 
3331                 llp = kmem_zalloc(lun_sz, KM_SLEEP);
3332                 bcopy(ll, llp, sizeof (*ll));
3333                 kmem_free(ll, sizeof (*ll));
3334 
3335                 /*
3336                  * Check to see if oid references a target-param oid.  If so,
3337                  * find the associated  session oid before getting lu list.
3338                  */
3339                 if (iscsi_targetparam_get_name(llp->ll_tgt_oid) != NULL) {
3340                         for (isp = ihp->hba_sess_list; isp;
3341                             isp = isp->sess_next) {
3342                                 if (isp->sess_target_oid == llp->ll_tgt_oid) {
3343                                         target_oid  = isp->sess_oid;
3344                                         break;
3345                                 }
3346                         }
3347                 } else {
3348                         target_oid = llp->ll_tgt_oid;
3349                 }
3350 
3351 
3352                 /*
3353                  * Look at the LUNs attached to the specified target. If there
3354                  * is space in the user structure save that information locally.
3355                  * Always add up the count to the total. By always adding
3356                  * the count this code can be used if ll_in_cnt == 0 and
3357                  * the user just wishes to know the appropriate size to
3358                  * allocate.
3359                  */
3360                 rw_enter(&ihp->hba_sess_list_rwlock, RW_READER);
3361                 for (isp = ihp->hba_sess_list; isp; isp = isp->sess_next) {
3362                         if ((llp->ll_all_tgts == B_FALSE) &&
3363                             (isp->sess_oid != target_oid)) {
3364                                 continue;
3365                         }
3366                         rw_enter(&isp->sess_lun_list_rwlock, RW_READER);
3367                         for (ilp = isp->sess_lun_list; ilp;
3368                             ilp = ilp->lun_next) {
3369                                 if ((ilp->lun_state &
3370                                     ISCSI_LUN_STATE_ONLINE) &&
3371                                     !(ilp->lun_state &
3372                                     ISCSI_LUN_STATE_INVALID)) {
3373                                         if (llp->ll_out_cnt <
3374                                             llp->ll_in_cnt) {
3375                                                 iscsi_if_lun_t *lp;
3376                                                 lp = &llp->ll_luns[
3377                                                     llp->ll_out_cnt];
3378 
3379                                                 lp->l_tgt_oid =
3380                                                     isp->sess_oid;
3381                                                 lp->l_oid = ilp->lun_oid;
3382                                                 lp->l_num = ilp->lun_num;
3383                                         }
3384                                 llp->ll_out_cnt++;
3385                                 }
3386                         }
3387                         rw_exit(&isp->sess_lun_list_rwlock);
3388                 }
3389                 rw_exit(&ihp->hba_sess_list_rwlock);
3390 
3391                 if (ddi_copyout(llp, (caddr_t)arg, lun_sz, mode)) {
3392                         rtn = EFAULT;
3393                 }
3394 
3395                 kmem_free(llp, lun_sz);
3396                 break;
3397 
3398         /*
3399          * ISCSI_LUN_PROPS_GET --
3400          */
3401         case ISCSI_LUN_PROPS_GET:
3402                 lun = (iscsi_lun_props_t *)kmem_zalloc(sizeof (*lun), KM_SLEEP);
3403                 if (ddi_copyin((caddr_t)arg, lun, sizeof (*lun), mode)) {
3404                         rtn = EFAULT;
3405                         kmem_free(lun, sizeof (*lun));
3406                         break;
3407                 }
3408 
3409                 if (lun->lp_vers != ISCSI_INTERFACE_VERSION) {
3410                         rtn = EINVAL;
3411                         kmem_free(lun, sizeof (*lun));
3412                         break;
3413                 }
3414 
3415                 /*
3416                  * For the target specified, find the LUN specified and
3417                  * return its properties
3418                  */
3419                 rw_enter(&ihp->hba_sess_list_rwlock, RW_READER);
3420                 rtn = iscsi_sess_get(lun->lp_tgt_oid, ihp, &isp);
3421                 if (rtn != 0) {
3422                         rw_exit(&ihp->hba_sess_list_rwlock);
3423                         rtn = EFAULT;
3424                         kmem_free(lun, sizeof (*lun));
3425                         break;
3426                 }
3427                 rtn = EINVAL;   /* Set bad rtn, correct only if found */
3428                 rw_enter(&isp->sess_lun_list_rwlock, RW_READER);
3429                 for (ilp = isp->sess_lun_list; ilp; ilp = ilp->lun_next) {
3430                         if (ilp->lun_oid == lun->lp_oid) {
3431                                 lun->lp_num  = ilp->lun_num;
3432                                 lun->lp_status       = LunValid;
3433                                 lun->lp_time_online = ilp->lun_time_online;
3434 
3435                                 if (ilp->lun_pip != NULL) {
3436                                         lun_dip = mdi_pi_get_client(
3437                                             ilp->lun_pip);
3438                                 } else {
3439                                         lun_dip = ilp->lun_dip;
3440                                 }
3441 
3442                                 if (lun_dip != NULL &&
3443                                     ((i_ddi_devi_attached(lun_dip)) ||
3444                                     (ddi_get_devstate(lun_dip) ==
3445                                     DDI_DEVSTATE_UP))) {
3446                                         (void) ddi_pathname(lun_dip,
3447                                             lun->lp_pathname);
3448                                 } else {
3449                                         /*
3450                                          * The LUN is not exported to the
3451                                          * OS yet.  It is in the process
3452                                          * of being added.
3453                                          */
3454                                         lun->lp_status       = LunDoesNotExist;
3455                                 }
3456                                 bcopy(ilp->lun_vid, lun->lp_vid,
3457                                     sizeof (lun->lp_vid));
3458                                 bcopy(ilp->lun_pid, lun->lp_pid,
3459                                     sizeof (lun->lp_pid));
3460                                 rtn = ddi_copyout(lun, (caddr_t)arg,
3461                                     sizeof (*lun), mode);
3462                                 if (rtn == -1) {
3463                                         rtn = EFAULT;
3464                                 }
3465                                 break;
3466                         }
3467                 }
3468                 rw_exit(&isp->sess_lun_list_rwlock);
3469                 rw_exit(&ihp->hba_sess_list_rwlock);
3470 
3471                 kmem_free(lun, sizeof (*lun));
3472                 break;
3473 
3474         /*
3475          * ISCSI_CONN_OID_LIST_GET --
3476          */
3477 #define ISCSIIOCOLGC iscsi_ioctl_conn_oid_list_get_copyout
3478         case ISCSI_CONN_OID_LIST_GET:
3479                 {
3480                         iscsi_conn_list_t       *cl;
3481 
3482                         /* Asuume the worst */
3483                         rtn = EFAULT;
3484 
3485                         /* Copy the input argument into kernel world. */
3486                         cl = iscsi_ioctl_conn_oid_list_get_copyin(
3487                             (caddr_t)arg,
3488                             mode);
3489                         if (cl != NULL) {
3490                                 if (iscsi_ioctl_conn_oid_list_get(ihp, cl) ==
3491                                     B_TRUE) {
3492                                         rtn =
3493                                             ISCSIIOCOLGC(
3494                                             cl, (caddr_t)arg, mode);
3495                                 }
3496                         }
3497                         break;
3498                 }
3499 #undef ISCSIIOCOLGC
3500         /*
3501          * ISCSI_CONN_OID_LIST_GET --
3502          */
3503         case ISCSI_CONN_PROPS_GET:
3504                 {
3505                         iscsi_conn_props_t      *cp;
3506 
3507                         /* Asuume the worst */
3508                         rtn = EFAULT;
3509 
3510                         /* Copy the input argument into kernel world. */
3511                         cp = iscsi_ioctl_copyin(
3512                             (caddr_t)arg,
3513                             mode,
3514                             sizeof (iscsi_conn_props_t));
3515 
3516                         if (cp != NULL) {
3517                                 /* Get the propereties. */
3518                                 if (iscsi_ioctl_conn_props_get(ihp, cp) ==
3519                                     B_TRUE) {
3520                                         rtn =
3521                                             iscsi_ioctl_copyout(
3522                                             cp,
3523                                             sizeof (*cp),
3524                                             (caddr_t)arg,
3525                                             mode);
3526                                 } else {
3527                                         kmem_free(cp, sizeof (*cp));
3528                                         cp = NULL;
3529                                 }
3530                         }
3531                         break;
3532                 }
3533 
3534         /*
3535          * ISCSI_RADIUS_GET -
3536          */
3537         case ISCSI_RADIUS_GET:
3538         {
3539                 iscsi_nvfile_status_t   status;
3540 
3541                 radius = (iscsi_radius_props_t *)kmem_zalloc(sizeof (*radius),
3542                     KM_SLEEP);
3543                 if (ddi_copyin((caddr_t)arg, radius, sizeof (*radius), mode)) {
3544                         kmem_free(radius, sizeof (*radius));
3545                         rtn = EFAULT;
3546                         break;
3547                 } else if (radius->r_vers != ISCSI_INTERFACE_VERSION) {
3548                         kmem_free(radius, sizeof (*radius));
3549                         rtn = EINVAL;
3550                         break;
3551                 }
3552 
3553                 old_oid = radius->r_oid;
3554 
3555                 if (radius->r_oid == ihp->hba_oid) {
3556                         name = ihp->hba_name;
3557                 } else {
3558                         /*
3559                          * RADIUS configuration should be done on a per
3560                          * initiator basis.
3561                          */
3562                         kmem_free(radius, sizeof (*radius));
3563                         rtn = EINVAL;
3564                         break;
3565                 }
3566 
3567                 status = persistent_radius_get(radius);
3568                 if (status == ISCSI_NVFILE_SUCCESS) {
3569                         /*
3570                          * Restore the value for overridden (and bogus) oid.
3571                          */
3572                         radius->r_oid = old_oid;
3573                         rtn = ddi_copyout(radius, (caddr_t)arg,
3574                             sizeof (*radius), mode);
3575                 } else if (status == ISCSI_NVFILE_NAMEVAL_NOT_FOUND) {
3576                         rtn = ENOENT;
3577                 } else {
3578                         rtn = EIO;
3579                 }
3580                 kmem_free(radius, sizeof (*radius));
3581                 break;
3582         }
3583 
3584         /*
3585          * ISCSI_RADIUS_SET -
3586          */
3587         case ISCSI_RADIUS_SET:
3588                 radius = (iscsi_radius_props_t *)kmem_zalloc(sizeof (*radius),
3589                     KM_SLEEP);
3590                 if (ddi_copyin((caddr_t)arg, radius, sizeof (*radius), mode)) {
3591                         rtn = EFAULT;
3592                         kmem_free(radius, sizeof (*radius));
3593                         break;
3594                 } else if (radius->r_vers != ISCSI_INTERFACE_VERSION) {
3595                         rtn = EINVAL;
3596                         kmem_free(radius, sizeof (*radius));
3597                         break;
3598                 }
3599 
3600                 if (radius->r_oid == ihp->hba_oid) {
3601                         name = ihp->hba_name;
3602                 } else {
3603                         /*
3604                          * RADIUS configuration should be done on a per
3605                          * initiator basis.
3606                          */
3607                         kmem_free(radius, sizeof (*radius));
3608                         rtn = EINVAL;
3609                         break;
3610                 }
3611 
3612                 if (persistent_radius_set(radius) == B_FALSE) {
3613                         rtn = EIO;
3614                 }
3615 
3616                 kmem_free(radius, sizeof (*radius));
3617                 break;
3618 
3619         /*
3620          *  ISCSI_AUTH_GET -
3621          */
3622         case ISCSI_AUTH_GET:
3623                 auth = (iscsi_auth_props_t *)kmem_zalloc(sizeof (*auth),
3624                     KM_SLEEP);
3625                 if (ddi_copyin((caddr_t)arg, auth, sizeof (*auth), mode)) {
3626                         kmem_free(auth, sizeof (*auth));
3627                         rtn = EFAULT;
3628                         break;
3629                 } else if (auth->a_vers != ISCSI_INTERFACE_VERSION) {
3630                         kmem_free(auth, sizeof (*auth));
3631                         rtn = EINVAL;
3632                         break;
3633                 }
3634 
3635                 old_oid = auth->a_oid;
3636 
3637                 if (auth->a_oid == ihp->hba_oid) {
3638                         name = ihp->hba_name;
3639                 } else {
3640 
3641                         rw_enter(&ihp->hba_sess_list_rwlock, RW_READER);
3642                         /*
3643                          * If the oid does represent a session check to see
3644                          * if it is a target oid.  If so, return the target's
3645                          * associated session.
3646                          */
3647                         rtn = iscsi_sess_get(auth->a_oid, ihp, &isp);
3648                         if (rtn != 0) {
3649                                 rtn = iscsi_sess_get_by_target(auth->a_oid,
3650                                     ihp, &isp);
3651                         }
3652                         rw_exit(&ihp->hba_sess_list_rwlock);
3653 
3654                         /*
3655                          * If rtn is zero then we have found an
3656                          * existing session.  Use the session name to
3657                          * do param lookup.  If rtn is non-zero then
3658                          * create a targetparam object and use its name
3659                          * for param lookup.
3660                          */
3661                         if (rtn == 0) {
3662                                 name = isp->sess_name;
3663                         } else {
3664                                 name =
3665                                     iscsi_targetparam_get_name(auth->a_oid);
3666                         }
3667                 }
3668 
3669                 if (name == NULL) {
3670                         rtn = EFAULT;
3671                         break;
3672                 }
3673 
3674                 if (persistent_auth_get((char *)name, auth) == B_TRUE) {
3675                         /*
3676                          * Restore the value for overridden (and bogus) oid.
3677                          */
3678                         auth->a_oid = old_oid;
3679                         rtn = ddi_copyout(auth, (caddr_t)arg,
3680                             sizeof (*auth), mode);
3681                 } else {
3682                         rtn = EIO;
3683                 }
3684 
3685                 kmem_free(auth, sizeof (*auth));
3686                 break;
3687 
3688         /*
3689          *  ISCSI_AUTH_SET -
3690          */
3691         case ISCSI_AUTH_SET:
3692                 auth = (iscsi_auth_props_t *)kmem_zalloc(sizeof (*auth),
3693                     KM_SLEEP);
3694                 if (ddi_copyin((caddr_t)arg, auth, sizeof (*auth), mode)) {
3695                         kmem_free(auth, sizeof (*auth));
3696                         rtn = EFAULT;
3697                         break;
3698                 } else if (auth->a_vers != ISCSI_INTERFACE_VERSION) {
3699                         kmem_free(auth, sizeof (*auth));
3700                         rtn = EINVAL;
3701                         break;
3702                 }
3703 
3704                 if (auth->a_oid == ihp->hba_oid) {
3705                         name = ihp->hba_name;
3706                 } else {
3707                         rw_enter(&ihp->hba_sess_list_rwlock, RW_READER);
3708                         /*
3709                          * If the oid does represent a session check to see
3710                          * if it is a target oid.  If so, return the target's
3711                          * associated session.
3712                          */
3713                         rtn = iscsi_sess_get(auth->a_oid, ihp, &isp);
3714                         if (rtn != 0) {
3715                                 rtn = iscsi_sess_get_by_target(auth->a_oid,
3716                                     ihp, &isp);
3717                         }
3718                         rw_exit(&ihp->hba_sess_list_rwlock);
3719 
3720                         /*
3721                          * If rtn is zero then we have found an
3722                          * existing session.  Use the session name to
3723                          * do param lookup.  If rtn is non-zero then
3724                          * create a targetparam object and use its name
3725                          * for param lookup.
3726                          */
3727                         if (rtn == 0) {
3728                                 name = isp->sess_name;
3729                         } else {
3730                                 name =
3731                                     iscsi_targetparam_get_name(auth->a_oid);
3732                                 rtn = 0;
3733                         }
3734                 }
3735 
3736                 if (name == NULL) {
3737                         rtn = EFAULT;
3738                 } else if (persistent_auth_set((char *)name, auth)
3739                     == B_FALSE) {
3740                         rtn = EIO;
3741                 }
3742 
3743                 kmem_free(auth, sizeof (*auth));
3744                 break;
3745 
3746         /*
3747          *  ISCSI_AUTH_CLEAR -
3748          */
3749         case ISCSI_AUTH_CLEAR:
3750                 auth = (iscsi_auth_props_t *)kmem_alloc(sizeof (*auth),
3751                     KM_SLEEP);
3752                 if (ddi_copyin((caddr_t)arg, auth, sizeof (*auth), mode)) {
3753                         kmem_free(auth, sizeof (*auth));
3754                         rtn = EFAULT;
3755                         break;
3756                 } else if (auth->a_vers != ISCSI_INTERFACE_VERSION) {
3757                         kmem_free(auth, sizeof (*auth));
3758                         rtn = EINVAL;
3759                         break;
3760                 }
3761 
3762                 rw_enter(&ihp->hba_sess_list_rwlock, RW_READER);
3763                 /*
3764                  * If the oid does represent a session check to see
3765                  * if it is a target oid.  If so, return the target's
3766                  * associated session.
3767                  */
3768                 rtn = iscsi_sess_get(auth->a_oid, ihp, &isp);
3769                 if (rtn != 0) {
3770                         rtn = iscsi_sess_get_by_target(auth->a_oid, ihp, &isp);
3771                 }
3772                 rw_exit(&ihp->hba_sess_list_rwlock);
3773 
3774                 /*
3775                  * If rtn is zero then we have found an
3776                  * existing session.  Use the session name to
3777                  * do param lookup.  If rtn is non-zero then
3778                  * create a targetparam object and use its name
3779                  * for param lookup.
3780                  */
3781                 if (rtn == 0) {
3782                         name = isp->sess_name;
3783                 } else {
3784                         name =
3785                             iscsi_targetparam_get_name(auth->a_oid);
3786                         rtn = 0;
3787                         discovered = B_FALSE;
3788                 }
3789 
3790                 if (name == NULL) {
3791                         rtn = EFAULT;
3792                         break;
3793                 }
3794 
3795                 if (persistent_auth_clear((char *)name) == B_FALSE) {
3796                         rtn = EIO;
3797                 }
3798 
3799                 /*
3800                  * ISCSI_TARGET_PARAM_CLEAR, ISCSI_CHAP_CLEAR and
3801                  * ISCSI_AUTH_CLEAR ioctl are called sequentially to remove
3802                  * target parameters. Here, the target that is not discovered
3803                  * by initiator should be removed from the iscsi_targets list
3804                  * residing in the memory.
3805                  */
3806                 if (discovered == B_FALSE) {
3807                         (void) iscsi_targetparam_remove_target(auth->a_oid);
3808                 }
3809 
3810                 kmem_free(auth, sizeof (*auth));
3811                 break;
3812 
3813         /*
3814          * ISCSI_DB_DUMP -
3815          */
3816         case ISCSI_DB_DUMP:
3817                 persistent_dump_data();
3818                 break;
3819 
3820         case ISCSI_USCSI:
3821 
3822 #ifdef _MULTI_DATAMODEL
3823                 model = ddi_model_convert_from(mode & FMODELS);
3824                 switch (model) {
3825                 case DDI_MODEL_ILP32:
3826 
3827                         if (ddi_copyin((caddr_t)arg, &iu32_caller,
3828                             sizeof (iscsi_uscsi32_t), mode)) {
3829                                 rtn = EFAULT;
3830                                 break;
3831                         }
3832 
3833                         /* perform conversion from 32 -> 64 */
3834                         iu_caller.iu_vers = iu32_caller.iu_vers;
3835                         iu_caller.iu_oid = iu32_caller.iu_oid;
3836                         iu_caller.iu_tpgt = iu32_caller.iu_tpgt;
3837                         iu_caller.iu_len = iu32_caller.iu_len;
3838                         iu_caller.iu_lun = iu32_caller.iu_lun;
3839                         uscsi_cmd32touscsi_cmd((&iu32_caller.iu_ucmd),
3840                             (&iu_caller.iu_ucmd));
3841 
3842                         break;
3843                 case DDI_MODEL_NONE:
3844                         if (ddi_copyin((caddr_t)arg, &iu_caller,
3845                             sizeof (iscsi_uscsi_t), mode)) {
3846                                 rtn = EFAULT;
3847                                 break;
3848                         }
3849                         break;
3850                 default:
3851                         ASSERT(FALSE);
3852                         rtn = EINVAL;
3853                         break;
3854                 }
3855 #endif /* _MULTI_DATAMODEL */
3856 
3857                 /* If failures earlier break */
3858                 if (rtn != 0) {
3859                         break;
3860                 }
3861 
3862                 /* copy from caller to internel cmd */
3863                 bcopy(&iu_caller, &iu, sizeof (iu));
3864 
3865                 if (iu.iu_vers != ISCSI_INTERFACE_VERSION) {
3866                         rtn = EINVAL;
3867                         break;
3868                 }
3869                 /*
3870                  * Check to see if oid references a target-param oid.  If so,
3871                  * find the associated  session oid before getting lu list.
3872                  */
3873                 if (iscsi_targetparam_get_name(iu.iu_oid) != NULL) {
3874                         for (isp = ihp->hba_sess_list; isp; isp =
3875                             isp->sess_next) {
3876                                 if (isp->sess_target_oid == iu.iu_oid) {
3877                                         target_oid  = isp->sess_oid;
3878                                         break;
3879                                 }
3880                         }
3881                 } else {
3882                         target_oid = iu.iu_oid;
3883                 }
3884 
3885                 /* make sure we have a matching session for this command */
3886                 rw_enter(&ihp->hba_sess_list_rwlock, RW_READER);
3887                 rtn = iscsi_sess_get(target_oid, ihp, &isp);
3888                 if (rtn != 0) {
3889                         rtn = iscsi_sess_get_by_target(target_oid, ihp,
3890                             &isp);
3891                         if (rtn != 0) {
3892                                 rw_exit(&ihp->hba_sess_list_rwlock);
3893                                 rtn = EFAULT;
3894                                 break;
3895                         }
3896                 }
3897                 /*
3898                  * If a caller buffer is present allocate duplicate
3899                  * kernel space and copyin caller memory.
3900                  */
3901                 if (iu.iu_ucmd.uscsi_buflen > 0) {
3902                         iu.iu_ucmd.uscsi_bufaddr = (caddr_t)kmem_alloc(
3903                             iu.iu_ucmd.uscsi_buflen, KM_SLEEP);
3904                         if (ddi_copyin(iu_caller.iu_ucmd.uscsi_bufaddr,
3905                             iu.iu_ucmd.uscsi_bufaddr,
3906                             iu.iu_ucmd.uscsi_buflen, mode)) {
3907                                 rw_exit(&ihp->hba_sess_list_rwlock);
3908                                 rtn = EFAULT;
3909                                 break;
3910                         }
3911                 }
3912 
3913                 /*
3914                  * If a caller cdb is present allocate duplicate
3915                  * kernel space and copyin caller memory.
3916                  */
3917                 if (iu.iu_ucmd.uscsi_cdblen > 0) {
3918                         iu.iu_ucmd.uscsi_cdb = (caddr_t)kmem_alloc(
3919                             iu_caller.iu_ucmd.uscsi_cdblen, KM_SLEEP);
3920                         if (ddi_copyin(iu_caller.iu_ucmd.uscsi_cdb,
3921                             iu.iu_ucmd.uscsi_cdb,
3922                             iu.iu_ucmd.uscsi_cdblen, mode)) {
3923                                 if (iu.iu_ucmd.uscsi_buflen > 0) {
3924                                         kmem_free(iu.iu_ucmd.uscsi_bufaddr,
3925                                             iu_caller.iu_ucmd.uscsi_buflen);
3926                                 }
3927                                 rw_exit(&ihp->hba_sess_list_rwlock);
3928                                 rtn = EFAULT;
3929                                 break;
3930                         }
3931                 }
3932 
3933                 /*
3934                  * If a caller request sense is present allocate
3935                  * duplicate kernel space.  No need to copyin.
3936                  */
3937                 if (iu.iu_ucmd.uscsi_rqlen > 0) {
3938                         iu.iu_ucmd.uscsi_rqbuf = (caddr_t)kmem_alloc(
3939                             iu.iu_ucmd.uscsi_rqlen, KM_SLEEP);
3940                 }
3941 
3942                 /* issue passthru to io path handler */
3943                 rtn = iscsi_handle_passthru(isp, iu.iu_lun, &iu.iu_ucmd);
3944                 if (rtn != 0) {
3945                         rtn = EFAULT;
3946                 }
3947 
3948                 /*
3949                  * If the caller had a buf we need to do a copyout
3950                  * and free the kernel memory
3951                  */
3952                 if (iu.iu_ucmd.uscsi_buflen > 0) {
3953                         if (ddi_copyout(iu.iu_ucmd.uscsi_bufaddr,
3954                             iu_caller.iu_ucmd.uscsi_bufaddr,
3955                             iu.iu_ucmd.uscsi_buflen, mode) != 0) {
3956                                 rtn = EFAULT;
3957                         }
3958                         kmem_free(iu.iu_ucmd.uscsi_bufaddr,
3959                             iu.iu_ucmd.uscsi_buflen);
3960                 }
3961 
3962                 /* We need to free kernel cdb, no need to copyout */
3963                 if (iu.iu_ucmd.uscsi_cdblen > 0) {
3964                         kmem_free(iu.iu_ucmd.uscsi_cdb,
3965                             iu.iu_ucmd.uscsi_cdblen);
3966                 }
3967 
3968                 /*
3969                  * If the caller had a request sense we need to
3970                  * do a copyout and free the kernel memory
3971                  */
3972                 if (iu.iu_ucmd.uscsi_rqlen > 0) {
3973                         if (ddi_copyout(iu.iu_ucmd.uscsi_rqbuf,
3974                             iu_caller.iu_ucmd.uscsi_rqbuf,
3975                             iu.iu_ucmd.uscsi_rqlen - iu.iu_ucmd.uscsi_rqresid,
3976                             mode) != 0) {
3977                                 rtn = EFAULT;
3978                         }
3979                         kmem_free(iu.iu_ucmd.uscsi_rqbuf,
3980                             iu.iu_ucmd.uscsi_rqlen);
3981                 }
3982 
3983 #ifdef _MULTI_DATAMODEL
3984                 switch (model = ddi_model_convert_from(mode & FMODELS)) {
3985                 case DDI_MODEL_ILP32:
3986                         if (iu.iu_ucmd.uscsi_status != 0) {
3987                                 iu32_caller.iu_ucmd.uscsi_status =
3988                                     iu.iu_ucmd.uscsi_status;
3989                                 iu32_caller.iu_ucmd.uscsi_rqresid =
3990                                     iu.iu_ucmd.uscsi_rqresid;
3991                         }
3992                         iu32_caller.iu_ucmd.uscsi_resid =
3993                             iu.iu_ucmd.uscsi_resid;
3994                         if (ddi_copyout((void *)&iu32_caller, (caddr_t)arg,
3995                             sizeof (iscsi_uscsi32_t), mode) != 0) {
3996                                 rtn = EFAULT;
3997                         }
3998                         break;
3999                 case DDI_MODEL_NONE:
4000                         if (iu.iu_ucmd.uscsi_status != 0) {
4001                                 iu_caller.iu_ucmd.uscsi_status =
4002                                     iu.iu_ucmd.uscsi_status;
4003                                 iu_caller.iu_ucmd.uscsi_rqresid =
4004                                     iu.iu_ucmd.uscsi_rqresid;
4005                         }
4006                         iu_caller.iu_ucmd.uscsi_resid = iu.iu_ucmd.uscsi_resid;
4007                         if (ddi_copyout((void *)&iu_caller, (caddr_t)arg,
4008                             sizeof (iscsi_uscsi_t), mode) != 0) {
4009                                 rtn = EFAULT;
4010                         }
4011                         break;
4012                 default:
4013                         ASSERT(FALSE);
4014                 }
4015 #endif /* _MULTI_DATAMODEL */
4016                 rw_exit(&ihp->hba_sess_list_rwlock);
4017                 break;
4018 
4019         case ISCSI_SMF_ONLINE:
4020                 if (ddi_copyin((caddr_t)arg, &did, sizeof (int), mode) != 0) {
4021                         rtn = EFAULT;
4022                         break;
4023                 }
4024                 /* just a theoretical case */
4025                 if (ihp->hba_persistent_loaded == B_FALSE) {
4026                         rtn = EFAULT;
4027                         break;
4028                 }
4029 
4030                 /* doesn't need to overwrite the status anymore */
4031                 mutex_enter(&ihp->hba_service_lock);
4032                 if (ihp->hba_service_status_overwrite == B_TRUE) {
4033                         ihp->hba_service_status = ISCSI_SERVICE_DISABLED;
4034                         ihp->hba_service_status_overwrite = B_FALSE;
4035                 }
4036                 mutex_exit(&ihp->hba_service_lock);
4037 
4038                 if (iscsi_enter_service_zone(ihp, ISCSI_SERVICE_ENABLED) ==
4039                     B_FALSE) {
4040                         break;
4041                 }
4042 
4043                 rval = iscsi_door_bind(did);
4044                 if (rval == B_TRUE) {
4045                         rval = iscsid_start(ihp);
4046                         if (rval == B_FALSE) {
4047                                 iscsi_door_unbind();
4048                         }
4049                 }
4050 
4051                 if (rval == B_TRUE) {
4052                         iscsi_exit_service_zone(ihp, ISCSI_SERVICE_ENABLED);
4053                 } else {
4054                         iscsi_exit_service_zone(ihp, ISCSI_SERVICE_DISABLED);
4055                         rtn = EFAULT;
4056                 }
4057 
4058                 break;
4059 
4060         case ISCSI_SMF_OFFLINE:
4061                 if (iscsi_enter_service_zone(ihp, ISCSI_SERVICE_DISABLED)
4062                     == B_FALSE) {
4063                         break;
4064                 }
4065 
4066                 rval = iscsid_stop(ihp);
4067                 iscsi_door_unbind();
4068 
4069                 iscsi_exit_service_zone(ihp, ISCSI_SERVICE_DISABLED);
4070 
4071                 if (ddi_copyout((void *)&rval, (caddr_t)arg,
4072                     sizeof (boolean_t), mode) != 0) {
4073                         rtn = EFAULT;
4074                 }
4075 
4076                 break;
4077 
4078         case ISCSI_SMF_GET:
4079                 mutex_enter(&ihp->hba_service_lock);
4080                 while (ihp->hba_service_status ==
4081                     ISCSI_SERVICE_TRANSITION) {
4082                         cv_wait(&ihp->hba_service_cv,
4083                             &ihp->hba_service_lock);
4084                 }
4085                 if (ddi_copyout((void *)&ihp->hba_service_status,
4086                     (caddr_t)arg, sizeof (boolean_t), mode) != 0) {
4087                         rtn = EFAULT;
4088                 }
4089                 mutex_exit(&ihp->hba_service_lock);
4090                 break;
4091 
4092         case ISCSI_DISCOVERY_EVENTS:
4093                 /*
4094                  * If discovery has not been completed and not in progress,
4095                  * poke the discovery methods
4096                  */
4097                 mutex_enter(&ihp->hba_discovery_events_mutex);
4098                 method = ihp->hba_discovery_events;
4099                 if ((method != ISCSI_ALL_DISCOVERY_METHODS) &&
4100                     (ihp->hba_discovery_in_progress == B_FALSE)) {
4101                         ihp->hba_discovery_in_progress = B_TRUE;
4102                         mutex_exit(&ihp->hba_discovery_events_mutex);
4103                         iscsid_poke_discovery(ihp, iSCSIDiscoveryMethodUnknown);
4104                         mutex_enter(&ihp->hba_discovery_events_mutex);
4105                         ihp->hba_discovery_in_progress = B_FALSE;
4106                         method = ihp->hba_discovery_events;
4107                 }
4108                 mutex_exit(&ihp->hba_discovery_events_mutex);
4109 
4110                 if (ddi_copyout((void *)&method, (caddr_t)arg,
4111                     sizeof (method), mode) != 0)
4112                         rtn = EFAULT;
4113                 break;
4114 
4115         /*
4116          * ISCSI_SENDTGTS_GET --
4117          */
4118         case ISCSI_SENDTGTS_GET:
4119                 stl_hdr = iscsi_ioctl_copyin((caddr_t)arg, mode,
4120                     sizeof (*stl_hdr));
4121                 if (stl_hdr == NULL) {
4122                         rtn = EFAULT;
4123                         break;
4124                 }
4125 
4126                 if (stl_hdr->stl_entry.e_vers != ISCSI_INTERFACE_VERSION) {
4127                         rtn = EINVAL;
4128                         kmem_free(stl_hdr, sizeof (*stl_hdr));
4129                         break;
4130                 }
4131 
4132                 /* calculate how much memory user allocated for SendTgts */
4133                 stl_sz = sizeof (*stl_hdr);
4134                 if (stl_hdr->stl_in_cnt > 0) {
4135                         stl_sz += ((stl_hdr->stl_in_cnt - 1) *
4136                             sizeof (iscsi_sendtgts_entry_t));
4137                 }
4138 
4139                 /* allocate local SendTgts list of the same size */
4140                 istl = kmem_zalloc(stl_sz, KM_SLEEP);
4141                 bcopy(stl_hdr, istl, sizeof (*stl_hdr));
4142                 kmem_free(stl_hdr, sizeof (*stl_hdr));
4143 
4144                 /* lock interface so only one SendTargets operation occurs */
4145                 sema_p(&ihp->hba_sendtgts_semaphore);
4146 
4147                 rtn = iscsi_ioctl_sendtgts_get(ihp, istl);
4148 
4149                 if (rtn == 0) {
4150                         rtn = iscsi_ioctl_copyout(istl, stl_sz,
4151                             (caddr_t)arg, mode);
4152                 }
4153 
4154                 /* release lock to allow another SendTargets discovery */
4155                 sema_v(&ihp->hba_sendtgts_semaphore);
4156 
4157                 break;
4158 
4159                 /*
4160                  * ISCSI_ISNS_SERVER_GET --
4161                  */
4162         case ISCSI_ISNS_SERVER_GET:
4163                 server_pg_list_hdr = iscsi_ioctl_copyin((caddr_t)arg, mode,
4164                     sizeof (*server_pg_list_hdr));
4165                 if (server_pg_list_hdr == NULL) {
4166                         rtn = EFAULT;
4167                         break;
4168                 }
4169 
4170                 /* If iSNS discovery mode is not set, return with zero entry */
4171                 method = persistent_disc_meth_get();
4172                 if ((method & iSCSIDiscoveryMethodISNS) == 0) {
4173                         kmem_free(server_pg_list_hdr,
4174                             sizeof (*server_pg_list_hdr));
4175                         server_pg_list_hdr = NULL;
4176                         rtn = EACCES;
4177                         break;
4178                 }
4179 
4180                 initiator_node_name = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP);
4181                 if (persistent_initiator_name_get(initiator_node_name,
4182                     ISCSI_MAX_NAME_LEN) != B_TRUE) {
4183                         kmem_free(initiator_node_name, ISCSI_MAX_NAME_LEN);
4184                         initiator_node_name = NULL;
4185                         kmem_free(server_pg_list_hdr,
4186                             sizeof (*server_pg_list_hdr));
4187                         server_pg_list_hdr = NULL;
4188                         rtn = EIO;
4189                         break;
4190                 }
4191                 if (strlen(initiator_node_name) == 0) {
4192                         kmem_free(initiator_node_name, ISCSI_MAX_NAME_LEN);
4193                         initiator_node_name = NULL;
4194                         kmem_free(server_pg_list_hdr,
4195                             sizeof (*server_pg_list_hdr));
4196                         server_pg_list_hdr = NULL;
4197                         rtn = EIO;
4198                         break;
4199                 }
4200 
4201                 initiator_node_alias = kmem_zalloc(
4202                     ISCSI_MAX_NAME_LEN, KM_SLEEP);
4203                 if (persistent_alias_name_get(initiator_node_alias,
4204                     ISCSI_MAX_NAME_LEN) != B_TRUE) {
4205                         initiator_node_alias[0] = '\0';
4206                 }
4207                 rtn = isns_query_one_server(&(server_pg_list_hdr->addr),
4208                     ihp->hba_isid,
4209                     (uint8_t *)initiator_node_name,
4210                     (uint8_t *)initiator_node_alias,
4211                     ISNS_INITIATOR_NODE_TYPE,
4212                     &pg_list);
4213                 if (rtn != isns_ok || pg_list == NULL) {
4214                         kmem_free(initiator_node_name, ISCSI_MAX_NAME_LEN);
4215                         initiator_node_name = NULL;
4216                         kmem_free(initiator_node_alias, ISCSI_MAX_NAME_LEN);
4217                         initiator_node_alias = NULL;
4218                         kmem_free(server_pg_list_hdr,
4219                             sizeof (*server_pg_list_hdr));
4220                         server_pg_list_hdr = NULL;
4221                         rtn = EIO;
4222                         break;
4223                 }
4224 
4225                 /*
4226                  * pg_list_sz is the size of the pg_list returned from the
4227                  *      isns_query_all
4228                  *
4229                  * pg_sz_copy_out is the size of the pg_list we are going to
4230                  *      return back to the caller
4231                  *
4232                  * server_pg_list_sz is total amount of data we are returning
4233                  *      back to the caller
4234                  */
4235                 pg_list->pg_in_cnt =
4236                     server_pg_list_hdr->addr_port_list.pg_in_cnt;
4237                 pg_list_sz = sizeof (isns_portal_group_list_t);
4238                 if (pg_list->pg_out_cnt > 0) {
4239                         pg_list_sz += (pg_list->pg_out_cnt - 1) *
4240                             sizeof (isns_portal_group_t);
4241                 }
4242                 /*
4243                  * check if caller passed in a buffer with enough space
4244                  * if there isn't enough space, fill the caller's buffer with
4245                  * as much information as possible.
4246                  *
4247                  * if pg_out_cnt > pg_in_cnt, pg_out_cnt will be returned with
4248                  * the total number of targets found
4249                  *
4250                  * if pg_out_cnt < pg_in_cnt, pg_out_cnt will be the number
4251                  * of targets returned
4252                  */
4253                 if (pg_list->pg_in_cnt < pg_list->pg_out_cnt) {
4254                         pg_sz_copy_out = sizeof (isns_portal_group_list_t);
4255                         if (pg_list->pg_in_cnt > 0) {
4256                                 pg_sz_copy_out += (pg_list->pg_in_cnt - 1) *
4257                                     sizeof (isns_portal_group_t);
4258                         }
4259                         server_pg_list_sz =
4260                             sizeof (isns_server_portal_group_list_t);
4261                         if (pg_list->pg_in_cnt > 0) {
4262                                 server_pg_list_sz += (pg_list->pg_in_cnt - 1) *
4263                                     sizeof (isns_portal_group_t);
4264                         }
4265                 } else {
4266                         pg_sz_copy_out = pg_list_sz;
4267                         server_pg_list_sz =
4268                             sizeof (isns_server_portal_group_list_t);
4269                         if (pg_list->pg_out_cnt > 0) {
4270                                 server_pg_list_sz += (pg_list->pg_out_cnt - 1) *
4271                                     sizeof (isns_portal_group_t);
4272                         }
4273                 }
4274 
4275                 server_pg_list = (isns_server_portal_group_list_t *)kmem_zalloc(
4276                     server_pg_list_sz, KM_SLEEP);
4277 
4278                 bcopy(&(server_pg_list_hdr->addr), &(server_pg_list->addr),
4279                     sizeof (server_pg_list->addr));
4280                 bcopy(pg_list, &server_pg_list->addr_port_list, pg_sz_copy_out);
4281 
4282                 if (ddi_copyout(server_pg_list, (caddr_t)arg, server_pg_list_sz,
4283                     mode) != 0) {
4284                         rtn = EFAULT;
4285                 }
4286                 DTRACE_PROBE1(iscsi_ioctl_iscsi_isns_server_get_pg_sz,
4287                     int, pg_list_sz);
4288                 kmem_free(initiator_node_name, ISCSI_MAX_NAME_LEN);
4289                 initiator_node_name = NULL;
4290                 kmem_free(initiator_node_alias, ISCSI_MAX_NAME_LEN);
4291                 initiator_node_alias = NULL;
4292                 kmem_free(pg_list, pg_list_sz);
4293                 pg_list = NULL;
4294                 kmem_free(server_pg_list, server_pg_list_sz);
4295                 server_pg_list = NULL;
4296                 kmem_free(server_pg_list_hdr, sizeof (*server_pg_list_hdr));
4297                 server_pg_list_hdr = NULL;
4298                 break;
4299 
4300         /*
4301          * ISCSI_GET_CONFIG_SESSIONS --
4302          */
4303         case ISCSI_GET_CONFIG_SESSIONS:
4304                 /* FALLTHRU */
4305 
4306         case ISCSI_SET_CONFIG_SESSIONS:
4307                 size = sizeof (*ics);
4308                 ics = iscsi_ioctl_copyin((caddr_t)arg, mode, size);
4309                 if (ics == NULL) {
4310                         rtn = EFAULT;
4311                         break;
4312                 }
4313 
4314                 /* verify version infomration */
4315                 if (ics->ics_ver != ISCSI_INTERFACE_VERSION) {
4316                         rtn = EINVAL;
4317                         kmem_free(ics, size);
4318                         ics = NULL;
4319                         break;
4320                 }
4321 
4322                 /* Check to see if we need to copy in more memory */
4323                 if (ics->ics_in > 1) {
4324                         /* record correct size */
4325                         size = ISCSI_SESSION_CONFIG_SIZE(ics->ics_in);
4326                         /* free old buffer */
4327                         kmem_free(ics, sizeof (*ics));
4328 
4329                         /* copy in complete buffer size */
4330                         ics = iscsi_ioctl_copyin((caddr_t)arg, mode, size);
4331                         if (ics == NULL) {
4332                                 rtn = EFAULT;
4333                                 break;
4334                         }
4335                 }
4336 
4337                 /* switch action based on get or set */
4338                 if (cmd == ISCSI_GET_CONFIG_SESSIONS) {
4339                         /* get */
4340                         rtn = iscsi_ioctl_get_config_sess(ihp, ics);
4341                         if (rtn == 0) {
4342                                 /* copyout data for gets */
4343                                 rtn = iscsi_ioctl_copyout(ics, size,
4344                                     (caddr_t)arg, mode);
4345                         } else {
4346                                 kmem_free(ics, size);
4347                                 ics = NULL;
4348                         }
4349                 } else {
4350                         /* set */
4351                         rtn = iscsi_ioctl_set_config_sess(ihp, ics);
4352                         if (iscsiboot_prop) {
4353                                 if (iscsi_cmp_boot_sess_oid(ihp,
4354                                     ics->ics_oid)) {
4355                                         /*
4356                                          * found active session for this object
4357                                          * or this is initiator object
4358                                          * with mpxio enabled
4359                                          */
4360                                         if (!iscsi_reconfig_boot_sess(ihp)) {
4361                                                 kmem_free(ics, size);
4362                                                 ics = NULL;
4363                                                 rtn = EINVAL;
4364                                                 break;
4365                                         }
4366                                 }
4367                         }
4368                         kmem_free(ics, size);
4369                         ics = NULL;
4370                 }
4371                 break;
4372 
4373         case ISCSI_IS_ACTIVE:
4374                 /*
4375                  * dhcpagent calls here to check if there are
4376                  * active iSCSI sessions
4377                  */
4378                 instance = 0;
4379                 if (iscsiboot_prop) {
4380                         instance = 1;
4381                 }
4382                 if (!instance) {
4383                         rw_enter(&ihp->hba_sess_list_rwlock,
4384                             RW_READER);
4385                         for (isp = ihp->hba_sess_list; isp;
4386                             isp = isp->sess_next) {
4387                                 if ((isp->sess_state ==
4388                                     ISCSI_SESS_STATE_LOGGED_IN) &&
4389                                     (isp->sess_lun_list !=
4390                                     NULL)) {
4391                                         instance = 1;
4392                                         break;
4393                                 }
4394                         }
4395                         rw_exit(&ihp->hba_sess_list_rwlock);
4396                 }
4397                 size = sizeof (instance);
4398                 if (ddi_copyout(&instance, (caddr_t)arg, size,
4399                     mode) != 0) {
4400                         rtn = EFAULT;
4401                 }
4402                 break;
4403 
4404         case ISCSI_BOOTPROP_GET:
4405                 size = sizeof (*bootProp);
4406                 bootProp = iscsi_ioctl_copyin((caddr_t)arg, mode, size);
4407                 if (bootProp == NULL) {
4408                         rtn = EFAULT;
4409                         break;
4410                 }
4411                 bootProp->hba_mpxio_enabled =
4412                     iscsi_chk_bootlun_mpxio(ihp);
4413                 if (iscsiboot_prop == NULL) {
4414                         bootProp->iscsiboot = 0;
4415                         rtn = iscsi_ioctl_copyout(bootProp, size,
4416                             (caddr_t)arg, mode);
4417                         break;
4418                 } else {
4419                         bootProp->iscsiboot = 1;
4420                 }
4421 
4422                 if (iscsiboot_prop->boot_init.ini_name != NULL) {
4423                         (void) strncpy((char *)bootProp->ini_name.n_name,
4424                             (char *)iscsiboot_prop->boot_init.ini_name,
4425                             ISCSI_MAX_NAME_LEN);
4426                 }
4427                 if (iscsiboot_prop->boot_init.ini_chap_name != NULL) {
4428                         bootProp->auth.a_auth_method = authMethodCHAP;
4429                         (void) strncpy((char *)bootProp->ini_chap.c_user,
4430                             (char *)iscsiboot_prop->boot_init.ini_chap_name,
4431                             ISCSI_MAX_NAME_LEN);
4432                         (void) strncpy((char *)bootProp->ini_chap.c_secret,
4433                             (char *)iscsiboot_prop->boot_init.ini_chap_sec,
4434                             ISCSI_CHAP_SECRET_LEN);
4435                         if (iscsiboot_prop->boot_tgt.tgt_chap_name !=
4436                             NULL) {
4437                                 bootProp->auth.a_bi_auth = B_TRUE;
4438                         } else {
4439                                 bootProp->auth.a_bi_auth = B_FALSE;
4440                         }
4441                 }
4442                 if (iscsiboot_prop->boot_tgt.tgt_name != NULL) {
4443                         (void) strncpy((char *)bootProp->tgt_name.n_name,
4444                             (char *)iscsiboot_prop->boot_tgt.tgt_name,
4445                             ISCSI_MAX_NAME_LEN);
4446                 }
4447                 if (iscsiboot_prop->boot_tgt.tgt_chap_name != NULL) {
4448                         (void) strncpy((char *)bootProp->tgt_chap.c_user,
4449                             (char *)iscsiboot_prop->boot_tgt.tgt_chap_name,
4450                             ISCSI_MAX_NAME_LEN);
4451                         (void) strncpy((char *)bootProp->tgt_chap.c_secret,
4452                             (char *)iscsiboot_prop->boot_tgt.tgt_chap_sec,
4453                             ISCSI_CHAP_SECRET_LEN);
4454                 }
4455 
4456                 rtn = iscsi_ioctl_copyout(bootProp, size, (caddr_t)arg, mode);
4457                 break;
4458 
4459         case ISCSI_TARGET_REENUM:
4460                 size = sizeof (iscsi_reen_t);
4461                 reenum = (iscsi_reen_t *)kmem_alloc(size, KM_SLEEP);
4462 
4463                 if (ddi_copyin((caddr_t)arg, reenum, size, mode) != 0) {
4464                         rtn = EFAULT;
4465                         kmem_free(reenum, size);
4466                         break;
4467                 }
4468                 if (reenum->re_ver != ISCSI_INTERFACE_VERSION) {
4469                         rtn = EINVAL;
4470                         kmem_free(reenum, size);
4471                         break;
4472                 }
4473                 rw_enter(&ihp->hba_sess_list_rwlock, RW_READER);
4474                 rtn = iscsi_sess_get(reenum->re_oid, ihp, &isp);
4475                 if (rtn != 0) {
4476                         rtn = iscsi_sess_get_by_target(
4477                             reenum->re_oid, ihp, &isp);
4478                 }
4479 
4480                 if (rtn != 0) {
4481                         rw_exit(&ihp->hba_sess_list_rwlock);
4482                         kmem_free(reenum, size);
4483                         break;
4484                 }
4485                 kmem_free(reenum, size);
4486                 if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
4487                         rw_enter(&isp->sess_state_rwlock, RW_READER);
4488                         if ((isp->sess_state ==
4489                             ISCSI_SESS_STATE_LOGGED_IN) &&
4490                             (iscsi_sess_enum_request(isp, B_TRUE,
4491                             isp->sess_state_event_count)
4492                             == ISCSI_SESS_ENUM_SUBMITTED)) {
4493                                 (void) iscsi_sess_enum_query(isp);
4494                         }
4495                         rw_exit(&isp->sess_state_rwlock);
4496                 }
4497                 rw_exit(&ihp->hba_sess_list_rwlock);
4498                 break;
4499 
4500         case ISCSI_TUNABLE_PARAM_SET:
4501                 tpss = (iscsi_tunable_object_t *)kmem_alloc(sizeof (*tpss),
4502                     KM_SLEEP);
4503                 if (ddi_copyin((caddr_t)arg, tpss, sizeof (*tpss), mode)) {
4504                         rtn = EFAULT;
4505                         kmem_free(tpss, sizeof (*tpss));
4506                         break;
4507                 }
4508                 rtn = iscsi_ioctl_set_tunable_param(ihp, tpss);
4509                 kmem_free(tpss, sizeof (*tpss));
4510                 break;
4511 
4512         case ISCSI_TUNABLE_PARAM_GET:
4513                 tpsg = (iscsi_tunable_object_t *)kmem_alloc(sizeof (*tpsg),
4514                     KM_SLEEP);
4515                 if (ddi_copyin((caddr_t)arg, tpsg, sizeof (*tpsg), mode)) {
4516                         rtn = EFAULT;
4517                         kmem_free(tpsg, sizeof (*tpsg));
4518                         break;
4519                 }
4520                 if (tpsg->t_oid == ihp->hba_oid) {
4521                         /* initiator */
4522                         name = ihp->hba_name;
4523                         if (iscsi_get_persisted_tunable_param((uchar_t *)name,
4524                             tpsg) == 1) {
4525                                 /*
4526                                  * no persisted tunable parameters found
4527                                  * for iscsi initiator, use default tunable
4528                                  * params for initiator node.
4529                                  */
4530                                 iscsi_get_tunable_default(tpsg);
4531                         }
4532                 } else {
4533                         /* check whether it is a target oid */
4534                         name = iscsi_targetparam_get_name(tpsg->t_oid);
4535                         if (name == NULL) {
4536                                 /* invalid node name */
4537                                 rtn = EINVAL;
4538                                 kmem_free(tpsg, sizeof (*tpsg));
4539                                 break;
4540                         }
4541                         if (iscsi_get_persisted_tunable_param((uchar_t *)name,
4542                             tpsg) == 1) {
4543                                 /*
4544                                  * no persisted tunable parameters found for
4545                                  * iscsi target, use initiator's configure.
4546                                  */
4547                                 if (iscsi_get_persisted_tunable_param(
4548                                     (uchar_t *)ihp->hba_name, tpsg) == -1) {
4549                                         /*
4550                                          * No initiator tunable parameters set
4551                                          * use default value for target
4552                                          */
4553                                         iscsi_get_tunable_default(tpsg);
4554                                 }
4555                         }
4556                 }
4557 
4558                 if (ddi_copyout(tpsg, (caddr_t)arg,
4559                     sizeof (iscsi_tunable_object_t), mode) != 0) {
4560                         rtn = EFAULT;
4561                 }
4562                 kmem_free(tpsg, sizeof (*tpsg));
4563                 break;
4564 
4565         default:
4566                 rtn = ENOTTY;
4567                 cmn_err(CE_NOTE, "unrecognized ioctl 0x%x", cmd);
4568         } /* end of ioctl type switch/cases */
4569 
4570         if ((cmd != ISCSI_SMF_ONLINE) && (cmd != ISCSI_SMF_OFFLINE) &&
4571             (cmd != ISCSI_SMF_GET)) {
4572                 /* other cmds need to release the service */
4573                 iscsi_client_release_service(ihp);
4574         }
4575 
4576         return (rtn);
4577 }
4578 
4579 /*
4580  * +--------------------------------------------------------------------+
4581  * | End of cb_ops routines                                          |
4582  * +--------------------------------------------------------------------+
4583  */
4584 
4585 
4586 /*
4587  * +--------------------------------------------------------------------+
4588  * | Common scsi_tran support routines                            |
4589  * +--------------------------------------------------------------------+
4590  */
4591 
4592 /*
4593  * iscsi_i_commoncap -- SCSA host adapter get/set capability routines.
4594  *
4595  * Need to determine if any of these can be determined through the iSCSI
4596  * protocol. For now just return error on most.
4597  */
4598 /* ARGSUSED */
4599 static int
4600 iscsi_i_commoncap(struct scsi_address *ap, char *cap, int val,
4601     int tgtonly, int doset)
4602 {
4603         int             rtn;
4604         int             cidx;
4605         iscsi_lun_t     *ilp;
4606 
4607         ASSERT((ap)->a_hba_tran->tran_hba_private != NULL);
4608         ilp     = (iscsi_lun_t *)((ap)->a_hba_tran->tran_tgt_private);
4609         ASSERT(ilp != NULL);
4610 
4611         if (cap == (char *)0) {
4612                 return (FALSE);
4613         }
4614 
4615         cidx = scsi_hba_lookup_capstr(cap);
4616         if (cidx == -1) {
4617                 return (cidx);
4618         }
4619 
4620         /*
4621          * Process setcap request.
4622          */
4623         if (doset) {
4624                 /*
4625                  * At present, we can only set binary (0/1) values
4626                  */
4627                 switch (cidx) {
4628                 case SCSI_CAP_LUN_RESET:
4629                         if (val) {
4630                                 ilp->lun_cap |= ISCSI_LUN_CAP_RESET;
4631                         } else {
4632                                 ilp->lun_cap &= ~ISCSI_LUN_CAP_RESET;
4633                         }
4634                         rtn = TRUE;
4635                         break;
4636                 default:
4637                         /*
4638                          * None of these are settable via
4639                          * the capability interface.
4640                          */
4641                         rtn = FALSE;
4642                         break;
4643                 }
4644 
4645                 /*
4646                  * Process getcap request.
4647                  */
4648         } else {
4649                 switch (cidx) {
4650                 case SCSI_CAP_DMA_MAX:
4651                         /* no DMA, Psuedo value */
4652                         rtn = INT32_MAX;
4653                         break;
4654                 case SCSI_CAP_INITIATOR_ID:
4655                         rtn = 7;
4656                         break;
4657                 case SCSI_CAP_ARQ:
4658                 case SCSI_CAP_RESET_NOTIFICATION:
4659                 case SCSI_CAP_TAGGED_QING:
4660                         rtn = TRUE;
4661                         break;
4662                 case SCSI_CAP_SCSI_VERSION:
4663                         rtn = SCSI_VERSION_3;
4664                         break;
4665                 case SCSI_CAP_INTERCONNECT_TYPE:
4666                         rtn = INTERCONNECT_FABRIC;
4667                         break;
4668                 case SCSI_CAP_LUN_RESET:
4669                         rtn = ((ilp->lun_cap & ISCSI_LUN_CAP_RESET) != 0) ?
4670                             TRUE : FALSE;
4671                         break;
4672                 case SCSI_CAP_CDB_LEN:
4673                         /*
4674                          * iSCSI RFC 3720 defines a default 16 byte
4675                          * CDB as part of the Basic Header Segment
4676                          * (BHS) (10.2.1) and allows for an Additional
4677                          * Header Segment (AHS) Length of 255 * 4
4678                          * (10.2.1.5).  The AHS length can be used
4679                          * for different purposes two of which are
4680                          * Extended CDB ADS (10.2.2.3) and Bidirectional
4681                          * Expected Read-Data Length AHS (10.2.2.4).
4682                          * The largest header of these consumes is
4683                          * 32 bytes.  So the total Max CDB Length is
4684                          * 16 + ((255 * 4 ) - 32) = 1004.
4685                          */
4686                         rtn = 1004;
4687                         break;
4688                 default:
4689                         rtn = UNDEFINED;
4690                         break;
4691                 }
4692         }
4693         return (rtn);
4694 }
4695 
4696 /*
4697  * iscsi_virt_lun_init - attempts to complete a mdi/scsi_vhci binding
4698  *
4699  * This routine is used to associate the tran_tgt_private to our ilp
4700  * structure.  This function is indirectly called from our
4701  * iscsi_lun_create_xxx routines.  These routines must prevent
4702  * the session and lun lists from changing during this call.
4703  */
4704 /* ARGSUSED */
4705 static int
4706 iscsi_virt_lun_init(dev_info_t *hba_dip, dev_info_t *lun_dip,
4707     scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
4708 {
4709         iscsi_lun_t     *ilp            = NULL;
4710         iscsi_lun_t     *ilp_check      = NULL;
4711         iscsi_sess_t    *isp            = NULL;
4712         char            *lun_guid       = NULL;
4713         mdi_pathinfo_t  *pip            = NULL;
4714         iscsi_hba_t     *ihp    = (iscsi_hba_t *)hba_tran->tran_hba_private;
4715         char            target_port_name[MAX_NAME_PROP_SIZE];
4716 
4717         /*
4718          * Here's a nice little piece of undocumented stuff.
4719          */
4720         if ((pip = (mdi_pathinfo_t *)sd->sd_private) == NULL) {
4721                 /*
4722                  * Very bad news if this occurs. Somehow SCSI_vhci has
4723                  * lost the pathinfo node for this target.
4724                  */
4725                 return (DDI_NOT_WELL_FORMED);
4726         }
4727 
4728         ilp = (iscsi_lun_t *)mdi_pi_get_phci_private(pip);
4729 
4730         /*
4731          * +----------------------------------------------------+
4732          * | Looking to find the target device via the property |
4733          * | is not required since the driver can easily get    |
4734          * | this information from the mdi_phci_get_private()   |
4735          * | call above.  This is just a consistency check      |
4736          * | which can be removed.                              |
4737          */
4738         if (mdi_prop_lookup_string(pip, MDI_GUID, &lun_guid) !=
4739             DDI_PROP_SUCCESS) {
4740                 return (DDI_NOT_WELL_FORMED);
4741         }
4742 
4743         for (isp = ihp->hba_sess_list; isp; isp = isp->sess_next) {
4744 
4745                 /* If this isn't the matching session continue */
4746                 if (ilp->lun_sess != isp) {
4747                         continue;
4748                 }
4749 
4750                 /*
4751                  * We are already holding the lun list rwlock
4752                  * for this thread on the callers side of mdi_pi_online
4753                  * or ndi_devi_online.  Which lead to this functions
4754                  * call.
4755                  */
4756                 for (ilp_check = isp->sess_lun_list; ilp_check;
4757                     ilp_check = ilp_check->lun_next) {
4758 
4759                         /*
4760                          * If this is the matching LUN and contains
4761                          * the same LUN GUID then break we found our
4762                          * match.
4763                          */
4764                         if ((ilp == ilp_check) &&
4765                             (strcmp(lun_guid, ilp_check->lun_guid) == 0)) {
4766                                 break;
4767                         }
4768                 }
4769                 if (ilp_check != NULL) {
4770                         break;
4771                 }
4772         }
4773 
4774         /*
4775          * Free resource that's no longer required.
4776          */
4777         if (lun_guid != NULL)
4778                 (void) mdi_prop_free(lun_guid);
4779 
4780         if (ilp_check == NULL) {
4781                 /*
4782                  * Failed to find iSCSI LUN in HBA chain based
4783                  * on the GUID that was stored as a property on
4784                  * the pathinfo node.
4785                  */
4786                 return (DDI_NOT_WELL_FORMED);
4787         }
4788 
4789         if (ilp != ilp_check) {
4790                 /*
4791                  * The iSCSI target that we found on the HBA link is
4792                  * different than the iSCSI target that was stored as
4793                  * private data on the pathinfo node.
4794                  */
4795                 return (DDI_NOT_WELL_FORMED);
4796         }
4797         /*
4798          * | End of consistency check                           |
4799          * +----------------------------------------------------+
4800          */
4801 
4802         hba_tran->tran_tgt_private = ilp;
4803 
4804         target_port_name[0] = '\0';
4805         if (ilp->lun_sess->sess_tpgt_conf == ISCSI_DEFAULT_TPGT) {
4806                 (void) snprintf(target_port_name, MAX_NAME_PROP_SIZE,
4807                     "%02x%02x%02x%02x%02x%02x,%s",
4808                     ilp->lun_sess->sess_isid[0], ilp->lun_sess->sess_isid[1],
4809                     ilp->lun_sess->sess_isid[2], ilp->lun_sess->sess_isid[3],
4810                     ilp->lun_sess->sess_isid[4], ilp->lun_sess->sess_isid[5],
4811                     ilp->lun_sess->sess_name);
4812         } else {
4813                 (void) snprintf(target_port_name, MAX_NAME_PROP_SIZE,
4814                     "%02x%02x%02x%02x%02x%02x,%s,%d",
4815                     ilp->lun_sess->sess_isid[0], ilp->lun_sess->sess_isid[1],
4816                     ilp->lun_sess->sess_isid[2], ilp->lun_sess->sess_isid[3],
4817                     ilp->lun_sess->sess_isid[4], ilp->lun_sess->sess_isid[5],
4818                     ilp->lun_sess->sess_name, ilp->lun_sess->sess_tpgt_conf);
4819         }
4820 
4821         if (mdi_prop_update_string(pip,
4822             SCSI_ADDR_PROP_TARGET_PORT, target_port_name) != DDI_PROP_SUCCESS) {
4823                 cmn_err(CE_WARN, "iscsi_virt_lun_init: Creating '"
4824                     SCSI_ADDR_PROP_TARGET_PORT "' property on Path(%p) "
4825                     "for Target(%s), Lun(%d) Failed",
4826                     (void *)pip, ilp->lun_sess->sess_name, ilp->lun_num);
4827         }
4828 
4829         return (DDI_SUCCESS);
4830 }
4831 
4832 /*
4833  * iscsi_phys_lun_init - attempts to complete a ndi binding
4834  *
4835  * This routine is used to associate the tran_tgt_private to our
4836  * ilp structure.  This function is indirectly called from our
4837  * iscsi_lun_create_xxx routines.  These routines must prevent
4838  * the session and lun lists from changing during this call.
4839  */
4840 static int
4841 iscsi_phys_lun_init(dev_info_t *hba_dip, dev_info_t *lun_dip,
4842     scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
4843 {
4844         int             rtn     = DDI_SUCCESS;
4845         iscsi_hba_t     *ihp    = NULL;
4846         iscsi_sess_t    *isp    = NULL;
4847         iscsi_lun_t     *ilp    = NULL;
4848         char            target_port_name[MAX_NAME_PROP_SIZE];
4849         int             *words = NULL;
4850         uint_t          nwords = 0;
4851 
4852         ASSERT(hba_dip);
4853         ASSERT(lun_dip);
4854         ASSERT(hba_tran);
4855         ASSERT(sd);
4856         ihp = (iscsi_hba_t *)hba_tran->tran_hba_private;
4857         ASSERT(ihp);
4858 
4859         if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, lun_dip,
4860             DDI_PROP_DONTPASS, LUN_PROP, &words, &nwords) != DDI_PROP_SUCCESS) {
4861                 cmn_err(CE_WARN, "iscsi_phys_lun_init: Returning DDI_FAILURE:"
4862                     "lun for %s (instance %d)", ddi_get_name(lun_dip),
4863                     ddi_get_instance(lun_dip));
4864                 return (DDI_FAILURE);
4865         }
4866 
4867         if (nwords == 0) {
4868                 ddi_prop_free(words);
4869                 return (DDI_FAILURE);
4870         }
4871 
4872         ASSERT(words != NULL);
4873 
4874         /* See if we already created this session */
4875 
4876         /* Walk the HBA's session list */
4877         for (isp = ihp->hba_sess_list; isp; isp = isp->sess_next) {
4878                 /* compare target name as the unique identifier */
4879                 if (sd->sd_address.a_target == isp->sess_oid) {
4880                         /* found match */
4881                         break;
4882                 }
4883         }
4884 
4885         /* If we found matching session continue searching for tgt */
4886         if (isp != NULL) {
4887                 /*
4888                  * Search for the matching iscsi lun structure.  We don't
4889                  * need to hold the READER for the lun list at this point.
4890                  * because the tran_get_name is being called from the online
4891                  * function which is already holding a reader on the lun
4892                  * list.
4893                  */
4894                 for (ilp = isp->sess_lun_list; ilp; ilp = ilp->lun_next) {
4895                         if (*words == ilp->lun_num) {
4896                                 /* found match */
4897                                 break;
4898                         }
4899                 }
4900 
4901                 if (ilp != NULL) {
4902                         /*
4903                          * tgt found path it to the tran_lun_private
4904                          * this is used later for fast access on
4905                          * init_pkt and start
4906                          */
4907                         hba_tran->tran_tgt_private = ilp;
4908                 } else {
4909                         /* tgt not found */
4910                         ddi_prop_free(words);
4911                         return (DDI_FAILURE);
4912                 }
4913         } else {
4914                 /* sess not found */
4915                 ddi_prop_free(words);
4916                 return (DDI_FAILURE);
4917         }
4918         ddi_prop_free(words);
4919 
4920         target_port_name[0] = '\0';
4921         if (ilp->lun_sess->sess_tpgt_conf == ISCSI_DEFAULT_TPGT) {
4922                 (void) snprintf(target_port_name, MAX_NAME_PROP_SIZE,
4923                     "%02x%02x%02x%02x%02x%02x,%s",
4924                     ilp->lun_sess->sess_isid[0], ilp->lun_sess->sess_isid[1],
4925                     ilp->lun_sess->sess_isid[2], ilp->lun_sess->sess_isid[3],
4926                     ilp->lun_sess->sess_isid[4], ilp->lun_sess->sess_isid[5],
4927                     ilp->lun_sess->sess_name);
4928         } else {
4929                 (void) snprintf(target_port_name, MAX_NAME_PROP_SIZE,
4930                     "%02x%02x%02x%02x%02x%02x,%s,%d",
4931                     ilp->lun_sess->sess_isid[0], ilp->lun_sess->sess_isid[1],
4932                     ilp->lun_sess->sess_isid[2], ilp->lun_sess->sess_isid[3],
4933                     ilp->lun_sess->sess_isid[4], ilp->lun_sess->sess_isid[5],
4934                     ilp->lun_sess->sess_name, ilp->lun_sess->sess_tpgt_conf);
4935         }
4936 
4937         if (ddi_prop_update_string(DDI_DEV_T_NONE, lun_dip,
4938             SCSI_ADDR_PROP_TARGET_PORT, target_port_name) != DDI_PROP_SUCCESS) {
4939                 cmn_err(CE_WARN, "iscsi_phys_lun_init: Creating '"
4940                     SCSI_ADDR_PROP_TARGET_PORT "' property on Target(%s), "
4941                     "Lun(%d) Failed", ilp->lun_sess->sess_name, ilp->lun_num);
4942         }
4943 
4944         return (rtn);
4945 }
4946 
4947 /*
4948  * +--------------------------------------------------------------------+
4949  * | End of scsi_tran support routines                                  |
4950  * +--------------------------------------------------------------------+
4951  */
4952 
4953 /*
4954  * +--------------------------------------------------------------------+
4955  * | Begin of struct utility routines                                   |
4956  * +--------------------------------------------------------------------+
4957  */
4958 
4959 
4960 /*
4961  * iscsi_set_default_login_params - This function sets the
4962  * driver default login params.  This is using during the
4963  * creation of our iSCSI HBA structure initialization by
4964  * could be used at other times to reset back to the defaults.
4965  */
4966 void
4967 iscsi_set_default_login_params(iscsi_login_params_t *params)
4968 {
4969         params->immediate_data               = ISCSI_DEFAULT_IMMEDIATE_DATA;
4970         params->initial_r2t          = ISCSI_DEFAULT_INITIALR2T;
4971         params->first_burst_length   = ISCSI_DEFAULT_FIRST_BURST_LENGTH;
4972         params->max_burst_length     = ISCSI_DEFAULT_MAX_BURST_LENGTH;
4973         params->data_pdu_in_order    = ISCSI_DEFAULT_DATA_PDU_IN_ORDER;
4974         params->data_sequence_in_order       = ISCSI_DEFAULT_DATA_SEQUENCE_IN_ORDER;
4975         params->default_time_to_wait = ISCSI_DEFAULT_TIME_TO_WAIT;
4976         params->default_time_to_retain       = ISCSI_DEFAULT_TIME_TO_RETAIN;
4977         params->header_digest                = ISCSI_DEFAULT_HEADER_DIGEST;
4978         params->data_digest          = ISCSI_DEFAULT_DATA_DIGEST;
4979         params->max_recv_data_seg_len        = ISCSI_DEFAULT_MAX_RECV_SEG_LEN;
4980         params->max_xmit_data_seg_len        = ISCSI_DEFAULT_MAX_XMIT_SEG_LEN;
4981         params->max_connections              = ISCSI_DEFAULT_MAX_CONNECTIONS;
4982         params->max_outstanding_r2t  = ISCSI_DEFAULT_MAX_OUT_R2T;
4983         params->error_recovery_level = ISCSI_DEFAULT_ERROR_RECOVERY_LEVEL;
4984         params->ifmarker             = ISCSI_DEFAULT_IFMARKER;
4985         params->ofmarker             = ISCSI_DEFAULT_OFMARKER;
4986 }
4987 
4988 /* Helper function to sets the driver default tunable parameters */
4989 static void
4990 iscsi_set_default_tunable_params(iscsi_tunable_params_t *params)
4991 {
4992         params->recv_login_rsp_timeout = ISCSI_DEFAULT_RX_TIMEOUT_VALUE;
4993         params->conn_login_max = ISCSI_DEFAULT_CONN_DEFAULT_LOGIN_MAX;
4994         params->polling_login_delay = ISCSI_DEFAULT_LOGIN_POLLING_DELAY;
4995 }
4996 
4997 /*
4998  * +--------------------------------------------------------------------+
4999  * | End of struct utility routines                                  |
5000  * +--------------------------------------------------------------------+
5001  */
5002 
5003 /*
5004  * +--------------------------------------------------------------------+
5005  * | Begin of ioctl utility routines                                |
5006  * +--------------------------------------------------------------------+
5007  */
5008 
5009 /*
5010  * iscsi_get_param - This function is a helper to ISCSI_GET_PARAM
5011  * IOCTL
5012  */
5013 int
5014 iscsi_get_param(iscsi_login_params_t *params, boolean_t valid_flag,
5015     iscsi_param_get_t *ipgp) {
5016         int rtn = 0;
5017 
5018         /* ---- Default to settable, possibly changed later ---- */
5019         ipgp->g_value.v_valid    = valid_flag;
5020         ipgp->g_value.v_settable = B_TRUE;
5021 
5022         switch (ipgp->g_param) {
5023         /*
5024          * Boolean parameters
5025          */
5026         case ISCSI_LOGIN_PARAM_DATA_SEQUENCE_IN_ORDER:
5027                 ipgp->g_value.v_bool.b_current =
5028                     params->data_sequence_in_order;
5029                 ipgp->g_value.v_bool.b_default =
5030                     ISCSI_DEFAULT_DATA_SEQUENCE_IN_ORDER;
5031                 break;
5032         case ISCSI_LOGIN_PARAM_IMMEDIATE_DATA:
5033                 ipgp->g_value.v_bool.b_current =
5034                     params->immediate_data;
5035                 ipgp->g_value.v_bool.b_default =
5036                     ISCSI_DEFAULT_IMMEDIATE_DATA;
5037                 break;
5038         case ISCSI_LOGIN_PARAM_INITIAL_R2T:
5039                 ipgp->g_value.v_bool.b_current =
5040                     params->initial_r2t;
5041                 ipgp->g_value.v_bool.b_default =
5042                     ISCSI_DEFAULT_IMMEDIATE_DATA;
5043                 break;
5044         case ISCSI_LOGIN_PARAM_DATA_PDU_IN_ORDER:
5045                 ipgp->g_value.v_bool.b_current =
5046                     params->data_pdu_in_order;
5047                 ipgp->g_value.v_bool.b_default =
5048                     ISCSI_DEFAULT_DATA_PDU_IN_ORDER;
5049                 break;
5050 
5051         /*
5052          * Integer parameters
5053          */
5054         case ISCSI_LOGIN_PARAM_HEADER_DIGEST:
5055                 ipgp->g_value.v_integer.i_current = params->header_digest;
5056                 ipgp->g_value.v_integer.i_default = ISCSI_DEFAULT_HEADER_DIGEST;
5057                 ipgp->g_value.v_integer.i_min = 0;
5058                 ipgp->g_value.v_integer.i_max = ISCSI_MAX_HEADER_DIGEST;
5059                 ipgp->g_value.v_integer.i_incr = 1;
5060                 break;
5061         case ISCSI_LOGIN_PARAM_DATA_DIGEST:
5062                 ipgp->g_value.v_integer.i_current = params->data_digest;
5063                 ipgp->g_value.v_integer.i_default = ISCSI_DEFAULT_DATA_DIGEST;
5064                 ipgp->g_value.v_integer.i_min = 0;
5065                 ipgp->g_value.v_integer.i_max = ISCSI_MAX_DATA_DIGEST;
5066                 ipgp->g_value.v_integer.i_incr = 1;
5067                 break;
5068         case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_RETAIN:
5069                 ipgp->g_value.v_integer.i_current =
5070                     params->default_time_to_retain;
5071                 ipgp->g_value.v_integer.i_default =
5072                     ISCSI_DEFAULT_TIME_TO_RETAIN;
5073                 ipgp->g_value.v_integer.i_min = 0;
5074                 ipgp->g_value.v_integer.i_max = ISCSI_MAX_TIME2RETAIN;
5075                 ipgp->g_value.v_integer.i_incr = 1;
5076                 break;
5077         case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_WAIT:
5078                 ipgp->g_value.v_integer.i_current =
5079                     params->default_time_to_wait;
5080                 ipgp->g_value.v_integer.i_default =
5081                     ISCSI_DEFAULT_TIME_TO_WAIT;
5082                 ipgp->g_value.v_integer.i_min = 0;
5083                 ipgp->g_value.v_integer.i_max = ISCSI_MAX_TIME2WAIT;
5084                 ipgp->g_value.v_integer.i_incr = 1;
5085                 break;
5086         case ISCSI_LOGIN_PARAM_ERROR_RECOVERY_LEVEL:
5087                 ipgp->g_value.v_integer.i_current =
5088                     params->error_recovery_level;
5089                 ipgp->g_value.v_integer.i_default =
5090                     ISCSI_DEFAULT_ERROR_RECOVERY_LEVEL;
5091                 ipgp->g_value.v_integer.i_min = 0;
5092                 ipgp->g_value.v_integer.i_max = ISCSI_MAX_ERROR_RECOVERY_LEVEL;
5093                 ipgp->g_value.v_integer.i_incr = 1;
5094                 ipgp->g_value.v_settable = B_FALSE;
5095                 break;
5096         case ISCSI_LOGIN_PARAM_FIRST_BURST_LENGTH:
5097                 ipgp->g_value.v_integer.i_current =
5098                     params->first_burst_length;
5099                 ipgp->g_value.v_integer.i_default =
5100                     ISCSI_DEFAULT_FIRST_BURST_LENGTH;
5101                 ipgp->g_value.v_integer.i_min = 512;
5102                 ipgp->g_value.v_integer.i_max = ISCSI_MAX_FIRST_BURST_LENGTH;
5103                 ipgp->g_value.v_integer.i_incr = 1;
5104                 break;
5105         case ISCSI_LOGIN_PARAM_MAX_BURST_LENGTH:
5106                 ipgp->g_value.v_integer.i_current =
5107                     params->max_burst_length;
5108                 ipgp->g_value.v_integer.i_default =
5109                     ISCSI_DEFAULT_MAX_BURST_LENGTH;
5110                 ipgp->g_value.v_integer.i_min = 512;
5111                 ipgp->g_value.v_integer.i_max = ISCSI_MAX_BURST_LENGTH;
5112                 ipgp->g_value.v_integer.i_incr = 1;
5113                 break;
5114         case ISCSI_LOGIN_PARAM_MAX_CONNECTIONS:
5115                 ipgp->g_value.v_integer.i_current =
5116                     params->max_connections;
5117                 ipgp->g_value.v_settable = B_FALSE;
5118                 ipgp->g_value.v_integer.i_default =
5119                     ISCSI_DEFAULT_MAX_CONNECTIONS;
5120                 ipgp->g_value.v_integer.i_min = 1;
5121                 ipgp->g_value.v_integer.i_max = ISCSI_MAX_CONNECTIONS;
5122                 ipgp->g_value.v_integer.i_incr = 1;
5123                 break;
5124         case ISCSI_LOGIN_PARAM_OUTSTANDING_R2T:
5125                 ipgp->g_value.v_integer.i_current =
5126                     params->max_outstanding_r2t;
5127                 ipgp->g_value.v_settable = B_FALSE;
5128                 ipgp->g_value.v_integer.i_default =
5129                     ISCSI_DEFAULT_MAX_OUT_R2T;
5130                 ipgp->g_value.v_integer.i_min = 1;
5131                 ipgp->g_value.v_integer.i_max = ISCSI_MAX_OUTSTANDING_R2T;
5132                 ipgp->g_value.v_integer.i_incr = 1;
5133                 break;
5134         case ISCSI_LOGIN_PARAM_MAX_RECV_DATA_SEGMENT_LENGTH:
5135                 ipgp->g_value.v_integer.i_current =
5136                     params->max_recv_data_seg_len;
5137                 ipgp->g_value.v_integer.i_default =
5138                     ISCSI_DEFAULT_MAX_RECV_SEG_LEN;
5139                 ipgp->g_value.v_integer.i_min = 512;
5140                 ipgp->g_value.v_integer.i_max =
5141                     ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH;
5142                 ipgp->g_value.v_integer.i_incr = 1;
5143                 break;
5144         default:
5145                 rtn = EINVAL;
5146         }
5147 
5148         return (rtn);
5149 }
5150 
5151 /*
5152  * +--------------------------------------------------------------------+
5153  * | End of ioctl utility routines                                      |
5154  * +--------------------------------------------------------------------+
5155  */
5156 
5157 /*
5158  * iscsi_get_name_from_iqn - Translates a normal iqn/eui into a
5159  * IEEE safe address.  IEEE addresses have a number of characters
5160  * set aside as reserved.
5161  */
5162 static void
5163 iscsi_get_name_from_iqn(char *name, int name_max_len)
5164 {
5165         char    *tmp            = NULL;
5166         char    *oldch          = NULL;
5167         char    *newch          = NULL;
5168 
5169         tmp = kmem_zalloc(MAX_GET_NAME_SIZE, KM_SLEEP);
5170 
5171         for (oldch = &name[0], newch = &tmp[0]; *oldch != '\0';
5172             oldch++, newch++) {
5173                 switch (*oldch) {
5174                 case ':':
5175                         *newch++ = '%';
5176                         *newch++ = '3';
5177                         *newch = 'A';
5178                         break;
5179                 case ' ':
5180                         *newch++ = '%';
5181                         *newch++ = '2';
5182                         *newch = '0';
5183                         break;
5184                 case '@':
5185                         *newch++ = '%';
5186                         *newch++ = '4';
5187                         *newch = '0';
5188                         break;
5189                 case '/':
5190                         *newch++ = '%';
5191                         *newch++ = '2';
5192                         *newch = 'F';
5193                         break;
5194                 default:
5195                         *newch = *oldch;
5196                 }
5197         }
5198         (void) strncpy(name, tmp, name_max_len);
5199         kmem_free(tmp, MAX_GET_NAME_SIZE);
5200 }
5201 
5202 /*
5203  * iscsi_get_name_to_iqn - Converts IEEE safe address back
5204  * into a iscsi iqn/eui.
5205  */
5206 static void
5207 iscsi_get_name_to_iqn(char *name, int name_max_len)
5208 {
5209         char    *tmp            = NULL;
5210         char    *oldch          = NULL;
5211         char    *newch          = NULL;
5212 
5213         tmp = kmem_zalloc(MAX_GET_NAME_SIZE, KM_SLEEP);
5214 
5215         for (oldch = &name[0], newch = &tmp[0]; *oldch != '\0';
5216             oldch++, newch++) {
5217                 if (*oldch == '%') {
5218                         switch (*(oldch+1)) {
5219                         case '2':
5220                                 if (*(oldch+2) == '0') {
5221                                         *newch = ' ';
5222                                         oldch += 2;
5223                                 } else if (*(oldch+2) == 'F') {
5224                                         *newch = '/';
5225                                         oldch += 2;
5226                                 } else {
5227                                         *newch = *oldch;
5228                                 }
5229                                 break;
5230                         case '3':
5231                                 if (*(oldch+2) == 'A') {
5232                                         *newch = ':';
5233                                         oldch += 2;
5234                                 } else {
5235                                         *newch = *oldch;
5236                                 }
5237                                 break;
5238                         case '4':
5239                                 if (*(oldch+2) == '0') {
5240                                         *newch = '@';
5241                                         oldch += 2;
5242                                 } else {
5243                                         *newch = *oldch;
5244                                 }
5245                                 break;
5246                         default:
5247                                 *newch = *oldch;
5248                         }
5249                 } else {
5250                         *newch = *oldch;
5251                 }
5252         }
5253         (void) strncpy(name, tmp, name_max_len);
5254         kmem_free(tmp, MAX_GET_NAME_SIZE);
5255 }
5256 
5257 /*
5258  * iscsi_get_persisted_param * - a helper to ISCSI_GET_PARAM ioctl
5259  *
5260  * On return 0 means persisted parameter found
5261  */
5262 int
5263 iscsi_get_persisted_param(uchar_t *name, iscsi_param_get_t *ipgp,
5264     iscsi_login_params_t *params)
5265 {
5266         int rtn = 1;
5267         persistent_param_t *pparam;
5268 
5269         if (name == NULL || strlen((char *)name) == 0) {
5270                 return (rtn);
5271         }
5272 
5273         pparam = (persistent_param_t *)kmem_zalloc(sizeof (*pparam), KM_SLEEP);
5274 
5275         if (persistent_param_get((char *)name, pparam) == B_TRUE) {
5276                 if (pparam->p_bitmap & (1 << ipgp->g_param)) {
5277                         /* Found configured parameter. */
5278                         bcopy(&pparam->p_params, params, sizeof (*params));
5279                         rtn = 0;
5280                 }
5281         }
5282 
5283         kmem_free(pparam, sizeof (*pparam));
5284 
5285         return (rtn);
5286 }
5287 
5288 /*
5289  * iscsi_override_target_default - helper function set the target's default
5290  * login parameter if there is a configured initiator parameter.
5291  *
5292  */
5293 static void
5294 iscsi_override_target_default(iscsi_hba_t *ihp, iscsi_param_get_t *ipg)
5295 {
5296         persistent_param_t *pp;
5297         iscsi_login_params_t *params;
5298 
5299         pp = (persistent_param_t *)kmem_zalloc(sizeof (*pp), KM_SLEEP);
5300         if (persistent_param_get((char *)ihp->hba_name, pp) == B_TRUE) {
5301                 if (pp->p_bitmap & (1 << ipg->g_param)) {
5302                         params = &pp->p_params;
5303                         switch (ipg->g_param) {
5304                         case ISCSI_LOGIN_PARAM_DATA_SEQUENCE_IN_ORDER:
5305                                 ipg->g_value.v_bool.b_default =
5306                                     params->data_sequence_in_order;
5307                                 break;
5308                         case ISCSI_LOGIN_PARAM_IMMEDIATE_DATA:
5309                                 ipg->g_value.v_bool.b_default =
5310                                     params->immediate_data;
5311                                 break;
5312                         case ISCSI_LOGIN_PARAM_INITIAL_R2T:
5313                                 ipg->g_value.v_bool.b_default =
5314                                     params->initial_r2t;
5315                                 break;
5316                         case ISCSI_LOGIN_PARAM_DATA_PDU_IN_ORDER:
5317                                 ipg->g_value.v_bool.b_default =
5318                                     params->data_pdu_in_order;
5319                                 break;
5320                         case ISCSI_LOGIN_PARAM_HEADER_DIGEST:
5321                                 ipg->g_value.v_integer.i_default =
5322                                     params->header_digest;
5323                                 break;
5324                         case ISCSI_LOGIN_PARAM_DATA_DIGEST:
5325                                 ipg->g_value.v_integer.i_default =
5326                                     params->data_digest;
5327                                 break;
5328                         case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_RETAIN:
5329                                 ipg->g_value.v_integer.i_default =
5330                                     params->default_time_to_retain;
5331                                 break;
5332                         case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_WAIT:
5333                                 ipg->g_value.v_integer.i_default =
5334                                     params->default_time_to_wait;
5335                                 break;
5336                         case ISCSI_LOGIN_PARAM_ERROR_RECOVERY_LEVEL:
5337                                 ipg->g_value.v_integer.i_default =
5338                                     params->error_recovery_level;
5339                                 break;
5340                         case ISCSI_LOGIN_PARAM_FIRST_BURST_LENGTH:
5341                                 ipg->g_value.v_integer.i_default =
5342                                     params->first_burst_length;
5343                                 break;
5344                         case ISCSI_LOGIN_PARAM_MAX_BURST_LENGTH:
5345                                 ipg->g_value.v_integer.i_default =
5346                                     params->max_burst_length;
5347                                 break;
5348                         case ISCSI_LOGIN_PARAM_MAX_CONNECTIONS:
5349                                 ipg->g_value.v_integer.i_default =
5350                                     params->max_connections;
5351                                 break;
5352                         case ISCSI_LOGIN_PARAM_OUTSTANDING_R2T:
5353                                 ipg->g_value.v_integer.i_default =
5354                                     params->max_outstanding_r2t;
5355                                 break;
5356                         case ISCSI_LOGIN_PARAM_MAX_RECV_DATA_SEGMENT_LENGTH:
5357                                 ipg->g_value.v_integer.i_default =
5358                                     params->max_xmit_data_seg_len;
5359                                 break;
5360                         default:
5361                                 break;
5362                         }
5363                 }
5364         }
5365         kmem_free(pp, sizeof (*pp));
5366 }
5367 
5368 static boolean_t
5369 iscsi_cmp_boot_sess_oid(iscsi_hba_t *ihp, uint32_t oid)
5370 {
5371         iscsi_sess_t *isp = NULL;
5372 
5373         if (iscsi_chk_bootlun_mpxio(ihp)) {
5374                 for (isp = ihp->hba_sess_list; isp; isp = isp->sess_next) {
5375                         if ((isp->sess_oid == oid) && isp->sess_boot) {
5376                                 /* oid is session object */
5377                                 break;
5378                         }
5379                         if ((isp->sess_target_oid == oid) && isp->sess_boot) {
5380                                 /*
5381                                  * oid is target object while
5382                                  * this session is boot session
5383                                  */
5384                                 break;
5385                         }
5386                 }
5387                 if (oid == ihp->hba_oid) {
5388                         /* oid is initiator object id */
5389                         return (B_TRUE);
5390                 } else if ((isp != NULL) && (isp->sess_boot)) {
5391                         /* oid is boot session object id */
5392                         return (B_TRUE);
5393                 }
5394         }
5395         return (B_FALSE);
5396 }
5397 
5398 /*
5399  * iscsi_client_request_service - request the iSCSI service
5400  *     returns true if the service is enabled and increases the count
5401  *     returns false if the service is disabled
5402  *     blocks until the service status is either enabled or disabled
5403  */
5404 boolean_t
5405 iscsi_client_request_service(iscsi_hba_t *ihp) {
5406         boolean_t       rval = B_TRUE;
5407 
5408         mutex_enter(&ihp->hba_service_lock);
5409         while ((ihp->hba_service_status == ISCSI_SERVICE_TRANSITION) ||
5410             (ihp->hba_service_client_count == UINT_MAX)) {
5411                 cv_wait(&ihp->hba_service_cv, &ihp->hba_service_lock);
5412         }
5413         if (ihp->hba_service_status == ISCSI_SERVICE_ENABLED) {
5414                 ihp->hba_service_client_count++;
5415         } else {
5416                 rval = B_FALSE;
5417         }
5418         mutex_exit(&ihp->hba_service_lock);
5419 
5420         return (rval);
5421 }
5422 
5423 /*
5424  * iscsi_client_release_service - decrease the count and wake up
5425  *     blocking threads if the count reaches zero
5426  */
5427 void
5428 iscsi_client_release_service(iscsi_hba_t *ihp) {
5429         mutex_enter(&ihp->hba_service_lock);
5430         ASSERT(ihp->hba_service_client_count > 0);
5431         ihp->hba_service_client_count--;
5432         if (ihp->hba_service_client_count == 0) {
5433                 cv_broadcast(&ihp->hba_service_cv);
5434         }
5435         mutex_exit(&ihp->hba_service_lock);
5436 }
5437 
5438 /*
5439  * iscsi_enter_service_zone - enter the service zone, should be called
5440  * before doing any modifications to the service status
5441  * return TRUE if the zone is entered
5442  *        FALSE if no need to enter the zone
5443  */
5444 static boolean_t
5445 iscsi_enter_service_zone(iscsi_hba_t *ihp, uint32_t status) {
5446         if ((status != ISCSI_SERVICE_ENABLED) &&
5447             (status != ISCSI_SERVICE_DISABLED)) {
5448                 return (B_FALSE);
5449         }
5450 
5451         mutex_enter(&ihp->hba_service_lock);
5452         while (ihp->hba_service_status == ISCSI_SERVICE_TRANSITION) {
5453                 cv_wait(&ihp->hba_service_cv, &ihp->hba_service_lock);
5454         }
5455         if (ihp->hba_service_status == status) {
5456                 mutex_exit(&ihp->hba_service_lock);
5457                 return (B_FALSE);
5458         }
5459         ihp->hba_service_status = ISCSI_SERVICE_TRANSITION;
5460         while (ihp->hba_service_client_count > 0) {
5461                 cv_wait(&ihp->hba_service_cv, &ihp->hba_service_lock);
5462         }
5463         mutex_exit(&ihp->hba_service_lock);
5464         return (B_TRUE);
5465 }
5466 
5467 /*
5468  * iscsi_exit_service_zone - exits the service zone and wakes up waiters
5469  */
5470 static void
5471 iscsi_exit_service_zone(iscsi_hba_t *ihp, uint32_t status) {
5472         if ((status != ISCSI_SERVICE_ENABLED) &&
5473             (status != ISCSI_SERVICE_DISABLED)) {
5474                 return;
5475         }
5476 
5477         mutex_enter(&ihp->hba_service_lock);
5478         ASSERT(ihp->hba_service_status == ISCSI_SERVICE_TRANSITION);
5479         ihp->hba_service_status = status;
5480         cv_broadcast(&ihp->hba_service_cv);
5481         mutex_exit(&ihp->hba_service_lock);
5482 }
5483 
5484 static void
5485 iscsi_check_miniroot(iscsi_hba_t *ihp) {
5486         if (strncmp(rootfs.bo_name, "/ramdisk", 8) == 0) {
5487                 /*
5488                  * in miniroot we don't have the persistent store
5489                  * so just to need to ensure an enabled status
5490                  */
5491                 ihp->hba_service_status = ISCSI_SERVICE_ENABLED;
5492         }
5493 }
5494 
5495 static void
5496 iscsi_get_tunable_default(iscsi_tunable_object_t *param) {
5497         int     param_id = 0;
5498 
5499         param_id = 1 << (param->t_param - 1);
5500         param->t_set = B_FALSE;
5501         switch (param_id) {
5502         case ISCSI_TUNABLE_PARAM_RX_TIMEOUT_VALUE:
5503                 param->t_value.v_integer = ISCSI_DEFAULT_RX_TIMEOUT_VALUE;
5504                 break;
5505         case ISCSI_TUNABLE_PARAM_LOGIN_POLLING_DELAY:
5506                 param->t_value.v_integer = ISCSI_DEFAULT_LOGIN_POLLING_DELAY;
5507                 break;
5508         case ISCSI_TUNABLE_PARAM_CONN_LOGIN_MAX:
5509                 param->t_value.v_integer = ISCSI_DEFAULT_CONN_DEFAULT_LOGIN_MAX;
5510                 break;
5511         default:
5512                 break;
5513         }
5514 }
5515 
5516 /*
5517  * iscsi_get_persisted_tunable_param * - a helper to ISCSI_TUNABLE_PARAM_GET
5518  * ioctl
5519  * return:
5520  *    0         persisted tunable parameter found
5521  *    1         persisted tunable parameter not found
5522  */
5523 static int
5524 iscsi_get_persisted_tunable_param(uchar_t *name, iscsi_tunable_object_t *tpsg)
5525 {
5526         int rtn = 1;
5527         int param_id = 0;
5528         persistent_tunable_param_t *pparam;
5529 
5530         if ((name == NULL) || strlen((char *)name) == 0) {
5531                 return (rtn);
5532         }
5533 
5534         tpsg->t_set = B_FALSE;
5535         pparam = (persistent_tunable_param_t *)kmem_zalloc(sizeof (*pparam),
5536             KM_SLEEP);
5537         if (persistent_get_tunable_param((char *)name, pparam) == B_TRUE) {
5538                 if (pparam->p_bitmap & (1 << (tpsg->t_param - 1))) {
5539                         tpsg->t_set = B_TRUE;
5540                         param_id = 1 << (tpsg->t_param - 1);
5541                         switch (param_id) {
5542                         case ISCSI_TUNABLE_PARAM_RX_TIMEOUT_VALUE:
5543                                 tpsg->t_value.v_integer =
5544                                     pparam->p_params.recv_login_rsp_timeout;
5545                                 break;
5546                         case ISCSI_TUNABLE_PARAM_LOGIN_POLLING_DELAY:
5547                                 tpsg->t_value.v_integer =
5548                                     pparam->p_params.polling_login_delay;
5549                                 break;
5550                         case ISCSI_TUNABLE_PARAM_CONN_LOGIN_MAX:
5551                                 tpsg->t_value.v_integer =
5552                                     pparam->p_params.conn_login_max;
5553                                 break;
5554                         default:
5555                                 break;
5556                         }
5557                         rtn = 0;
5558                 }
5559         }
5560 
5561         kmem_free(pparam, sizeof (*pparam));
5562 
5563         return (rtn);
5564 }