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