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