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;