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