Print this page
NEX-18919 Platform component fix for the MetroHA reboot -dn issue
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-17910 vhci_scsi_reset is too noisy
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
NEX-1049 System panic in module "scsi_vhci" due to a NULL pointer dereference
OS-62 slow io error detector is needed.
re #13247 rb4316 Large, fixed command timeouts impair command drop recovery
        
*** 16,30 ****
   * fields enclosed by brackets "[]" replaced with your own identifying
   * information: Portions Copyright [yyyy] [name of copyright owner]
   *
   * CDDL HEADER END
   */
  /*
   * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
!  */
! /*
!  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
   * Copyright (c) 2016 by Delphix. All rights reserved.
   */
  
  /*
   * Multiplexed I/O SCSI vHCI implementation
--- 16,29 ----
   * fields enclosed by brackets "[]" replaced with your own identifying
   * information: Portions Copyright [yyyy] [name of copyright owner]
   *
   * CDDL HEADER END
   */
+ 
  /*
   * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
!  * Copyright 2018 Nexenta Systems, Inc.
   * Copyright (c) 2016 by Delphix. All rights reserved.
   */
  
  /*
   * Multiplexed I/O SCSI vHCI implementation
*** 52,61 ****
--- 51,65 ----
  
  /* retry for the vhci_do_prout command when a not ready is returned */
  int vhci_prout_not_ready_retry = 180;
  
  /*
+  * Timeout in seconds for SCSI commands used by vHCI.
+  */
+ int vhci_io_time = 30;
+ 
+ /*
   * These values are defined to support the internal retry of
   * SCSI packets for better sense code handling.
   */
  #define VHCI_CMD_CMPLT  0
  #define VHCI_CMD_RETRY  1
*** 130,139 ****
--- 134,144 ----
  static int vhci_scsi_abort(struct scsi_address *, struct scsi_pkt *);
  static int vhci_scsi_reset(struct scsi_address *, int);
  static int vhci_scsi_reset_target(struct scsi_address *, int level,
      uint8_t select_path);
  static int vhci_scsi_reset_bus(struct scsi_address *);
+ static int vhci_scsi_reset_all_paths(struct scsi_address *);
  static int vhci_scsi_getcap(struct scsi_address *, char *, int);
  static int vhci_scsi_setcap(struct scsi_address *, char *, int, int);
  static int vhci_commoncap(struct scsi_address *, char *, int, int, int);
  static int vhci_pHCI_cap(struct scsi_address *ap, char *cap, int val, int whom,
      mdi_pathinfo_t *pip);
*** 1384,1394 ****
                                  vlun->svl_flags &= ~VLUN_QUIESCED_FLG;
                                  return (TRAN_FATAL_ERROR);
                          }
  
                          rel_pkt->pkt_cdbp[0] = SCMD_RELEASE;
!                         rel_pkt->pkt_time = 60;
  
                          /*
                           * Ignore the return value.  If it will fail
                           * then most likely it is no longer reserved
                           * anyway.
--- 1389,1399 ----
                                  vlun->svl_flags &= ~VLUN_QUIESCED_FLG;
                                  return (TRAN_FATAL_ERROR);
                          }
  
                          rel_pkt->pkt_cdbp[0] = SCMD_RELEASE;
!                         rel_pkt->pkt_time = vhci_io_time;
  
                          /*
                           * Ignore the return value.  If it will fail
                           * then most likely it is no longer reserved
                           * anyway.
*** 1533,1556 ****
   *
   * Return Values : 0 - reset failed
   *                 1 - reset succeeded
   */
  
- /* ARGSUSED */
  static int
  vhci_scsi_reset(struct scsi_address *ap, int level)
  {
-         int rval = 0;
- 
-         cmn_err(CE_WARN, "!vhci_scsi_reset 0x%x", level);
          if ((level == RESET_TARGET) || (level == RESET_LUN)) {
                  return (vhci_scsi_reset_target(ap, level, TRUE));
          } else if (level == RESET_ALL) {
                  return (vhci_scsi_reset_bus(ap));
          }
- 
-         return (rval);
  }
  
  /*
   * vhci_recovery_reset:
   *      Issues reset to the device
--- 1538,1557 ----
   *
   * Return Values : 0 - reset failed
   *                 1 - reset succeeded
   */
  
  static int
  vhci_scsi_reset(struct scsi_address *ap, int level)
  {
          if ((level == RESET_TARGET) || (level == RESET_LUN)) {
                  return (vhci_scsi_reset_target(ap, level, TRUE));
          } else if (level == RESET_ALL) {
                  return (vhci_scsi_reset_bus(ap));
+         } else {
+                 return (0);
          }
  }
  
  /*
   * vhci_recovery_reset:
   *      Issues reset to the device
*** 1612,1622 ****
   * of the scsi_address passed in.
   */
  static int
  vhci_scsi_reset_target(struct scsi_address *ap, int level, uint8_t select_path)
  {
!         dev_info_t              *vdip, *cdip;
          mdi_pathinfo_t          *pip = NULL;
          mdi_pathinfo_t          *npip = NULL;
          int                     rval = -1;
          scsi_vhci_priv_t        *svp = NULL;
          struct scsi_address     *pap = NULL;
--- 1613,1623 ----
   * of the scsi_address passed in.
   */
  static int
  vhci_scsi_reset_target(struct scsi_address *ap, int level, uint8_t select_path)
  {
!         dev_info_t              *vdip, *cdip = NULL;
          mdi_pathinfo_t          *pip = NULL;
          mdi_pathinfo_t          *npip = NULL;
          int                     rval = -1;
          scsi_vhci_priv_t        *svp = NULL;
          struct scsi_address     *pap = NULL;
*** 1632,1642 ****
--- 1633,1650 ----
                          return (hba->tran_reset(ap, RESET_LUN));
                  }
                  return (scsi_reset(ap, level));
          }
  
