Print this page
    
NEX-19489 BDD tests causes node panic during stage-vm1
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-17944 HBA drivers don't need the redundant devfs_clean step
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
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_lun.c
          +++ new/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_lun.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
  
    | 
      ↓ open down ↓ | 
    10 lines elided | 
    
      ↑ open up ↑ | 
  
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  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   23   * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23   24   * Use is subject to license terms.
  24      - *
       25 + */
       26 +
       27 +/*
       28 + * Copyright 2019 Nexenta Systems, Inc.
       29 + */
       30 +
       31 +/*
  25   32   * iSCSI logical unit interfaces
  26   33   */
  27   34  
  28   35  #include "iscsi.h"
  29      -#include <sys/fs/dv_node.h>     /* devfs_clean */
  30   36  #include <sys/bootprops.h>
  31   37  #include <sys/sysevent/eventdefs.h>
  32   38  #include <sys/sysevent/dev.h>
  33   39  
  34   40  /* tpgt bytes in string form */
  35   41  #define TPGT_EXT_SIZE   5
  36   42  
  37   43  /* logical unit number bytes in string form */
  38   44  #define LUN_EXT_SIZE    10
  39   45  
  40   46  /*
  41   47   * Addition addr size of size of ',' + max str form of tpgt (2 bytes) +
  42   48   * ',' + max str form of logical unit number (4 bytes).
  43   49   */
  44   50  #define ADDR_EXT_SIZE   (1 + TPGT_EXT_SIZE + 1 + LUN_EXT_SIZE)
  45   51  
  46   52  /* internal interfaces */
  47   53  static iscsi_status_t iscsi_lun_virt_create(iscsi_sess_t *isp,
  48   54      uint16_t lun_num, iscsi_lun_t *ilp, struct scsi_inquiry *inq);
  49   55  static iscsi_status_t iscsi_lun_phys_create(iscsi_sess_t *isp,
  50   56      uint16_t lun_num, iscsi_lun_t *ilp, struct scsi_inquiry *inq);
  51   57  
  52   58  extern dev_info_t       *scsi_vhci_dip;
  53   59  extern ib_boot_prop_t   *iscsiboot_prop;
  54   60  
  55   61  /*
  56   62   * +--------------------------------------------------------------------+
  57   63   * | External Connection Interfaces                                     |
  58   64   * +--------------------------------------------------------------------+
  59   65   */
  60   66  
  61   67  
  62   68  /*
  63   69   * iscsi_lun_create - This function will create a lun mapping.
  64   70   * logic specific to MPxIO vs. NDI node creation is switched
  65   71   * out to a helper function.
  66   72   */
  67   73  iscsi_status_t
  68   74  iscsi_lun_create(iscsi_sess_t *isp, uint16_t lun_num, uint8_t lun_addr_type,
  69   75      struct scsi_inquiry *inq, char *guid)
  70   76  {
  71   77          iscsi_status_t          rtn             = ISCSI_STATUS_INTERNAL_ERROR;
  72   78          iscsi_hba_t             *ihp            = NULL;
  73   79          iscsi_lun_t             *ilp            = NULL;
  74   80          iscsi_lun_t             *ilp_tmp        = NULL;
  75   81          char                    *addr           = NULL;
  76   82          uint16_t                boot_lun_num    = 0;
  77   83          uint64_t                *lun_num_ptr    = NULL;
  78   84          uint32_t                oid_tmp         = 0;
  79   85  
  80   86          ASSERT(isp != NULL);
  81   87          ihp = isp->sess_hba;
  82   88          ASSERT(ihp != NULL);
  83   89  
  84   90          mutex_enter(&iscsi_oid_mutex);
  85   91          oid_tmp = iscsi_oid++;
  86   92          mutex_exit(&iscsi_oid_mutex);
  87   93  
  88   94          rw_enter(&isp->sess_lun_list_rwlock, RW_WRITER);
  89   95          /*
  90   96           * Check whether it has already existed in the list.
  91   97           */
  92   98          for (ilp_tmp = isp->sess_lun_list; ilp_tmp != NULL;
  93   99              ilp_tmp = ilp_tmp->lun_next) {
  94  100                  if (ilp_tmp->lun_num == lun_num) {
  95  101                          /*
  96  102                           * The logic unit has already existed in the list,
  97  103                           * return with success.
  98  104                           */
  99  105                          rw_exit(&isp->sess_lun_list_rwlock);
 100  106                          return (ISCSI_STATUS_SUCCESS);
 101  107                  }
 102  108          }
 103  109  
 104  110          addr = kmem_zalloc((strlen((char *)isp->sess_name) +
 105  111              ADDR_EXT_SIZE + 1), KM_SLEEP);
 106  112          (void) snprintf(addr,
 107  113              (strlen((char *)isp->sess_name) +
 108  114              ADDR_EXT_SIZE + 1),
 109  115              "%02X%02X%s%04X,%d", isp->sess_isid[4],
 110  116              isp->sess_isid[5], isp->sess_name,
 111  117              isp->sess_tpgt_nego & 0xFFFF, lun_num);
 112  118  
 113  119          /* allocate space for lun struct */
 114  120          ilp = kmem_zalloc(sizeof (iscsi_lun_t), KM_SLEEP);
 115  121          ilp->lun_sig = ISCSI_SIG_LUN;
  
    | 
      ↓ open down ↓ | 
    76 lines elided | 
    
      ↑ open up ↑ | 
  
 116  122          ilp->lun_state &= ISCSI_LUN_STATE_CLEAR;
 117  123          ilp->lun_state |= ISCSI_LUN_STATE_OFFLINE;
 118  124  
 119  125          /* initialize common LU information */
 120  126          ilp->lun_num        = lun_num;
 121  127          ilp->lun_addr_type  = lun_addr_type;
 122  128          ilp->lun_sess       = isp;
 123  129          ilp->lun_addr       = addr;
 124  130          ilp->lun_type       = inq->inq_dtype & DTYPE_MASK;
 125  131          ilp->lun_oid        = oid_tmp;
      132 +        /*
      133 +         * Setting refcnt to 1 is the first hold for the LUN structure.
      134 +         */
      135 +        ilp->lun_refcnt     = 1;
      136 +        mutex_init(&ilp->lun_mutex, NULL, MUTEX_DRIVER, NULL);
 126  137  
 127  138          bcopy(inq->inq_vid, ilp->lun_vid, sizeof (inq->inq_vid));
 128  139          bcopy(inq->inq_pid, ilp->lun_pid, sizeof (inq->inq_pid));
 129  140  
 130  141          /* store GUID if valid one exists */
 131  142          if (guid != NULL) {
 132  143                  ilp->lun_guid_size = strlen(guid) + 1;
 133  144                  ilp->lun_guid = kmem_zalloc(ilp->lun_guid_size, KM_SLEEP);
 134  145                  (void) strcpy(ilp->lun_guid, guid);
 135  146          } else {
 136  147                  ilp->lun_guid_size = 0;
 137  148                  ilp->lun_guid = NULL;
 138  149          }
 139  150  
 140  151          /*
 141  152           * We need to add the lun to our lists now because during the
 142  153           * lun creation we will get called back into multiple times
 143  154           * depending on the createion type.  These callbacks will
 144  155           * occur via our tran_init_lun, tran_get_name, tran_get_bus_addr,
 145  156           * tran_init_pkt, tran_start.
 146  157           */
 147  158          if (isp->sess_lun_list == NULL) {
 148  159                  isp->sess_lun_list = ilp;
 149  160          } else {
 150  161                  ilp->lun_next = isp->sess_lun_list;
 151  162                  isp->sess_lun_list = ilp;
 152  163          }
 153  164  
 154  165          /* Attempt to create a scsi_vhci binding if GUID is available */
 155  166          if ((ihp->hba_mpxio_enabled == B_TRUE) &&
 156  167              (guid != NULL)) {
 157  168                  rtn = iscsi_lun_virt_create(isp, lun_num, ilp, inq);
 158  169          }
 159  170          if (!ISCSI_SUCCESS(rtn)) {
 160  171                  /* unable to bind under scsi_vhci, failback to ndi */
 161  172                  rtn = iscsi_lun_phys_create(isp, lun_num, ilp, inq);
 162  173          }
 163  174  
 164  175          /*
 165  176           * If NOT successful we need to remove the lun from the
 166  177           * session and free any related resources.
 167  178           */
 168  179          if (!ISCSI_SUCCESS(rtn)) {
 169  180                  if (ilp == isp->sess_lun_list) {
 170  181                          /* if head, set head to our next */
 171  182                          isp->sess_lun_list = ilp->lun_next;
 172  183                  } else {
 173  184                          /* if not head, set prev lun's next to our next */
 174  185                          for (ilp_tmp = isp->sess_lun_list; ilp_tmp;
 175  186                              ilp_tmp = ilp_tmp->lun_next) {
 176  187                                  if (ilp_tmp->lun_next == ilp) {
 177  188                                          ilp_tmp->lun_next = ilp->lun_next;
 178  189                                          break;
 179  190                                  }
 180  191                          }
 181  192                  }
  
    | 
      ↓ open down ↓ | 
    46 lines elided | 
    
      ↑ open up ↑ | 
  
 182  193  
 183  194                  kmem_free(ilp->lun_addr,
 184  195                      (strlen((char *)isp->sess_name) +
 185  196                      ADDR_EXT_SIZE + 1));
 186  197                  ilp->lun_addr = NULL;
 187  198  
 188  199                  if (ilp->lun_guid != NULL) {
 189  200                          kmem_free(ilp->lun_guid, ilp->lun_guid_size);
 190  201                          ilp->lun_guid = NULL;
 191  202                  }
      203 +                mutex_destroy(&ilp->lun_mutex);
 192  204                  kmem_free(ilp, sizeof (iscsi_lun_t));
 193  205          } else {
 194  206                  ilp->lun_state &= ISCSI_LUN_STATE_CLEAR;
 195  207                  ilp->lun_state |= ISCSI_LUN_STATE_ONLINE;
 196  208                  ilp->lun_time_online = ddi_get_time();
 197  209  
 198  210                  /* Check whether this is the required LUN for iscsi boot */
 199  211                  if (iscsiboot_prop != NULL && isp->sess_boot == B_TRUE &&
 200  212                      iscsiboot_prop->boot_tgt.lun_online == 0) {
 201  213                          lun_num_ptr =
 202  214                              (uint64_t *)iscsiboot_prop->boot_tgt.tgt_boot_lun;
 203  215                          boot_lun_num = (uint16_t)(*lun_num_ptr);
 204  216                          if (boot_lun_num == ilp->lun_num) {
 205  217                                  /*
 206  218                                   * During iscsi boot, the boot lun has been
 207  219                                   * online, we should set the "online flag".
  
    | 
      ↓ open down ↓ | 
    6 lines elided | 
    
      ↑ open up ↑ | 
  
 208  220                                   */
 209  221                                  iscsiboot_prop->boot_tgt.lun_online = 1;
 210  222                          }
 211  223                  }
 212  224          }
 213  225          rw_exit(&isp->sess_lun_list_rwlock);
 214  226  
 215  227          return (rtn);
 216  228  }
 217  229  
      230 +void
      231 +iscsi_lun_hold(iscsi_lun_t *ilp)
      232 +{
      233 +        mutex_enter(&ilp->lun_mutex);
      234 +        /*
      235 +         * By design lun_refcnt should never be zero when this routine
      236 +         * is called. When the LUN is created the refcnt is set to 1.
      237 +         * If iscsi_lun_rele is called and the refcnt goes to zero the
      238 +         * structure will be freed so this method shouldn't be called
      239 +         * afterwards.
      240 +         */
      241 +        ASSERT(ilp->lun_refcnt > 0);
      242 +        ilp->lun_refcnt++;
      243 +        mutex_exit(&ilp->lun_mutex);
      244 +}
      245 +
      246 +void
      247 +iscsi_lun_rele(iscsi_lun_t *ilp)
      248 +{
      249 +        ASSERT(ilp != NULL);
      250 +
      251 +        mutex_enter(&ilp->lun_mutex);
      252 +        ASSERT(ilp->lun_refcnt > 0);
      253 +        if (--ilp->lun_refcnt == 0) {
      254 +                iscsi_sess_t            *isp;
      255 +
      256 +                isp = ilp->lun_sess;
      257 +                ASSERT(isp != NULL);
      258 +
      259 +                /* ---- release its memory ---- */
      260 +                kmem_free(ilp->lun_addr, (strlen((char *)isp->sess_name) +
      261 +                    ADDR_EXT_SIZE + 1));
      262 +
      263 +                if (ilp->lun_guid != NULL) {
      264 +                        kmem_free(ilp->lun_guid, ilp->lun_guid_size);
      265 +                }
      266 +                mutex_destroy(&ilp->lun_mutex);
      267 +                kmem_free(ilp, sizeof (iscsi_lun_t));
      268 +        } else {
      269 +                mutex_exit(&ilp->lun_mutex);
      270 +        }
      271 +}
      272 +
 218  273  /*
      274 + * iscsi_lun_cmd_cancel -- as the name implies, cancel all commands for the lun
      275 + *
      276 + * This code is similar to the timeout function with a lot less checking of
      277 + * state before sending the ABORT event for commands on the pending queue.
      278 + *
      279 + * This function is only used by iscsi_lun_destroy().
      280 + */
      281 +static void
      282 +iscsi_lun_cmd_cancel(iscsi_lun_t *ilp)
      283 +{
      284 +        iscsi_sess_t    *isp;
      285 +        iscsi_cmd_t     *icmdp, *nicmdp;
      286 +
      287 +        isp = ilp->lun_sess;
      288 +        rw_enter(&isp->sess_state_rwlock, RW_READER);
      289 +        mutex_enter(&isp->sess_queue_pending.mutex);
      290 +        for (icmdp = isp->sess_queue_pending.head;
      291 +             icmdp; icmdp = nicmdp) {
      292 +                nicmdp = icmdp->cmd_next;
      293 +
      294 +                /*
      295 +                 * For commands on the pending queue we can go straight
      296 +                 * to and abort request which will free the command
      297 +                 * and call back to the complete function.
      298 +                 */
      299 +                iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E4, isp);
      300 +        }
      301 +        mutex_exit(&isp->sess_queue_pending.mutex);
      302 +        rw_exit(&isp->sess_state_rwlock);
      303 +}
      304 +
      305 +/*
 219  306   * iscsi_lun_destroy - offline and remove lun
 220  307   *
 221  308   * This interface is called when a name service change has
 222  309   * occured and the storage is no longer available to this
 223  310   * initiator.  This function will offline and free the
 224  311   * solaris node resources.  Then it will free all iscsi lun
 225  312   * resources.
 226  313   *
 227  314   * This function can fail with ISCSI_STATUS_BUSY if the
 228  315   * logical unit is in use.  The user should unmount or
 229  316   * close the device and perform the nameservice operation
 230  317   * again if this occurs.
 231  318   */
 232  319  iscsi_status_t
  
    | 
      ↓ open down ↓ | 
    4 lines elided | 
    
      ↑ open up ↑ | 
  
 233  320  iscsi_lun_destroy(iscsi_hba_t *ihp, iscsi_lun_t *ilp)
 234  321  {
 235  322          iscsi_status_t          status          = ISCSI_STATUS_SUCCESS;
 236  323          iscsi_sess_t            *isp            = NULL;
 237  324          iscsi_lun_t             *t_ilp          = NULL;
 238  325  
 239  326          ASSERT(ilp != NULL);
 240  327          isp = ilp->lun_sess;
 241  328          ASSERT(isp != NULL);
 242  329  
      330 +        /* flush all outstanding commands first */
      331 +        iscsi_lun_cmd_cancel(ilp);
      332 +
 243  333          /* attempt to offline and free solaris node */
 244  334          status = iscsi_lun_offline(ihp, ilp, B_TRUE);
 245  335  
 246  336          /* If we successfully unplumbed the lun remove it from our lists */
 247  337          if (ISCSI_SUCCESS(status)) {
 248  338                  if (isp->sess_lun_list == ilp) {
 249  339                          /* target first item in list */
 250  340                          isp->sess_lun_list = ilp->lun_next;
 251  341                  } else {
 252  342                          /*
 253  343                           * search session list for ilp pointing
 254  344                           * to lun being removed.  Then
 255  345                           * update that luns next pointer.
 256  346                           */
 257  347                          t_ilp = isp->sess_lun_list;
 258  348                          while (t_ilp->lun_next != NULL) {
 259  349                                  if (t_ilp->lun_next == ilp) {
 260  350                                          break;
 261  351                                  }
  
    | 
      ↓ open down ↓ | 
    9 lines elided | 
    
      ↑ open up ↑ | 
  
 262  352                                  t_ilp = t_ilp->lun_next;
 263  353                          }
 264  354                          if (t_ilp->lun_next == ilp) {
 265  355                                  t_ilp->lun_next = ilp->lun_next;
 266  356                          } else {
 267  357                                  /* couldn't find session */
 268  358                                  ASSERT(FALSE);
 269  359                          }
 270  360                  }
 271  361  
 272      -                /* release its memory */
 273      -                kmem_free(ilp->lun_addr, (strlen((char *)isp->sess_name) +
 274      -                    ADDR_EXT_SIZE + 1));
 275      -                ilp->lun_addr = NULL;
 276      -                if (ilp->lun_guid != NULL) {
 277      -                        kmem_free(ilp->lun_guid, ilp->lun_guid_size);
 278      -                        ilp->lun_guid = NULL;
 279      -                }
 280      -                kmem_free(ilp, sizeof (iscsi_lun_t));
 281      -                ilp = NULL;
      362 +                iscsi_lun_rele(ilp);
 282  363          }
 283  364  
 284  365          return (status);
 285  366  }
 286  367  
 287  368  /*
 288  369   * +--------------------------------------------------------------------+
 289  370   * | External Logical Unit Interfaces                                   |
 290  371   * +--------------------------------------------------------------------+
 291  372   */
 292  373  
 293  374  /*
 294  375   * iscsi_lun_virt_create - Creates solaris logical unit via MDI
 295  376   */
 296  377  static iscsi_status_t
 297  378  iscsi_lun_virt_create(iscsi_sess_t *isp, uint16_t lun_num, iscsi_lun_t *ilp,
 298  379      struct scsi_inquiry *inq)
 299  380  {
 300  381          iscsi_status_t          rtn             = ISCSI_STATUS_INTERNAL_ERROR;
 301  382          int                     mdi_rtn         = MDI_FAILURE;
 302  383          iscsi_hba_t             *ihp            = NULL;
 303  384          mdi_pathinfo_t          *pip            = NULL;
 304  385          char                    *nodename       = NULL;
 305  386          char                    **compatible    = NULL;
 306  387          int                     ncompatible     = 0;
 307  388          int                     circ = 0;
 308  389  
 309  390          ASSERT(isp != NULL);
 310  391          ASSERT(ilp != NULL);
 311  392          ihp = isp->sess_hba;
 312  393          ASSERT(ihp != NULL);
 313  394  
 314  395          /*
 315  396           * Generate compatible property
 316  397           */
 317  398          scsi_hba_nodename_compatible_get(inq, "vhci",
 318  399              inq->inq_dtype, NULL, &nodename, &compatible, &ncompatible);
 319  400  
 320  401          /* if nodename can't be determined then print a message and skip it */
 321  402          if (nodename == NULL) {
 322  403                  cmn_err(CE_WARN, "iscsi driver found no compatible driver "
 323  404                      "for %s lun %d dtype:0x%02x", isp->sess_name, lun_num,
 324  405                      inq->inq_dtype);
 325  406                  return (ISCSI_STATUS_INTERNAL_ERROR);
 326  407          }
 327  408  
 328  409          /*
 329  410           *
 330  411           */
 331  412          ndi_devi_enter(scsi_vhci_dip, &circ);
 332  413          mdi_rtn = mdi_pi_alloc_compatible(ihp->hba_dip, nodename,
 333  414              ilp->lun_guid, ilp->lun_addr, compatible, ncompatible,
 334  415              0, &pip);
 335  416  
 336  417          if (mdi_rtn == MDI_SUCCESS) {
 337  418                  mdi_pi_set_phci_private(pip, (caddr_t)ilp);
 338  419  
 339  420                  if (mdi_prop_update_string(pip, MDI_GUID,
 340  421                      ilp->lun_guid) != DDI_SUCCESS) {
 341  422                          cmn_err(CE_WARN, "iscsi driver unable to create "
 342  423                              "property for %s lun %d (MDI_GUID)",
 343  424                              isp->sess_name, lun_num);
 344  425                          mdi_rtn = MDI_FAILURE;
 345  426                          goto virt_create_done;
 346  427                  }
 347  428  
 348  429                  if (mdi_prop_update_int(pip, TARGET_PROP,
 349  430                      isp->sess_oid) != DDI_SUCCESS) {
 350  431                          cmn_err(CE_WARN, "iscsi driver unable to create "
 351  432                              "property for %s lun %d (TARGET_PROP)",
 352  433                              isp->sess_name, lun_num);
 353  434                          mdi_rtn = MDI_FAILURE;
 354  435                          goto virt_create_done;
 355  436                  }
 356  437  
 357  438                  if (mdi_prop_update_int(pip, LUN_PROP,
 358  439                      ilp->lun_num) != DDI_SUCCESS) {
 359  440                          cmn_err(CE_WARN, "iscsi driver unable to create "
 360  441                              "property for %s lun %d (LUN_PROP)",
 361  442                              isp->sess_name, lun_num);
 362  443                          mdi_rtn = MDI_FAILURE;
 363  444                          goto virt_create_done;
 364  445                  }
 365  446  
 366  447                  if (mdi_prop_update_string_array(pip, "compatible",
 367  448                      compatible, ncompatible) !=
 368  449                      DDI_PROP_SUCCESS) {
 369  450                          cmn_err(CE_WARN, "iscsi driver unable to create "
 370  451                              "property for %s lun %d (COMPATIBLE)",
 371  452                              isp->sess_name, lun_num);
 372  453                          mdi_rtn = MDI_FAILURE;
 373  454                          goto virt_create_done;
 374  455                  }
 375  456  
 376  457                  mdi_rtn = mdi_pi_online(pip, 0);
 377  458                  if (mdi_rtn == MDI_NOT_SUPPORTED) {
 378  459                          mdi_rtn = MDI_FAILURE;
 379  460                          goto virt_create_done;
 380  461                  }
 381  462  
 382  463                  ilp->lun_pip = pip;
 383  464                  ilp->lun_dip = NULL;
 384  465  
 385  466  virt_create_done:
 386  467  
 387  468                  if (pip && mdi_rtn != MDI_SUCCESS) {
 388  469                          ilp->lun_pip = NULL;
 389  470                          ilp->lun_dip = NULL;
 390  471                          (void) mdi_prop_remove(pip, NULL);
 391  472                          (void) mdi_pi_free(pip, 0);
 392  473                  } else {
 393  474                          rtn = ISCSI_STATUS_SUCCESS;
 394  475                  }
 395  476          }
 396  477          ndi_devi_exit(scsi_vhci_dip, circ);
 397  478  
 398  479          scsi_hba_nodename_compatible_free(nodename, compatible);
 399  480  
 400  481          return (rtn);
 401  482  }
 402  483  
 403  484  
 404  485  /*
 405  486   * iscsi_lun_phys_create - creates solaris logical unit via NDI
 406  487   */
 407  488  static iscsi_status_t
 408  489  iscsi_lun_phys_create(iscsi_sess_t *isp, uint16_t lun_num,
 409  490      iscsi_lun_t *ilp, struct scsi_inquiry *inq)
 410  491  {
 411  492          iscsi_status_t          rtn             = ISCSI_STATUS_INTERNAL_ERROR;
 412  493          int                     ndi_rtn         = NDI_FAILURE;
 413  494          iscsi_hba_t             *ihp            = NULL;
 414  495          dev_info_t              *lun_dip        = NULL;
 415  496          char                    *nodename       = NULL;
 416  497          char                    **compatible    = NULL;
 417  498          int                     ncompatible     = 0;
 418  499          char                    *scsi_binding_set = NULL;
 419  500          char                    instance[32];
 420  501          int                     circ            = 0;
 421  502  
 422  503          ASSERT(isp != NULL);
 423  504          ASSERT(ilp != NULL);
 424  505          ihp = isp->sess_hba;
 425  506          ASSERT(ihp != NULL);
 426  507          ASSERT(inq != NULL);
 427  508  
 428  509          /* get the 'scsi-binding-set' property */
 429  510          if (ddi_prop_lookup_string(DDI_DEV_T_ANY, isp->sess_hba->hba_dip,
 430  511              DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, "scsi-binding-set",
 431  512              &scsi_binding_set) != DDI_PROP_SUCCESS) {
 432  513                  scsi_binding_set = NULL;
 433  514          }
 434  515  
 435  516          /* generate compatible property */
 436  517          scsi_hba_nodename_compatible_get(inq, scsi_binding_set,
 437  518              inq->inq_dtype, NULL, &nodename, &compatible, &ncompatible);
 438  519          if (scsi_binding_set)
 439  520                  ddi_prop_free(scsi_binding_set);
 440  521  
 441  522          /* if nodename can't be determined then print a message and skip it */
 442  523          if (nodename == NULL) {
 443  524                  cmn_err(CE_WARN, "iscsi driver found no compatible driver "
 444  525                      "for %s lun %d", isp->sess_name, lun_num);
 445  526                  return (ISCSI_STATUS_INTERNAL_ERROR);
 446  527          }
 447  528  
 448  529          ndi_devi_enter(ihp->hba_dip, &circ);
 449  530  
 450  531          ndi_rtn = ndi_devi_alloc(ihp->hba_dip, nodename,
 451  532              DEVI_SID_NODEID, &lun_dip);
 452  533  
 453  534          /* if lun alloc success, set props */
 454  535          if (ndi_rtn == NDI_SUCCESS) {
 455  536  
 456  537                  if (ndi_prop_update_int(DDI_DEV_T_NONE,
 457  538                      lun_dip, TARGET_PROP, (int)isp->sess_oid) !=
 458  539                      DDI_PROP_SUCCESS) {
 459  540                          cmn_err(CE_WARN, "iscsi driver unable to create "
 460  541                              "property for %s lun %d (TARGET_PROP)",
 461  542                              isp->sess_name, lun_num);
 462  543                          ndi_rtn = NDI_FAILURE;
 463  544                          goto phys_create_done;
 464  545                  }
 465  546  
 466  547                  if (ndi_prop_update_int(DDI_DEV_T_NONE,
 467  548                      lun_dip, LUN_PROP, (int)ilp->lun_num) !=
 468  549                      DDI_PROP_SUCCESS) {
 469  550                          cmn_err(CE_WARN, "iscsi driver unable to create "
 470  551                              "property for %s lun %d (LUN_PROP)",
 471  552                              isp->sess_name, lun_num);
 472  553                          ndi_rtn = NDI_FAILURE;
 473  554                          goto phys_create_done;
 474  555                  }
 475  556  
 476  557                  if (ndi_prop_update_string_array(DDI_DEV_T_NONE,
 477  558                      lun_dip, "compatible", compatible, ncompatible)
 478  559                      != DDI_PROP_SUCCESS) {
 479  560                          cmn_err(CE_WARN, "iscsi driver unable to create "
 480  561                              "property for %s lun %d (COMPATIBLE)",
 481  562                              isp->sess_name, lun_num);
 482  563                          ndi_rtn = NDI_FAILURE;
 483  564                          goto phys_create_done;
 484  565                  }
 485  566  
 486  567  phys_create_done:
 487  568                  /* If props were setup ok, online the lun */
 488  569                  if (ndi_rtn == NDI_SUCCESS) {
 489  570                          /* Try to online the new node */
 490  571                          ndi_rtn = ndi_devi_online(lun_dip, 0);
 491  572                  }
 492  573  
 493  574                  /* If success set rtn flag, else unwire alloc'd lun */
 494  575                  if (ndi_rtn == NDI_SUCCESS) {
 495  576                          rtn = ISCSI_STATUS_SUCCESS;
 496  577                          /*
 497  578                           * Assign the instance number for the dev_link
 498  579                           * generator.  This will ensure the link name is
 499  580                           * unique and persistent across reboots.
 500  581                           */
 501  582                          (void) snprintf(instance, 32, "%d",
 502  583                              ddi_get_instance(lun_dip));
 503  584                          (void) ndi_prop_update_string(DDI_DEV_T_NONE,
 504  585                              lun_dip, NDI_GUID, instance);
 505  586                  } else {
 506  587                          cmn_err(CE_WARN, "iscsi driver unable to online "
 507  588                              "%s lun %d", isp->sess_name, lun_num);
 508  589                          ndi_prop_remove_all(lun_dip);
 509  590                          (void) ndi_devi_free(lun_dip);
 510  591                  }
 511  592  
 512  593          }
 513  594          ndi_devi_exit(ihp->hba_dip, circ);
 514  595  
 515  596          ilp->lun_dip = lun_dip;
 516  597          ilp->lun_pip = NULL;
 517  598  
 518  599          scsi_hba_nodename_compatible_free(nodename, compatible);
 519  600  
 520  601          return (rtn);
 521  602  }
 522  603  
 523  604  
 524  605  /*
 525  606   * iscsi_lun_online - _di_online logical unit
 526  607   *
 527  608   * This is called after a path has recovered it will cause
 528  609   * an offline path to become online/active again.
 529  610   */
 530  611  void
 531  612  iscsi_lun_online(iscsi_hba_t *ihp, iscsi_lun_t *ilp)
 532  613  {
 533  614          int                     circ            = 0;
 534  615          int                     rval            = 0;
 535  616          uint64_t                *lun_num_ptr    = NULL;
 536  617          uint16_t                boot_lun_num    = 0;
 537  618          iscsi_sess_t            *isp            = NULL;
 538  619          boolean_t               online          = B_FALSE;
 539  620          nvlist_t                *attr_list      = NULL;
 540  621          char                    *pathname       = NULL;
 541  622          dev_info_t              *lun_dip        = NULL;
 542  623  
 543  624          ASSERT(ilp != NULL);
 544  625          ASSERT((ilp->lun_pip != NULL) || (ilp->lun_dip != NULL));
 545  626  
 546  627          if (ilp->lun_pip != NULL) {
 547  628                  ndi_devi_enter(scsi_vhci_dip, &circ);
 548  629                  rval =  mdi_pi_online(ilp->lun_pip, 0);
 549  630                  ndi_devi_exit(scsi_vhci_dip, circ);
 550  631                  if (rval == MDI_SUCCESS) {
 551  632                          ilp->lun_state &= ISCSI_LUN_STATE_CLEAR;
 552  633                          ilp->lun_state |= ISCSI_LUN_STATE_ONLINE;
 553  634                          ilp->lun_time_online = ddi_get_time();
 554  635                          online = B_TRUE;
 555  636                  }
 556  637  
 557  638          } else if (ilp->lun_dip != NULL) {
 558  639                  ndi_devi_enter(ihp->hba_dip, &circ);
 559  640                  rval =  ndi_devi_online(ilp->lun_dip, 0);
 560  641                  ndi_devi_exit(ihp->hba_dip, circ);
 561  642                  if (rval == NDI_SUCCESS) {
 562  643                          ilp->lun_state &= ISCSI_LUN_STATE_CLEAR;
 563  644                          ilp->lun_state |= ISCSI_LUN_STATE_ONLINE;
 564  645                          ilp->lun_time_online = ddi_get_time();
 565  646                          online = B_TRUE;
 566  647                  }
 567  648          }
 568  649  
 569  650          /* Check whether this is the required LUN for iscsi boot */
 570  651          if (iscsiboot_prop != NULL &&
 571  652              iscsiboot_prop->boot_tgt.lun_online == 0) {
 572  653                  isp = ilp->lun_sess;
 573  654                  if (isp->sess_boot == B_TRUE) {
 574  655                          lun_num_ptr =
 575  656                              (uint64_t *)iscsiboot_prop->boot_tgt.tgt_boot_lun;
 576  657                          boot_lun_num = (uint16_t)(*lun_num_ptr);
 577  658                          if (boot_lun_num == ilp->lun_num) {
 578  659                                  /*
 579  660                                   * During iscsi boot, the boot lun has been
 580  661                                   * online, we should set the "online flag".
 581  662                                   */
 582  663                                  iscsiboot_prop->boot_tgt.lun_online = 1;
 583  664                          }
 584  665                  }
 585  666          }
 586  667  
 587  668          /*
 588  669           * If the LUN has been online and it is a disk,
 589  670           * send out a system event.
 590  671           */
 591  672          if (online == B_TRUE && ilp->lun_type == DTYPE_DIRECT) {
 592  673                  if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_SLEEP) !=
 593  674                      DDI_SUCCESS) {
 594  675                          return;
 595  676                  }
 596  677  
 597  678                  if (ilp->lun_pip != NULL) {
 598  679                          lun_dip = mdi_pi_get_client(ilp->lun_pip);
 599  680                  } else {
 600  681                          lun_dip = ilp->lun_dip;
 601  682                  }
 602  683  
 603  684                  pathname = kmem_zalloc(MAXNAMELEN + 1, KM_SLEEP);
 604  685                  (void) ddi_pathname(lun_dip, pathname);
 605  686  
 606  687                  if (nvlist_add_string(attr_list, DEV_PHYS_PATH, pathname) !=
 607  688                      DDI_SUCCESS) {
 608  689                          nvlist_free(attr_list);
 609  690                          kmem_free(pathname, MAXNAMELEN + 1);
 610  691                          return;
 611  692                  }
 612  693                  iscsi_send_sysevent(ihp, EC_DEV_ADD, ESC_DISK, attr_list);
 613  694                  kmem_free(pathname, MAXNAMELEN + 1);
 614  695                  nvlist_free(attr_list);
 615  696          }
 616  697  }
 617  698  
 618  699  /*
 619  700   * iscsi_lun_offline - attempt _di_offline [and optional _di_free]
 620  701   *
 621  702   * This function is called via two paths.  When a transport
 622  703   * path has failed it will be called to offline the logical
 623  704   * unit.  When nameservice access has been removed it will
 624  705   * be called to both offline and free the logical unit.
 625  706   * (This operates soley on the solaris node states.
 626  707   * iscsi_lun_destroy() should be called when attempting
 627  708   * to free all iscsi lun resources.)
 628  709   *
 629  710   * This function can fail with ISCSI_STATUS_BUSY if the
 630  711   * logical unit is in use.  The user should unmount or
 631  712   * close the device and perform the nameservice operation
 632  713   * again if this occurs.
 633  714   *
  
    | 
      ↓ open down ↓ | 
    342 lines elided | 
    
      ↑ open up ↑ | 
  
 634  715   * If we fail to offline a LUN that we don't want to destroy,
 635  716   * we will mark it with invalid state. If this LUN still
 636  717   * exists on the target, we can have another chance to online
 637  718   * it again when we do the LUN enumeration.
 638  719   */
 639  720  iscsi_status_t
 640  721  iscsi_lun_offline(iscsi_hba_t *ihp, iscsi_lun_t *ilp, boolean_t lun_free)
 641  722  {
 642  723          iscsi_status_t          status          = ISCSI_STATUS_SUCCESS;
 643  724          int                     circ            = 0;
 644      -        dev_info_t              *cdip, *pdip;
 645      -        char                    *devname        = NULL;
      725 +        dev_info_t              *cdip;
 646  726          char                    *pathname       = NULL;
 647      -        int                     rval;
 648  727          boolean_t               offline         = B_FALSE;
 649  728          nvlist_t                *attr_list      = NULL;
 650  729  
 651  730          ASSERT(ilp != NULL);
 652  731          ASSERT((ilp->lun_pip != NULL) || (ilp->lun_dip != NULL));
 653  732  
 654      -        /*
 655      -         * Since we carry the logical units parent
 656      -         * lock across the offline call it will not
 657      -         * issue devfs_clean() and may fail with a
 658      -         * devi_ref count > 0.
 659      -         */
 660      -        if (ilp->lun_pip == NULL) {
      733 +        if (ilp->lun_pip == NULL)
 661  734                  cdip = ilp->lun_dip;
 662      -        } else {
      735 +        else
 663  736                  cdip = mdi_pi_get_client(ilp->lun_pip);
 664      -        }
 665  737  
 666      -        if ((cdip != NULL) &&
 667      -            (lun_free == B_TRUE) &&
 668      -            (ilp->lun_state & ISCSI_LUN_STATE_ONLINE)) {
 669      -                /*
 670      -                 * Make sure node is attached otherwise
 671      -                 * it won't have related cache nodes to
 672      -                 * clean up.  i_ddi_devi_attached is
 673      -                 * similiar to i_ddi_node_state(cdip) >=
 674      -                 * DS_ATTACHED. We should clean up only
 675      -                 * when lun_free is set.
 676      -                 */
 677      -                if (i_ddi_devi_attached(cdip)) {
 678      -
 679      -                        /* Get parent dip */
 680      -                        pdip = ddi_get_parent(cdip);
 681      -
 682      -                        /* Get full devname */
 683      -                        devname = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
 684      -                        ndi_devi_enter(pdip, &circ);
 685      -                        (void) ddi_deviname(cdip, devname);
 686      -                        /* Release lock before devfs_clean() */
 687      -                        ndi_devi_exit(pdip, circ);
 688      -
 689      -                        /* Clean cache */
 690      -                        (void) devfs_clean(pdip, devname + 1, DV_CLEAN_FORCE);
 691      -                        kmem_free(devname, MAXNAMELEN + 1);
 692      -                }
 693      -        }
 694      -
 695  738          if (cdip != NULL && ilp->lun_type == DTYPE_DIRECT) {
 696  739                  pathname = kmem_zalloc(MAXNAMELEN + 1, KM_SLEEP);
 697  740                  (void) ddi_pathname(cdip, pathname);
 698  741          }
 699  742  
 700  743          /* Attempt to offline the logical units */
 701  744          if (ilp->lun_pip != NULL) {
 702      -
 703  745                  /* virt/mdi */
 704  746                  ndi_devi_enter(scsi_vhci_dip, &circ);
 705      -                if ((lun_free == B_TRUE) &&
 706      -                    (ilp->lun_state & ISCSI_LUN_STATE_ONLINE)) {
 707      -                        rval = mdi_pi_offline(ilp->lun_pip,
 708      -                            NDI_DEVI_REMOVE);
 709      -                } else {
 710      -                        rval = mdi_pi_offline(ilp->lun_pip, 0);
 711      -                }
 712      -
 713      -                if (rval == MDI_SUCCESS) {
      747 +                if (mdi_pi_offline(ilp->lun_pip, 0) == MDI_SUCCESS) {
 714  748                          ilp->lun_state &= ISCSI_LUN_STATE_CLEAR;
 715  749                          ilp->lun_state |= ISCSI_LUN_STATE_OFFLINE;
 716  750                          if (lun_free == B_TRUE) {
 717  751                                  (void) mdi_prop_remove(ilp->lun_pip, NULL);
 718  752                                  (void) mdi_pi_free(ilp->lun_pip, 0);
 719  753                          }
 720  754                          offline = B_TRUE;
 721  755                  } else {
 722  756                          status = ISCSI_STATUS_BUSY;
 723  757                          if (lun_free == B_FALSE) {
 724  758                                  ilp->lun_state |= ISCSI_LUN_STATE_INVALID;
 725  759                                  offline = B_TRUE;
 726  760                          }
 727  761                  }
 728  762                  ndi_devi_exit(scsi_vhci_dip, circ);
 729  763  
 730  764          } else  {
 731      -
 732  765                  /* phys/ndi */
      766 +                int flags = NDI_DEVFS_CLEAN;
      767 +
 733  768                  ndi_devi_enter(ihp->hba_dip, &circ);
 734      -                if ((lun_free == B_TRUE) &&
 735      -                    (ilp->lun_state & ISCSI_LUN_STATE_ONLINE)) {
 736      -                        rval = ndi_devi_offline(
 737      -                            ilp->lun_dip, NDI_DEVI_REMOVE);
 738      -                } else {
 739      -                        rval = ndi_devi_offline(
 740      -                            ilp->lun_dip, 0);
 741      -                }
 742      -                if (rval != NDI_SUCCESS) {
      769 +                if (lun_free == B_TRUE &&
      770 +                    (ilp->lun_state & ISCSI_LUN_STATE_ONLINE))
      771 +                        flags |= NDI_DEVI_REMOVE;
      772 +                if (ndi_devi_offline(ilp->lun_dip, flags) != NDI_SUCCESS) {
 743  773                          status = ISCSI_STATUS_BUSY;
 744  774                          if (lun_free == B_FALSE) {
 745  775                                  ilp->lun_state |= ISCSI_LUN_STATE_INVALID;
 746  776                                  offline = B_TRUE;
 747  777                          }
 748  778                  } else {
 749  779                          ilp->lun_state &= ISCSI_LUN_STATE_CLEAR;
 750  780                          ilp->lun_state |= ISCSI_LUN_STATE_OFFLINE;
 751  781                          offline = B_TRUE;
 752  782                  }
 753  783                  ndi_devi_exit(ihp->hba_dip, circ);
 754  784          }
 755  785  
 756  786          if (offline == B_TRUE && pathname != NULL &&
 757  787              ilp->lun_type == DTYPE_DIRECT) {
 758  788                  if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_SLEEP) !=
 759  789                      DDI_SUCCESS) {
 760  790                          kmem_free(pathname, MAXNAMELEN + 1);
 761  791                          return (status);
 762  792                  }
 763  793  
 764  794                  if (nvlist_add_string(attr_list, DEV_PHYS_PATH, pathname) !=
 765  795                      DDI_SUCCESS) {
 766  796                          nvlist_free(attr_list);
 767  797                          kmem_free(pathname, MAXNAMELEN + 1);
 768  798                          return (status);
 769  799                  }
 770  800  
 771  801                  iscsi_send_sysevent(ihp, EC_DEV_REMOVE, ESC_DISK, attr_list);
 772  802                  nvlist_free(attr_list);
 773  803          }
 774  804  
 775  805          if (pathname != NULL) {
 776  806                  kmem_free(pathname, MAXNAMELEN + 1);
 777  807          }
 778  808  
 779  809          return (status);
 780  810  }
  
    | 
      ↓ open down ↓ | 
    28 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX