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;