+         /*
+          * SCSI address should be interpreted according to the pHBA flags.
+          */
+         if (ap->a_hba_tran->tran_hba_flags & SCSI_HBA_ADDR_COMPLEX)
                  cdip = ADDR2DIP(ap);
+         else if (ap->a_hba_tran->tran_hba_flags & SCSI_HBA_TRAN_CLONE)
+                 cdip = ap->a_hba_tran->tran_sd->sd_dev;
+ 
          ASSERT(cdip != NULL);
          vdip = ddi_get_parent(cdip);
          ASSERT(vdip != NULL);
          vhci = ddi_get_soft_state(vhci_softstate, ddi_get_instance(vdip));
          ASSERT(vhci != NULL);
*** 1703,1721 ****
          }
          mdi_rele_path(pip);
          return (0);
  }
  
- 
  /* ARGSUSED */
  static int
  vhci_scsi_reset_bus(struct scsi_address *ap)
  {
          return (1);
  }
  
  
  /*
   * called by vhci_getcap and vhci_setcap to get and set (respectively)
   * SCSI capabilities
   */
  /* ARGSUSED */
--- 1711,1825 ----
          }
          mdi_rele_path(pip);
          return (0);
  }
  
  /* ARGSUSED */
  static int
  vhci_scsi_reset_bus(struct scsi_address *ap)
  {
          return (1);
  }
  
+ /*
+  * This is a special version of LUN reset routine
+  * which sends a reset down all available paths.
+  */
+ static int
+ vhci_scsi_reset_all_paths(struct scsi_address *ap)
+ {
+         dev_info_t              *vdip, *cdip = NULL;
+         mdi_pathinfo_t          *pip = NULL;
+         mdi_pathinfo_t          *npip = NULL;
+         int                     rval = -1;
+         scsi_vhci_priv_t        *svp = NULL;
+         struct scsi_address     *pap = NULL;
+         scsi_hba_tran_t         *hba = NULL;
+         int                     sps = MDI_SUCCESS;
+         int                     reset_result = 0;
+         struct scsi_vhci        *vhci = NULL;
  
+         /*
+          * SCSI address should be interpreted according to the pHBA flags.
+          */
+         if (ap->a_hba_tran->tran_hba_flags & SCSI_HBA_ADDR_COMPLEX)
+                 cdip = ADDR2DIP(ap);
+         else if (ap->a_hba_tran->tran_hba_flags & SCSI_HBA_TRAN_CLONE)
+                 cdip = ap->a_hba_tran->tran_sd->sd_dev;
+ 
+         if (cdip == NULL || (vdip = ddi_get_parent(cdip)) == NULL ||
+             (vhci = ddi_get_soft_state(vhci_softstate,
+                 ddi_get_instance(vdip))) == NULL) {
+                 VHCI_DEBUG(2, (CE_WARN, NULL, "!%s: "
+                     "Child info pointer NULL, cdip 0x%p",
+                     __func__, (void *)cdip));
+                 return (0);
+         }
+ 
+         rval = mdi_select_path(cdip, NULL, MDI_SELECT_ONLINE_PATH, NULL, &pip);
+         if ((rval != MDI_SUCCESS) || (pip == NULL)) {
+                 VHCI_DEBUG(2, (CE_WARN, NULL, "!%s: "
+                     "Unable to get a path, dip 0x%p",
+                     __func__, (void *)cdip));
+                 return (0);
+         }
+ again:
+         svp = (scsi_vhci_priv_t *)mdi_pi_get_vhci_private(pip);
+ 
+         if (svp == NULL || svp->svp_psd == NULL) {
+                 VHCI_DEBUG(2, (CE_WARN, NULL, "!%s: "
+                     "private data is NULL, pip 0x%p",
+                     __func__, (void *)pip));
+                 mdi_rele_path(pip);
+                 return (0);
+         }
+ 
+         pap = &svp->svp_psd->sd_address;
+         hba = pap->a_hba_tran;
+ 
+         if (pap != NULL && hba != NULL && hba->tran_reset != NULL) {
+                 /*
+                  * The following sends reset down all available paths
+                  */
+                 if (sps == MDI_SUCCESS) {
+                         reset_result = hba->tran_reset(pap, RESET_LUN);
+ 
+                         VHCI_DEBUG(2, (CE_WARN, vdip, "!%s%d: "
+                             "path %s, reset LUN %s",
+                             ddi_driver_name(cdip), ddi_get_instance(cdip),
+                             mdi_pi_spathname(pip),
+                             (reset_result ? "Success" : "Failed")));
+ 
+                         /*
+                          * Select next path and issue the reset, repeat
+                          * until all paths are exhausted regardless of success
+                          * or failure of the previous reset.
+                          */
+                         sps = mdi_select_path(cdip, NULL,
+                             MDI_SELECT_ONLINE_PATH, pip, &npip);
+                         if ((sps != MDI_SUCCESS) || (npip == NULL)) {
+                                 mdi_rele_path(pip);
+                                 return (0);
+                         }
+                         mdi_rele_path(pip);
+                         pip = npip;
+                         goto again;
+                 }
+                 mdi_rele_path(pip);
+                 mutex_enter(&vhci->vhci_mutex);
+                 scsi_hba_reset_notify_callback(&vhci->vhci_mutex,
+                     &vhci->vhci_reset_notify_listf);
+                 mutex_exit(&vhci->vhci_mutex);
+                 VHCI_DEBUG(6, (CE_NOTE, NULL, "!vhci_scsi_reset_target: "
+                     "reset %d sent down pip:%p for cdip:%p\n", RESET_LUN,
+                     (void *)pip, (void *)cdip));
+                 return (1);
+         }
+         mdi_rele_path(pip);
+         return (0);
+ }
+ 
  /*
   * called by vhci_getcap and vhci_setcap to get and set (respectively)
   * SCSI capabilities
   */
  /* ARGSUSED */
