Print this page
4779 vhci shouldn't abuse ddi_get_time(9f)
Reviewed by: Robert Mustacchi <rm@joyent.com>


   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
  23  */



  24 
  25 /*
  26  * Multiplexed I/O SCSI vHCI implementation
  27  */
  28 
  29 #include <sys/conf.h>
  30 #include <sys/file.h>
  31 #include <sys/ddi.h>
  32 #include <sys/sunddi.h>
  33 #include <sys/scsi/scsi.h>
  34 #include <sys/scsi/impl/scsi_reset_notify.h>
  35 #include <sys/scsi/impl/services.h>
  36 #include <sys/sunmdi.h>
  37 #include <sys/mdi_impldefs.h>
  38 #include <sys/scsi/adapters/scsi_vhci.h>
  39 #include <sys/disp.h>
  40 #include <sys/byteorder.h>
  41 
  42 extern uintptr_t scsi_callback_id;
  43 extern ddi_dma_attr_t scsi_alloc_attr;


2209         return (NULL);
2210 }
2211 
2212 static int
2213 vhci_bind_transport(struct scsi_address *ap, struct vhci_pkt *vpkt, int flags,
2214     int (*func)(caddr_t))
2215 {
2216         struct scsi_vhci        *vhci = ADDR2VHCI(ap);
2217         dev_info_t              *cdip = ADDR2DIP(ap);
2218         mdi_pathinfo_t          *pip = NULL;
2219         mdi_pathinfo_t          *npip = NULL;
2220         scsi_vhci_priv_t        *svp = NULL;
2221         struct scsi_device      *psd = NULL;
2222         struct scsi_address     *address = NULL;
2223         struct scsi_pkt         *pkt = NULL;
2224         int                     rval = -1;
2225         int                     pgr_sema_held = 0;
2226         int                     held;
2227         int                     mps_flag = MDI_SELECT_ONLINE_PATH;
2228         struct scsi_vhci_lun    *vlun;
2229         time_t                  tnow;
2230         int                     path_instance = 0;
2231 
2232         vlun = ADDR2VLUN(ap);
2233         ASSERT(vlun != 0);
2234 
2235         if ((vpkt->vpkt_tgt_pkt->pkt_cdbp[0] == SCMD_PROUT) &&
2236             (((vpkt->vpkt_tgt_pkt->pkt_cdbp[1] & 0x1f) ==
2237             VHCI_PROUT_REGISTER) ||
2238             ((vpkt->vpkt_tgt_pkt->pkt_cdbp[1] & 0x1f) ==
2239             VHCI_PROUT_R_AND_IGNORE))) {
2240                 if (!sema_tryp(&vlun->svl_pgr_sema))
2241                         return (TRAN_BUSY);
2242                 pgr_sema_held = 1;
2243                 if (vlun->svl_first_path != NULL) {
2244                         rval = mdi_select_path(cdip, NULL,
2245                             MDI_SELECT_ONLINE_PATH | MDI_SELECT_STANDBY_PATH,
2246                             NULL, &pip);
2247                         if ((rval != MDI_SUCCESS) || (pip == NULL)) {
2248                                 VHCI_DEBUG(4, (CE_NOTE, NULL,
2249                                     "vhci_bind_transport: path select fail\n"));


2347                          * with attach/probe (eg. INQUIRY, block 0 read)
2348                          * are completed by targets even on passive paths
2349                          * If no ONLINE paths available, it is important
2350                          * to set svl_waiting_for_activepath for two
2351                          * reasons: (1) avoid sense analysis in the
2352                          * "external failure detection" codepath in
2353                          * vhci_intr().  Failure to do so will result in
2354                          * infinite loop (unless an ONLINE path becomes
2355                          * available at some point) (2) avoid
2356                          * unnecessary failover (see "---Waiting For Active
2357                          * Path---" comment below).
2358                          */
2359                         VHCI_DEBUG(1, (CE_NOTE, NULL, "!%p in onlining "
2360                             "state\n", (void *)cdip));
2361                         pip = NULL;
2362                         rval = mdi_select_path(cdip, vpkt->vpkt_tgt_init_bp,
2363                             mps_flag, NULL, &pip);
2364                         if ((rval != MDI_SUCCESS) || (pip == NULL)) {
2365                                 if (vlun->svl_waiting_for_activepath == 0) {
2366                                         vlun->svl_waiting_for_activepath = 1;
2367                                         vlun->svl_wfa_time = ddi_get_time();
2368                                 }
2369                                 mps_flag |= MDI_SELECT_STANDBY_PATH;
2370                                 rval = mdi_select_path(cdip,
2371                                     vpkt->vpkt_tgt_init_bp,
2372                                     mps_flag, NULL, &pip);
2373                                 if ((rval != MDI_SUCCESS) || (pip == NULL)) {
2374                                         if (pgr_sema_held) {
2375                                                 sema_v(&vlun->svl_pgr_sema);
2376                                         }
2377                                         return (TRAN_FATAL_ERROR);
2378                                 }
2379                                 goto bind_path;
2380                         }
2381                 } else if ((rval == MDI_FAILURE) ||
2382                     ((rval == MDI_NOPATH) && (path_instance))) {
2383                         if (pgr_sema_held) {
2384                                 sema_v(&vlun->svl_pgr_sema);
2385                         }
2386                         return (TRAN_FATAL_ERROR);
2387                 }
2388 
2389                 if ((pip == NULL) || (rval == MDI_NOPATH)) {
2390                         while (vlun->svl_waiting_for_activepath) {
2391                                 /*
2392                                  * ---Waiting For Active Path---
2393                                  * This device was discovered across a
2394                                  * passive path; lets wait for a little
2395                                  * bit, hopefully an active path will
2396                                  * show up obviating the need for a
2397                                  * failover
2398                                  */
2399                                 tnow = ddi_get_time();
2400                                 if (tnow - vlun->svl_wfa_time >= 60) {
2401                                         vlun->svl_waiting_for_activepath = 0;
2402                                 } else {
2403                                         drv_usecwait(1000);
2404                                         if (vlun->svl_waiting_for_activepath
2405                                             == 0) {
2406                                                 /*
2407                                                  * an active path has come
2408                                                  * online!
2409                                                  */
2410                                                 goto try_again;
2411                                         }
2412                                 }
2413                         }
2414                         VHCI_HOLD_LUN(vlun, VH_NOSLEEP, held);
2415                         if (!held) {
2416                                 VHCI_DEBUG(4, (CE_NOTE, NULL,
2417                                     "!Lun not held\n"));
2418                                 if (pgr_sema_held) {
2419                                         sema_v(&vlun->svl_pgr_sema);
2420                                 }


3607                 vlun->svl_flags |= VLUN_UPDATE_TPG;
3608                 (void) taskq_dispatch(vhci->vhci_update_pathstates_taskq,
3609                     vhci_update_pathstates, (void *)vlun, KM_SLEEP);
3610         } else {
3611                 path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
3612                 vhci_log(CE_NOTE, ddi_get_parent(vlun->svl_dip),
3613                     "!%s (%s%d): Waiting for externally initiated failover "
3614                     "to complete", ddi_pathname(vlun->svl_dip, path),
3615                     ddi_driver_name(vlun->svl_dip),
3616                     ddi_get_instance(vlun->svl_dip));
3617                 kmem_free(path, MAXPATHLEN);
3618                 swarg = kmem_alloc(sizeof (*swarg), KM_NOSLEEP);
3619                 if (swarg == NULL) {
3620                         VHCI_DEBUG(1, (CE_NOTE, NULL, "!vhci_handle_ext_fo: "
3621                             "request packet allocation for %s failed....\n",
3622                             vlun->svl_lun_wwn));
3623                         VHCI_RELEASE_LUN(vlun);
3624                         return (PKT_RETURN);
3625                 }
3626                 swarg->svs_svp = svp;
3627                 swarg->svs_tos = ddi_get_time();
3628                 swarg->svs_pi = vpkt->vpkt_path;
3629                 swarg->svs_release_lun = 0;
3630                 swarg->svs_done = 0;
3631                 /*
3632                  * place a hold on the path...we don't want it to
3633                  * vanish while scsi_watch is in progress
3634                  */
3635                 mdi_hold_path(vpkt->vpkt_path);
3636                 svp->svp_sw_token = scsi_watch_request_submit(svp->svp_psd,
3637                     VHCI_FOWATCH_INTERVAL, SENSE_LENGTH, vhci_efo_watch_cb,
3638                     (caddr_t)swarg);
3639         }
3640         return (BUSY_RETURN);
3641 }
3642 
3643 /*
3644  * vhci_efo_watch_cb:
3645  *      Callback from scsi_watch request to check the failover status.
3646  *      Completion is either due to successful failover or timeout.
3647  *      Upon successful completion, vhci_update_path_states is called.


3668         if (swarg->svs_done) {
3669                 /*
3670                  * Already completed failover or timedout.
3671                  * Waiting for vhci_efo_done to terminate this scsi_watch.
3672                  */
3673                 return (0);
3674         }
3675 
3676         ASSERT(svp != NULL);
3677         vlun = svp->svp_svl;
3678         ASSERT(vlun != NULL);
3679         ASSERT(VHCI_LUN_IS_HELD(vlun));
3680         vlun->svl_efo_update_path = 0;
3681         vdip = ddi_get_parent(vlun->svl_dip);
3682         vhci = ddi_get_soft_state(vhci_softstate,
3683             ddi_get_instance(vdip));
3684 
3685         updt_paths = 0;
3686 
3687         if (pkt->pkt_reason != CMD_CMPLT) {
3688                 if ((ddi_get_time() - swarg->svs_tos) >= VHCI_EXTFO_TIMEOUT) {
3689                         swarg->svs_release_lun = 1;
3690                         goto done;
3691                 }
3692                 return (0);
3693         }
3694         if (*((unsigned char *)statusp) == STATUS_CHECK) {
3695                 rval = vlun->svl_fops->sfo_analyze_sense(svp->svp_psd, sensep,
3696                     vlun->svl_fops_ctpriv);
3697                 switch (rval) {
3698                         /*
3699                          * Only update path states in case path is definitely
3700                          * inactive, or no failover occurred.  For all other
3701                          * check conditions continue pinging.  A unexpected
3702                          * check condition shouldn't cause pinging to complete
3703                          * prematurely.
3704                          */
3705                         case SCSI_SENSE_INACTIVE:
3706                         case SCSI_SENSE_NOFAILOVER:
3707                                 updt_paths = 1;
3708                                 break;
3709                         default:
3710                                 if ((ddi_get_time() - swarg->svs_tos)
3711                                     >= VHCI_EXTFO_TIMEOUT) {
3712                                         swarg->svs_release_lun = 1;
3713                                         goto done;
3714                                 }
3715                                 return (0);
3716                 }
3717         } else if (*((unsigned char *)statusp) ==
3718             STATUS_RESERVATION_CONFLICT) {
3719                 updt_paths = 1;
3720         } else if ((*((unsigned char *)statusp)) &
3721             (STATUS_BUSY | STATUS_QFULL)) {
3722                 return (0);
3723         }
3724         if ((*((unsigned char *)statusp) == STATUS_GOOD) ||
3725             (updt_paths == 1)) {
3726                 /*
3727                  * we got here because we had detected an
3728                  * externally initiated failover; things
3729                  * have settled down now, so let's
3730                  * start up a task to update the
3731                  * path states and target port group
3732                  */
3733                 vlun->svl_efo_update_path = 1;
3734                 swarg->svs_done = 1;
3735                 vlun->svl_swarg = swarg;
3736                 vlun->svl_flags |= VLUN_UPDATE_TPG;
3737                 (void) taskq_dispatch(vhci->vhci_update_pathstates_taskq,
3738                     vhci_update_pathstates, (void *)vlun,
3739                     KM_SLEEP);
3740                 return (0);
3741         }
3742         if ((ddi_get_time() - swarg->svs_tos) >= VHCI_EXTFO_TIMEOUT) {
3743                 swarg->svs_release_lun = 1;
3744                 goto done;
3745         }
3746         return (0);
3747 done:
3748         swarg->svs_done = 1;
3749         (void) taskq_dispatch(vhci->vhci_taskq,
3750             vhci_efo_done, (void *)swarg, KM_SLEEP);
3751         return (0);
3752 }
3753 
3754 /*
3755  * vhci_efo_done:
3756  *      cleanly terminates scsi_watch and free up resources.
3757  *      Called as taskq function in vhci_efo_watch_cb for EFO timeout condition
3758  *      or by vhci_update_path_states invoked during external initiated
3759  *      failover completion.
3760  */
3761 static void
3762 vhci_efo_done(void *arg)




   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
  23  */
  24 /*
  25  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
  26  */
  27 
  28 /*
  29  * Multiplexed I/O SCSI vHCI implementation
  30  */
  31 
  32 #include <sys/conf.h>
  33 #include <sys/file.h>
  34 #include <sys/ddi.h>
  35 #include <sys/sunddi.h>
  36 #include <sys/scsi/scsi.h>
  37 #include <sys/scsi/impl/scsi_reset_notify.h>
  38 #include <sys/scsi/impl/services.h>
  39 #include <sys/sunmdi.h>
  40 #include <sys/mdi_impldefs.h>
  41 #include <sys/scsi/adapters/scsi_vhci.h>
  42 #include <sys/disp.h>
  43 #include <sys/byteorder.h>
  44 
  45 extern uintptr_t scsi_callback_id;
  46 extern ddi_dma_attr_t scsi_alloc_attr;


2212         return (NULL);
2213 }
2214 
2215 static int
2216 vhci_bind_transport(struct scsi_address *ap, struct vhci_pkt *vpkt, int flags,
2217     int (*func)(caddr_t))
2218 {
2219         struct scsi_vhci        *vhci = ADDR2VHCI(ap);
2220         dev_info_t              *cdip = ADDR2DIP(ap);
2221         mdi_pathinfo_t          *pip = NULL;
2222         mdi_pathinfo_t          *npip = NULL;
2223         scsi_vhci_priv_t        *svp = NULL;
2224         struct scsi_device      *psd = NULL;
2225         struct scsi_address     *address = NULL;
2226         struct scsi_pkt         *pkt = NULL;
2227         int                     rval = -1;
2228         int                     pgr_sema_held = 0;
2229         int                     held;
2230         int                     mps_flag = MDI_SELECT_ONLINE_PATH;
2231         struct scsi_vhci_lun    *vlun;

2232         int                     path_instance = 0;
2233 
2234         vlun = ADDR2VLUN(ap);
2235         ASSERT(vlun != 0);
2236 
2237         if ((vpkt->vpkt_tgt_pkt->pkt_cdbp[0] == SCMD_PROUT) &&
2238             (((vpkt->vpkt_tgt_pkt->pkt_cdbp[1] & 0x1f) ==
2239             VHCI_PROUT_REGISTER) ||
2240             ((vpkt->vpkt_tgt_pkt->pkt_cdbp[1] & 0x1f) ==
2241             VHCI_PROUT_R_AND_IGNORE))) {
2242                 if (!sema_tryp(&vlun->svl_pgr_sema))
2243                         return (TRAN_BUSY);
2244                 pgr_sema_held = 1;
2245                 if (vlun->svl_first_path != NULL) {
2246                         rval = mdi_select_path(cdip, NULL,
2247                             MDI_SELECT_ONLINE_PATH | MDI_SELECT_STANDBY_PATH,
2248                             NULL, &pip);
2249                         if ((rval != MDI_SUCCESS) || (pip == NULL)) {
2250                                 VHCI_DEBUG(4, (CE_NOTE, NULL,
2251                                     "vhci_bind_transport: path select fail\n"));


2349                          * with attach/probe (eg. INQUIRY, block 0 read)
2350                          * are completed by targets even on passive paths
2351                          * If no ONLINE paths available, it is important
2352                          * to set svl_waiting_for_activepath for two
2353                          * reasons: (1) avoid sense analysis in the
2354                          * "external failure detection" codepath in
2355                          * vhci_intr().  Failure to do so will result in
2356                          * infinite loop (unless an ONLINE path becomes
2357                          * available at some point) (2) avoid
2358                          * unnecessary failover (see "---Waiting For Active
2359                          * Path---" comment below).
2360                          */
2361                         VHCI_DEBUG(1, (CE_NOTE, NULL, "!%p in onlining "
2362                             "state\n", (void *)cdip));
2363                         pip = NULL;
2364                         rval = mdi_select_path(cdip, vpkt->vpkt_tgt_init_bp,
2365                             mps_flag, NULL, &pip);
2366                         if ((rval != MDI_SUCCESS) || (pip == NULL)) {
2367                                 if (vlun->svl_waiting_for_activepath == 0) {
2368                                         vlun->svl_waiting_for_activepath = 1;
2369                                         vlun->svl_wfa_time = gethrtime();
2370                                 }
2371                                 mps_flag |= MDI_SELECT_STANDBY_PATH;
2372                                 rval = mdi_select_path(cdip,
2373                                     vpkt->vpkt_tgt_init_bp,
2374                                     mps_flag, NULL, &pip);
2375                                 if ((rval != MDI_SUCCESS) || (pip == NULL)) {
2376                                         if (pgr_sema_held) {
2377                                                 sema_v(&vlun->svl_pgr_sema);
2378                                         }
2379                                         return (TRAN_FATAL_ERROR);
2380                                 }
2381                                 goto bind_path;
2382                         }
2383                 } else if ((rval == MDI_FAILURE) ||
2384                     ((rval == MDI_NOPATH) && (path_instance))) {
2385                         if (pgr_sema_held) {
2386                                 sema_v(&vlun->svl_pgr_sema);
2387                         }
2388                         return (TRAN_FATAL_ERROR);
2389                 }
2390 
2391                 if ((pip == NULL) || (rval == MDI_NOPATH)) {
2392                         while (vlun->svl_waiting_for_activepath) {
2393                                 /*
2394                                  * ---Waiting For Active Path---
2395                                  * This device was discovered across a
2396                                  * passive path; lets wait for a little
2397                                  * bit, hopefully an active path will
2398                                  * show up obviating the need for a
2399                                  * failover
2400                                  */
2401                                 if ((gethrtime() - vlun->svl_wfa_time) >=
2402                                     (60 * NANOSEC)) {
2403                                         vlun->svl_waiting_for_activepath = 0;
2404                                 } else {
2405                                         drv_usecwait(1000);
2406                                         if (vlun->svl_waiting_for_activepath
2407                                             == 0) {
2408                                                 /*
2409                                                  * an active path has come
2410                                                  * online!
2411                                                  */
2412                                                 goto try_again;
2413                                         }
2414                                 }
2415                         }
2416                         VHCI_HOLD_LUN(vlun, VH_NOSLEEP, held);
2417                         if (!held) {
2418                                 VHCI_DEBUG(4, (CE_NOTE, NULL,
2419                                     "!Lun not held\n"));
2420                                 if (pgr_sema_held) {
2421                                         sema_v(&vlun->svl_pgr_sema);
2422                                 }


3609                 vlun->svl_flags |= VLUN_UPDATE_TPG;
3610                 (void) taskq_dispatch(vhci->vhci_update_pathstates_taskq,
3611                     vhci_update_pathstates, (void *)vlun, KM_SLEEP);
3612         } else {
3613                 path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
3614                 vhci_log(CE_NOTE, ddi_get_parent(vlun->svl_dip),
3615                     "!%s (%s%d): Waiting for externally initiated failover "
3616                     "to complete", ddi_pathname(vlun->svl_dip, path),
3617                     ddi_driver_name(vlun->svl_dip),
3618                     ddi_get_instance(vlun->svl_dip));
3619                 kmem_free(path, MAXPATHLEN);
3620                 swarg = kmem_alloc(sizeof (*swarg), KM_NOSLEEP);
3621                 if (swarg == NULL) {
3622                         VHCI_DEBUG(1, (CE_NOTE, NULL, "!vhci_handle_ext_fo: "
3623                             "request packet allocation for %s failed....\n",
3624                             vlun->svl_lun_wwn));
3625                         VHCI_RELEASE_LUN(vlun);
3626                         return (PKT_RETURN);
3627                 }
3628                 swarg->svs_svp = svp;
3629                 swarg->svs_tos = gethrtime();
3630                 swarg->svs_pi = vpkt->vpkt_path;
3631                 swarg->svs_release_lun = 0;
3632                 swarg->svs_done = 0;
3633                 /*
3634                  * place a hold on the path...we don't want it to
3635                  * vanish while scsi_watch is in progress
3636                  */
3637                 mdi_hold_path(vpkt->vpkt_path);
3638                 svp->svp_sw_token = scsi_watch_request_submit(svp->svp_psd,
3639                     VHCI_FOWATCH_INTERVAL, SENSE_LENGTH, vhci_efo_watch_cb,
3640                     (caddr_t)swarg);
3641         }
3642         return (BUSY_RETURN);
3643 }
3644 
3645 /*
3646  * vhci_efo_watch_cb:
3647  *      Callback from scsi_watch request to check the failover status.
3648  *      Completion is either due to successful failover or timeout.
3649  *      Upon successful completion, vhci_update_path_states is called.


3670         if (swarg->svs_done) {
3671                 /*
3672                  * Already completed failover or timedout.
3673                  * Waiting for vhci_efo_done to terminate this scsi_watch.
3674                  */
3675                 return (0);
3676         }
3677 
3678         ASSERT(svp != NULL);
3679         vlun = svp->svp_svl;
3680         ASSERT(vlun != NULL);
3681         ASSERT(VHCI_LUN_IS_HELD(vlun));
3682         vlun->svl_efo_update_path = 0;
3683         vdip = ddi_get_parent(vlun->svl_dip);
3684         vhci = ddi_get_soft_state(vhci_softstate,
3685             ddi_get_instance(vdip));
3686 
3687         updt_paths = 0;
3688 
3689         if (pkt->pkt_reason != CMD_CMPLT) {
3690                 if ((gethrtime() - swarg->svs_tos) >= VHCI_EXTFO_TIMEOUT) {
3691                         swarg->svs_release_lun = 1;
3692                         goto done;
3693                 }
3694                 return (0);
3695         }
3696         if (*((unsigned char *)statusp) == STATUS_CHECK) {
3697                 rval = vlun->svl_fops->sfo_analyze_sense(svp->svp_psd, sensep,
3698                     vlun->svl_fops_ctpriv);
3699                 switch (rval) {
3700                         /*
3701                          * Only update path states in case path is definitely
3702                          * inactive, or no failover occurred.  For all other
3703                          * check conditions continue pinging.  A unexpected
3704                          * check condition shouldn't cause pinging to complete
3705                          * prematurely.
3706                          */
3707                         case SCSI_SENSE_INACTIVE:
3708                         case SCSI_SENSE_NOFAILOVER:
3709                                 updt_paths = 1;
3710                                 break;
3711                         default:
3712                                 if ((gethrtime() - swarg->svs_tos)
3713                                     >= VHCI_EXTFO_TIMEOUT) {
3714                                         swarg->svs_release_lun = 1;
3715                                         goto done;
3716                                 }
3717                                 return (0);
3718                 }
3719         } else if (*((unsigned char *)statusp) ==
3720             STATUS_RESERVATION_CONFLICT) {
3721                 updt_paths = 1;
3722         } else if ((*((unsigned char *)statusp)) &
3723             (STATUS_BUSY | STATUS_QFULL)) {
3724                 return (0);
3725         }
3726         if ((*((unsigned char *)statusp) == STATUS_GOOD) ||
3727             (updt_paths == 1)) {
3728                 /*
3729                  * we got here because we had detected an
3730                  * externally initiated failover; things
3731                  * have settled down now, so let's
3732                  * start up a task to update the
3733                  * path states and target port group
3734                  */
3735                 vlun->svl_efo_update_path = 1;
3736                 swarg->svs_done = 1;
3737                 vlun->svl_swarg = swarg;
3738                 vlun->svl_flags |= VLUN_UPDATE_TPG;
3739                 (void) taskq_dispatch(vhci->vhci_update_pathstates_taskq,
3740                     vhci_update_pathstates, (void *)vlun,
3741                     KM_SLEEP);
3742                 return (0);
3743         }
3744         if ((gethrtime() - swarg->svs_tos) >= VHCI_EXTFO_TIMEOUT) {
3745                 swarg->svs_release_lun = 1;
3746                 goto done;
3747         }
3748         return (0);
3749 done:
3750         swarg->svs_done = 1;
3751         (void) taskq_dispatch(vhci->vhci_taskq,
3752             vhci_efo_done, (void *)swarg, KM_SLEEP);
3753         return (0);
3754 }
3755 
3756 /*
3757  * vhci_efo_done:
3758  *      cleanly terminates scsi_watch and free up resources.
3759  *      Called as taskq function in vhci_efo_watch_cb for EFO timeout condition
3760  *      or by vhci_update_path_states invoked during external initiated
3761  *      failover completion.
3762  */
3763 static void
3764 vhci_efo_done(void *arg)