/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include "cfga_fp.h"
/* Structure for walking the tree */
typedef struct {
char *xport_logp;
int l_errno;
typedef struct {
const char *ntype;
const char *name;
/* The TYPE field is parseable and should not contain spaces */
/* Indicates no plag passing */
#define NO_FLAG 0
/* defines for retry algorithm */
/* define for fcp scsi passthru wait */
/* define for fcp pseudo node */
/* Function prototypes */
static const char *get_device_type(di_node_t);
int *l_errnop);
int *l_errnop);
int *l_errnop);
/*
* This has to be the LAST entry for DTYPE_UNKNOWN_INDEX.
* Add entries before this.
*/
};
/*
* Main routine for list operation.
* It calls various routines to consturct ldata list and
* postprocess the list data.
*
* Overall algorithm:
* Get the device list on input hba port and construct ldata list for
* accesible devices.
* Stat hba port and devices through walking the device tree.
* Verify the validity of the list data.
*/
ldata_list_t **llpp,
int *nelemp,
char **errstring)
{
int retry;
return (FPCFGA_ERR);
}
/* Create the hba logid (also base component of logical ap_id) */
return (FPCFGA_ERR);
}
return (ret);
}
/*
* If stating a specific device, we will do limited stat on fca port.
* otherwise full stat on fca part is required.
* If stating a specific device we don't know if it exists or is
* configured yet. larg.ret is set to apid noexist for do_stat_dev.
* otherwise larg.ret is set to ok initially.
*/
} else {
limited_stat = 0; /* for do_stat_fca_xport */
}
/* For all list commands, the fca port needs to be stat'ed */
return (ret);
}
#ifdef DEBUG
if (limited_stat) {
} else {
}
#endif
/*
* If stat'ing a FCA port or ALL, we have the bus stat data at
* this point.
* Assume that the bus has no configured children.
*/
case FPCFGA_STAT_FC_DEV:
/* la_wwn_t has uchar_t raw_wwn[8] thus no need to free. */
return (FPCFGA_LIB_ERR);
}
/*
* if the dyncomp exists on disco ports construct list_data
* otherwise return FPCFGA_APID_NOEXIST.
*/
retry = 0;
do {
if (status == HBA_STATUS_ERROR_STALE_DATA) {
/* get Port Attributes again after refresh. */
} else {
break; /* either okay or some other error */
}
} while (retry++ < HBA_MAX_RETRIES);
if (status == HBA_STATUS_OK) {
/*
* if dyncomp found in disco ports
* construct ldata_list and return.
* otherwise continue to stat on dev tree with
* larg.ret set to access_ok which informs stat_fc_dev
* the existence of device on disco ports.
*
* if path is null that guatantees the node is not
* configured. if node is detached the path
* is incomplete and not usable for further
* operations like uscsi_inq so take care of it here.
*/
ERR_LIST, 0);
return (FPCFGA_LIB_ERR);
}
n = 0;
FPCFGA_OK) {
return (FPCFGA_LIB_ERR);
}
*nelemp = n;
return (FPCFGA_OK);
}
} else if (status == HBA_STATUS_ERROR_ILLEGAL_WWN) {
/*
* path indicates if the node exists in dev tree.
* if not found in dev tree return apid no exist.
* otherwise continue to stat with larg.ret set to
* apid_noexist.
*/
return (FPCFGA_APID_NOEXIST);
}
} else { /* any error */
/*
* path indicates if the node exists in dev tree.
* if not found in dev tree return lib error.
* otherwise continue to stat with larg.ret set to
* apid_noexist.
*/
return (FPCFGA_LIB_ERR);
}
}
break;
case FPCFGA_STAT_ALL:
/*
* for each dev in disco ports, create a ldata_list element.
* if if no disco ports found, continue to stat on devinfo tree
* to see if any node exist on the fca port.
*/
for (discIndex = 0;
discIndex++) {
discIndex, &discPortAttrs)) {
/* Move on to the next target */
continue;
}
return (FPCFGA_LIB_ERR);
}
if ((ret = init_ldata_for_accessible_dev(
return (FPCFGA_LIB_ERR);
}
}
break;
default:
break;
}
/* we need to stat at least 1 device for all commands */
} else {
}
/*
* Subtree is ALWAYS rooted at the HBA (not at the device) as
* otherwise deadlock may occur if bus is disconnected.
*
* DINFOPROP was sufficient on apidp->xport_phys prior to the support
* on scsi_vhci child node. In order to get the link between
* scsi_vhci node and path info node the snap shot of the
* the whole device tree is required with DINFOCPYALL | DINFOPATH flag.
*/
/*
* ret from walk_tree is either FPCFGA_OK or FPCFGA_ERR.
* larg.ret is used to detect other errors. Make sure larg.ret
* is set to a correct error.
*/
if (ret != FPCFGA_APID_NOEXIST) {
}
/* if larg.ret = FPCFGA_APID_NOEXIST; */
goto out;
}
n = 0;
NO_FLAG);
goto out;
}
*nelemp = n;
/* FALLTHROUGH */
out:
return (ret);
}
/*
* Main routine for list operation when show_FCP_dev option is given.
* It calls various routines to consturct ldata list and
* postprocess the list data.
*
* The difference between do_list() and do_list_FCP_dev() is to
* process FCP SCSI LUN data list via uscsi report lun operation and
* stat lun level instead of port WWN based target level.
* The rest of logic is same.
*
* Overall algorithm:
* Get the device list on input hba port and construct ldata list for
* accesible devices.
* For each configured device, USCSI report lun is issued and ldata list
* with FCP device level(LUN) information is created.
* Stat hba port and LUN devices through walking the device tree.
* Verify the validity of the list data.
*/
const char *ap_id,
ldata_list_t **llpp,
int *nelemp,
char **errstring)
{
int retry;
return (FPCFGA_ERR);
}
return (FPCFGA_LIB_ERR);
}
/* Extract the base(hba) and dynamic(device) component if any */
return (FPCFGA_LIB_ERR);
}
/* Remove the dynamic component from the base. */
*dyn = '\0';
/* if lun dyncomp exists delete it */
*lun_dyn = '\0';
}
}
/* Create the hba logid (also base component of logical ap_id) */
&l_errno);
return (FPCFGA_ERR);
}
return (ret);
}
/*
* If stating a specific device, we will do limited stat on fca port.
* otherwise full stat on fca part is required.
* If stating a specific device we don't know if it exists or is
* configured yet. larg.ret is set to apid noexist for do_stat_dev.
* otherwise larg.ret is set to ok initially.
*/
} else {
limited_stat = 0; /* for do_stat_fca_xport */
}
/* For all list commands, the fca port needs to be stat'ed */
return (ret);
}
/*
* If stat'ing a FCA port or ALL, we have the bus stat data at
* this point.
* Assume that the bus has no configured children.
*/
case FPCFGA_STAT_FC_DEV:
/* la_wwn_t has uchar_t raw_wwn[8] thus no need to free. */
return (FPCFGA_LIB_ERR);
}
/*
* if the dyncomp exists on disco ports construct list_data
* otherwise return FPCFGA_APID_NOEXIST.
*/
retry = 0;
do {
if (status == HBA_STATUS_ERROR_STALE_DATA) {
/* get Port Attributes again after refresh. */
} else {
break; /* either okay or some other error */
}
} while (retry++ < HBA_MAX_RETRIES);
if (status == HBA_STATUS_OK) {
/*
* if dyncomp exists only in dev list
* construct ldata_list and return.
* otherwise continue to stat on dev tree with
* larg.ret set to access_ok which informs stat_fc_dev
* the existence of device on dev_list.
*
* if path is null that guatantees the node is not
* configured. if node is detached the path
* is incomplete and not usable for further
* operations like uscsi_inq so take care of it here.
*/
if (status == HBA_STATUS_OK) {
} else if (status == HBA_STATUS_ERROR_NOT_A_TARGET) {
} else {
}
ERR_LIST, 0);
return (FPCFGA_LIB_ERR);
}
if ((ret = get_accessible_FCP_dev_ldata(
!= FPCFGA_OK) {
return (FPCFGA_LIB_ERR);
} else {
/* continue to stat dev with access okay. */
}
} else if (status == HBA_STATUS_ERROR_ILLEGAL_WWN) {
/*
* path indicates if the node exists in dev tree.
* if not found in dev tree return apid no exist.
* otherwise continue to stat with larg.ret set to
* apid_noexist.
*/
return (FPCFGA_APID_NOEXIST);
}
} else { /* not found or any error */
/*
* continue to stat dev with larg.ret set to
* apid_noexist.
*/
}
break;
case FPCFGA_STAT_ALL:
/*
* for each dev in disco ports, create a ldata_list element.
* if if no disco ports found, continue to stat on devinfo tree
* to see if any node exist on the fca port.
*/
for (discIndex = 0;
discIndex++) {
discIndex, &discPortAttrs)) {
/* Move on to the next target */
continue;
}
return (FPCFGA_LIB_ERR);
}
if (status == HBA_STATUS_OK) {
} else if (status == HBA_STATUS_ERROR_NOT_A_TARGET) {
} else {
}
if ((ret = init_ldata_for_accessible_dev(
return (FPCFGA_LIB_ERR);
}
if ((ret = get_accessible_FCP_dev_ldata(
return (ret);
}
}
break;
/* default: continue */
}
/* we need to stat at least 1 device for all commands */
} else {
}
/*
* Subtree is ALWAYS rooted at the HBA (not at the device) as
* otherwise deadlock may occur if bus is disconnected.
*
* DINFOPROP was sufficient on apidp->xport_phys prior to the support
* on scsi_vhci child node. In order to get the link between
* scsi_vhci node and path info node the snap shot of the
* the whole device tree is required with DINFOCPYALL | DINFOPATH flag.
*/
/*
* ret from walk_tree is either FPCFGA_OK or FPCFGA_ERR.
* larg.ret is used to detect other errors. Make sure larg.ret
* is set to a correct error.
*/
if (ret != FPCFGA_APID_NOEXIST) {
}
/* if larg.ret = FPCFGA_APID_NOEXIST return. */
return (ret);
}
n = 0;
flags);
return (FPCFGA_LIB_ERR);
}
*nelemp = n;
return (FPCFGA_OK);
}
/*
* This routine returns initialize struct fcp_ioctl.
*/
static void
struct fcp_scsi_cmd *fscsi,
void *scmdbuf,
void *respbuf,
void *sensebuf,
{
fscsi->scsi_fc_rspcode = 0;
fscsi->scsi_bufresid = 0;
fscsi->scsi_bufstatus = 0;
fscsi->scsi_rqresid = 0;
}
/*
* This routine returns issues FCP_TGT_SEND_SCSI
*/
static fpcfga_ret_t
const char *xport_phys,
struct fcp_scsi_cmd *fscsi,
int *l_errnop)
{
return (FPCFGA_LIB_ERR);
}
retry = 0;
(void) usleep(OPEN_RETRY_INTERVAL);
}
if (fcp_fd < 0) {
return (FPCFGA_LIB_ERR);
}
retry = 0;
(retry++ < IOCTL_RETRY_COUNT &&
== STATUS_BUSY)) {
(void) usleep(IOCTL_RETRY_INTERVAL);
}
return (FPCFGA_FCP_SEND_SCSI_DEV_NOT_TGT);
return (FPCFGA_FCP_TGT_SEND_SCSI_FAILED);
}
return (FPCFGA_OK);
}
/*
* This routine returns standard inq data for
* a target represented by dyncomp.
*
* Calls FCP passthru ioctl FCP_TGT_SEND_SCSI to get inquiry data.
*
* Caller should free the *inq_buf.
*/
static fpcfga_ret_t
const char *xport_phys,
const char *dyncomp,
struct scsi_inquiry **inq_buf,
int *l_errnop)
{
int alloc_len;
alloc_len = sizeof (struct scsi_inquiry);
return (FPCFGA_LIB_ERR);
}
return (FPCFGA_LIB_ERR);
}
sizeof (struct scsi_extended_sense));
!= FPCFGA_OK) {
return (ret);
}
return (FPCFGA_OK);
}
/*
* This routine returns report lun data and number of luns found
* on a target represented by dyncomp.
*
* Calls FCP passthru ioctl FCP_TGT_SEND_SCSI to get report lun data.
*
* Caller should free the *resp_buf when FPCFGA_OK is returned.
*/
const char *xport_phys,
const char *dyncomp,
int *num_luns,
struct scsi_extended_sense *sensebuf,
int *l_errnop)
{
int alloc_len;
alloc_len = sizeof (struct report_lun_resp);
return (FPCFGA_LIB_ERR);
}
return (FPCFGA_LIB_ERR);
}
/* sending to LUN 0 so initializing lun_data buffer to be 0 */
sizeof (struct scsi_extended_sense));
!= FPCFGA_OK) {
return (ret);
}
(sizeof (struct report_lun_resp) - REPORT_LUN_HDR_SIZE)) {
== NULL) {
return (FPCFGA_LIB_ERR);
}
!= FPCFGA_OK) {
return (ret);
}
}
/* num_lun represent number of luns * 8. */
return (FPCFGA_OK);
}
/*
* Routine for consturct ldata list for each FCP SCSI LUN device
* for a discovered target device.
* It calls get_report_lun_data to get report lun data and
* construct ldata list per each lun.
*
* It is called only when show_FCP_dev option is given.
*
* Overall algorithm:
* Get the report lun data thru FCP passthru ioctl.
* Call init_ldata_for_accessible_FCP_dev to process the report LUN data.
* For each LUN found standard inquiry is issued to get device type.
*/
static fpcfga_ret_t
const char *dyncomp,
int *l_errnop)
{
int num_luns;
/*
* when report lun data fails then return FPCFGA_OK thus
* keep the ldata for the target which is acquired previously.
* For remote hba node this will be normal.
* For a target error may already be detected through
* FCP_TGT_INQ.
*/
if ((ret == FPCFGA_FCP_TGT_SEND_SCSI_FAILED) ||
(ret == FPCFGA_FCP_SEND_SCSI_DEV_NOT_TGT)) {
}
return (ret);
}
if (num_luns > 0) {
} else {
/*
* proceed with to stat if no lun found.
* This will make the target apid will be kept.
*/
}
return (ret);
}
/*
* Routine for checking validity of ldata list based on input argumemnt.
* Set the occupant state of hba port if the list is valid.
*/
static fpcfga_ret_t
const ldata_list_t *listp,
int *np,
{
int i;
*np = 0;
return (FPCFGA_ERR);
}
i++;
/* A bus stat data */
#ifdef DEBUG
} else {
#endif
}
}
switch (cmd) {
case FPCFGA_STAT_FC_DEV:
return (FPCFGA_LIB_ERR);
}
} else {
return (FPCFGA_LIB_ERR);
}
}
break;
case FPCFGA_STAT_FCA_PORT:
return (FPCFGA_LIB_ERR);
}
break;
case FPCFGA_STAT_ALL:
return (FPCFGA_LIB_ERR);
}
break;
default:
return (FPCFGA_LIB_ERR);
}
*np = i;
/* Fill in the occupant (child) state. */
if (xport_ldatap != NULL) {
}
return (FPCFGA_OK);
}
/*
* Routine for checking each target device found in device tree.
* When the matching port WWN dev is found from the accessble ldata list
* the target device is updated with configured ostate.
*
* Overall algorithm:
* Parse the device tree to find configured devices which matches with
* list argument. If cmd is stat on a specific target device it
* matches port WWN and continues to further processing. If cmd is
* stat on hba port all the device target under the hba are processed.
*/
static int
{
int count;
/*
* Skip partial nodes
*
* This checking is from the scsi plug-in and will be deleted for
* fp plug-in. The node will be processed for fp even if it is
* in driver detached state. From fp perspective the node is configured
* as long as the node is not in offline or down state.
* scsi plug-in considers the known state when it is offlined
* regradless of driver detached state or when it is not in driver
* detached state like normal state.
* If the node is only in driver detached state it is considered as
* unknown state.
*
* if (!known_state(node) && (lap->cmd != FPCFGA_STAT_FC_DEV)) {
* return (DI_WALK_CONTINUE);
*
*/
goto out;
}
goto out;
}
/* Skip node if it is HBA */
match_minor = 0;
goto out;
}
/* If stat'ing a specific device, is this node that device */
/* checks port wwn property to find a match */
!= DI_PROP_NIL) {
if ((strcmp(PORT_WWN_PROP,
di_prop_name(prop)) == 0) &&
(di_prop_type(prop) ==
break;
}
}
if (prop != DI_PROP_NIL) {
goto out;
}
/*
* port wwn doesn't match contine to walk
* if match call do_stat_fc_dev.
*/
WWN_SIZE*2)) {
goto out;
}
} else {
goto out;
}
}
/*
* If stat'ing a xport only, we look at device nodes only to get
* xport configuration status. So a limited stat will suffice.
*/
limited_stat = 1;
} else {
limited_stat = 0;
}
/*
* Ignore errors if stat'ing a bus or listing all
*/
} else {
}
goto out;
}
/* Are we done ? */
/*
* If stat'ing a specific device, we are done at this point.
*/
}
/*FALLTHRU*/
out:
return (rv);
}
/*
* Routine for checking each FCP SCSI LUN device found in device tree.
* When the matching port WWN and LUN are found from the accessble ldata list
* the FCP SCSI LUN is updated with configured ostate.
*
* Overall algorithm:
* Parse the device tree to find configured devices which matches with
* list argument. If cmd is stat on a specific target device it
* matches port WWN and continues to further processing. If cmd is
* stat on hba port all the FCP SCSI LUN under the hba are processed.
*/
static int
{
goto out;
}
goto out;
}
/* Skip node if it is HBA */
match_minor = 0;
goto out;
}
/* If stat'ing a specific device, is this node that device */
/* checks port wwn property to find a match */
if (di_ret == -1) {
goto out;
} else {
/*
* port wwn doesn't match contine to walk
* if match call do_stat_FCP_dev.
*/
WWN_SIZE*2)) {
goto out;
}
}
}
/*
* If stat'ing a xport only, we look at device nodes only to get
* xport configuration status. So a limited stat will suffice.
*/
limited_stat = 1;
} else {
limited_stat = 0;
}
/*
* Ignore errors if stat'ing a bus or listing all
*/
goto out;
}
/* Are we done ? */
}
/*FALLTHRU*/
out:
return (rv);
}
static fpcfga_ret_t
{
int l_errno = 0;
/* Get xport state */
} else {
}
} else {
}
/*
* Get topology works okay even if the fp port is connected
* to a switch and no devices connected to the switch.
* In this case the list will only shows fp port info without
* any device listed.
*/
case HBA_PORTTYPE_NLPORT:
break;
case HBA_PORTTYPE_NPORT:
break;
case HBA_PORTTYPE_LPORT:
break;
case HBA_PORTTYPE_PTP:
break;
/*
* HBA_PORTTYPE_UNKNOWN means nothing is connected
*/
case HBA_PORTTYPE_UNKNOWN:
break;
/* NOT_PRESENT, OTHER, FPORT, FLPORT */
default:
break;
}
if (limited_stat) {
/* We only want to know bus(receptacle) connect status */
return (FPCFGA_OK);
}
return (FPCFGA_LIB_ERR);
}
lap->xport_logp);
/* Link it in. lap->listp is NULL originally. */
/* lap->listp now gets cfga_list_data for the fca port. */
return (FPCFGA_OK);
}
static int
{
return (DI_WALK_TERMINATE);
}
/*
* Routine for updating ldata list based on the state of device node.
* When no matching accessible ldata is found a new ldata is created
* with proper state information.
*
* Overall algorithm:
* If the device node is online and the matching ldata is found
* the target device is updated with configued and unknown condition.
* If the device node is offline or down and the matching ldata is found
* the target device is updated with configued and unusable condition.
* If the device node is online but the matching ldata is not found
* the target device is created with configued and failing condition.
* If the device node is offline or down and the matching ldata is not found
* the target device is created with configued and unusable condition.
*/
static fpcfga_ret_t
const char *nodepath,
int limited_stat)
{
int l_errno = 0;
/*
* NOTE: The framework cannot currently detect layered driver
* opens, so the busy indicator is not very reliable. Also,
* non-root users will not be able to determine busy
* status (libdevice needs root permissions).
* This should probably be fixed by adding a DI_BUSY to the di_state()
* routine in libdevinfo.
*/
} else {
busy = 0;
}
/* We only want to know device config state */
if (limited_stat) {
} else {
if (ostate != CFGA_STAT_UNCONFIGURED) {
}
}
return (FPCFGA_OK);
}
/*
* If child device is configured, see if it is accessible also
* for FPCFGA_STAT_FC_DEV cmd.
*/
switch (ostate) {
case CFGA_STAT_CONFIGURED:
/*
* if configured and not accessble, the device is
* till be displayed with failing condition.
* return code should be FPCFGA_OK to display it.
*/
case CFGA_STAT_NONE:
/*
* If not unconfigured and not attached
* the state is set to CFGA_STAT_NONE currently.
* This is okay for the detached node due to
* the driver being unloaded.
* May need to define another state to
* isolate the detached only state.
*
* handle the same way as configured.
*/
}
break;
case CFGA_STAT_UNCONFIGURED:
/*
* if unconfigured - offline or down,
* set to cond to unusable regardless of accessibility.
* This behavior needs to be examined further.
* When the device is not accessible the node
* may get offline or down. In that case failing
* cond may make more sense.
* In anycase the ostate will be set to configured
* configured.
*/
/*
* For fabric port the fca port is considered as
* configured since user configured previously
* for any existing node. Otherwise when the
* device was accessible, the hba is considered as
* configured.
*/
FP_FC_PUBLIC_PORT_TYPE) == 0) ||
FP_FC_FABRIC_PORT_TYPE) == 0)) ||
} else {
return (FPCFGA_OK);
}
break;
default:
break;
}
/* if device found in disco ports, ldata already created. */
/*
* if cond is not changed then don't update
* condition to keep the previous condition.
*/
if (cond != CFGA_COND_UNKNOWN) {
}
return (FPCFGA_OK);
}
}
/*
* if cmd is stat all check ldata list
* to see if the node exist on the dev list. Otherwise create
* the list element.
*/
return (ret);
}
switch (ret) {
case FPCFGA_ACCESS_OK:
/* node exists so set ostate to configured. */
switch (ostate) {
case CFGA_STAT_CONFIGURED:
/*
* If not unconfigured and not attached
* the state is set to CFGA_STAT_NONE currently.
* This is okay for the detached node due to
* the driver being unloaded.
* May need to define another state to
* isolate the detached only state.
*/
case CFGA_STAT_NONE:
/* update ap_type and ap_info */
break;
/*
* node is offline or down.
* set cond to unusable.
*/
case CFGA_STAT_UNCONFIGURED:
/*
* if cond is not unknown
* we already set the cond from
* a different node with the same
* port WWN or initial probing
* was failed so don't update again.
*/
}
break;
default:
break;
}
/* node found in ldata list so just return. */
return (FPCFGA_OK);
case FPCFGA_LIB_ERR:
return (ret);
case FPCFGA_APID_NOACCESS:
switch (ostate) {
/* node is attached but not in dev list */
case CFGA_STAT_CONFIGURED:
case CFGA_STAT_NONE:
break;
/*
* node is offline or down.
* set cond to unusable.
*/
case CFGA_STAT_UNCONFIGURED:
/*
* For fabric port the fca port is
* considered as configured since user
* configured previously for any
* existing node.
*/
FP_FC_PUBLIC_PORT_TYPE) == 0) ||
FP_FC_FABRIC_PORT_TYPE) == 0)) {
lap->chld_config =
} else {
return (FPCFGA_OK);
}
break;
default:
/*
* continue to create ldata_list struct for
* this node
*/
break;
}
default:
break;
}
} else {
/*
* dev_list is null so there is no accessible dev.
* set the cond and continue to create ldata.
*/
switch (ostate) {
case CFGA_STAT_CONFIGURED:
case CFGA_STAT_NONE:
break;
/*
* node is offline or down.
* set cond to unusable.
*/
case CFGA_STAT_UNCONFIGURED:
/*
* For fabric port the fca port is
* considered as configured since user
* configured previously for any
* existing node.
*/
FP_FC_PUBLIC_PORT_TYPE) == 0) ||
FP_FC_FABRIC_PORT_TYPE) == 0)) {
lap->chld_config =
} else {
return (FPCFGA_OK);
}
break;
default:
break;
}
}
}
return (FPCFGA_LIB_ERR);
}
/* Create the dynamic component. */
return (ret);
}
}
/* Create logical and physical ap_id */
/* set to ostate to configured and set cond with info. */
/* get ap_type and ap_info. */
/* Link it in */
return (FPCFGA_OK);
}
/*
* Wrapper routine for handling path info.
*
* When show_FCP_dev option is given stat_path_info_FCP_dev() is called.
* Otherwise stat_path_info_fc_dev() is called.
*/
int
void *arg,
int *l_errnop)
{
} else {
}
}
/*
* Routine for updating ldata list based on the state of path info node.
* When no matching accessible ldata is found a new ldata is created
* with proper state information.
*
* Overall algorithm:
* If the path info node is not offline and the matching ldata is found
* the target device is updated with configued and unknown condition.
* If the path info node is offline or failed and the matching ldata is found
* the target device is updated with configued and unusable condition.
* If the path info node is online but the matching ldata is not found
* the target device is created with configued and failing condition.
* If the path info is offline or failed and the matching ldata is not found
* the target device is created with configued and unusable condition.
*/
static int
int *l_errnop)
{
int count;
if (root == DI_NODE_NIL) {
return (FPCFGA_LIB_ERR);
}
/*
* if stat on a specific dev and walk_node found it okay
* then just return ok.
*/
return (FPCFGA_OK);
}
/*
* if stat on a fca xport and chld_config is set
* then just return ok.
*/
return (FPCFGA_OK);
}
/*
* when there is no path_info node return FPCFGA_OK.
* That way the result from walk_node shall be maintained.
*/
/*
* if the dev was in dev list but not found
* return OK to indicate is not configured.
*/
}
return (FPCFGA_OK);
}
/* if stat on fca port return. */
return (FPCFGA_OK);
} else {
return (FPCFGA_OK);
}
}
}
/*
* now parse the path info node.
*/
do {
break;
}
case FPCFGA_STAT_FC_DEV:
/* if no match contine to the next path info node. */
WWN_SIZE*2)) {
break;
}
/* if device in dev_list, ldata already created. */
(pstate == DI_PATH_STATE_FAULT)) {
}
return (FPCFGA_OK);
} else {
FP_FC_PUBLIC_PORT_TYPE) == 0) ||
FP_FC_FABRIC_PORT_TYPE) == 0)) {
return (init_ldata_for_mpath_dev(
} else {
if ((di_path_state(path)) !=
return (init_ldata_for_mpath_dev(
} else {
return (FPCFGA_OK);
}
}
}
case FPCFGA_STAT_ALL:
/* check if there is list data. */
if (ret == FPCFGA_ACCESS_OK) {
/*
* Update the condition as unusable
* if the pathinfo state is failed
* or offline.
*/
(pstate ==
}
break;
} else if (ret == FPCFGA_LIB_ERR) {
return (ret);
}
}
/*
* now create ldata for this particular path info node.
* if port top is private loop and pathinfo is in
* in offline state don't include to ldata list.
*/
FP_FC_PUBLIC_PORT_TYPE) == 0) ||
FP_FC_FABRIC_PORT_TYPE) == 0)) ||
(di_path_state(path) !=
return (ret);
}
}
break;
case FPCFGA_STAT_FCA_PORT:
return (FPCFGA_OK);
}
}
} while (path != DI_PATH_NIL);
return (FPCFGA_OK);
}
/*
* Routine for updating ldata list based on the state of path info node.
* When no matching accessible ldata is found a new ldata is created
* with proper state information.
*
* The difference from stat_path_info_fc_dev() is
* to handle FCP SCSI LUN information. Otherwise overall algorithm is
* same.
*
* Overall algorithm:
* If the path info node is not offline and the matching ldata is found
* the target device is updated with configued and unknown condition.
* If the path info node is offline or failed and the matching ldata is found
* the target device is updated with configued and unusable condition.
* If the path info node is online but the matching ldata is not found
* the target device is created with configued and failing condition.
* If the path info is offline or failed and the matching ldata is not found
* the target device is created with configued and unusable condition.
*/
static int
int *l_errnop)
{
int *lun_nump;
if (root == DI_NODE_NIL) {
return (FPCFGA_LIB_ERR);
}
/*
* if stat on a fca xport and chld_config is set
* then just return ok.
*/
return (FPCFGA_OK);
}
/*
* when there is no path_info node return FPCFGA_OK.
* That way the result from walk_node shall be maintained.
*/
/*
* if the dev was in dev list but not found
* return ok.
*/
}
return (FPCFGA_OK);
}
/*
* If stat on fca port and port topology is fabric return here.
* If not fabric return only when path state is not offfline.
* The other cases are handbled below.
*/
return (FPCFGA_OK);
} else {
return (FPCFGA_OK);
}
}
}
/*
* now parse the path info node.
*/
do {
case FPCFGA_STAT_FC_DEV:
return (FPCFGA_LIB_ERR);
}
== FPCFGA_LIB_ERR) {
return (ldata_ret);
}
if (ldata_ret == FPCFGA_ACCESS_OK) {
/*
* Update the condition as unusable
* if the pathinfo state is failed
* or offline.
*/
(pstate == DI_PATH_STATE_FAULT)) {
}
break;
}
!= 0) {
break;
}
/*
* now create ldata for this particular path info node.
* if port top is private loop and pathinfo is in
* in offline state don't include to ldata list.
*/
FP_FC_PUBLIC_PORT_TYPE) == 0) ||
FP_FC_FABRIC_PORT_TYPE) == 0)) ||
(di_path_state(path) !=
/* create ldata for this pi node. */
if (client_node == DI_NODE_NIL) {
return (FPCFGA_LIB_ERR);
}
!= FPCFGA_OK) {
return (FPCFGA_LIB_ERR);
}
return (FPCFGA_LIB_ERR);
}
/* Create logical and physical ap_id */
LUN_COMP_SEP, *lun_nump);
LUN_COMP_SEP, *lun_nump);
/*
* We reached here since FCP dev is not found
* in ldata list but path info node exists.
*
* Update the condition as failing
* if the pathinfo state was normal.
* Update the condition as unusable
* if the pathinfo state is failed
* or offline.
*/
== DI_PATH_STATE_OFFLINE) ||
(pstate == DI_PATH_STATE_FAULT)) {
} else {
}
/* update ap_type and ap_info */
== DEVICE_BUSY) ? 1 : 0;
} else {
busy = 0;
}
(void) insert_ldata_to_ldatalist(port_wwn,
}
break;
case FPCFGA_STAT_ALL:
return (FPCFGA_LIB_ERR);
}
== FPCFGA_LIB_ERR) {
return (ldata_ret);
}
if (ldata_ret == FPCFGA_ACCESS_OK) {
/*
* Update the condition as unusable
* if the pathinfo state is failed
* or offline.
*/
(pstate == DI_PATH_STATE_FAULT)) {
}
break;
}
/*
* now create ldata for this particular path info node.
* if port top is private loop and pathinfo is in
* in offline state don't include to ldata list.
*/
FP_FC_PUBLIC_PORT_TYPE) == 0) ||
FP_FC_FABRIC_PORT_TYPE) == 0)) ||
(di_path_state(path) !=
/* create ldata for this pi node. */
if (client_node == DI_NODE_NIL) {
return (FPCFGA_LIB_ERR);
}
!= FPCFGA_OK) {
return (FPCFGA_LIB_ERR);
}
return (FPCFGA_LIB_ERR);
}
/* Create logical and physical ap_id */
LUN_COMP_SEP, *lun_nump);
LUN_COMP_SEP, *lun_nump);
/*
* We reached here since FCP dev is not found
* in ldata list but path info node exists.
*
* Update the condition as failing
* if the pathinfo state was normal.
* Update the condition as unusable
* if the pathinfo state is failed
* or offline.
*/
== DI_PATH_STATE_OFFLINE) ||
(pstate == DI_PATH_STATE_FAULT)) {
} else {
}
/* update ap_type and ap_info */
== DEVICE_BUSY) ? 1 : 0;
} else {
busy = 0;
}
(void) insert_ldata_to_ldatalist(port_wwn,
}
break;
case FPCFGA_STAT_FCA_PORT:
return (FPCFGA_OK);
}
}
} while (path != DI_PATH_NIL);
return (FPCFGA_OK);
}
/*
* Routine for updating ldata list based on the state of device node.
* When no matching accessible ldata is found a new ldata is created
* with proper state information.
*
* The difference from do_stat_fc_dev() is
* to handle FCP SCSI LUN information. Otherwise overall algorithm is
* same.
*
* Overall algorithm:
* If the device node is online and the matching ldata is found
* the target device is updated with configued and unknown condition.
* If the device node is offline or down and the matching ldata is found
* the target device is updated with configued and unusable condition.
* If the device node is online but the matching ldata is not found
* the target device is created with configued and failing condition.
* If the device node is offline or down and the matching ldata is not found
* the target device is created with configued and unusable condition.
*/
static fpcfga_ret_t
const char *nodepath,
int limited_stat)
{
/*
* NOTE: The devctl framework cannot currently detect layered driver
* opens, so the busy indicator is not very reliable. Also,
* non-root users will not be able to determine busy
* status (libdevice needs root permissions).
* This should probably be fixed by adding a DI_BUSY to the di_state()
* routine in libdevinfo.
*/
} else {
busy = 0;
}
/* We only want to know device config state */
if (limited_stat) {
} else {
if (ostate != CFGA_STAT_UNCONFIGURED) {
}
}
return (FPCFGA_OK);
}
/*
* If child device is configured, see if it is accessible also
* for FPCFGA_STAT_FC_DEV cmd.
*/
return (FPCFGA_LIB_ERR);
}
return (ldata_ret);
}
switch (ostate) {
case CFGA_STAT_CONFIGURED:
/*
* if configured and not accessble, the device is
* till be displayed with failing condition.
* return code should be FPCFGA_OK to display it.
*/
case CFGA_STAT_NONE:
/*
* If not unconfigured and not attached
* the state is set to CFGA_STAT_NONE currently.
* This is okay for the detached node due to
* the driver being unloaded.
* May need to define another state to
* isolate the detached only state.
*
* handle the same way as configured.
*/
if (ldata_ret != FPCFGA_ACCESS_OK) {
}
break;
case CFGA_STAT_UNCONFIGURED:
/*
* if unconfigured - offline or down,
* set to cond to unusable regardless of accessibility.
* This behavior needs to be examined further.
* When the device is not accessible the node
* may get offline or down. In that case failing
* cond may make more sense.
* In anycase the ostate will be set to configured
* configured.
*/
/*
* For fabric port the fca port is considered as
* configured since user configured previously
* for any existing node. Otherwise when the
* device was accessible, the hba is considered as
* configured.
*/
FP_FC_PUBLIC_PORT_TYPE) == 0) ||
FP_FC_FABRIC_PORT_TYPE) == 0)) ||
} else {
/*
* if lap->ret is okay there is at least
* one matching ldata exist. Need to keep
* okay ret to display the matching ones.
*/
}
return (FPCFGA_OK);
}
break;
default:
break;
}
/* if device found in dev_list, ldata already created. */
if (ldata_ret == FPCFGA_ACCESS_OK) {
/*
* if cond is not changed then don't update
* condition to keep any condtion
* from initial discovery. If the initial
* cond was failed the same condition will be kept.
*/
if (cond != CFGA_COND_UNKNOWN) {
}
/* update ap_info via inquiry */
/* update ap_type and ap_info */
return (FPCFGA_OK);
}
}
/*
* if cmd is stat all check ldata list
* to see if the node exist on the dev list. Otherwise create
* the list element.
*/
switch (ldata_ret) {
case FPCFGA_ACCESS_OK:
/* node exists so set ostate to configured. */
switch (ostate) {
case CFGA_STAT_CONFIGURED:
/*
* If not unconfigured and not attached
* the state is set to CFGA_STAT_NONE currently.
* This is okay for the detached node due to
* the driver being unloaded.
* May need to define another state to
* isolate the detached only state.
*/
case CFGA_STAT_NONE:
/* update ap_type and ap_info */
break;
/*
* node is offline or down.
* set cond to unusable.
*/
case CFGA_STAT_UNCONFIGURED:
/*
* if cond is not unknown
* initial probing was failed
* so don't update again.
*/
}
break;
default:
break;
}
/* node found in ldata list so just return. */
return (FPCFGA_OK);
case FPCFGA_APID_NOACCESS:
switch (ostate) {
/* node is attached but not in dev list */
case CFGA_STAT_CONFIGURED:
case CFGA_STAT_NONE:
break;
/*
* node is offline or down.
* set cond to unusable.
*/
case CFGA_STAT_UNCONFIGURED:
/*
* For fabric port the fca port is
* considered as configured since user
* configured previously for any
* existing node.
*/
FP_FC_PUBLIC_PORT_TYPE) == 0) ||
FP_FC_FABRIC_PORT_TYPE) == 0)) {
lap->chld_config =
} else {
return (FPCFGA_OK);
}
break;
default:
/*
* continue to create ldata_list struct for
* this node
*/
break;
}
default:
break;
}
}
return (FPCFGA_LIB_ERR);
}
/* Create logical and physical ap_id */
LUN_COMP_SEP, *lun_nump);
LUN_COMP_SEP, *lun_nump);
return (FPCFGA_OK);
}
/*
* Searches the ldata_list to find if the the input port_wwn exist.
*
* Input: port_wwn, ldata_list.
* Return value: FPCFGA_APID_NOACCESS if not found on ldata_list.
* FPCFGA_ACCESS_OK if found on ldata_list.
*/
static fpcfga_ret_t
{
int len;
break;
}
break;
}
}
}
return (ret);
}
/*
* Searches the ldata_list to find if the the input port_wwn and lun exist.
*
* Input: port_wwn, ldata_list.
* Return value: FPCFGA_APID_NOACCESS if not found on ldata_list.
* FPCFGA_ACCESS_OK if found on ldata_list.
*/
static fpcfga_ret_t
{
int ldata_lun;
/*
* if there is no list data just return the FCP dev list.
* Normally this should not occur since list data should
* be created through discoveredPort list.
*/
return (ret);
}
return (FPCFGA_ACCESS_OK);
return (ret);
}
/* else continue */
} else {
/* we have match without lun comp. */
return (FPCFGA_ACCESS_OK);
}
}
return (FPCFGA_ACCESS_OK);
return (ret);
}
/* else continue */
} else {
/* we have match without lun comp. */
return (FPCFGA_ACCESS_OK);
}
}
}
return (ret);
}
/*
* This routine is called when a pathinfo without matching pwwn in dev_list
* is found.
*/
static fpcfga_ret_t
{
char *devpath;
char *client_path;
/* get the client node path */
if (path == DI_PATH_NIL) {
return (FPCFGA_LIB_ERR);
}
if (client_node == DI_NODE_NIL) {
return (FPCFGA_LIB_ERR);
}
return (FPCFGA_LIB_ERR);
}
return (FPCFGA_LIB_ERR);
}
/* now need to create ldata for this dev */
return (FPCFGA_LIB_ERR);
}
/* Create logical and physical ap_id */
/* Filled in by libcfgadm */
/* set to ostate to configured. */
/*
* This routine is called when a port WWN is not found in dev list
* but path info node exists.
*
* Update the condition as failing if the pathinfo state was normal.
* Update the condition as unusable if the pathinfo state is failed
* or offline.
*/
(pstate == DI_PATH_STATE_FAULT)) {
} else {
}
/* update ap_type and ap_info */
} else {
busy = 0;
}
/* Link it in */
/* now return with ok status with ldata. */
return (FPCFGA_OK);
}
/*
* Initialize the cfga_list_data struct for an accessible device
* from g_get_dev_list().
*
* Input: fca port ldata.
* Output: device cfga_list_data.
*
*/
static fpcfga_ret_t
{
int i;
return (FPCFGA_LIB_ERR);
}
/* Create logical and physical ap_id */
for (i = 0; i < N_DEVICE_TYPES; i++) {
break;
}
}
if (i == N_DEVICE_TYPES) {
if (inq_type == ERR_INQ_DTYPE) {
(char *)GET_MSG_STR(ERR_UNAVAILABLE));
} else {
"%s", "unknown");
}
}
/* Link it in */
return (FPCFGA_OK);
}
/*
* Initialize the cfga_list_data struct for an accessible FCP SCSI LUN device
* from the report lun data.
*
* Input: fca port ldata. report lun info
* Output: device cfga_list_data.
*
*/
static fpcfga_ret_t
const char *port_wwn,
int num_luns,
struct report_lun_resp *resp_buf,
int *l_errnop)
{
int i, j, str_ret;
/* when number of lun is 0 it is not an error. so just return ok. */
if (num_luns == 0) {
return (FPCFGA_OK);
}
for (i = 0; i < num_luns; i++) {
!= FPCFGA_OK) {
if (ret == FPCFGA_FCP_TGT_SEND_SCSI_FAILED) {
} else {
return (FPCFGA_LIB_ERR);
}
} else {
/*
* peripheral qualifier is not 0 so the device node should not
* included in the ldata list. There should not be a device
* node for the lun either.
*/
if (peri_qual != DPQ_POSSIBLE) {
continue;
}
for (j = 0; j < N_DEVICE_TYPES; j++) {
== device_list[j].itype) {
break;
}
}
}
}
/*
* Followed FCP driver for getting lun number from report
* lun data.
* According to SAM-2 there are multiple address method for
* FCP SCIS LUN. Logincal unit addressing, peripheral device
* addressing, flat space addressing, and extended logical
* unit addressing.
*
* as of 11/2001 FCP supports logical unit addressing and
* peripheral device addressing even thoough 3 defined.
* SSFCP_LUN_ADDRESSING 0x80
* SSFCP_PD_ADDRESSING 0x00
* SSFCP_VOLUME_ADDRESSING 0x40
*
* the menthod below is used by FCP when (lun_string[0] & 0xC0)
* is either SSFCP_LUN_ADDRESSING or SSFCP_PD_ADDRESSING mode.
*/
return (FPCFGA_LIB_ERR);
}
/* Create logical and physical ap_id */
if (listp_start == NULL) {
listp_start = listp;
} else {
if ((ret = insert_FCP_dev_ldata(
&listp_start)) != FPCFGA_OK) {
return (ret);
}
}
}
/*
* list data can be null when device peripheral qualifier is not 0
* for any luns. Return ok to continue.
*/
if (listp_start == NULL) {
return (FPCFGA_OK);
}
/*
* get the end of list for later uses.
*/
while (curlp) {
}
/*
* if there is no list data just return the FCP dev list.
* Normally this should not occur since list data should
* be created through g_get_dev_list().
*/
}
return (FPCFGA_OK);
}
} else {
break;
}
} else {
break;
}
}
/* fillup inqdtype */
}
/* link the new elem of lap->listp. */
/* free the one matching wwn. */
/* link lap->listp to listp_start. */
return (FPCFGA_OK);
} else if (str_ret > 0) {
}
return (FPCFGA_OK);
}
}
WWN_SIZE*2)) == 0) {
!= NULL)) {
== 0) {
} else {
break;
}
} else {
break;
}
}
}
/* link the next elem to listp_end. */
/* link prevlp to listp_start to drop curlp. */
/* free matching pwwn elem. */
return (FPCFGA_OK);
} else if (str_ret > 0) {
/*
* Dev not found from accessible
* fc dev list but the node should
* exist. Set to failing cond now
* and check the node state later.
*/
}
/* keep the cur elem by linking to list_end. */
return (FPCFGA_OK);
}
}
}
}
return (FPCFGA_OK);
}
/* fill in device type, vid, pid from properties */
static void
{
int i;
/*
* if the type is not previously assigned with valid SCSI device type
* check devinfo to find the type.
* once device is configured it should have a valid device type.
* device node is configured but no valid device type is found
* the type will be set to unavailable.
*/
/*
* if the type is not one of defined SCSI device type
* check devinfo to find the type.
*
* Note: unknown type is not a valid device type.
* It is added in to the device list table to provide
* constant string of "unknown".
*/
for (i = 0; i < (N_DEVICE_TYPES -1); i++) {
break;
}
}
if (i == (N_DEVICE_TYPES - 1)) {
}
}
} else {
}
}
/*
* Fill in vendor and product ID.
*/
}
}
/*
* Get dtype from "inquiry-device-type" property. If not present,
* derive it from minor node type
*/
static const char *
{
int *inq_dtype;
int i;
if (node == DI_NODE_NIL) {
return (NULL);
}
/* first, derive type based on inquiry property */
&inq_dtype) != -1) {
for (i = 0; i < N_DEVICE_TYPES; i++) {
break;
}
}
/*
* when found to be unknown type, set name to null to check
* device minor node type.
*/
if (i == (N_DEVICE_TYPES - 1)) {
}
}
/* if property fails, use minor nodetype */
char *nodetype;
if ((minor != DI_MINOR_NIL) &&
for (i = 0; i < N_DEVICE_TYPES; i++) {
if (device_list[i].ntype &&
== 0)) {
break;
}
}
}
}
return (name);
}
/* Transform list data to stat data */
ldata_list_t **llpp,
int nelem,
int *nlistp,
char **errstring)
{
int i = -1;
*ap_id_list = NULL;
*nlistp = 0;
return (FPCFGA_LIB_ERR);
}
if (nelem == 0) {
return (FPCFGA_APID_NOEXIST);
}
return (FPCFGA_LIB_ERR);
}
/* Extract the list_data structures from the linked list */
}
return (FPCFGA_LIB_ERR);
}
*ap_id_list = ldatap;
return (FPCFGA_OK);
}
/*
* Convert bus state to receptacle state
*/
static cfga_stat_t
{
switch (xport_di_state) {
case DI_BUS_QUIESCED:
case DI_BUS_DOWN:
break;
/*
* NOTE: An explicit flag for active should probably be added to
* libdevinfo.
*/
default:
break;
}
return (rs);
}
/*
* Convert device state to occupant state
* if driver is attached the node is configured.
* if offline or down the node is unconfigured.
* if only driver detached it is none state which is treated the same
* way as configured state.
*/
static cfga_stat_t
{
/* Driver attached ? */
return (CFGA_STAT_CONFIGURED);
}
return (CFGA_STAT_UNCONFIGURED);
} else {
return (CFGA_STAT_NONE);
}
}
/*
* Wrapper routine for inserting ldata to make an sorted ldata list.
*
* When show_FCP_dev option is given insert_FCP_dev_ldata() is called.
* Otherwise insert_fc_dev_ldata() is called.
*/
static fpcfga_ret_t
const char *port_wwn,
int *lun_nump,
{
} else {
return
}
}
/*
* Insert an input ldata to ldata list to make sorted ldata list.
*/
static fpcfga_ret_t
const char *port_wwn,
{
return (FPCFGA_OK);
}
return (FPCFGA_OK);
}
/* else continue */
return (FPCFGA_OK);
}
}
/* add the ldata to the end of the list. */
return (FPCFGA_OK);
}
/*
* Insert an input ldata to ldata list to make sorted ldata list.
*/
static fpcfga_ret_t
const char *port_wwn,
int lun_num,
{
return (FPCFGA_OK);
}
return (FPCFGA_OK);
}
}
return (FPCFGA_OK);
}
return (FPCFGA_OK);
}
}
/* else continue */
return (FPCFGA_OK);
}
/* else continue */
}
/* add the ldata to the end of the list. */
return (FPCFGA_OK);
}
/*
* This function will return the dtype for the given device
* It will first issue a report lun to lun 0 and then it will issue a SCSI
* Inquiry to the first lun returned by report luns.
*
* If everything is successful, the dtype will be returned with the peri
* qualifier masked out.
*
* If either the report lun or the scsi inquiry fails, we will first check
* the return status. If the return status is SCSI_DEVICE_NOT_TGT, then
* we will assume this is a remote HBA and return an UNKNOWN DTYPE
* for all other failures, we will return a dtype of ERR_INQ_DTYPE
*/
static uchar_t
!= FPCFGA_OK) {
/*
* Checking the sense key data as well as the additional
* sense key. The SES Node is not required to repond
* to Report LUN. In the case of Minnow, the SES node
* returns with KEY_ILLEGAL_REQUEST and the additional
* sense key of 0x20. In this case we will blindly
* send the SCSI Inquiry call to lun 0
*
* if we get any other error we will set the inq_type
* appropriately
*/
lun = 0;
} else {
if (ret == FPCFGA_FCP_SEND_SCSI_DEV_NOT_TGT) {
} else {
}
}
} else {
/* send the inquiry to the first lun */
}
if (status == HBA_STATUS_OK) {
} else if (status == HBA_STATUS_ERROR_NOT_A_TARGET) {
} else {
}
}