Thanks, James.
Just checked the code. If the caller tries to set the desire_state to
0x3 (unavailable), an illegal access state request error will be set and
an EINVAL will be returned. 
 
* Constants for accessState */
 
#define MP_DRVR_ACCESS_STATE_ACTIVE_OPTIMIZED         0
#define MP_DRVR_ACCESS_STATE_ACTIVE_NONOPTIMIZED      0x1
#define MP_DRVR_ACCESS_STATE_STANDBY                  0x2
#define MP_DRVR_ACCESS_STATE_UNAVAILABLE              0x3
#define MP_DRVR_ACCESS_STATE_TRANSITIONING            0xf
#define MP_DRVR_ACCESS_STATE_ACTIVE                   0x10
 
 
 
 
 
 
/* ARGSUSED */
static int
vhci_set_tpg_access_state(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
    void *input_data, void *output_data, int mode)
{
        int                    rval = 0, retval = 0, held = 0;
        uint32_t               desired_state, t10_tpgid;
        uint64_t               lu_oid, tpg_oid;
        mp_set_tpg_state_req_t mp_set_tpg;
        mpapi_item_list_t      *lu_list, *tpg_list;
        mpapi_tpg_data_t       *mptpgd;
        scsi_vhci_lun_t        *svl;
        scsi_vhci_priv_t       *svp;
        mdi_pathinfo_t         *pip;
        struct scsi_address    *ap = NULL;
 
        lu_list =
vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_MULTIPATH_LU]
            ->head;
        tpg_list =
vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_TARGET_PORT_GROUP]
            ->head;
 
        rval = ddi_copyin(mpioc->mp_ibuf, &mp_set_tpg, mpioc->mp_ilen,
mode);
        lu_oid = mp_set_tpg.luTpgPair.luId;
        tpg_oid = mp_set_tpg.luTpgPair.tpgId;
        desired_state = mp_set_tpg.desiredState;
 
        VHCI_DEBUG(1, (CE_NOTE, NULL, "vhci_set_tpg_access_state:
lu_oid: %lx,"
            "tpg_oid: %lx, des_as: %x\n", (long)lu_oid, (long)tpg_oid,
            desired_state));
 
        while ((lu_list != NULL) && (lu_oid !=
lu_list->item->oid.raw_oid))
               lu_list = lu_list->next;
        while ((tpg_list != NULL) && (tpg_oid !=
tpg_list->item->oid.raw_oid))
               tpg_list = tpg_list->next;
 
        if ((lu_list == NULL) || (tpg_list == NULL)) {
               VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_set_tpg_access_state:
"
                   "OID NOT FOUND"));
               mpioc->mp_errno = MP_DRVR_INVALID_ID;
               return (EINVAL);
        }
        if ((desired_state != MP_DRVR_ACCESS_STATE_ACTIVE) &&
            (desired_state != MP_DRVR_ACCESS_STATE_ACTIVE_OPTIMIZED) &&
            (desired_state != MP_DRVR_ACCESS_STATE_ACTIVE_NONOPTIMIZED)
&&
            (desired_state != MP_DRVR_ACCESS_STATE_STANDBY)) {
               mpioc->mp_errno = MP_DRVR_ILLEGAL_ACCESS_STATE_REQUEST;
               return (EINVAL);
        }
        mptpgd = (mpapi_tpg_data_t *)(tpg_list->item->idata);
        if (desired_state == mptpgd->prop.accessState) {
               VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_set_tpg_access_"
                   "state: TPG already in desired State"));
               return (EINVAL);
        }
        t10_tpgid = mptpgd->prop.tpgId;
 
        /*
         * All input seems to be ok, Go ahead & change state.
         */
        svl = ((mpapi_lu_data_t *)(lu_list->item->idata))->resp;
        if (!SCSI_FAILOVER_IS_TPGS(svl->svl_fops)) {
 
               VHCI_HOLD_LUN(svl, VH_SLEEP, held);
               /*
                * retval specifically cares about failover
                * status and not about this routine's success.
                */
               retval = mdi_failover(vhci->vhci_dip, svl->svl_dip,
                   MDI_FAILOVER_SYNC);
               if (retval != 0) {
                       VHCI_DEBUG(1, (CE_WARN, NULL,
"vhci_set_tpg_access_"
                           "state: FAILOVER FAILED: %x", retval));
                       VHCI_RELEASE_LUN(svl);
                       return (EIO);
               } else {
                       /*
                        * Don't set TPG's accessState here. Let
mdi_failover's
                        * call-back routine "vhci_failover()" call
                        * vhci_mpapi_update_tpg_acc_state_for_lu().
                        */
                       VHCI_DEBUG(1, (CE_WARN, NULL,
"vhci_set_tpg_access_"
                           "state: FAILOVER SUCCESS: %x", retval));
               }
               VHCI_RELEASE_LUN(svl);
        } else {
               /*
                * Send SET_TARGET_PORT_GROUP SCSI Command. This is
supported
                * ONLY by devices which have TPGS EXPLICIT Failover
support.
                */
               retval = mdi_select_path(svl->svl_dip, NULL,
                   MDI_SELECT_ONLINE_PATH, NULL, &pip);
               if ((rval != MDI_SUCCESS) || (pip == NULL)) {
                       VHCI_DEBUG(1, (CE_WARN, NULL,
"vhci_set_tpg_access_"
                           "state: Unable to find path: %x", retval));
                       return (EINVAL);
               }
               svp = (scsi_vhci_priv_t *)mdi_pi_get_vhci_private(pip);
               if (svp == NULL) {
                       VHCI_DEBUG(1, (CE_WARN, NULL,
"vhci_set_tpg_access_"
                           "state: Unable to find vhci private data"));
                       mdi_rele_path(pip);
                       return (EINVAL);
               }
               if (svp->svp_psd == NULL) {
                       VHCI_DEBUG(1, (CE_WARN, NULL,
"vhci_set_tpg_access_"
                           "state: Unable to find scsi device"));
                       mdi_rele_path(pip);
                       return (EINVAL);
               }
               mdi_rele_path(pip);
               ap = &svp->svp_psd->sd_address;
               ASSERT(ap != NULL);
 
               retval = (*tpgs_set_target_groups)
                   (ap, desired_state, t10_tpgid);
               if (retval != 0) {
                       VHCI_DEBUG(1, (CE_WARN, NULL,
"vhci_set_tpg_access_"
                           "state:(ALUA) FAILOVER FAILED: %x", retval));
                       return (EIO);
               } else {
                       /*
                        * Don't set accessState here.
                        * std_report_target_groups() call needs to sync
up
                        * properly.
                        */
                       VHCI_DEBUG(4, (CE_WARN, NULL,
"vhci_set_tpg_access_"
                           "state:(ALUA) FAILOVER SUCCESS: %x",
retval));
 
                       VHCI_HOLD_LUN(svl, VH_NOSLEEP, held);
                       if (!held) {
                               return (TRAN_BUSY);
                       } else {
                               vhci_update_pathstates((void *)svl);
                       }
                       if (desired_state != mptpgd->prop.accessState) {
                               VHCI_DEBUG(1, (CE_WARN, NULL,
"vhci_set_tpg_"
                                   "access_state: TPGAccessState NOT
Set: "
                                   "des_state=%x, cur_state=%x",
desired_state,
                                   mptpgd->prop.accessState));
                               return (EIO);
                       }
 
               }
        }
 
        return (rval);
}

> -----Original Message-----
> From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]
> Sent: Wednesday, November 28, 2007 3:34 PM
> To: Qi, Yanling
> Cc: [email protected]
> Subject: Re: [storage-discuss] Unavailable state in SPC TPGS/ALUA
> 
> Yanling Qi wrote:
> > I would like to understand how the opensolairs MPxIO handles TPGS
> > UNAVAILABLE state. Does MPxIO try to set a target port group to
> > UNAVAILABLE state? If so, in what condition will the MPxIO do so?
> 
> Hi Yanling,
> is this not mentioned in the source?
> 
> http://src.opensolaris.org/source/xref/onnv/onnv-
> gate/usr/src/uts/common/io/scsi/adapters/scsi_vhci/fops
> is a good place to start.
> 
> 
> James C. McPherson
> --
> Senior Kernel Software Engineer, Solaris
> Sun Microsystems
> http://blogs.sun.com/jmcp     http://www.jmcp.homeunix.com/blog
_______________________________________________
storage-discuss mailing list
[email protected]
http://mail.opensolaris.org/mailman/listinfo/storage-discuss

Reply via email to