#include "cfga_fp.h"
#include <sys/fibre-channel/impl/fc_error.h>
typedef struct {
apid_t *apidp;
char *xport_logp;
ldata_list_t *listp;
fpcfga_cmd_t cmd;
cfga_stat_t chld_config;
cfga_type_t xport_type;
cfga_stat_t xport_rstate;
fpcfga_ret_t ret;
int l_errno;
} fpcfga_list_t;
typedef struct {
uint_t itype;
const char *ntype;
const char *name;
} fpcfga_devtype_t;
#define ERR_INQ_DTYPE 0xff
#define FP_FC_PORT_TYPE "fc"
#define FP_FC_PORT_ERROR "fc-error"
#define FP_FC_FABRIC_PORT_TYPE "fc-fabric"
#define FP_FC_PUBLIC_PORT_TYPE "fc-public"
#define FP_FC_PRIVATE_PORT_TYPE "fc-private"
#define FP_FC_PT_TO_PT_PORT_TYPE "fc-pt_to_pt"
#define NO_FLAG 0
#define OPEN_RETRY_COUNT 5
#define OPEN_RETRY_INTERVAL 10000
#define IOCTL_RETRY_COUNT 5
#define IOCTL_RETRY_INTERVAL 5000000
#define FCP_SCSI_CMD_TIMEOUT 10
#define FCP_PATH "/devices/pseudo/fcp@0:fcp"
static fpcfga_ret_t postprocess_list_data(const ldata_list_t *listp,
fpcfga_cmd_t cmd, cfga_stat_t chld_config, int *np, uint_t flags);
static int stat_fc_dev(di_node_t node, void *arg);
static int stat_FCP_dev(di_node_t node, void *arg);
static fpcfga_ret_t do_stat_fca_xport(fpcfga_list_t *lap, int limited_stat,
HBA_PORTATTRIBUTES portAttrs);
static int get_xport_state(di_node_t node, void *arg);
static fpcfga_ret_t do_stat_fc_dev(const di_node_t node, const char *nodepath,
fpcfga_list_t *lap, int limited_stat);
static fpcfga_ret_t do_stat_FCP_dev(const di_node_t node, const char *nodepath,
fpcfga_list_t *lap, int limited_stat);
static cfga_stat_t xport_devinfo_to_recep_state(uint_t xport_di_state);
static cfga_stat_t dev_devinfo_to_occupant_state(uint_t dev_di_state);
static void get_hw_info(di_node_t node, cfga_list_data_t *clp);
static const char *get_device_type(di_node_t);
static fpcfga_ret_t init_ldata_for_accessible_dev(const char *dyncomp,
uchar_t inq_type, fpcfga_list_t *lap);
static fpcfga_ret_t init_ldata_for_accessible_FCP_dev(const char *port_wwn,
int num_luns, struct report_lun_resp *resp_buf,
fpcfga_list_t *larg, int *l_errnop);
static fpcfga_ret_t is_dyn_ap_on_ldata_list(const char *port_wwn,
const ldata_list_t *listp, ldata_list_t **matchldpp, int *l_errno);
static fpcfga_ret_t is_FCP_dev_ap_on_ldata_list(const char *port_wwn,
const int lun_num, ldata_list_t *ldatap, ldata_list_t **matchldpp);
static fpcfga_ret_t init_ldata_for_mpath_dev(di_path_t path, char *port_wwn,
int *l_errnop, fpcfga_list_t *lap);
static fpcfga_ret_t insert_ldata_to_ldatalist(const char *port_wwn,
int *lun_nump, ldata_list_t *listp, ldata_list_t **ldatapp);
static fpcfga_ret_t insert_fc_dev_ldata(const char *port_wwn,
ldata_list_t *listp, ldata_list_t **ldatapp);
static fpcfga_ret_t insert_FCP_dev_ldata(const char *port_wwn, int lun_num,
ldata_list_t *listp, ldata_list_t **ldatapp);
static int stat_path_info_fc_dev(di_node_t root, fpcfga_list_t *lap,
int *l_errnop);
static int stat_path_info_FCP_dev(di_node_t root, fpcfga_list_t *lap,
int *l_errnop);
static fpcfga_ret_t get_accessible_FCP_dev_ldata(const char *dyncomp,
fpcfga_list_t *lap, int *l_errnop);
static fpcfga_ret_t get_standard_inq_data(const char *xport_phys,
const char *dyncomp, uchar_t *lun_num, struct scsi_inquiry **inq_buf,
int *l_errnop);
static void init_fcp_scsi_cmd(struct fcp_scsi_cmd *fscsi, uchar_t *lun_num,
la_wwn_t *pwwn, void *scmdbuf, size_t scmdbuf_len, void *respbuf,
size_t respbuf_len, void *sensebuf, size_t sensebuf_len);
static fpcfga_ret_t issue_fcp_scsi_cmd(const char *xport_phys,
struct fcp_scsi_cmd *fscsi, int *l_errnop);
static uchar_t get_inq_dtype(char *xport_phys, char *dyncomp, HBA_HANDLE handle,
HBA_PORTATTRIBUTES *portAttrs, HBA_PORTATTRIBUTES *discPortAttrs);
static fpcfga_devtype_t device_list[] = {
{ DTYPE_DIRECT, DDI_NT_BLOCK_CHAN, "disk"},
{ DTYPE_DIRECT, DDI_NT_BLOCK, "disk"},
{ DTYPE_DIRECT, DDI_NT_BLOCK_WWN, "disk"},
{ DTYPE_DIRECT, DDI_NT_BLOCK_FABRIC, "disk"},
{ DTYPE_SEQUENTIAL, DDI_NT_TAPE, "tape"},
{ DTYPE_PRINTER, NULL, "printer"},
{ DTYPE_PROCESSOR, NULL, "processor"},
{ DTYPE_WORM, NULL, "WORM"},
{ DTYPE_RODIRECT, DDI_NT_CD_CHAN, "CD-ROM"},
{ DTYPE_RODIRECT, DDI_NT_CD, "CD-ROM"},
{ DTYPE_SCANNER, NULL, "scanner"},
{ DTYPE_OPTICAL, NULL, "optical"},
{ DTYPE_CHANGER, NULL, "med-changer"},
{ DTYPE_COMM, NULL, "comm-device"},
{ DTYPE_ARRAY_CTRL, NULL, "array-ctrl"},
{ DTYPE_ESI, NULL, "ESI"},
{ DTYPE_UNKNOWN, NULL, "unknown"}
};
#define N_DEVICE_TYPES (sizeof (device_list) / sizeof (device_list[0]))
#define DTYPE_UNKNOWN_INDEX (N_DEVICE_TYPES - 1)
fpcfga_ret_t
do_list(
apid_t *apidp,
fpcfga_cmd_t cmd,
ldata_list_t **llpp,
int *nelemp,
char **errstring)
{
int n = -1, l_errno = 0, limited_stat;
walkarg_t walkarg;
fpcfga_list_t larg = {NULL};
fpcfga_ret_t ret;
la_wwn_t pwwn;
char *dyncomp = NULL;
HBA_HANDLE handle;
HBA_PORTATTRIBUTES portAttrs;
HBA_PORTATTRIBUTES discPortAttrs;
HBA_STATUS status;
int portIndex, discIndex;
int retry;
uchar_t inq_dtype;
if (*llpp != NULL || *nelemp != 0) {
return (FPCFGA_ERR);
}
ret = make_xport_logid(apidp->xport_phys, &larg.xport_logp, &l_errno);
if (ret != FPCFGA_OK) {
cfga_err(errstring, l_errno, ERR_LIST, 0);
return (FPCFGA_ERR);
}
assert(larg.xport_logp != NULL);
larg.cmd = cmd;
larg.apidp = apidp;
larg.xport_rstate = CFGA_STAT_NONE;
if ((ret = findMatchingAdapterPort(larg.apidp->xport_phys, &handle,
&portIndex, &portAttrs, errstring)) != FPCFGA_OK) {
S_FREE(larg.xport_logp);
return (ret);
}
if (larg.cmd == FPCFGA_STAT_FC_DEV) {
limited_stat = 1;
larg.ret = FPCFGA_APID_NOEXIST;
} else {
limited_stat = 0;
larg.ret = FPCFGA_OK;
}
if ((ret = do_stat_fca_xport(&larg, limited_stat,
portAttrs)) != FPCFGA_OK) {
cfga_err(errstring, larg.l_errno, ERR_LIST, 0);
list_free(&larg.listp);
S_FREE(larg.xport_logp);
HBA_CloseAdapter(handle);
HBA_FreeLibrary();
return (ret);
}
#ifdef DEBUG
if (limited_stat) {
assert(larg.listp == NULL);
} else {
assert(larg.listp != NULL);
}
#endif
larg.chld_config = CFGA_STAT_UNCONFIGURED;
switch (larg.cmd) {
case FPCFGA_STAT_FC_DEV:
if (cvt_dyncomp_to_lawwn(apidp->dyncomp, &pwwn) != 0) {
cfga_err(errstring, 0, ERR_LIST, 0);
list_free(&larg.listp);
S_FREE(larg.xport_logp);
HBA_CloseAdapter(handle);
HBA_FreeLibrary();
return (FPCFGA_LIB_ERR);
}
retry = 0;
do {
status = getPortAttrsByWWN(handle,
*((HBA_WWN *)(&pwwn)), &discPortAttrs);
if (status == HBA_STATUS_ERROR_STALE_DATA) {
HBA_RefreshInformation(handle);
} else {
break;
}
} while (retry++ < HBA_MAX_RETRIES);
if (status == HBA_STATUS_OK) {
inq_dtype = get_inq_dtype(apidp->xport_phys,
apidp->dyncomp, handle, &portAttrs, &discPortAttrs);
if (init_ldata_for_accessible_dev(apidp->dyncomp,
inq_dtype, &larg) != FPCFGA_OK) {
cfga_err(errstring, larg.l_errno,
ERR_LIST, 0);
list_free(&larg.listp);
S_FREE(larg.xport_logp);
HBA_CloseAdapter(handle);
HBA_FreeLibrary();
return (FPCFGA_LIB_ERR);
}
if (apidp->lunlist == NULL) {
n = 0;
if (postprocess_list_data(
larg.listp, cmd,
larg.chld_config, &n, NO_FLAG) !=
FPCFGA_OK) {
cfga_err(errstring,
larg.l_errno, ERR_LIST, 0);
list_free(&larg.listp);
S_FREE(larg.xport_logp);
HBA_CloseAdapter(handle);
HBA_FreeLibrary();
return (FPCFGA_LIB_ERR);
}
*nelemp = n;
*llpp = larg.listp;
S_FREE(larg.xport_logp);
HBA_CloseAdapter(handle);
HBA_FreeLibrary();
return (FPCFGA_OK);
}
larg.ret = FPCFGA_ACCESS_OK;
} else if (status == HBA_STATUS_ERROR_ILLEGAL_WWN) {
if (apidp->lunlist == NULL) {
list_free(&larg.listp);
S_FREE(larg.xport_logp);
HBA_CloseAdapter(handle);
HBA_FreeLibrary();
return (FPCFGA_APID_NOEXIST);
}
} else {
if (apidp->lunlist == NULL) {
cfga_err(errstring, 0, ERR_FC_GET_DEVLIST, 0);
list_free(&larg.listp);
S_FREE(larg.xport_logp);
HBA_CloseAdapter(handle);
HBA_FreeLibrary();
return (FPCFGA_LIB_ERR);
}
}
break;
case FPCFGA_STAT_ALL:
for (discIndex = 0;
discIndex < portAttrs.NumberofDiscoveredPorts;
discIndex++) {
if (getDiscPortAttrs(handle, portIndex,
discIndex, &discPortAttrs)) {
continue;
}
memcpy(&pwwn, &discPortAttrs.PortWWN, sizeof (la_wwn_t));
cvt_lawwn_to_dyncomp(&pwwn, &dyncomp, &l_errno);
if (dyncomp == NULL) {
cfga_err(errstring, l_errno, ERR_LIST, 0);
list_free(&larg.listp);
S_FREE(larg.xport_logp);
HBA_CloseAdapter(handle);
HBA_FreeLibrary();
return (FPCFGA_LIB_ERR);
}
inq_dtype = get_inq_dtype(apidp->xport_phys, dyncomp,
handle, &portAttrs, &discPortAttrs);
if ((ret = init_ldata_for_accessible_dev(
dyncomp, inq_dtype, &larg)) != FPCFGA_OK) {
S_FREE(dyncomp);
cfga_err(errstring, larg.l_errno, ERR_LIST, 0);
list_free(&larg.listp);
S_FREE(larg.xport_logp);
HBA_CloseAdapter(handle);
HBA_FreeLibrary();
return (FPCFGA_LIB_ERR);
}
S_FREE(dyncomp);
}
break;
default:
break;
}
if (apidp->flags == FLAG_DEVINFO_FORCE) {
walkarg.flags = FLAG_DEVINFO_FORCE;
} else {
walkarg.flags = 0;
}
walkarg.flags |= FLAG_PATH_INFO_WALK;
walkarg.walkmode.node_args.flags = DI_WALK_CLDFIRST;
walkarg.walkmode.node_args.fcn = stat_fc_dev;
ret = walk_tree(apidp->xport_phys, &larg, DINFOCPYALL | DINFOPATH,
&walkarg, FPCFGA_WALK_NODE, &larg.l_errno);
if (ret != FPCFGA_OK || (ret = larg.ret) != FPCFGA_OK) {
if (ret != FPCFGA_APID_NOEXIST) {
cfga_err(errstring, larg.l_errno, ERR_LIST, 0);
}
goto out;
}
assert(larg.listp != NULL);
n = 0;
ret = postprocess_list_data(larg.listp, cmd, larg.chld_config, &n,
NO_FLAG);
if (ret != FPCFGA_OK) {
cfga_err(errstring, 0, ERR_LIST, 0);
ret = FPCFGA_LIB_ERR;
goto out;
}
*nelemp = n;
*llpp = larg.listp;
ret = FPCFGA_OK;
out:
if (ret != FPCFGA_OK) list_free(&larg.listp);
S_FREE(larg.xport_logp);
HBA_CloseAdapter(handle);
HBA_FreeLibrary();
return (ret);
}
fpcfga_ret_t
do_list_FCP_dev(
const char *ap_id,
uint_t flags,
fpcfga_cmd_t cmd,
ldata_list_t **llpp,
int *nelemp,
char **errstring)
{
int n = -1, l_errno = 0, limited_stat, len;
walkarg_t walkarg;
fpcfga_list_t larg = {NULL};
fpcfga_ret_t ret;
la_wwn_t pwwn;
char *xport_phys = NULL, *dyn = NULL, *dyncomp = NULL,
*lun_dyn = NULL;
apid_t apid_con = {NULL};
HBA_HANDLE handle;
HBA_PORTATTRIBUTES portAttrs;
HBA_PORTATTRIBUTES discPortAttrs;
HBA_STATUS status;
int portIndex, discIndex;
int retry;
uint64_t lun = 0;
struct scsi_inquiry inq;
struct scsi_extended_sense sense;
HBA_UINT8 scsiStatus;
uint32_t inquirySize = sizeof (inq),
senseSize = sizeof (sense);
if (*llpp != NULL || *nelemp != 0) {
return (FPCFGA_ERR);
}
if ((xport_phys = pathdup(ap_id, &l_errno)) == NULL) {
cfga_err(errstring, l_errno, ERR_OP_FAILED, 0);
return (FPCFGA_LIB_ERR);
}
if ((dyn = GET_DYN(xport_phys)) != NULL) {
len = strlen(DYN_TO_DYNCOMP(dyn)) + 1;
dyncomp = calloc(1, len);
if (dyncomp == NULL) {
cfga_err(errstring, errno, ERR_OP_FAILED, 0);
S_FREE(xport_phys);
return (FPCFGA_LIB_ERR);
}
(void) strcpy(dyncomp, DYN_TO_DYNCOMP(dyn));
*dyn = '\0';
if ((lun_dyn = GET_LUN_DYN(dyncomp)) != NULL) {
*lun_dyn = '\0';
}
}
apid_con.xport_phys = xport_phys;
apid_con.dyncomp = dyncomp;
apid_con.flags = flags;
larg.apidp = &apid_con;
ret = make_xport_logid(larg.apidp->xport_phys, &larg.xport_logp,
&l_errno);
if (ret != FPCFGA_OK) {
cfga_err(errstring, l_errno, ERR_LIST, 0);
S_FREE(larg.apidp->xport_phys);
S_FREE(larg.apidp->dyncomp);
return (FPCFGA_ERR);
}
assert(larg.xport_logp != NULL);
larg.cmd = cmd;
larg.xport_rstate = CFGA_STAT_NONE;
if ((ret = findMatchingAdapterPort(larg.apidp->xport_phys, &handle,
&portIndex, &portAttrs, errstring)) != FPCFGA_OK) {
S_FREE(larg.xport_logp);
S_FREE(larg.apidp->dyncomp);
return (ret);
}
if (larg.cmd == FPCFGA_STAT_FC_DEV) {
limited_stat = 1;
larg.ret = FPCFGA_APID_NOEXIST;
} else {
limited_stat = 0;
larg.ret = FPCFGA_OK;
}
if ((ret = do_stat_fca_xport(&larg, limited_stat,
portAttrs)) != FPCFGA_OK) {
cfga_err(errstring, larg.l_errno, ERR_LIST, 0);
list_free(&larg.listp);
S_FREE(larg.xport_logp);
S_FREE(larg.apidp->xport_phys);
S_FREE(larg.apidp->dyncomp);
HBA_CloseAdapter(handle);
HBA_FreeLibrary();
return (ret);
}
larg.chld_config = CFGA_STAT_UNCONFIGURED;
switch (larg.cmd) {
case FPCFGA_STAT_FC_DEV:
if (cvt_dyncomp_to_lawwn(larg.apidp->dyncomp, &pwwn) != 0) {
cfga_err(errstring, 0, ERR_LIST, 0);
list_free(&larg.listp);
S_FREE(larg.xport_logp);
S_FREE(larg.apidp->xport_phys);
S_FREE(larg.apidp->dyncomp);
HBA_CloseAdapter(handle);
HBA_FreeLibrary();
return (FPCFGA_LIB_ERR);
}
retry = 0;
do {
status = getPortAttrsByWWN(handle,
*((HBA_WWN *)(&pwwn)), &discPortAttrs);
if (status == HBA_STATUS_ERROR_STALE_DATA) {
HBA_RefreshInformation(handle);
} else {
break;
}
} while (retry++ < HBA_MAX_RETRIES);
if (status == HBA_STATUS_OK) {
status = HBA_ScsiInquiryV2(handle, portAttrs.PortWWN,
discPortAttrs.PortWWN, lun, 0, 0,
&inq, &inquirySize, &scsiStatus,
&sense, &senseSize);
if (status == HBA_STATUS_OK) {
inq.inq_dtype = inq.inq_dtype & DTYPE_MASK;
} else if (status == HBA_STATUS_ERROR_NOT_A_TARGET) {
inq.inq_dtype = DTYPE_UNKNOWN;
} else {
inq.inq_dtype = ERR_INQ_DTYPE;
}
if (init_ldata_for_accessible_dev(larg.apidp->dyncomp,
inq.inq_dtype, &larg) != FPCFGA_OK) {
cfga_err(errstring, larg.l_errno,
ERR_LIST, 0);
list_free(&larg.listp);
S_FREE(larg.xport_logp);
S_FREE(larg.apidp->xport_phys);
S_FREE(larg.apidp->dyncomp);
HBA_CloseAdapter(handle);
HBA_FreeLibrary();
return (FPCFGA_LIB_ERR);
}
if ((ret = get_accessible_FCP_dev_ldata(
larg.apidp->dyncomp, &larg, &l_errno))
!= FPCFGA_OK) {
cfga_err(errstring, larg.l_errno, ERR_LIST, 0);
list_free(&larg.listp);
S_FREE(larg.xport_logp);
S_FREE(larg.apidp->xport_phys);
S_FREE(larg.apidp->dyncomp);
HBA_CloseAdapter(handle);
HBA_FreeLibrary();
return (FPCFGA_LIB_ERR);
} else {
larg.ret = FPCFGA_ACCESS_OK;
}
} else if (status == HBA_STATUS_ERROR_ILLEGAL_WWN) {
if (larg.apidp->lunlist == NULL) {
list_free(&larg.listp);
S_FREE(larg.xport_logp);
HBA_CloseAdapter(handle);
HBA_FreeLibrary();
return (FPCFGA_APID_NOEXIST);
}
} else {
larg.ret = FPCFGA_APID_NOEXIST;
}
break;
case FPCFGA_STAT_ALL:
for (discIndex = 0;
discIndex < portAttrs.NumberofDiscoveredPorts;
discIndex++) {
if (getDiscPortAttrs(handle, portIndex,
discIndex, &discPortAttrs)) {
continue;
}
memcpy(&pwwn, &discPortAttrs.PortWWN, sizeof (la_wwn_t));
cvt_lawwn_to_dyncomp(&pwwn, &dyncomp, &l_errno);
if (dyncomp == NULL) {
cfga_err(errstring, l_errno, ERR_LIST, 0);
list_free(&larg.listp);
S_FREE(larg.xport_logp);
S_FREE(larg.apidp->xport_phys);
S_FREE(larg.apidp->dyncomp);
HBA_CloseAdapter(handle);
HBA_FreeLibrary();
return (FPCFGA_LIB_ERR);
}
status = HBA_ScsiInquiryV2(handle, portAttrs.PortWWN,
discPortAttrs.PortWWN, lun, 0, 0,
&inq, &inquirySize, &scsiStatus,
&sense, &senseSize);
if (status == HBA_STATUS_OK) {
inq.inq_dtype = inq.inq_dtype & DTYPE_MASK;
} else if (status == HBA_STATUS_ERROR_NOT_A_TARGET) {
inq.inq_dtype = DTYPE_UNKNOWN;
} else {
inq.inq_dtype = ERR_INQ_DTYPE;
}
if ((ret = init_ldata_for_accessible_dev(
dyncomp, inq.inq_dtype, &larg)) != FPCFGA_OK) {
S_FREE(dyncomp);
cfga_err(errstring, larg.l_errno, ERR_LIST, 0);
list_free(&larg.listp);
S_FREE(larg.xport_logp);
S_FREE(larg.apidp->xport_phys);
S_FREE(larg.apidp->dyncomp);
HBA_CloseAdapter(handle);
HBA_FreeLibrary();
return (FPCFGA_LIB_ERR);
}
if ((ret = get_accessible_FCP_dev_ldata(
dyncomp, &larg, &l_errno)) != FPCFGA_OK) {
S_FREE(dyncomp);
cfga_err(errstring, larg.l_errno, ERR_LIST, 0);
list_free(&larg.listp);
S_FREE(larg.xport_logp);
S_FREE(larg.apidp->xport_phys);
S_FREE(larg.apidp->dyncomp);
HBA_CloseAdapter(handle);
HBA_FreeLibrary();
return (ret);
}
S_FREE(dyncomp);
}
break;
}
if ((larg.apidp->flags & FLAG_DEVINFO_FORCE) == FLAG_DEVINFO_FORCE) {
walkarg.flags = FLAG_DEVINFO_FORCE;
} else {
walkarg.flags = 0;
}
walkarg.flags |= FLAG_PATH_INFO_WALK;
walkarg.walkmode.node_args.flags = DI_WALK_CLDFIRST;
walkarg.walkmode.node_args.fcn = stat_FCP_dev;
ret = walk_tree(larg.apidp->xport_phys, &larg, DINFOCPYALL | DINFOPATH,
&walkarg, FPCFGA_WALK_NODE, &larg.l_errno);
if (ret != FPCFGA_OK || (ret = larg.ret) != FPCFGA_OK) {
if (ret != FPCFGA_APID_NOEXIST) {
cfga_err(errstring, larg.l_errno, ERR_LIST, 0);
}
list_free(&larg.listp);
S_FREE(larg.xport_logp);
S_FREE(larg.apidp->xport_phys);
S_FREE(larg.apidp->dyncomp);
HBA_CloseAdapter(handle);
HBA_FreeLibrary();
return (ret);
}
assert(larg.listp != NULL);
n = 0;
ret = postprocess_list_data(larg.listp, cmd, larg.chld_config, &n,
flags);
if (ret != FPCFGA_OK) {
cfga_err(errstring, 0, ERR_LIST, 0);
list_free(&larg.listp);
S_FREE(larg.xport_logp);
S_FREE(larg.apidp->xport_phys);
S_FREE(larg.apidp->dyncomp);
HBA_CloseAdapter(handle);
HBA_FreeLibrary();
return (FPCFGA_LIB_ERR);
}
*nelemp = n;
*llpp = larg.listp;
ret = FPCFGA_OK;
S_FREE(larg.xport_logp);
S_FREE(larg.apidp->xport_phys);
S_FREE(larg.apidp->dyncomp);
HBA_CloseAdapter(handle);
HBA_FreeLibrary();
return (FPCFGA_OK);
}
static void
init_fcp_scsi_cmd(
struct fcp_scsi_cmd *fscsi,
uchar_t *lun_num,
la_wwn_t *pwwn,
void *scmdbuf,
size_t scmdbuf_len,
void *respbuf,
size_t respbuf_len,
void *sensebuf,
size_t sensebuf_len)
{
memset(fscsi, 0, sizeof (struct fcp_scsi_cmd));
memset(scmdbuf, 0, scmdbuf_len);
memcpy(fscsi->scsi_fc_pwwn.raw_wwn, pwwn, sizeof (u_longlong_t));
fscsi->scsi_fc_rspcode = 0;
fscsi->scsi_flags = FCP_SCSI_READ;
fscsi->scsi_timeout = FCP_SCSI_CMD_TIMEOUT;
fscsi->scsi_cdbbufaddr = (caddr_t)scmdbuf;
fscsi->scsi_cdblen = scmdbuf_len;
fscsi->scsi_bufaddr = (caddr_t)respbuf;
fscsi->scsi_buflen = respbuf_len;
fscsi->scsi_bufresid = 0;
fscsi->scsi_bufstatus = 0;
fscsi->scsi_rqbufaddr = (caddr_t)sensebuf;
fscsi->scsi_rqlen = sensebuf_len;
fscsi->scsi_rqresid = 0;
memcpy(&fscsi->scsi_lun, lun_num, sizeof (fscsi->scsi_lun));
}
static fpcfga_ret_t
issue_fcp_scsi_cmd(
const char *xport_phys,
struct fcp_scsi_cmd *fscsi,
int *l_errnop)
{
struct stat stbuf;
int fcp_fd, retry, rv;
if (stat(xport_phys, &stbuf) < 0) {
*l_errnop = errno;
return (FPCFGA_LIB_ERR);
}
fscsi->scsi_fc_port_num = (uint32_t)minor(stbuf.st_rdev);
fcp_fd = open(FCP_PATH, O_RDONLY | O_NDELAY);
retry = 0;
while (fcp_fd < 0 && retry++ < OPEN_RETRY_COUNT && (
errno == EBUSY || errno == EAGAIN)) {
(void) usleep(OPEN_RETRY_INTERVAL);
fcp_fd = open(FCP_PATH, O_RDONLY|O_NDELAY);
}
if (fcp_fd < 0) {
*l_errnop = errno;
return (FPCFGA_LIB_ERR);
}
rv = ioctl(fcp_fd, FCP_TGT_SEND_SCSI, fscsi);
retry = 0;
while ((rv != 0 && retry++ < IOCTL_RETRY_COUNT &&
(errno == EBUSY || errno == EAGAIN)) ||
(retry++ < IOCTL_RETRY_COUNT &&
((uchar_t)fscsi->scsi_bufstatus & STATUS_MASK)
== STATUS_BUSY)) {
(void) usleep(IOCTL_RETRY_INTERVAL);
rv = ioctl(fcp_fd, FCP_TGT_SEND_SCSI, fscsi);
}
close(fcp_fd);
if (fscsi->scsi_fc_status == FC_DEVICE_NOT_TGT) {
return (FPCFGA_FCP_SEND_SCSI_DEV_NOT_TGT);
} else if (rv != 0 || fscsi->scsi_bufstatus != 0) {
*l_errnop = errno;
return (FPCFGA_FCP_TGT_SEND_SCSI_FAILED);
}
return (FPCFGA_OK);
}
static fpcfga_ret_t
get_standard_inq_data(
const char *xport_phys,
const char *dyncomp,
uchar_t *lun_num,
struct scsi_inquiry **inq_buf,
int *l_errnop)
{
struct fcp_scsi_cmd fscsi;
struct scsi_extended_sense sensebuf;
union scsi_cdb scsi_inq_req;
la_wwn_t pwwn;
int alloc_len;
fpcfga_ret_t ret;
alloc_len = sizeof (struct scsi_inquiry);
if ((*inq_buf = (struct scsi_inquiry *)calloc(1, alloc_len)) == NULL) {
*l_errnop = errno;
return (FPCFGA_LIB_ERR);
}
if (cvt_dyncomp_to_lawwn(dyncomp, &pwwn) != 0) {
return (FPCFGA_LIB_ERR);
}
init_fcp_scsi_cmd(&fscsi, lun_num, &pwwn, &scsi_inq_req,
sizeof (scsi_inq_req), *inq_buf, alloc_len, &sensebuf,
sizeof (struct scsi_extended_sense));
scsi_inq_req.scc_cmd = SCMD_INQUIRY;
scsi_inq_req.g0_count0 = sizeof (struct scsi_inquiry);
if ((ret = issue_fcp_scsi_cmd(xport_phys, &fscsi, l_errnop))
!= FPCFGA_OK) {
S_FREE(*inq_buf);
return (ret);
}
return (FPCFGA_OK);
}
fpcfga_ret_t
get_report_lun_data(
const char *xport_phys,
const char *dyncomp,
int *num_luns,
report_lun_resp_t **resp_buf,
struct scsi_extended_sense *sensebuf,
int *l_errnop)
{
struct fcp_scsi_cmd fscsi;
union scsi_cdb scsi_rl_req;
la_wwn_t pwwn;
int alloc_len;
fpcfga_ret_t ret;
uchar_t lun_data[SAM_LUN_SIZE];
alloc_len = sizeof (struct report_lun_resp);
if ((*resp_buf = (report_lun_resp_t *)calloc(1, alloc_len)) == NULL) {
*l_errnop = errno;
return (FPCFGA_LIB_ERR);
}
if (cvt_dyncomp_to_lawwn(dyncomp, &pwwn) != 0) {
S_FREE(*resp_buf);
return (FPCFGA_LIB_ERR);
}
memset(lun_data, 0, sizeof (lun_data));
init_fcp_scsi_cmd(&fscsi, lun_data, &pwwn, &scsi_rl_req,
sizeof (scsi_rl_req), *resp_buf, alloc_len, sensebuf,
sizeof (struct scsi_extended_sense));
scsi_rl_req.scc_cmd = FP_SCMD_REPORT_LUN;
FORMG5COUNT(&scsi_rl_req, alloc_len);
if ((ret = issue_fcp_scsi_cmd(xport_phys, &fscsi, l_errnop))
!= FPCFGA_OK) {
S_FREE(*resp_buf);
return (ret);
}
if (ntohl((*resp_buf)->num_lun) >
(sizeof (struct report_lun_resp) - REPORT_LUN_HDR_SIZE)) {
alloc_len = (*resp_buf)->num_lun + REPORT_LUN_HDR_SIZE;
S_FREE(*resp_buf);
if ((*resp_buf = (report_lun_resp_t *)calloc(1, alloc_len))
== NULL) {
*l_errnop = errno;
return (FPCFGA_LIB_ERR);
}
(void) memset((char *)*resp_buf, 0, alloc_len);
FORMG5COUNT(&scsi_rl_req, alloc_len);
fscsi.scsi_bufaddr = (caddr_t)*resp_buf;
fscsi.scsi_buflen = alloc_len;
if ((ret = issue_fcp_scsi_cmd(xport_phys, &fscsi, l_errnop))
!= FPCFGA_OK) {
S_FREE(*resp_buf);
return (ret);
}
}
*num_luns = ntohl((*resp_buf)->num_lun) >> 3;
return (FPCFGA_OK);
}
static fpcfga_ret_t
get_accessible_FCP_dev_ldata(
const char *dyncomp,
fpcfga_list_t *lap,
int *l_errnop)
{
report_lun_resp_t *resp_buf;
struct scsi_extended_sense sense;
int num_luns;
fpcfga_ret_t ret;
memset(&sense, 0, sizeof (sense));
if ((ret = get_report_lun_data(lap->apidp->xport_phys, dyncomp,
&num_luns, &resp_buf, &sense, l_errnop)) != FPCFGA_OK) {
if ((ret == FPCFGA_FCP_TGT_SEND_SCSI_FAILED) ||
(ret == FPCFGA_FCP_SEND_SCSI_DEV_NOT_TGT)) {
ret = FPCFGA_OK;
}
return (ret);
}
if (num_luns > 0) {
ret = init_ldata_for_accessible_FCP_dev(
dyncomp, num_luns, resp_buf, lap, l_errnop);
} else {
ret = FPCFGA_OK;
}
S_FREE(resp_buf);
return (ret);
}
static fpcfga_ret_t
postprocess_list_data(
const ldata_list_t *listp,
fpcfga_cmd_t cmd,
cfga_stat_t chld_config,
int *np,
uint_t flags)
{
ldata_list_t *tmplp = NULL;
cfga_list_data_t *xport_ldatap = NULL;
int i;
*np = 0;
if (listp == NULL) {
return (FPCFGA_ERR);
}
tmplp = (ldata_list_t *)listp;
for (i = 0; tmplp != NULL; tmplp = tmplp->next) {
i++;
if (GET_DYN(tmplp->ldata.ap_phys_id) == NULL) {
assert(GET_DYN(tmplp->ldata.ap_log_id) == NULL);
xport_ldatap = &tmplp->ldata;
#ifdef DEBUG
} else {
assert(GET_DYN(tmplp->ldata.ap_log_id) != NULL);
#endif
}
}
switch (cmd) {
case FPCFGA_STAT_FC_DEV:
if ((flags & FLAG_FCP_DEV) == FLAG_FCP_DEV) {
if (i < 1 || xport_ldatap != NULL) {
return (FPCFGA_LIB_ERR);
}
} else {
if (i != 1 || xport_ldatap != NULL) {
return (FPCFGA_LIB_ERR);
}
}
break;
case FPCFGA_STAT_FCA_PORT:
if (i != 1 || xport_ldatap == NULL) {
return (FPCFGA_LIB_ERR);
}
break;
case FPCFGA_STAT_ALL:
if (i < 1 || xport_ldatap == NULL) {
return (FPCFGA_LIB_ERR);
}
break;
default:
return (FPCFGA_LIB_ERR);
}
*np = i;
if (xport_ldatap != NULL) {
xport_ldatap->ap_o_state = chld_config;
}
return (FPCFGA_OK);
}
static int
stat_fc_dev(di_node_t node, void *arg)
{
fpcfga_list_t *lap = NULL;
char *devfsp = NULL, *nodepath = NULL;
size_t len = 0;
int limited_stat = 0, match_minor, rv;
fpcfga_ret_t ret;
di_prop_t prop = DI_PROP_NIL;
uchar_t *port_wwn_data;
char port_wwn[WWN_SIZE*2+1];
int count;
lap = (fpcfga_list_t *)arg;
devfsp = di_devfs_path(node);
if (devfsp == NULL) {
rv = DI_WALK_CONTINUE;
goto out;
}
len = strlen(DEVICES_DIR) + strlen(devfsp) + 1;
nodepath = calloc(1, len);
if (nodepath == NULL) {
lap->l_errno = errno;
lap->ret = FPCFGA_LIB_ERR;
rv = DI_WALK_TERMINATE;
goto out;
}
(void) snprintf(nodepath, len, "%s%s", DEVICES_DIR, devfsp);
match_minor = 0;
if (!dev_cmp(lap->apidp->xport_phys, nodepath, match_minor)) {
rv = DI_WALK_CONTINUE;
goto out;
}
if (lap->cmd == FPCFGA_STAT_FC_DEV) {
while ((prop = di_prop_next(node, prop))
!= DI_PROP_NIL) {
if ((strcmp(PORT_WWN_PROP,
di_prop_name(prop)) == 0) &&
(di_prop_type(prop) ==
DI_PROP_TYPE_BYTE)) {
break;
}
}
if (prop != DI_PROP_NIL) {
count = di_prop_bytes(prop, &port_wwn_data);
if (count != WWN_SIZE) {
lap->ret = FPCFGA_LIB_ERR;
rv = DI_WALK_TERMINATE;
goto out;
}
(void) sprintf(port_wwn, "%016llx",
(wwnConversion(port_wwn_data)));
if (strncmp(port_wwn, lap->apidp->dyncomp,
WWN_SIZE*2)) {
rv = DI_WALK_CONTINUE;
goto out;
}
} else {
rv = DI_WALK_CONTINUE;
goto out;
}
}
if (lap->cmd == FPCFGA_STAT_FCA_PORT) {
limited_stat = 1;
} else {
limited_stat = 0;
}
ret = do_stat_fc_dev(node, nodepath, lap, limited_stat);
if (ret != FPCFGA_OK) {
if (lap->cmd == FPCFGA_STAT_FC_DEV) {
lap->ret = ret;
rv = DI_WALK_TERMINATE;
} else {
rv = DI_WALK_CONTINUE;
}
goto out;
}
rv = DI_WALK_CONTINUE;
if (lap->cmd == FPCFGA_STAT_FCA_PORT &&
lap->chld_config == CFGA_STAT_CONFIGURED) {
rv = DI_WALK_TERMINATE;
} else if (lap->cmd == FPCFGA_STAT_FC_DEV) {
rv = DI_WALK_TERMINATE;
}
out:
S_FREE(nodepath);
if (devfsp != NULL) di_devfs_path_free(devfsp);
return (rv);
}
static int
stat_FCP_dev(di_node_t node, void *arg)
{
fpcfga_list_t *lap = NULL;
char *devfsp = NULL, *nodepath = NULL;
size_t len = 0;
int limited_stat = 0, match_minor, rv, di_ret;
fpcfga_ret_t ret;
uchar_t *port_wwn_data;
char port_wwn[WWN_SIZE*2+1];
lap = (fpcfga_list_t *)arg;
devfsp = di_devfs_path(node);
if (devfsp == NULL) {
rv = DI_WALK_CONTINUE;
goto out;
}
len = strlen(DEVICES_DIR) + strlen(devfsp) + 1;
nodepath = calloc(1, len);
if (nodepath == NULL) {
lap->l_errno = errno;
lap->ret = FPCFGA_LIB_ERR;
rv = DI_WALK_TERMINATE;
goto out;
}
(void) snprintf(nodepath, len, "%s%s", DEVICES_DIR, devfsp);
match_minor = 0;
if (!dev_cmp(lap->apidp->xport_phys, nodepath, match_minor)) {
rv = DI_WALK_CONTINUE;
goto out;
}
if (lap->cmd == FPCFGA_STAT_FC_DEV) {
di_ret = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
PORT_WWN_PROP, &port_wwn_data);
if (di_ret == -1) {
rv = DI_WALK_CONTINUE;
goto out;
} else {
(void) sprintf(port_wwn, "%016llx",
(wwnConversion(port_wwn_data)));
if (strncmp(port_wwn, lap->apidp->dyncomp,
WWN_SIZE*2)) {
rv = DI_WALK_CONTINUE;
goto out;
}
}
}
if (lap->cmd == FPCFGA_STAT_FCA_PORT) {
limited_stat = 1;
} else {
limited_stat = 0;
}
ret = do_stat_FCP_dev(node, nodepath, lap, limited_stat);
if (ret != FPCFGA_OK) {
rv = DI_WALK_CONTINUE;
goto out;
}
rv = DI_WALK_CONTINUE;
if (lap->cmd == FPCFGA_STAT_FCA_PORT &&
lap->chld_config == CFGA_STAT_CONFIGURED) {
rv = DI_WALK_TERMINATE;
}
out:
S_FREE(nodepath);
if (devfsp != NULL) di_devfs_path_free(devfsp);
return (rv);
}
static fpcfga_ret_t
do_stat_fca_xport(fpcfga_list_t *lap, int limited_stat,
HBA_PORTATTRIBUTES portAttrs)
{
cfga_list_data_t *clp = NULL;
ldata_list_t *listp = NULL;
int l_errno = 0;
uint_t devinfo_state = 0;
walkarg_t walkarg;
fpcfga_ret_t ret;
cfga_cond_t cond = CFGA_COND_UNKNOWN;
assert(lap->xport_logp != NULL);
if (lap->apidp->flags == FLAG_DEVINFO_FORCE) {
walkarg.flags = FLAG_DEVINFO_FORCE;
} else {
walkarg.flags = 0;
}
walkarg.walkmode.node_args.flags = 0;
walkarg.walkmode.node_args.fcn = get_xport_state;
ret = walk_tree(lap->apidp->xport_phys, &devinfo_state,
DINFOCPYALL | DINFOPATH, &walkarg, FPCFGA_WALK_NODE, &l_errno);
if (ret == FPCFGA_OK) {
lap->xport_rstate = xport_devinfo_to_recep_state(devinfo_state);
} else {
lap->xport_rstate = CFGA_STAT_NONE;
}
switch (portAttrs.PortType) {
case HBA_PORTTYPE_NLPORT:
(void) snprintf(lap->xport_type,
sizeof (lap->xport_type), "%s",
FP_FC_PUBLIC_PORT_TYPE);
break;
case HBA_PORTTYPE_NPORT:
(void) snprintf(lap->xport_type,
sizeof (lap->xport_type), "%s",
FP_FC_FABRIC_PORT_TYPE);
break;
case HBA_PORTTYPE_LPORT:
(void) snprintf(lap->xport_type,
sizeof (lap->xport_type), "%s",
FP_FC_PRIVATE_PORT_TYPE);
break;
case HBA_PORTTYPE_PTP:
(void) snprintf(lap->xport_type,
sizeof (lap->xport_type), "%s",
FP_FC_PT_TO_PT_PORT_TYPE);
break;
case HBA_PORTTYPE_UNKNOWN:
(void) snprintf(lap->xport_type,
sizeof (lap->xport_type), "%s",
FP_FC_PORT_TYPE);
break;
default:
(void) snprintf(lap->xport_type,
sizeof (lap->xport_type), "%s",
FP_FC_PORT_TYPE);
cond = CFGA_COND_FAILED;
break;
}
if (limited_stat) {
return (FPCFGA_OK);
}
listp = calloc(1, sizeof (ldata_list_t));
if (listp == NULL) {
lap->l_errno = errno;
return (FPCFGA_LIB_ERR);
}
clp = &listp->ldata;
(void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id), "%s",
lap->xport_logp);
(void) snprintf(clp->ap_phys_id, sizeof (clp->ap_phys_id), "%s",
lap->apidp->xport_phys);
clp->ap_class[0] = '\0';
clp->ap_r_state = lap->xport_rstate;
clp->ap_o_state = lap->chld_config;
clp->ap_cond = cond;
clp->ap_busy = 0;
clp->ap_status_time = (time_t)-1;
clp->ap_info[0] = '\0';
(void) strncpy(clp->ap_type, lap->xport_type, sizeof (clp->ap_type));
listp->next = lap->listp;
lap->listp = listp;
return (FPCFGA_OK);
}
static int
get_xport_state(di_node_t node, void *arg)
{
uint_t *di_statep = (uint_t *)arg;
*di_statep = di_state(node);
return (DI_WALK_TERMINATE);
}
static fpcfga_ret_t
do_stat_fc_dev(
const di_node_t node,
const char *nodepath,
fpcfga_list_t *lap,
int limited_stat)
{
uint_t dctl_state = 0, devinfo_state = 0;
char *dyncomp = NULL;
cfga_list_data_t *clp = NULL;
cfga_busy_t busy;
ldata_list_t *listp = NULL;
ldata_list_t *matchldp = NULL;
int l_errno = 0;
cfga_stat_t ostate;
cfga_cond_t cond;
fpcfga_ret_t ret;
assert(lap->apidp->xport_phys != NULL);
assert(lap->xport_logp != NULL);
cond = CFGA_COND_UNKNOWN;
devinfo_state = di_state(node);
ostate = dev_devinfo_to_occupant_state(devinfo_state);
if (devctl_cmd(nodepath, FPCFGA_DEV_GETSTATE, &dctl_state,
&l_errno) == FPCFGA_OK) {
busy = ((dctl_state & DEVICE_BUSY) == DEVICE_BUSY) ? 1 : 0;
} else {
busy = 0;
}
if (limited_stat) {
if (((strcmp(lap->xport_type, FP_FC_FABRIC_PORT_TYPE) == 0) ||
strcmp(lap->xport_type, FP_FC_PUBLIC_PORT_TYPE) == 0)) {
lap->chld_config = CFGA_STAT_CONFIGURED;
} else {
if (ostate != CFGA_STAT_UNCONFIGURED) {
lap->chld_config = CFGA_STAT_CONFIGURED;
}
}
return (FPCFGA_OK);
}
if (lap->cmd == FPCFGA_STAT_FC_DEV) {
switch (ostate) {
case CFGA_STAT_CONFIGURED:
case CFGA_STAT_NONE:
if (lap->ret != FPCFGA_ACCESS_OK) {
cond = CFGA_COND_FAILING;
}
lap->chld_config = CFGA_STAT_CONFIGURED;
break;
case CFGA_STAT_UNCONFIGURED:
cond = CFGA_COND_UNUSABLE;
if (((strcmp(lap->xport_type,
FP_FC_PUBLIC_PORT_TYPE) == 0) ||
(strcmp(lap->xport_type,
FP_FC_FABRIC_PORT_TYPE) == 0)) ||
(lap->ret == FPCFGA_ACCESS_OK)) {
lap->chld_config = CFGA_STAT_CONFIGURED;
} else {
lap->ret = FPCFGA_APID_NOEXIST;
return (FPCFGA_OK);
}
break;
default:
break;
}
if (lap->ret == FPCFGA_ACCESS_OK) {
if (cond != CFGA_COND_UNKNOWN) {
lap->listp->ldata.ap_cond = cond;
}
lap->listp->ldata.ap_o_state = CFGA_STAT_CONFIGURED;
lap->listp->ldata.ap_busy = busy;
lap->ret = FPCFGA_OK;
return (FPCFGA_OK);
}
}
if (lap->cmd == FPCFGA_STAT_ALL) {
if (lap->listp != NULL) {
if ((ret = make_dyncomp_from_dinode(node,
&dyncomp, &l_errno)) != FPCFGA_OK) {
return (ret);
}
ret = is_dyn_ap_on_ldata_list(dyncomp, lap->listp,
&matchldp, &l_errno);
switch (ret) {
case FPCFGA_ACCESS_OK:
lap->chld_config = CFGA_STAT_CONFIGURED;
matchldp->ldata.ap_o_state =
CFGA_STAT_CONFIGURED;
matchldp->ldata.ap_busy = busy;
clp = &matchldp->ldata;
switch (ostate) {
case CFGA_STAT_CONFIGURED:
case CFGA_STAT_NONE:
get_hw_info(node, clp);
break;
case CFGA_STAT_UNCONFIGURED:
if (matchldp->ldata.ap_cond ==
CFGA_COND_UNKNOWN) {
matchldp->ldata.ap_cond =
CFGA_COND_UNUSABLE;
}
break;
default:
break;
}
lap->ret = FPCFGA_OK;
S_FREE(dyncomp);
return (FPCFGA_OK);
case FPCFGA_LIB_ERR:
lap->l_errno = l_errno;
S_FREE(dyncomp);
return (ret);
case FPCFGA_APID_NOACCESS:
switch (ostate) {
case CFGA_STAT_CONFIGURED:
case CFGA_STAT_NONE:
lap->chld_config = CFGA_STAT_CONFIGURED;
cond = CFGA_COND_FAILING;
break;
case CFGA_STAT_UNCONFIGURED:
cond = CFGA_COND_UNUSABLE;
if ((strcmp(lap->xport_type,
FP_FC_PUBLIC_PORT_TYPE) == 0) ||
(strcmp(lap->xport_type,
FP_FC_FABRIC_PORT_TYPE) == 0)) {
lap->chld_config =
CFGA_STAT_CONFIGURED;
} else {
lap->ret = FPCFGA_OK;
S_FREE(dyncomp);
return (FPCFGA_OK);
}
break;
default:
break;
}
default:
break;
}
} else {
switch (ostate) {
case CFGA_STAT_CONFIGURED:
case CFGA_STAT_NONE:
cond = CFGA_COND_FAILING;
lap->chld_config = CFGA_STAT_CONFIGURED;
break;
case CFGA_STAT_UNCONFIGURED:
cond = CFGA_COND_UNUSABLE;
if ((strcmp(lap->xport_type,
FP_FC_PUBLIC_PORT_TYPE) == 0) ||
(strcmp(lap->xport_type,
FP_FC_FABRIC_PORT_TYPE) == 0)) {
lap->chld_config =
CFGA_STAT_CONFIGURED;
} else {
lap->ret = FPCFGA_OK;
S_FREE(dyncomp);
return (FPCFGA_OK);
}
break;
default:
break;
}
}
}
listp = calloc(1, sizeof (ldata_list_t));
if (listp == NULL) {
lap->l_errno = errno;
S_FREE(dyncomp);
return (FPCFGA_LIB_ERR);
}
clp = &listp->ldata;
if (dyncomp == NULL) {
ret = make_dyncomp_from_dinode(node, &dyncomp, &l_errno);
if (ret != FPCFGA_OK) {
S_FREE(listp);
return (ret);
}
}
(void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id), "%s%s%s",
lap->xport_logp, DYN_SEP, dyncomp);
(void) snprintf(clp->ap_phys_id, sizeof (clp->ap_phys_id), "%s%s%s",
lap->apidp->xport_phys, DYN_SEP, dyncomp);
S_FREE(dyncomp);
clp->ap_class[0] = '\0';
clp->ap_r_state = lap->xport_rstate;
clp->ap_o_state = CFGA_STAT_CONFIGURED;
clp->ap_cond = cond;
clp->ap_busy = busy;
clp->ap_status_time = (time_t)-1;
get_hw_info(node, clp);
listp->next = lap->listp;
lap->listp = listp;
lap->ret = FPCFGA_OK;
return (FPCFGA_OK);
}
int
stat_path_info_node(
di_node_t root,
void *arg,
int *l_errnop)
{
fpcfga_list_t *lap = NULL;
lap = (fpcfga_list_t *)arg;
if ((lap->apidp->flags & (FLAG_FCP_DEV)) == FLAG_FCP_DEV) {
return (stat_path_info_FCP_dev(root, lap, l_errnop));
} else {
return (stat_path_info_fc_dev(root, lap, l_errnop));
}
}
static int
stat_path_info_fc_dev(
di_node_t root,
fpcfga_list_t *lap,
int *l_errnop)
{
ldata_list_t *matchldp = NULL;
di_path_t path = DI_PATH_NIL;
uchar_t *port_wwn_data;
char port_wwn[WWN_SIZE*2+1];
int count;
fpcfga_ret_t ret;
di_path_state_t pstate;
if (root == DI_NODE_NIL) {
return (FPCFGA_LIB_ERR);
}
if ((lap->cmd == FPCFGA_STAT_FC_DEV) && (lap->ret == FPCFGA_OK)) {
return (FPCFGA_OK);
}
if ((lap->cmd == FPCFGA_STAT_FCA_PORT) &&
(lap->chld_config == CFGA_STAT_CONFIGURED)) {
return (FPCFGA_OK);
}
if ((path = di_path_next_client(root, path)) == DI_PATH_NIL) {
if (lap->ret == FPCFGA_ACCESS_OK) {
lap->ret = FPCFGA_OK;
}
return (FPCFGA_OK);
}
if (lap->cmd == FPCFGA_STAT_FCA_PORT) {
if (((strcmp(lap->xport_type, FP_FC_FABRIC_PORT_TYPE) == 0) ||
strcmp(lap->xport_type, FP_FC_PUBLIC_PORT_TYPE) == 0)) {
lap->chld_config = CFGA_STAT_CONFIGURED;
return (FPCFGA_OK);
} else {
if ((pstate = di_path_state(path)) !=
DI_PATH_STATE_OFFLINE) {
lap->chld_config = CFGA_STAT_CONFIGURED;
return (FPCFGA_OK);
}
}
}
do {
count = di_path_prop_lookup_bytes(path, PORT_WWN_PROP,
&port_wwn_data);
if (count != WWN_SIZE) {
ret = FPCFGA_LIB_ERR;
break;
}
(void) sprintf(port_wwn, "%016llx",
(wwnConversion(port_wwn_data)));
switch (lap->cmd) {
case FPCFGA_STAT_FC_DEV:
if (strncmp(port_wwn, lap->apidp->dyncomp,
WWN_SIZE*2)) {
break;
}
if (lap->ret == FPCFGA_ACCESS_OK) {
lap->listp->ldata.ap_o_state =
CFGA_STAT_CONFIGURED;
if (((pstate = di_path_state(path)) ==
DI_PATH_STATE_OFFLINE) ||
(pstate == DI_PATH_STATE_FAULT)) {
lap->listp->ldata.ap_cond =
CFGA_COND_UNUSABLE;
}
lap->ret = FPCFGA_OK;
return (FPCFGA_OK);
} else {
if ((strcmp(lap->xport_type,
FP_FC_PUBLIC_PORT_TYPE) == 0) ||
(strcmp(lap->xport_type,
FP_FC_FABRIC_PORT_TYPE) == 0)) {
lap->chld_config = CFGA_STAT_CONFIGURED;
return (init_ldata_for_mpath_dev(
path, port_wwn, l_errnop, lap));
} else {
if ((di_path_state(path)) !=
DI_PATH_STATE_OFFLINE) {
return (init_ldata_for_mpath_dev(
path, port_wwn, l_errnop, lap));
} else {
lap->ret = FPCFGA_APID_NOEXIST;
return (FPCFGA_OK);
}
}
}
case FPCFGA_STAT_ALL:
if (lap->listp != NULL) {
ret = is_dyn_ap_on_ldata_list(port_wwn,
lap->listp, &matchldp, l_errnop);
if (ret == FPCFGA_ACCESS_OK) {
lap->chld_config = CFGA_STAT_CONFIGURED;
matchldp->ldata.ap_o_state =
CFGA_STAT_CONFIGURED;
if (((pstate = di_path_state(path)) ==
DI_PATH_STATE_OFFLINE) ||
(pstate ==
DI_PATH_STATE_FAULT)) {
matchldp->ldata.ap_cond =
CFGA_COND_UNUSABLE;
}
break;
} else if (ret == FPCFGA_LIB_ERR) {
lap->l_errno = *l_errnop;
return (ret);
}
}
if (((strcmp(lap->xport_type,
FP_FC_PUBLIC_PORT_TYPE) == 0) ||
(strcmp(lap->xport_type,
FP_FC_FABRIC_PORT_TYPE) == 0)) ||
(di_path_state(path) !=
DI_PATH_STATE_OFFLINE)) {
lap->chld_config = CFGA_STAT_CONFIGURED;
ret = init_ldata_for_mpath_dev(
path, port_wwn, l_errnop, lap);
if (ret != FPCFGA_OK) {
return (ret);
}
}
break;
case FPCFGA_STAT_FCA_PORT:
if (di_path_state(path) != DI_PATH_STATE_OFFLINE) {
lap->chld_config = CFGA_STAT_CONFIGURED;
return (FPCFGA_OK);
}
}
path = di_path_next_client(root, path);
} while (path != DI_PATH_NIL);
return (FPCFGA_OK);
}
static int
stat_path_info_FCP_dev(
di_node_t root,
fpcfga_list_t *lap,
int *l_errnop)
{
ldata_list_t *matchldp = NULL, *listp = NULL;
cfga_list_data_t *clp;
di_path_t path = DI_PATH_NIL;
di_node_t client_node = DI_NODE_NIL;
char *port_wwn = NULL, *nodepath = NULL;
int *lun_nump;
fpcfga_ret_t ldata_ret;
di_path_state_t pstate;
cfga_busy_t busy;
uint_t dctl_state = 0;
if (root == DI_NODE_NIL) {
return (FPCFGA_LIB_ERR);
}
if ((lap->cmd == FPCFGA_STAT_FCA_PORT) &&
(lap->chld_config == CFGA_STAT_CONFIGURED)) {
return (FPCFGA_OK);
}
if ((path = di_path_next_client(root, path)) == DI_PATH_NIL) {
if (lap->ret == FPCFGA_ACCESS_OK) {
lap->ret = FPCFGA_OK;
}
return (FPCFGA_OK);
}
if (lap->cmd == FPCFGA_STAT_FCA_PORT) {
if (((strcmp(lap->xport_type, FP_FC_FABRIC_PORT_TYPE) == 0) ||
strcmp(lap->xport_type, FP_FC_PUBLIC_PORT_TYPE) == 0)) {
lap->chld_config = CFGA_STAT_CONFIGURED;
return (FPCFGA_OK);
} else {
if ((pstate = di_path_state(path)) !=
DI_PATH_STATE_OFFLINE) {
lap->chld_config = CFGA_STAT_CONFIGURED;
return (FPCFGA_OK);
}
}
}
do {
switch (lap->cmd) {
case FPCFGA_STAT_FC_DEV:
if ((make_portwwn_luncomp_from_pinode(path, &port_wwn,
&lun_nump, l_errnop)) != FPCFGA_OK) {
return (FPCFGA_LIB_ERR);
}
if ((ldata_ret = is_FCP_dev_ap_on_ldata_list(port_wwn,
*lun_nump, lap->listp, &matchldp))
== FPCFGA_LIB_ERR) {
S_FREE(port_wwn);
return (ldata_ret);
}
if (ldata_ret == FPCFGA_ACCESS_OK) {
lap->chld_config = CFGA_STAT_CONFIGURED;
matchldp->ldata.ap_o_state =
CFGA_STAT_CONFIGURED;
if (((pstate = di_path_state(path)) ==
DI_PATH_STATE_OFFLINE) ||
(pstate == DI_PATH_STATE_FAULT)) {
matchldp->ldata.ap_cond =
CFGA_COND_UNUSABLE;
}
lap->ret = FPCFGA_OK;
break;
}
if (strncmp(port_wwn, lap->apidp->dyncomp, WWN_SIZE*2)
!= 0) {
break;
}
if (((strcmp(lap->xport_type,
FP_FC_PUBLIC_PORT_TYPE) == 0) ||
(strcmp(lap->xport_type,
FP_FC_FABRIC_PORT_TYPE) == 0)) ||
(di_path_state(path) !=
DI_PATH_STATE_OFFLINE)) {
lap->chld_config = CFGA_STAT_CONFIGURED;
client_node = di_path_client_node(path);
if (client_node == DI_NODE_NIL) {
*l_errnop = errno;
S_FREE(port_wwn);
return (FPCFGA_LIB_ERR);
}
if ((construct_nodepath_from_dinode(
client_node, &nodepath, l_errnop))
!= FPCFGA_OK) {
S_FREE(port_wwn);
return (FPCFGA_LIB_ERR);
}
listp = calloc(1, sizeof (ldata_list_t));
if (listp == NULL) {
S_FREE(port_wwn);
S_FREE(nodepath);
lap->l_errno = errno;
return (FPCFGA_LIB_ERR);
}
clp = &listp->ldata;
(void) snprintf(clp->ap_log_id,
sizeof (clp->ap_log_id), "%s%s%s%s%d",
lap->xport_logp, DYN_SEP, port_wwn,
LUN_COMP_SEP, *lun_nump);
(void) snprintf(clp->ap_phys_id,
sizeof (clp->ap_phys_id), "%s%s%s%s%d",
lap->apidp->xport_phys, DYN_SEP, port_wwn,
LUN_COMP_SEP, *lun_nump);
clp->ap_class[0] = '\0';
clp->ap_o_state = CFGA_STAT_CONFIGURED;
if (((pstate = di_path_state(path))
== DI_PATH_STATE_OFFLINE) ||
(pstate == DI_PATH_STATE_FAULT)) {
clp->ap_cond = CFGA_COND_UNUSABLE;
} else {
clp->ap_cond = CFGA_COND_FAILING;
}
clp->ap_r_state = lap->xport_rstate;
clp->ap_info[0] = '\0';
get_hw_info(client_node, clp);
if (devctl_cmd(nodepath, FPCFGA_DEV_GETSTATE,
&dctl_state, l_errnop) == FPCFGA_OK) {
busy = ((dctl_state & DEVICE_BUSY)
== DEVICE_BUSY) ? 1 : 0;
} else {
busy = 0;
}
clp->ap_busy = busy;
clp->ap_status_time = (time_t)-1;
(void) insert_ldata_to_ldatalist(port_wwn,
lun_nump, listp, &(lap->listp));
}
break;
case FPCFGA_STAT_ALL:
if ((make_portwwn_luncomp_from_pinode(path, &port_wwn,
&lun_nump, l_errnop)) != FPCFGA_OK) {
return (FPCFGA_LIB_ERR);
}
if ((ldata_ret = is_FCP_dev_ap_on_ldata_list(port_wwn,
*lun_nump, lap->listp, &matchldp))
== FPCFGA_LIB_ERR) {
S_FREE(port_wwn);
return (ldata_ret);
}
if (ldata_ret == FPCFGA_ACCESS_OK) {
lap->chld_config = CFGA_STAT_CONFIGURED;
matchldp->ldata.ap_o_state =
CFGA_STAT_CONFIGURED;
if (((pstate = di_path_state(path)) ==
DI_PATH_STATE_OFFLINE) ||
(pstate == DI_PATH_STATE_FAULT)) {
matchldp->ldata.ap_cond =
CFGA_COND_UNUSABLE;
}
break;
}
if (((strcmp(lap->xport_type,
FP_FC_PUBLIC_PORT_TYPE) == 0) ||
(strcmp(lap->xport_type,
FP_FC_FABRIC_PORT_TYPE) == 0)) ||
(di_path_state(path) !=
DI_PATH_STATE_OFFLINE)) {
lap->chld_config = CFGA_STAT_CONFIGURED;
client_node = di_path_client_node(path);
if (client_node == DI_NODE_NIL) {
*l_errnop = errno;
S_FREE(port_wwn);
return (FPCFGA_LIB_ERR);
}
if ((construct_nodepath_from_dinode(
client_node, &nodepath, l_errnop))
!= FPCFGA_OK) {
S_FREE(port_wwn);
return (FPCFGA_LIB_ERR);
}
listp = calloc(1, sizeof (ldata_list_t));
if (listp == NULL) {
S_FREE(port_wwn);
S_FREE(nodepath);
lap->l_errno = errno;
return (FPCFGA_LIB_ERR);
}
clp = &listp->ldata;
(void) snprintf(clp->ap_log_id,
sizeof (clp->ap_log_id), "%s%s%s%s%d",
lap->xport_logp, DYN_SEP, port_wwn,
LUN_COMP_SEP, *lun_nump);
(void) snprintf(clp->ap_phys_id,
sizeof (clp->ap_phys_id), "%s%s%s%s%d",
lap->apidp->xport_phys, DYN_SEP, port_wwn,
LUN_COMP_SEP, *lun_nump);
clp->ap_class[0] = '\0';
clp->ap_o_state = CFGA_STAT_CONFIGURED;
if (((pstate = di_path_state(path))
== DI_PATH_STATE_OFFLINE) ||
(pstate == DI_PATH_STATE_FAULT)) {
clp->ap_cond = CFGA_COND_UNUSABLE;
} else {
clp->ap_cond = CFGA_COND_FAILING;
}
clp->ap_r_state = lap->xport_rstate;
clp->ap_info[0] = '\0';
get_hw_info(client_node, clp);
if (devctl_cmd(nodepath, FPCFGA_DEV_GETSTATE,
&dctl_state, l_errnop) == FPCFGA_OK) {
busy = ((dctl_state & DEVICE_BUSY)
== DEVICE_BUSY) ? 1 : 0;
} else {
busy = 0;
}
clp->ap_busy = busy;
clp->ap_status_time = (time_t)-1;
(void) insert_ldata_to_ldatalist(port_wwn,
lun_nump, listp, &(lap->listp));
}
break;
case FPCFGA_STAT_FCA_PORT:
if (di_path_state(path) != DI_PATH_STATE_OFFLINE) {
lap->chld_config = CFGA_STAT_CONFIGURED;
lap->ret = FPCFGA_OK;
return (FPCFGA_OK);
}
}
path = di_path_next_client(root, path);
} while (path != DI_PATH_NIL);
lap->ret = FPCFGA_OK;
S_FREE(port_wwn);
S_FREE(nodepath);
return (FPCFGA_OK);
}
static fpcfga_ret_t
do_stat_FCP_dev(
const di_node_t node,
const char *nodepath,
fpcfga_list_t *lap,
int limited_stat)
{
uint_t dctl_state = 0, devinfo_state = 0;
char *port_wwn = NULL;
cfga_list_data_t *clp = NULL;
cfga_busy_t busy;
ldata_list_t *listp = NULL;
ldata_list_t *matchldp = NULL;
int l_errno = 0, *lun_nump;
cfga_stat_t ostate;
cfga_cond_t cond;
fpcfga_ret_t ldata_ret;
assert(lap->apidp->xport_phys != NULL);
assert(lap->xport_logp != NULL);
cond = CFGA_COND_UNKNOWN;
devinfo_state = di_state(node);
ostate = dev_devinfo_to_occupant_state(devinfo_state);
if (devctl_cmd(nodepath, FPCFGA_DEV_GETSTATE, &dctl_state,
&l_errno) == FPCFGA_OK) {
busy = ((dctl_state & DEVICE_BUSY) == DEVICE_BUSY) ? 1 : 0;
} else {
busy = 0;
}
if (limited_stat) {
if (((strcmp(lap->xport_type, FP_FC_FABRIC_PORT_TYPE) == 0) ||
strcmp(lap->xport_type, FP_FC_PUBLIC_PORT_TYPE) == 0)) {
lap->chld_config = CFGA_STAT_CONFIGURED;
} else {
if (ostate != CFGA_STAT_UNCONFIGURED) {
lap->chld_config = CFGA_STAT_CONFIGURED;
}
}
return (FPCFGA_OK);
}
if ((make_portwwn_luncomp_from_dinode(node, &port_wwn, &lun_nump,
&l_errno)) != FPCFGA_OK) {
lap->l_errno = l_errno;
return (FPCFGA_LIB_ERR);
}
if ((ldata_ret = is_FCP_dev_ap_on_ldata_list(port_wwn, *lun_nump,
lap->listp, &matchldp)) == FPCFGA_LIB_ERR) {
lap->l_errno = l_errno;
S_FREE(port_wwn);
return (ldata_ret);
}
if (lap->cmd == FPCFGA_STAT_FC_DEV) {
switch (ostate) {
case CFGA_STAT_CONFIGURED:
case CFGA_STAT_NONE:
if (ldata_ret != FPCFGA_ACCESS_OK) {
cond = CFGA_COND_FAILING;
}
lap->chld_config = CFGA_STAT_CONFIGURED;
break;
case CFGA_STAT_UNCONFIGURED:
cond = CFGA_COND_UNUSABLE;
if (((strcmp(lap->xport_type,
FP_FC_PUBLIC_PORT_TYPE) == 0) ||
(strcmp(lap->xport_type,
FP_FC_FABRIC_PORT_TYPE) == 0)) ||
(lap->ret == FPCFGA_ACCESS_OK)) {
lap->chld_config = CFGA_STAT_CONFIGURED;
} else {
if (lap->ret != FPCFGA_OK) {
lap->ret = FPCFGA_APID_NOEXIST;
}
S_FREE(port_wwn);
return (FPCFGA_OK);
}
break;
default:
break;
}
if (ldata_ret == FPCFGA_ACCESS_OK) {
if (cond != CFGA_COND_UNKNOWN) {
matchldp->ldata.ap_cond = cond;
}
matchldp->ldata.ap_o_state = CFGA_STAT_CONFIGURED;
matchldp->ldata.ap_busy = busy;
clp = &matchldp->ldata;
get_hw_info(node, clp);
lap->ret = FPCFGA_OK;
S_FREE(port_wwn);
return (FPCFGA_OK);
}
}
if (lap->cmd == FPCFGA_STAT_ALL) {
switch (ldata_ret) {
case FPCFGA_ACCESS_OK:
lap->chld_config = CFGA_STAT_CONFIGURED;
matchldp->ldata.ap_o_state =
CFGA_STAT_CONFIGURED;
matchldp->ldata.ap_busy = busy;
clp = &matchldp->ldata;
switch (ostate) {
case CFGA_STAT_CONFIGURED:
case CFGA_STAT_NONE:
get_hw_info(node, clp);
break;
case CFGA_STAT_UNCONFIGURED:
if (matchldp->ldata.ap_cond ==
CFGA_COND_UNKNOWN) {
matchldp->ldata.ap_cond =
CFGA_COND_UNUSABLE;
}
break;
default:
break;
}
lap->ret = FPCFGA_OK;
S_FREE(port_wwn);
return (FPCFGA_OK);
case FPCFGA_APID_NOACCESS:
switch (ostate) {
case CFGA_STAT_CONFIGURED:
case CFGA_STAT_NONE:
lap->chld_config = CFGA_STAT_CONFIGURED;
cond = CFGA_COND_FAILING;
break;
case CFGA_STAT_UNCONFIGURED:
cond = CFGA_COND_UNUSABLE;
if ((strcmp(lap->xport_type,
FP_FC_PUBLIC_PORT_TYPE) == 0) ||
(strcmp(lap->xport_type,
FP_FC_FABRIC_PORT_TYPE) == 0)) {
lap->chld_config =
CFGA_STAT_CONFIGURED;
} else {
lap->ret = FPCFGA_OK;
S_FREE(port_wwn);
return (FPCFGA_OK);
}
break;
default:
break;
}
default:
break;
}
}
listp = calloc(1, sizeof (ldata_list_t));
if (listp == NULL) {
lap->l_errno = errno;
S_FREE(port_wwn);
return (FPCFGA_LIB_ERR);
}
clp = &listp->ldata;
(void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id),
"%s%s%s%s%d", lap->xport_logp, DYN_SEP, port_wwn,
LUN_COMP_SEP, *lun_nump);
(void) snprintf(clp->ap_phys_id, sizeof (clp->ap_phys_id),
"%s%s%s%s%d", lap->apidp->xport_phys, DYN_SEP, port_wwn,
LUN_COMP_SEP, *lun_nump);
clp->ap_class[0] = '\0';
clp->ap_r_state = lap->xport_rstate;
clp->ap_o_state = CFGA_STAT_CONFIGURED;
clp->ap_cond = cond;
clp->ap_busy = busy;
clp->ap_status_time = (time_t)-1;
clp->ap_info[0] = '\0';
get_hw_info(node, clp);
(void) insert_ldata_to_ldatalist(port_wwn, lun_nump, listp,
&(lap->listp));
lap->ret = FPCFGA_OK;
S_FREE(port_wwn);
return (FPCFGA_OK);
}
static fpcfga_ret_t
is_dyn_ap_on_ldata_list(const char *port_wwn, const ldata_list_t *listp,
ldata_list_t **matchldpp, int *l_errnop)
{
char *dyn = NULL, *dyncomp = NULL;
int len;
ldata_list_t *tmplp;
fpcfga_ret_t ret;
ret = FPCFGA_APID_NOACCESS;
tmplp = (ldata_list_t *)listp;
while (tmplp != NULL) {
if ((dyn = GET_DYN(tmplp->ldata.ap_phys_id)) != NULL) {
len = strlen(DYN_TO_DYNCOMP(dyn)) + 1;
dyncomp = calloc(1, len);
if (dyncomp == NULL) {
*l_errnop = errno;
ret = FPCFGA_LIB_ERR;
break;
}
(void) strcpy(dyncomp, DYN_TO_DYNCOMP(dyn));
if (!(strncmp(port_wwn, dyncomp, WWN_SIZE*2))) {
*matchldpp = tmplp;
S_FREE(dyncomp);
ret = FPCFGA_ACCESS_OK;
break;
}
S_FREE(dyncomp);
}
tmplp = tmplp->next;
}
return (ret);
}
static fpcfga_ret_t
is_FCP_dev_ap_on_ldata_list(const char *port_wwn, const int lun_num,
ldata_list_t *ldatap,
ldata_list_t **matchldpp)
{
ldata_list_t *curlp = NULL;
char *dyn = NULL, *dyncomp = NULL;
char *lun_dyn = NULL, *lunp = NULL;
int ldata_lun;
fpcfga_ret_t ret;
ret = FPCFGA_APID_NOACCESS;
if (ldatap == NULL) {
return (ret);
}
dyn = GET_DYN(ldatap->ldata.ap_phys_id);
if (dyn != NULL) dyncomp = DYN_TO_DYNCOMP(dyn);
if ((dyncomp != NULL) &&
(strncmp(dyncomp, port_wwn, WWN_SIZE*2) == 0)) {
lun_dyn = GET_LUN_DYN(dyncomp);
if (lun_dyn != NULL) {
lunp = LUN_DYN_TO_LUNCOMP(lun_dyn);
if ((ldata_lun = atoi(lunp)) == lun_num) {
*matchldpp = ldatap;
return (FPCFGA_ACCESS_OK);
} else if (ldata_lun > lun_num) {
return (ret);
}
} else {
*matchldpp = ldatap;
return (FPCFGA_ACCESS_OK);
}
}
curlp = ldatap->next;
dyn = dyncomp = NULL;
lun_dyn = lunp = NULL;
while (curlp != NULL) {
dyn = GET_DYN(curlp->ldata.ap_phys_id);
if (dyn != NULL) dyncomp = DYN_TO_DYNCOMP(dyn);
if ((dyncomp != NULL) &&
(strncmp(dyncomp, port_wwn, WWN_SIZE*2) == 0)) {
lun_dyn = GET_LUN_DYN(dyncomp);
if (lun_dyn != NULL) {
lunp = LUN_DYN_TO_LUNCOMP(lun_dyn);
if ((ldata_lun = atoi(lunp)) == lun_num) {
*matchldpp = curlp;
return (FPCFGA_ACCESS_OK);
} else if (ldata_lun > lun_num) {
return (ret);
}
} else {
*matchldpp = curlp;
return (FPCFGA_ACCESS_OK);
}
}
dyn = dyncomp = NULL;
lun_dyn = lunp = NULL;
curlp = curlp->next;
}
return (ret);
}
static fpcfga_ret_t
init_ldata_for_mpath_dev(di_path_t path, char *pwwn, int *l_errnop,
fpcfga_list_t *lap)
{
ldata_list_t *listp = NULL;
cfga_list_data_t *clp = NULL;
size_t devlen;
char *devpath;
di_node_t client_node = DI_NODE_NIL;
uint_t dctl_state = 0;
cfga_busy_t busy;
char *client_path;
di_path_state_t pstate;
if (path == DI_PATH_NIL) {
return (FPCFGA_LIB_ERR);
}
client_node = di_path_client_node(path);
if (client_node == DI_NODE_NIL) {
return (FPCFGA_LIB_ERR);
}
if ((client_path = di_devfs_path(client_node)) == NULL) {
return (FPCFGA_LIB_ERR);
}
devlen = strlen(DEVICES_DIR) + strlen(client_path) + 1;
devpath = calloc(1, devlen);
if (devpath == NULL) {
di_devfs_path_free(client_path);
*l_errnop = errno;
return (FPCFGA_LIB_ERR);
}
(void) snprintf(devpath, devlen, "%s%s", DEVICES_DIR, client_path);
listp = calloc(1, sizeof (ldata_list_t));
if (listp == NULL) {
di_devfs_path_free(client_path);
S_FREE(devpath);
*l_errnop = errno;
return (FPCFGA_LIB_ERR);
}
clp = &listp->ldata;
(void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id), "%s%s%s",
lap->xport_logp, DYN_SEP, pwwn);
(void) snprintf(clp->ap_phys_id, sizeof (clp->ap_phys_id), "%s%s%s",
lap->apidp->xport_phys, DYN_SEP, pwwn);
clp->ap_class[0] = '\0';
clp->ap_r_state = lap->xport_rstate;
clp->ap_o_state = CFGA_STAT_CONFIGURED;
if (((pstate = di_path_state(path)) == DI_PATH_STATE_OFFLINE) ||
(pstate == DI_PATH_STATE_FAULT)) {
clp->ap_cond = CFGA_COND_UNUSABLE;
} else {
clp->ap_cond = CFGA_COND_FAILING;
}
clp->ap_status_time = (time_t)-1;
get_hw_info(client_node, clp);
if (devctl_cmd(devpath, FPCFGA_DEV_GETSTATE,
&dctl_state, l_errnop) == FPCFGA_OK) {
busy = ((dctl_state & DEVICE_BUSY) == DEVICE_BUSY) ? 1 : 0;
} else {
busy = 0;
}
clp->ap_busy = busy;
listp->next = lap->listp;
lap->listp = listp;
di_devfs_path_free(client_path);
S_FREE(devpath);
lap->ret = FPCFGA_OK;
return (FPCFGA_OK);
}
static fpcfga_ret_t
init_ldata_for_accessible_dev(const char *dyncomp, uchar_t inq_type,
fpcfga_list_t *lap)
{
ldata_list_t *listp = NULL;
cfga_list_data_t *clp = NULL;
int i;
listp = calloc(1, sizeof (ldata_list_t));
if (listp == NULL) {
lap->l_errno = errno;
return (FPCFGA_LIB_ERR);
}
clp = &listp->ldata;
assert(dyncomp != NULL);
(void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id), "%s%s%s",
lap->xport_logp, DYN_SEP, dyncomp);
(void) snprintf(clp->ap_phys_id, sizeof (clp->ap_phys_id), "%s%s%s",
lap->apidp->xport_phys, DYN_SEP, dyncomp);
clp->ap_class[0] = '\0';
clp->ap_r_state = lap->xport_rstate;
clp->ap_o_state = CFGA_STAT_UNCONFIGURED;
clp->ap_cond = CFGA_COND_UNKNOWN;
clp->ap_busy = 0;
clp->ap_status_time = (time_t)-1;
clp->ap_info[0] = '\0';
for (i = 0; i < N_DEVICE_TYPES; i++) {
if (inq_type == device_list[i].itype) {
(void) snprintf(clp->ap_type, sizeof (clp->ap_type),
"%s", (char *)device_list[i].name);
break;
}
}
if (i == N_DEVICE_TYPES) {
if (inq_type == ERR_INQ_DTYPE) {
clp->ap_cond = CFGA_COND_FAILED;
snprintf(clp->ap_type, sizeof (clp->ap_type), "%s",
(char *)GET_MSG_STR(ERR_UNAVAILABLE));
} else {
(void) snprintf(clp->ap_type, sizeof (clp->ap_type),
"%s", "unknown");
}
}
(void) insert_ldata_to_ldatalist(dyncomp, NULL, listp, &(lap->listp));
return (FPCFGA_OK);
}
static fpcfga_ret_t
init_ldata_for_accessible_FCP_dev(
const char *port_wwn,
int num_luns,
struct report_lun_resp *resp_buf,
fpcfga_list_t *lap,
int *l_errnop)
{
ldata_list_t *listp = NULL, *listp_start = NULL, *listp_end = NULL,
*prevlp = NULL, *curlp = NULL, *matchp_start = NULL,
*matchp_end = NULL;
cfga_list_data_t *clp = NULL;
char *dyn = NULL, *dyncomp = NULL;
uchar_t *lun_string;
uint16_t lun_num;
int i, j, str_ret;
fpcfga_ret_t ret;
char dtype[CFGA_TYPE_LEN];
struct scsi_inquiry *inq_buf;
uchar_t peri_qual;
cfga_cond_t cond = CFGA_COND_UNKNOWN;
uchar_t lun_num_raw[SAM_LUN_SIZE];
if (num_luns == 0) {
return (FPCFGA_OK);
}
for (i = 0; i < num_luns; i++) {
lun_string = (uchar_t *)&(resp_buf->lun_string[i]);
memcpy(lun_num_raw, lun_string, sizeof (lun_num_raw));
if ((ret = get_standard_inq_data(lap->apidp->xport_phys, port_wwn,
lun_num_raw, &inq_buf, l_errnop))
!= FPCFGA_OK) {
if (ret == FPCFGA_FCP_TGT_SEND_SCSI_FAILED) {
(void) strlcpy(dtype,
(char *)GET_MSG_STR(ERR_UNAVAILABLE), CFGA_TYPE_LEN);
cond = CFGA_COND_FAILED;
} else {
S_FREE(inq_buf);
return (FPCFGA_LIB_ERR);
}
} else {
peri_qual = inq_buf->inq_dtype & FP_PERI_QUAL_MASK;
if (peri_qual != DPQ_POSSIBLE) {
S_FREE(inq_buf);
continue;
}
*dtype = '\0';
for (j = 0; j < N_DEVICE_TYPES; j++) {
if ((inq_buf->inq_dtype & DTYPE_MASK)
== device_list[j].itype) {
(void) strlcpy(dtype, (char *)device_list[j].name,
CFGA_TYPE_LEN);
break;
}
}
if (*dtype == '\0') {
(void) strlcpy(dtype,
(char *)device_list[DTYPE_UNKNOWN_INDEX].name,
CFGA_TYPE_LEN);
}
}
lun_num = ((lun_string[0] & 0x3F) << 8) | lun_string[1];
listp = calloc(1, sizeof (ldata_list_t));
if (listp == NULL) {
*l_errnop = errno;
list_free(&listp_start);
return (FPCFGA_LIB_ERR);
}
clp = &listp->ldata;
(void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id),
"%s%s%s%s%d", lap->xport_logp, DYN_SEP, port_wwn,
LUN_COMP_SEP, lun_num);
(void) snprintf(clp->ap_phys_id, sizeof (clp->ap_phys_id),
"%s%s%s%s%d", lap->apidp->xport_phys, DYN_SEP, port_wwn,
LUN_COMP_SEP, lun_num);
(void) strncpy(clp->ap_type, dtype, strlen(dtype));
clp->ap_class[0] = '\0';
clp->ap_r_state = lap->xport_rstate;
clp->ap_o_state = CFGA_STAT_UNCONFIGURED;
clp->ap_cond = cond;
clp->ap_busy = 0;
clp->ap_status_time = (time_t)-1;
clp->ap_info[0] = '\0';
if (listp_start == NULL) {
listp_start = listp;
} else {
if ((ret = insert_FCP_dev_ldata(
port_wwn, lun_num, listp,
&listp_start)) != FPCFGA_OK) {
list_free(&listp_start);
return (ret);
}
}
listp = NULL;
S_FREE(inq_buf);
}
if (listp_start == NULL) {
return (FPCFGA_OK);
}
curlp = listp_start->next;
prevlp = listp_start;
while (curlp) {
prevlp = curlp;
curlp = curlp->next;
}
listp_end = prevlp;
if (lap->listp == NULL) {
lap->listp = listp_start;
for (listp = listp_start; listp != NULL; listp = listp->next) {
listp->ldata.ap_cond = CFGA_COND_FAILING;
}
return (FPCFGA_OK);
}
dyn = GET_DYN(lap->listp->ldata.ap_phys_id);
if ((dyn != NULL) && ((dyncomp = DYN_TO_DYNCOMP(dyn)) != NULL)) {
if ((str_ret = strncmp(dyncomp, port_wwn, WWN_SIZE*2)) == 0) {
matchp_start = matchp_end = lap->listp;
while (matchp_end->next != NULL) {
dyn = GET_DYN(
matchp_end->next->ldata.ap_phys_id);
if ((dyn != NULL) &&
((dyncomp = DYN_TO_DYNCOMP(dyn)) != NULL)) {
if ((str_ret = strncmp(dyncomp,
port_wwn, WWN_SIZE*2)) == 0) {
matchp_end = matchp_end->next;
} else {
break;
}
} else {
break;
}
}
for (listp = listp_start; listp != NULL;
listp = listp->next) {
listp->ldata.ap_cond =
lap->listp->ldata.ap_cond;
}
listp_end->next = matchp_end->next;
matchp_end->next = NULL;
list_free(&matchp_start);
lap->listp = listp_start;
return (FPCFGA_OK);
} else if (str_ret > 0) {
for (listp = listp_start; listp != NULL;
listp = listp->next) {
listp->ldata.ap_cond = CFGA_COND_FAILING;
}
listp_end->next = lap->listp->next;
lap->listp = listp_start;
return (FPCFGA_OK);
}
}
prevlp = lap->listp;
curlp = lap->listp->next;
dyn = dyncomp = NULL;
while (curlp != NULL) {
dyn = GET_DYN(curlp->ldata.ap_phys_id);
if ((dyn != NULL) &&
((dyncomp = DYN_TO_DYNCOMP(dyn)) != NULL)) {
if ((str_ret = strncmp(dyncomp, port_wwn,
WWN_SIZE*2)) == 0) {
matchp_start = matchp_end = curlp;
while (matchp_end->next != NULL) {
dyn = GET_DYN(
matchp_end->next->ldata.ap_phys_id);
if ((dyn != NULL) &&
((dyncomp = DYN_TO_DYNCOMP(dyn))
!= NULL)) {
if ((str_ret = strncmp(dyncomp,
port_wwn, WWN_SIZE*2))
== 0) {
matchp_end =
matchp_end->next;
} else {
break;
}
} else {
break;
}
}
for (listp = listp_start; listp != NULL;
listp = listp->next) {
listp->ldata.ap_cond = curlp->ldata.ap_cond;
}
listp_end->next = matchp_end->next;
prevlp->next = listp_start;
matchp_end->next = NULL;
list_free(&matchp_start);
return (FPCFGA_OK);
} else if (str_ret > 0) {
for (listp = listp_start; listp != NULL;
listp = listp->next) {
listp->ldata.ap_cond = CFGA_COND_FAILING;
}
listp_end->next = curlp;
prevlp->next = listp_start;
return (FPCFGA_OK);
}
}
dyn = dyncomp = NULL;
prevlp = curlp;
curlp = curlp->next;
}
prevlp->next = listp_start;
for (listp = listp_start; listp != NULL; listp = listp->next) {
listp->ldata.ap_cond = CFGA_COND_FAILING;
}
return (FPCFGA_OK);
}
static void
get_hw_info(di_node_t node, cfga_list_data_t *clp)
{
char *cp = NULL;
char *inq_vid, *inq_pid;
int i;
if (clp->ap_type != NULL) {
for (i = 0; i < (N_DEVICE_TYPES -1); i++) {
if (strncmp((char *)clp->ap_type, (char *)device_list[i].name,
sizeof (clp->ap_type)) == 0) {
break;
}
}
if (i == (N_DEVICE_TYPES - 1)) {
cp = (char *)get_device_type(node);
if (cp == NULL) {
cp = (char *)GET_MSG_STR(ERR_UNAVAILABLE);
}
(void) snprintf(clp->ap_type, sizeof (clp->ap_type), "%s",
S_STR(cp));
}
} else {
cp = (char *)get_device_type(node);
if (cp == NULL) {
cp = (char *)GET_MSG_STR(ERR_UNAVAILABLE);
}
(void) snprintf(clp->ap_type, sizeof (clp->ap_type), "%s",
S_STR(cp));
}
if ((di_prop_lookup_strings(DDI_DEV_T_ANY, node,
"inquiry-product-id", &inq_pid) == 1) &&
(di_prop_lookup_strings(DDI_DEV_T_ANY, node,
"inquiry-vendor-id", &inq_vid) == 1)) {
(void) snprintf(clp->ap_info, sizeof (clp->ap_info),
"%s %s", inq_vid, inq_pid);
}
}
static const char *
get_device_type(di_node_t node)
{
char *name = NULL;
int *inq_dtype;
int i;
if (node == DI_NODE_NIL) {
return (NULL);
}
if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "inquiry-device-type",
&inq_dtype) != -1) {
int itype = (*inq_dtype) & DTYPE_MASK;
for (i = 0; i < N_DEVICE_TYPES; i++) {
if (itype == device_list[i].itype) {
name = (char *)device_list[i].name;
break;
}
}
if (i == (N_DEVICE_TYPES - 1)) {
name = NULL;
}
}
if (name == NULL) {
char *nodetype;
di_minor_t minor = di_minor_next(node, DI_MINOR_NIL);
if ((minor != DI_MINOR_NIL) &&
((nodetype = di_minor_nodetype(minor)) != NULL)) {
for (i = 0; i < N_DEVICE_TYPES; i++) {
if (device_list[i].ntype &&
(strcmp(nodetype, device_list[i].ntype)
== 0)) {
name = (char *)device_list[i].name;
break;
}
}
}
}
return (name);
}
fpcfga_ret_t
list_ext_postprocess(
ldata_list_t **llpp,
int nelem,
cfga_list_data_t **ap_id_list,
int *nlistp,
char **errstring)
{
cfga_list_data_t *ldatap = NULL;
ldata_list_t *tmplp = NULL;
int i = -1;
*ap_id_list = NULL;
*nlistp = 0;
if (*llpp == NULL || nelem < 0) {
return (FPCFGA_LIB_ERR);
}
if (nelem == 0) {
return (FPCFGA_APID_NOEXIST);
}
ldatap = calloc(nelem, sizeof (cfga_list_data_t));
if (ldatap == NULL) {
cfga_err(errstring, errno, ERR_LIST, 0);
return (FPCFGA_LIB_ERR);
}
tmplp = *llpp;
for (i = 0; i < nelem && tmplp != NULL; i++) {
ldatap[i] = tmplp->ldata;
tmplp = tmplp->next;
}
if (i < nelem || tmplp != NULL) {
S_FREE(ldatap);
return (FPCFGA_LIB_ERR);
}
*nlistp = nelem;
*ap_id_list = ldatap;
return (FPCFGA_OK);
}
static cfga_stat_t
xport_devinfo_to_recep_state(uint_t xport_di_state)
{
cfga_stat_t rs;
switch (xport_di_state) {
case DI_BUS_QUIESCED:
case DI_BUS_DOWN:
rs = CFGA_STAT_DISCONNECTED;
break;
default:
rs = CFGA_STAT_CONNECTED;
break;
}
return (rs);
}
static cfga_stat_t
dev_devinfo_to_occupant_state(uint_t dev_di_state)
{
if ((dev_di_state & DI_DRIVER_DETACHED) != DI_DRIVER_DETACHED) {
return (CFGA_STAT_CONFIGURED);
}
if ((dev_di_state & DI_DEVICE_OFFLINE) == DI_DEVICE_OFFLINE ||
(dev_di_state & DI_DEVICE_DOWN) == DI_DEVICE_DOWN) {
return (CFGA_STAT_UNCONFIGURED);
} else {
return (CFGA_STAT_NONE);
}
}
static fpcfga_ret_t
insert_ldata_to_ldatalist(
const char *port_wwn,
int *lun_nump,
ldata_list_t *listp,
ldata_list_t **ldatapp)
{
if (lun_nump == NULL) {
return (insert_fc_dev_ldata(port_wwn, listp, ldatapp));
} else {
return
(insert_FCP_dev_ldata(port_wwn, *lun_nump, listp, ldatapp));
}
}
static fpcfga_ret_t
insert_fc_dev_ldata(
const char *port_wwn,
ldata_list_t *listp,
ldata_list_t **ldatapp)
{
ldata_list_t *prevlp = NULL, *curlp = NULL;
char *dyn = NULL, *dyncomp = NULL;
if (*ldatapp == NULL) {
*ldatapp = listp;
return (FPCFGA_OK);
}
dyn = GET_DYN((*ldatapp)->ldata.ap_phys_id);
if (dyn != NULL) dyncomp = DYN_TO_DYNCOMP(dyn);
if ((dyncomp != NULL) &&
(strncmp(dyncomp, port_wwn, WWN_SIZE*2) >= 0)) {
listp->next = *ldatapp;
*ldatapp = listp;
return (FPCFGA_OK);
}
prevlp = *ldatapp;
curlp = (*ldatapp)->next;
dyn = dyncomp = NULL;
while (curlp != NULL) {
dyn = GET_DYN(curlp->ldata.ap_phys_id);
if (dyn != NULL) dyncomp = DYN_TO_DYNCOMP(dyn);
if ((dyncomp != NULL) &&
(strncmp(dyncomp, port_wwn, WWN_SIZE*2) >= 0)) {
listp->next = prevlp->next;
prevlp->next = listp;
return (FPCFGA_OK);
}
dyn = dyncomp = NULL;
prevlp = curlp;
curlp = curlp->next;
}
prevlp->next = listp;
return (FPCFGA_OK);
}
static fpcfga_ret_t
insert_FCP_dev_ldata(
const char *port_wwn,
int lun_num,
ldata_list_t *listp,
ldata_list_t **ldatapp)
{
ldata_list_t *prevlp = NULL, *curlp = NULL;
char *dyn = NULL, *dyncomp = NULL;
char *lun_dyn = NULL, *lunp = NULL;
if (*ldatapp == NULL) {
*ldatapp = listp;
return (FPCFGA_OK);
}
dyn = GET_DYN((*ldatapp)->ldata.ap_phys_id);
if (dyn != NULL) dyncomp = DYN_TO_DYNCOMP(dyn);
if ((dyncomp != NULL) &&
(strncmp(dyncomp, port_wwn, WWN_SIZE*2) == 0)) {
lun_dyn = GET_LUN_DYN(dyncomp);
if (lun_dyn != NULL) {
lunp = LUN_DYN_TO_LUNCOMP(lun_dyn);
if ((atoi(lunp)) >= lun_num) {
listp->next = *ldatapp;
*ldatapp = listp;
return (FPCFGA_OK);
}
}
} else if ((dyncomp != NULL) &&
(strncmp(dyncomp, port_wwn, WWN_SIZE*2) > 0)) {
listp->next = *ldatapp;
*ldatapp = listp;
return (FPCFGA_OK);
}
prevlp = *ldatapp;
curlp = (*ldatapp)->next;
dyn = dyncomp = NULL;
lun_dyn = lunp = NULL;
while (curlp != NULL) {
dyn = GET_DYN(curlp->ldata.ap_phys_id);
if (dyn != NULL) dyncomp = DYN_TO_DYNCOMP(dyn);
if ((dyncomp != NULL) &&
(strncmp(dyncomp, port_wwn, WWN_SIZE*2) == 0)) {
lun_dyn = GET_LUN_DYN(dyncomp);
if (lun_dyn != NULL) {
lunp = LUN_DYN_TO_LUNCOMP(lun_dyn);
if ((atoi(lunp)) >= lun_num) {
listp->next = prevlp->next;
prevlp->next = listp;
return (FPCFGA_OK);
}
}
} else if ((dyncomp != NULL) &&
(strncmp(dyncomp, port_wwn, WWN_SIZE*2) > 0)) {
listp->next = prevlp->next;
prevlp->next = listp;
return (FPCFGA_OK);
}
dyn = dyncomp = NULL;
lun_dyn = lunp = NULL;
prevlp = curlp;
curlp = curlp->next;
}
prevlp->next = listp;
return (FPCFGA_OK);
}
static uchar_t
get_inq_dtype(char *xport_phys, char *dyncomp, HBA_HANDLE handle,
HBA_PORTATTRIBUTES *portAttrs, HBA_PORTATTRIBUTES *discPortAttrs) {
HBA_STATUS status;
report_lun_resp_t *resp_buf;
int num_luns = 0, ret, l_errno;
uchar_t *lun_string;
uint64_t lun = 0;
struct scsi_inquiry inq;
struct scsi_extended_sense sense;
HBA_UINT8 scsiStatus;
uint32_t inquirySize = sizeof (inq);
uint32_t senseSize = sizeof (sense);
memset(&inq, 0, sizeof (inq));
memset(&sense, 0, sizeof (sense));
if ((ret = get_report_lun_data(xport_phys, dyncomp,
&num_luns, &resp_buf, &sense, &l_errno))
!= FPCFGA_OK) {
if ((sense.es_key == KEY_ILLEGAL_REQUEST) &&
(sense.es_add_code == 0x20)) {
lun = 0;
} else {
if (ret == FPCFGA_FCP_SEND_SCSI_DEV_NOT_TGT) {
inq.inq_dtype = DTYPE_UNKNOWN;
} else {
inq.inq_dtype = ERR_INQ_DTYPE;
}
return (inq.inq_dtype);
}
} else {
lun_string = (uchar_t *)&(resp_buf->lun_string[0]);
memcpy(&lun, lun_string, sizeof (lun));
S_FREE(resp_buf);
}
memset(&sense, 0, sizeof (sense));
status = HBA_ScsiInquiryV2(handle,
portAttrs->PortWWN, discPortAttrs->PortWWN, lun, 0, 0,
&inq, &inquirySize, &scsiStatus, &sense, &senseSize);
if (status == HBA_STATUS_OK) {
inq.inq_dtype = inq.inq_dtype & DTYPE_MASK;
} else if (status == HBA_STATUS_ERROR_NOT_A_TARGET) {
inq.inq_dtype = DTYPE_UNKNOWN;
} else {
inq.inq_dtype = ERR_INQ_DTYPE;
}
return (inq.inq_dtype);
}