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
↓ 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  
↓ 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 {
↓ 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 =
↓ 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
↓ 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                          /*
↓ 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   */
↓ 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                  }
↓ open down ↓ 28 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX