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,15 +16,14 @@
  * 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 2018 Nexenta Systems, Inc.
  * Copyright (c) 2016 by Delphix. All rights reserved.
  */
 
 /*
  * Multiplexed I/O SCSI vHCI implementation
@@ -52,10 +51,15 @@
 
 /* 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,10 +134,11 @@
 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,11 +1389,11 @@
                                 vlun->svl_flags &= ~VLUN_QUIESCED_FLG;
                                 return (TRAN_FATAL_ERROR);
                         }
 
                         rel_pkt->pkt_cdbp[0] = SCMD_RELEASE;
-                        rel_pkt->pkt_time = 60;
+                        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,24 +1538,20 @@
  *
  * 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));
+        } else {
+                return (0);
         }
-
-        return (rval);
 }
 
 /*
  * vhci_recovery_reset:
  *      Issues reset to the device
@@ -1612,11 +1613,11 @@
  * 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;
+        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,11 +1633,18 @@
                         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,19 +1711,115 @@
         }
         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,10 +3288,12 @@
         *(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,11 +4061,11 @@
                             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_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,11 +5326,11 @@
                                     (void *)pip));
                                 rval = MDI_FAILURE;
                                 goto failure;
                         }
                         pkt->pkt_cdbp[0] = SCMD_RELEASE;
-                        pkt->pkt_time = 60;
+                        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,16 +6253,19 @@
                             "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));
+
+                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,11 +7085,11 @@
                         (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;
+                        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,11 +8446,11 @@
             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_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,10 +8661,13 @@
                 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;