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