*** 3184,3193 ****
--- 3288,3299 ----
          *(tpkt->pkt_scbp) = *(pkt->pkt_scbp);
          tpkt->pkt_resid = pkt->pkt_resid;
          tpkt->pkt_state = pkt->pkt_state;
          tpkt->pkt_statistics = pkt->pkt_statistics;
          tpkt->pkt_reason = pkt->pkt_reason;
+         tpkt->pkt_start = pkt->pkt_start;
+         tpkt->pkt_stop = pkt->pkt_stop;
  
          /* Return path_instance information back to the target driver. */
          if (scsi_pkt_allocated_correctly(tpkt)) {
                  if (scsi_pkt_allocated_correctly(pkt)) {
                          /*
*** 3955,3965 ****
                              PKT_CONSISTENT, NULL, NULL);
                          if (pkt) {
                                  (void) scsi_setup_cdb((union scsi_cdb *)
                                      (uintptr_t)pkt->pkt_cdbp, SCMD_READ, 1, 1,
                                      0);
!                                 pkt->pkt_time = 3*30;
                                  pkt->pkt_flags = FLAG_NOINTR;
                                  pkt->pkt_path_instance =
                                      mdi_pi_get_path_instance(pip);
  
                                  if ((scsi_transport(pkt) == TRAN_ACCEPT) &&
--- 4061,4071 ----
                              PKT_CONSISTENT, NULL, NULL);
                          if (pkt) {
                                  (void) scsi_setup_cdb((union scsi_cdb *)
                                      (uintptr_t)pkt->pkt_cdbp, SCMD_READ, 1, 1,
                                      0);
!                                 pkt->pkt_time = 2 * vhci_io_time;
                                  pkt->pkt_flags = FLAG_NOINTR;
                                  pkt->pkt_path_instance =
                                      mdi_pi_get_path_instance(pip);
  
                                  if ((scsi_transport(pkt) == TRAN_ACCEPT) &&
*** 5220,5230 ****
                                      (void *)pip));
                                  rval = MDI_FAILURE;
                                  goto failure;
                          }
                          pkt->pkt_cdbp[0] = SCMD_RELEASE;
!                         pkt->pkt_time = 60;
  
                          VHCI_DEBUG(1, (CE_NOTE, NULL,
                              "!vhci_path_online: path:%p "
                              "Issued SCSI-2 RELEASE\n", (void *)pip));
  
--- 5326,5336 ----
                                      (void *)pip));
                                  rval = MDI_FAILURE;
                                  goto failure;
                          }
                          pkt->pkt_cdbp[0] = SCMD_RELEASE;
!                         pkt->pkt_time = vhci_io_time;
  
                          VHCI_DEBUG(1, (CE_NOTE, NULL,
                              "!vhci_path_online: path:%p "
                              "Issued SCSI-2 RELEASE\n", (void *)pip));
  
*** 6147,6162 ****
                              "Unable to get a path, dip 0x%p", (void *)child));
                          rv = ENXIO;
                          break;
                  }
                  svp = (scsi_vhci_priv_t *)mdi_pi_get_vhci_private(pip);
!                 if (vhci_recovery_reset(svp->svp_svl,
!                     &svp->svp_psd->sd_address, TRUE,
!                     VHCI_DEPTH_TARGET) == 0) {
!                         VHCI_DEBUG(1, (CE_NOTE, NULL,
!                             "!vhci_ioctl(pip:%p): "
!                             "reset failed\n", (void *)pip));
                          rv = ENXIO;
                  }
                  mdi_rele_path(pip);
                  break;
  
--- 6253,6271 ----
                              "Unable to get a path, dip 0x%p", (void *)child));
                          rv = ENXIO;
                          break;
                  }
                  svp = (scsi_vhci_priv_t *)mdi_pi_get_vhci_private(pip);
! 
!                 VHCI_DEBUG(2, (CE_NOTE, NULL,
!                     "!reset %s@%s on all available paths",
!                     ndi_dc_getname(dcp), ndi_dc_getaddr(dcp)));
! 
!                 if (vhci_scsi_reset_all_paths(&svp->svp_psd->sd_address) != 0) {
!                         VHCI_DEBUG(2, (CE_WARN, NULL,
!                             "!vhci_ioctl(pip:%p): reset failed\n",
!                             (void *)pip));
                          rv = ENXIO;
                  }
                  mdi_rele_path(pip);
                  break;
  
*** 6976,6986 ****
                          (void) scsi_setup_cdb((union scsi_cdb *)(uintptr_t)
                              pkt->pkt_cdbp, SCMD_READ, 1, 1, 0);
                          pkt->pkt_flags = FLAG_NOINTR;
  check_path_again:
                          pkt->pkt_path_instance = mdi_pi_get_path_instance(npip);
!                         pkt->pkt_time = 3*30;
  
                          if (scsi_transport(pkt) == TRAN_ACCEPT) {
                                  switch (pkt->pkt_reason) {
                                  case CMD_CMPLT:
                                          switch (SCBP_C(pkt)) {
--- 7085,7095 ----
                          (void) scsi_setup_cdb((union scsi_cdb *)(uintptr_t)
                              pkt->pkt_cdbp, SCMD_READ, 1, 1, 0);
                          pkt->pkt_flags = FLAG_NOINTR;
  check_path_again:
                          pkt->pkt_path_instance = mdi_pi_get_path_instance(npip);
!                         pkt->pkt_time = 2 * vhci_io_time;
  
                          if (scsi_transport(pkt) == TRAN_ACCEPT) {
                                  switch (pkt->pkt_reason) {
                                  case CMD_CMPLT:
                                          switch (SCBP_C(pkt)) {
*** 8337,8347 ****
              SCMD_REQUEST_SENSE, 0, SENSE_LENGTH, 0);
  
          mp_uscmdp->rqbp = rqbp;
          rqbp->b_private = mp_uscmdp;
          rqpkt->pkt_flags |= FLAG_SENSING;
!         rqpkt->pkt_time = 60;
          rqpkt->pkt_comp = vhci_uscsi_iodone;
          rqpkt->pkt_private = mp_uscmdp;
  
          /*
           * NOTE: This code path is related to MPAPI uscsi(7I), so path
--- 8446,8456 ----
              SCMD_REQUEST_SENSE, 0, SENSE_LENGTH, 0);
  
          mp_uscmdp->rqbp = rqbp;
          rqbp->b_private = mp_uscmdp;
          rqpkt->pkt_flags |= FLAG_SENSING;
!         rqpkt->pkt_time = vhci_io_time;
          rqpkt->pkt_comp = vhci_uscsi_iodone;
          rqpkt->pkt_private = mp_uscmdp;
  
          /*
           * NOTE: This code path is related to MPAPI uscsi(7I), so path
*** 8552,8561 ****
--- 8661,8673 ----
                  biodone(bp);
                  return (EINVAL);
          }
  
          pkt->pkt_time = uscmdp->uscsi_timeout;
+         if (pkt->pkt_time == 0)
+                 pkt->pkt_time = vhci_io_time;
+ 
          bcopy(uscmdp->uscsi_cdb, pkt->pkt_cdbp, (size_t)uscmdp->uscsi_cdblen);
          pkt->pkt_comp = vhci_uscsi_iodone;
          pkt->pkt_private = mp_uscmdp;
          if (uscmdp->uscsi_flags & USCSI_SILENT)
                  pkt->pkt_flags |= FLAG_SILENT;