#include "cfga_fp.h"
#define ALL_APID_LUNS_UNUSABLE 0x10
#define DEFAULT_LUN_COUNT 1024
#define LUN_SIZE 8
#define LUN_HEADER_SIZE 8
#define DEFAULT_LUN_LENGTH DEFAULT_LUN_COUNT * \
LUN_SIZE + \
LUN_HEADER_SIZE
static fpcfga_ret_t do_devctl_dev_create(apid_t *, char *, int,
uchar_t, char **);
static fpcfga_ret_t dev_rcm_online(apid_t *, int, cfga_flags_t, char **);
static void dev_rcm_online_nonoperationalpath(apid_t *, cfga_flags_t, char **);
static fpcfga_ret_t dev_rcm_offline(apid_t *, cfga_flags_t, char **);
static fpcfga_ret_t dev_rcm_remove(apid_t *, cfga_flags_t, char **);
static fpcfga_ret_t lun_unconf(char *, int, char *, char *, char **);
static fpcfga_ret_t dev_unconf(apid_t *, char **, uchar_t *);
static fpcfga_ret_t is_xport_phys_in_pathlist(apid_t *, char **);
static void copy_pwwn_data_to_str(char *, const uchar_t *);
static fpcfga_ret_t unconf_vhci_nodes(di_path_t, di_node_t, char *,
char *, int, int *, int *, char **, cfga_flags_t);
static fpcfga_ret_t unconf_non_vhci_nodes(di_node_t, char *, char *,
int, int *, int *, char **, cfga_flags_t);
static fpcfga_ret_t unconf_any_devinfo_nodes(apid_t *, cfga_flags_t, char **,
int *, int *);
static fpcfga_ret_t handle_devs(cfga_cmd_t, apid_t *, cfga_flags_t,
char **, HBA_HANDLE, int, HBA_PORTATTRIBUTES);
static fpcfga_ret_t
do_devctl_dev_create(apid_t *apidt, char *dev_path, int pathlen,
uchar_t dev_dtype, char **errstring)
{
devctl_ddef_t ddef_hdl;
devctl_hdl_t bus_hdl, dev_hdl;
char *drvr_name = "dummy";
la_wwn_t pwwn;
*dev_path = '\0';
if ((ddef_hdl = devctl_ddef_alloc(drvr_name, 0)) == NULL) {
cfga_err(errstring, errno, ERRARG_DC_DDEF_ALLOC, drvr_name, 0);
return (FPCFGA_LIB_ERR);
}
if (cvt_dyncomp_to_lawwn(apidt->dyncomp, &pwwn)) {
devctl_ddef_free(ddef_hdl);
cfga_err(errstring, 0, ERR_APID_INVAL, 0);
return (FPCFGA_LIB_ERR);
}
if (devctl_ddef_byte_array(ddef_hdl, PORT_WWN_PROP, FC_WWN_SIZE,
pwwn.raw_wwn) == -1) {
devctl_ddef_free(ddef_hdl);
cfga_err(errstring, errno, ERRARG_DC_BYTE_ARRAY,
PORT_WWN_PROP, 0);
return (FPCFGA_LIB_ERR);
}
if ((bus_hdl = devctl_bus_acquire(apidt->xport_phys, 0)) == NULL) {
devctl_ddef_free(ddef_hdl);
cfga_err(errstring, errno, ERRARG_DC_BUS_ACQUIRE,
apidt->xport_phys, 0);
return (FPCFGA_LIB_ERR);
}
if (devctl_bus_dev_create(bus_hdl, ddef_hdl, 0, &dev_hdl)) {
devctl_ddef_free(ddef_hdl);
devctl_release(bus_hdl);
if (dev_dtype == DTYPE_UNKNOWN) {
cfga_err(errstring, errno,
ERRARG_BUS_DEV_CREATE_UNKNOWN, apidt->dyncomp, 0);
} else {
cfga_err(errstring, errno, ERRARG_BUS_DEV_CREATE,
apidt->dyncomp, 0);
}
return (FPCFGA_LIB_ERR);
}
devctl_release(bus_hdl);
devctl_ddef_free(ddef_hdl);
devctl_get_pathname(dev_hdl, dev_path, pathlen);
devctl_release(dev_hdl);
return (FPCFGA_OK);
}
static fpcfga_ret_t
dev_rcm_online(apid_t *apidt, int count, cfga_flags_t flags, char **errstring)
{
luninfo_list_t *lunlistp;
int i = 0, ret = 0;
fpcfga_ret_t retval = FPCFGA_OK;
if ((apidt->flags & FLAG_DISABLE_RCM) != 0) {
return (FPCFGA_OK);
}
lunlistp = apidt->lunlist;
for (lunlistp = apidt->lunlist; lunlistp != NULL;
i++, lunlistp = lunlistp->next) {
if ((count >= 0) && (i >= count))
break;
if (fp_rcm_online(lunlistp->path, errstring, flags) !=
FPCFGA_OK) {
ret++;
}
}
if (ret > 0)
retval = FPCFGA_LIB_ERR;
return (retval);
}
void
dev_rcm_online_nonoperationalpath(apid_t *apidt, cfga_flags_t flags,
char **errstring)
{
luninfo_list_t *lunlistp;
if ((apidt->flags & FLAG_DISABLE_RCM) != 0) {
return;
}
lunlistp = apidt->lunlist;
for (lunlistp = apidt->lunlist; lunlistp != NULL;
lunlistp = lunlistp->next) {
if ((lunlistp->lun_flag & FLAG_SKIP_ONLINEOTHERS) != 0) {
continue;
}
(void) fp_rcm_online(lunlistp->path, errstring, flags);
}
}
static fpcfga_ret_t
dev_rcm_offline(apid_t *apidt, cfga_flags_t flags, char **errstring)
{
int count = 0;
luninfo_list_t *lunlistp;
if ((apidt->flags & FLAG_DISABLE_RCM) != 0) {
return (FPCFGA_OK);
}
for (lunlistp = apidt->lunlist; lunlistp != NULL;
lunlistp = lunlistp->next) {
if ((lunlistp->lun_flag & FLAG_SKIP_RCMOFFLINE) != 0) {
continue;
}
if ((apidt->flags & FLAG_REMOVE_UNUSABLE_FCP_DEV) ==
FLAG_REMOVE_UNUSABLE_FCP_DEV) {
int ret = strncmp(lunlistp->path, SCSI_VHCI_ROOT,
strlen(SCSI_VHCI_ROOT));
if (((ret == 0) &&
(lunlistp->node_state == DI_PATH_STATE_OFFLINE)) ||
((ret != 0) &&
((lunlistp->node_state & DI_DEVICE_OFFLINE) ==
DI_DEVICE_OFFLINE))) {
if (fp_rcm_offline(lunlistp->path, errstring,
flags) != 0) {
(void) dev_rcm_online(apidt, count,
flags, NULL);
return (FPCFGA_LIB_ERR);
}
count++;
}
} else {
if (fp_rcm_offline(lunlistp->path, errstring,
flags) != 0) {
(void) dev_rcm_online(apidt, count, flags,
NULL);
return (FPCFGA_LIB_ERR);
}
count++;
}
}
return (FPCFGA_OK);
}
static fpcfga_ret_t
dev_rcm_remove(apid_t *apidt, cfga_flags_t flags, char **errstring)
{
int count = 0;
luninfo_list_t *lunlistp;
if ((apidt->flags & FLAG_DISABLE_RCM) != 0) {
return (FPCFGA_OK);
}
for (lunlistp = apidt->lunlist; lunlistp != NULL;
lunlistp = lunlistp->next) {
if ((lunlistp->lun_flag & FLAG_SKIP_RCMREMOVE) != 0)
continue;
if ((apidt->flags & FLAG_REMOVE_UNUSABLE_FCP_DEV) ==
FLAG_REMOVE_UNUSABLE_FCP_DEV) {
int ret = strncmp(lunlistp->path, SCSI_VHCI_ROOT,
strlen(SCSI_VHCI_ROOT));
if (((ret == 0) &&
(lunlistp->node_state == DI_PATH_STATE_OFFLINE)) ||
((ret != 0) &&
((lunlistp->node_state & DI_DEVICE_OFFLINE) ==
DI_DEVICE_OFFLINE))) {
if (fp_rcm_remove(lunlistp->path, errstring,
flags) != 0) {
(void) dev_rcm_online(apidt, count,
flags, NULL);
return (FPCFGA_LIB_ERR);
}
count++;
}
} else {
if (fp_rcm_remove(lunlistp->path, errstring,
flags) != 0) {
(void) dev_rcm_online(apidt, count, flags,
NULL);
return (FPCFGA_LIB_ERR);
}
count++;
}
}
return (FPCFGA_OK);
}
static fpcfga_ret_t
lun_unconf(char *path, int lunnum, char *xport_phys, char *dyncomp,
char **errstring)
{
devctl_hdl_t hdl;
char *ptr;
char pathname[MAXPATHLEN];
if (path == NULL)
return (FPCFGA_OK);
if (strncmp(path, SCSI_VHCI_ROOT, strlen(SCSI_VHCI_ROOT)) == 0) {
(void) strlcpy(pathname, xport_phys, MAXPATHLEN);
if ((ptr = strrchr(pathname, ':')) != NULL) {
*ptr = '\0';
}
if ((ptr = strrchr(path, '/')) == NULL) {
cfga_err(errstring, 0, ERRARG_INVALID_PATH, path, 0);
return (FPCFGA_LIB_ERR);
}
strcat(pathname, ptr);
if ((ptr = strrchr(pathname, '@')) == NULL) {
cfga_err(errstring, 0, ERRARG_INVALID_PATH,
pathname, 0);
return (FPCFGA_LIB_ERR);
}
*ptr = '\0';
sprintf(&pathname[strlen(pathname)], "@w%s,%x",
dyncomp, lunnum);
ptr = pathname;
} else {
ptr = path;
}
if ((hdl = devctl_device_acquire(ptr, 0)) == NULL) {
cfga_err(errstring, errno, ERRARG_DEV_ACQUIRE, ptr, 0);
return (FPCFGA_LIB_ERR);
}
if (devctl_device_remove(hdl) != 0) {
devctl_release(hdl);
cfga_err(errstring, errno, ERRARG_DEV_REMOVE, ptr, 0);
return (FPCFGA_LIB_ERR);
}
devctl_release(hdl);
return (FPCFGA_OK);
}
static fpcfga_ret_t
dev_unconf(apid_t *apidt, char **errstring, uchar_t *flag)
{
luninfo_list_t *lunlistp;
fpcfga_ret_t ret = FPCFGA_OK;
int lun_cnt = 0, unusable_lun_cnt = 0;
for (lunlistp = apidt->lunlist; lunlistp != NULL;
lunlistp = lunlistp->next) {
lun_cnt++;
if ((apidt->flags & FLAG_REMOVE_UNUSABLE_FCP_DEV) ==
FLAG_REMOVE_UNUSABLE_FCP_DEV) {
if (strncmp(lunlistp->path, SCSI_VHCI_ROOT,
strlen(SCSI_VHCI_ROOT)) == 0) {
if (lunlistp->node_state ==
DI_PATH_STATE_OFFLINE) {
unusable_lun_cnt++;
if ((ret = lun_unconf(lunlistp->path,
lunlistp->lunnum, apidt->xport_phys,
apidt->dyncomp, errstring)) != FPCFGA_OK) {
return (ret);
}
}
} else {
if ((lunlistp->node_state & DI_DEVICE_OFFLINE) ==
DI_DEVICE_OFFLINE) {
unusable_lun_cnt++;
if ((ret = lun_unconf(lunlistp->path,
lunlistp->lunnum, apidt->xport_phys,
apidt->dyncomp, errstring)) != FPCFGA_OK) {
return (ret);
}
}
}
} else {
if ((ret = lun_unconf(lunlistp->path, lunlistp->lunnum,
apidt->xport_phys, apidt->dyncomp,
errstring)) != FPCFGA_OK) {
return (ret);
}
}
}
if ((apidt->flags & FLAG_REMOVE_UNUSABLE_FCP_DEV) ==
FLAG_REMOVE_UNUSABLE_FCP_DEV) {
if (lun_cnt == unusable_lun_cnt) {
*flag = ALL_APID_LUNS_UNUSABLE;
}
}
return (ret);
}
static fpcfga_ret_t
is_xport_phys_in_pathlist(apid_t *apidt, char **errstring)
{
di_node_t root, vhci, node, phci;
di_path_t path = DI_PATH_NIL;
int num_active_paths, found = 0;
char *vhci_path_ptr, *pathname_ptr, pathname[MAXPATHLEN];
char *phci_path, *node_path;
char phci_addr[MAXPATHLEN];
char *xport_phys, *vhci_path, *dyncomp;
luninfo_list_t *lunlistp, *temp;
int non_operational_path_count;
if ((apidt->dyncomp == NULL) || (*apidt->dyncomp == '\0')) {
return (FPCFGA_LIB_ERR);
}
xport_phys = apidt->xport_phys;
dyncomp = apidt->dyncomp;
lunlistp = apidt->lunlist;
for (lunlistp = apidt->lunlist; lunlistp != NULL;
lunlistp = lunlistp->next) {
if (strncmp(lunlistp->path, SCSI_VHCI_ROOT,
strlen(SCSI_VHCI_ROOT)) != 0) {
lunlistp->lun_flag |= FLAG_SKIP_ONLINEOTHERS;
continue;
}
vhci_path = lunlistp->path;
num_active_paths = 0;
non_operational_path_count = 0;
if (xport_phys == NULL || vhci_path == NULL) {
cfga_err(errstring, 0, ERRARG_XPORT_NOT_IN_PHCI_LIST,
xport_phys, 0);
return (FPCFGA_LIB_ERR);
}
(void) strlcpy(pathname, xport_phys, MAXPATHLEN);
if ((pathname_ptr = strrchr(pathname, ':')) != NULL) {
*pathname_ptr = '\0';
}
pathname_ptr = pathname + strlen(DEVICES_DIR);
root = di_init("/", DINFOCPYALL|DINFOPATH);
if (root == DI_NODE_NIL) {
return (FPCFGA_LIB_ERR);
}
vhci_path_ptr = vhci_path + strlen(DEVICES_DIR);
if ((vhci = di_drv_first_node(SCSI_VHCI_DRVR, root)) ==
DI_NODE_NIL) {
return (FPCFGA_LIB_ERR);
}
found = 0;
for (node = di_child_node(vhci); node != DI_NODE_NIL;
node = di_sibling_node(node)) {
if ((node_path = di_devfs_path(node)) != NULL) {
if (strncmp(vhci_path_ptr, node_path,
strlen(node_path)) != 0) {
di_devfs_path_free(node_path);
} else {
found = 1;
break;
}
}
}
if (found == 0) {
cfga_err(errstring, 0, ERRARG_XPORT_NOT_IN_PHCI_LIST,
xport_phys, 0);
di_fini(root);
return (FPCFGA_LIB_ERR);
}
di_devfs_path_free(node_path);
found = 0;
for (path = di_path_next_phci(node, DI_PATH_NIL);
path != DI_PATH_NIL;
path = di_path_next_phci(node, path)) {
if ((phci = di_path_phci_node(path)) == DI_NODE_NIL) {
cfga_err(errstring, 0,
ERRARG_XPORT_NOT_IN_PHCI_LIST,
xport_phys, 0);
di_fini(root);
return (FPCFGA_LIB_ERR);
}
if ((phci_path = di_devfs_path(phci)) == NULL) {
cfga_err(errstring, 0,
ERRARG_XPORT_NOT_IN_PHCI_LIST,
xport_phys, 0);
di_fini(root);
return (FPCFGA_LIB_ERR);
}
(void) di_path_addr(path, (char *)phci_addr);
if ((phci_addr == NULL) || (*phci_addr == '\0')) {
cfga_err(errstring, 0,
ERRARG_XPORT_NOT_IN_PHCI_LIST,
xport_phys, 0);
di_devfs_path_free(phci_path);
di_fini(root);
return (FPCFGA_LIB_ERR);
}
if ((strncmp(phci_path, pathname_ptr,
strlen(pathname_ptr)) == 0) &&
(strstr(phci_addr, dyncomp) != NULL)) {
found = 1;
} else if ((di_path_state(path) ==
DI_PATH_STATE_ONLINE) ||
(di_path_state(path) == DI_PATH_STATE_STANDBY)) {
num_active_paths++;
} else {
non_operational_path_count++;
}
di_devfs_path_free(phci_path);
}
di_fini(root);
if (found == 1) {
if (num_active_paths != 0) {
lunlistp->lun_flag |= FLAG_SKIP_RCMREMOVE;
lunlistp->lun_flag |= FLAG_SKIP_RCMOFFLINE;
}
if (non_operational_path_count == 0) {
lunlistp->lun_flag |= FLAG_SKIP_ONLINEOTHERS;
}
} else {
cfga_err(errstring, 0, ERRARG_XPORT_NOT_IN_PHCI_LIST,
xport_phys, 0);
return (FPCFGA_APID_NOEXIST);
}
}
for (lunlistp = apidt->lunlist; lunlistp != NULL;
lunlistp = lunlistp->next) {
if (strncmp(lunlistp->path, SCSI_VHCI_ROOT,
strlen(SCSI_VHCI_ROOT)) != 0) {
continue;
}
for (temp = lunlistp->next; temp != NULL;
temp = temp->next) {
if (strcmp(lunlistp->path, temp->path) == 0) {
lunlistp->lun_flag |= FLAG_SKIP_RCMREMOVE;
lunlistp->lun_flag |= FLAG_SKIP_RCMOFFLINE;
lunlistp->lun_flag |= FLAG_SKIP_ONLINEOTHERS;
}
}
}
return (FPCFGA_OK);
}
fpcfga_ret_t
dev_change_state(cfga_cmd_t state_change_cmd, apid_t *apidt, la_wwn_t *pwwn,
cfga_flags_t flags, char **errstring, HBA_HANDLE handle,
HBA_PORTATTRIBUTES portAttrs)
{
char dev_path[MAXPATHLEN];
char *update_str, *t_apid;
int optflag = apidt->flags;
int no_config_attempt = 0;
fpcfga_ret_t ret;
apid_t my_apidt;
uchar_t unconf_flag = 0, peri_qual;
HBA_STATUS status;
HBA_PORTATTRIBUTES discPortAttrs;
uint64_t lun = 0;
struct scsi_inquiry inq;
struct scsi_extended_sense sense;
HBA_UINT8 scsiStatus;
uint32_t inquirySize = sizeof (inq),
senseSize = sizeof (sense);
report_lun_resp_t *resp_buf;
int i, l_errno, num_luns = 0;
uchar_t *lun_string;
if ((apidt->dyncomp == NULL) || (*apidt->dyncomp == '\0')) {
return (FPCFGA_OK);
}
if ((update_str = calloc(1, (strlen(apidt->xport_phys) +
strlen(DYN_SEP) + strlen(apidt->dyncomp) + 1))) == NULL) {
cfga_err(errstring, errno, ERR_MEM_ALLOC, 0);
return (FPCFGA_LIB_ERR);
}
strcpy(update_str, apidt->xport_phys);
strcat(update_str, DYN_SEP);
strcat(update_str, apidt->dyncomp);
if (optflag & FLAG_FORCE_UPDATE_REP) {
(void) update_fabric_wwn_list(
((state_change_cmd == CFGA_CMD_CONFIGURE) ?
ADD_ENTRY : REMOVE_ENTRY),
update_str, errstring);
}
memset(&sense, 0, sizeof (sense));
if ((ret = get_report_lun_data(apidt->xport_phys, apidt->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 {
if ((apidt->lunlist == NULL) ||
(state_change_cmd == CFGA_CMD_CONFIGURE)) {
S_FREE(update_str);
status = getPortAttrsByWWN(handle,
*((HBA_WWN *)(pwwn)),
&discPortAttrs);
if (status ==
HBA_STATUS_ERROR_ILLEGAL_WWN) {
return (FPCFGA_APID_NOEXIST);
} else {
cfga_err(errstring, 0,
ERRARG_FC_REP_LUNS,
apidt->dyncomp, 0);
return (FPCFGA_LIB_ERR);
}
} else {
no_config_attempt++;
}
}
}
}
for (i = 0; i < num_luns; i++) {
lun_string = (uchar_t *)&(resp_buf->lun_string[i]);
memcpy(&lun, lun_string, sizeof (lun));
memset(&sense, 0, sizeof (sense));
status = HBA_ScsiInquiryV2(handle, portAttrs.PortWWN,
*(HBA_WWN *)(pwwn), lun, 0, 0, &inq, &inquirySize,
&scsiStatus, &sense, &senseSize);
if (status == HBA_STATUS_OK) {
peri_qual = inq.inq_dtype & FP_PERI_QUAL_MASK;
if (peri_qual == DPQ_POSSIBLE) {
break;
}
}
}
if (ret == FPCFGA_OK)
S_FREE(resp_buf);
if (num_luns == 0) {
lun = 0;
status = HBA_ScsiInquiryV2(handle, portAttrs.PortWWN,
*(HBA_WWN *)(pwwn), lun, 0, 0, &inq, &inquirySize,
&scsiStatus, &sense, &senseSize);
}
if (status != HBA_STATUS_OK) {
if (status == HBA_STATUS_ERROR_NOT_A_TARGET) {
inq.inq_dtype = DTYPE_UNKNOWN;
} else if (status == HBA_STATUS_ERROR_ILLEGAL_WWN) {
free(update_str);
return (FPCFGA_APID_NOEXIST);
} else {
if ((apidt->lunlist == NULL) ||
(state_change_cmd == CFGA_CMD_CONFIGURE)) {
cfga_err(errstring, 0,
ERRARG_FC_INQUIRY,
apidt->dyncomp, 0);
free(update_str);
return (FPCFGA_LIB_ERR);
} else {
no_config_attempt++;
}
}
}
switch (state_change_cmd) {
case CFGA_CMD_CONFIGURE:
if (portAttrs.PortType != HBA_PORTTYPE_NLPORT &&
portAttrs.PortType != HBA_PORTTYPE_NPORT) {
free(update_str);
return (FPCFGA_OK);
}
if (((inq.inq_dtype & DTYPE_MASK) == DTYPE_UNKNOWN) &&
((flags & CFGA_FLAG_FORCE) == 0)) {
free(update_str);
return (FPCFGA_OK);
}
errno = 0;
if ((ret = do_devctl_dev_create(apidt, dev_path, MAXPATHLEN,
inq.inq_dtype, errstring)) != FPCFGA_OK) {
status = getPortAttrsByWWN(handle, *((HBA_WWN *)(pwwn)),
&discPortAttrs);
S_FREE(update_str);
if (status == HBA_STATUS_ERROR_ILLEGAL_WWN) {
return (FPCFGA_APID_NOEXIST);
} else {
return (FPCFGA_LIB_ERR);
}
}
if (((optflag & (FLAG_FORCE_UPDATE_REP|FLAG_NO_UPDATE_REP)) == 0) &&
update_fabric_wwn_list(ADD_ENTRY, update_str, errstring)) {
cfga_err(errstring, 0, ERR_CONF_OK_UPD_REP, 0);
}
S_FREE(update_str);
if ((apidt->flags & FLAG_DISABLE_RCM) == 0) {
if ((t_apid = calloc(1, strlen(apidt->xport_phys) +
strlen(DYN_SEP) +
strlen(apidt->dyncomp) + 1)) == NULL) {
cfga_err(errstring, errno, ERR_MEM_ALLOC, 0);
return (FPCFGA_LIB_ERR);
}
sprintf(t_apid, "%s%s%s", apidt->xport_phys, DYN_SEP,
apidt->dyncomp);
if ((ret = apidt_create(t_apid, &my_apidt,
errstring)) != FPCFGA_OK) {
free(t_apid);
return (ret);
}
my_apidt.flags = apidt->flags;
if ((ret = dev_rcm_online(&my_apidt, -1, flags,
NULL)) != FPCFGA_OK) {
cfga_err(errstring, 0, ERRARG_RCM_ONLINE,
apidt->lunlist->path, 0);
apidt_free(&my_apidt);
free(t_apid);
return (ret);
}
S_FREE(t_apid);
apidt_free(&my_apidt);
}
return (FPCFGA_OK);
case CFGA_CMD_UNCONFIGURE:
if (portAttrs.PortType != HBA_PORTTYPE_NLPORT &&
portAttrs.PortType != HBA_PORTTYPE_NPORT) {
free(update_str);
return (FPCFGA_OPNOTSUPP);
}
status = getPortAttrsByWWN(handle, *((HBA_WWN *)(pwwn)),
&discPortAttrs);
if (apidt->lunlist == NULL) {
if ((optflag &
(FLAG_FORCE_UPDATE_REP|FLAG_NO_UPDATE_REP)) == 0) {
if (update_fabric_wwn_list(REMOVE_ENTRY,
update_str, errstring)) {
free(update_str);
cfga_err(errstring, 0,
ERR_UNCONF_OK_UPD_REP, 0);
return
(FPCFGA_UNCONF_OK_UPD_REP_FAILED);
}
}
S_FREE(update_str);
if (status == HBA_STATUS_ERROR_ILLEGAL_WWN) {
return (FPCFGA_APID_NOEXIST);
}
return (FPCFGA_OK);
}
if (is_xport_phys_in_pathlist(apidt, errstring) !=
FPCFGA_OK) {
free(update_str);
return (FPCFGA_XPORT_NOT_IN_PHCI_LIST);
}
if ((ret = dev_rcm_offline(apidt, flags, errstring)) !=
FPCFGA_OK) {
free(update_str);
return (ret);
}
if ((ret = dev_unconf(apidt, errstring, &unconf_flag)) !=
FPCFGA_OK) {
if (!no_config_attempt) {
(void) do_devctl_dev_create(apidt, dev_path, MAXPATHLEN,
inq.inq_dtype, NULL);
(void) dev_rcm_online(apidt, -1, flags, NULL);
}
free(update_str);
return (ret);
}
if ((ret = dev_rcm_remove(apidt, flags, errstring)) !=
FPCFGA_OK) {
(void) do_devctl_dev_create(apidt, dev_path, MAXPATHLEN,
inq.inq_dtype, NULL);
(void) dev_rcm_online(apidt, -1, flags, NULL);
free(update_str);
return (ret);
}
dev_rcm_online_nonoperationalpath(apidt, flags, NULL);
if ((optflag &
(FLAG_FORCE_UPDATE_REP|FLAG_NO_UPDATE_REP)) == 0) {
if (((optflag & FLAG_REMOVE_UNUSABLE_FCP_DEV) !=
FLAG_REMOVE_UNUSABLE_FCP_DEV) ||
(((optflag & FLAG_REMOVE_UNUSABLE_FCP_DEV) ==
FLAG_REMOVE_UNUSABLE_FCP_DEV) &&
(unconf_flag == ALL_APID_LUNS_UNUSABLE))) {
if (update_fabric_wwn_list(REMOVE_ENTRY,
update_str, errstring)) {
free(update_str);
cfga_err(errstring, errno,
ERR_UNCONF_OK_UPD_REP, 0);
return (FPCFGA_UNCONF_OK_UPD_REP_FAILED);
}
}
}
free(update_str);
return (FPCFGA_OK);
default:
free(update_str);
return (FPCFGA_OPNOTSUPP);
}
}
static void
copy_pwwn_data_to_str(char *to_ptr, const uchar_t *from_ptr)
{
if ((to_ptr == NULL) || (from_ptr == NULL))
return;
(void) sprintf(to_ptr, "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
from_ptr[0], from_ptr[1], from_ptr[2], from_ptr[3],
from_ptr[4], from_ptr[5], from_ptr[6], from_ptr[7]);
}
static fpcfga_ret_t
unconf_vhci_nodes(di_path_t pnode, di_node_t fp_node, char *xport_phys,
char *dyncomp, int unusable_flag,
int *num_devs, int *failure_count, char **errstring,
cfga_flags_t flags)
{
int iret1, iret2, *lunnump;
char *ptr;
char *node_path, *vhci_path, *update_str;
char port_wwn[WWN_SIZE*2+1], pathname[MAXPATHLEN];
uchar_t *port_wwn_data = NULL;
di_node_t client_node;
while (pnode != DI_PATH_NIL) {
(*num_devs)++;
if ((node_path = di_devfs_path(fp_node)) == NULL) {
cfga_err(errstring, 0, ERRARG_DEVINFO,
xport_phys, 0);
(*failure_count)++;
pnode = di_path_next_client(fp_node, pnode);
continue;
}
iret1 = di_path_prop_lookup_bytes(pnode, PORT_WWN_PROP,
&port_wwn_data);
iret2 = di_path_prop_lookup_ints(pnode, LUN_PROP, &lunnump);
if ((iret1 == -1) || (iret2 == -1)) {
cfga_err(errstring, 0, ERRARG_DI_GET_PROP,
node_path, 0);
di_devfs_path_free(node_path);
node_path = NULL;
(*failure_count)++;
pnode = di_path_next_client(fp_node, pnode);
continue;
}
copy_pwwn_data_to_str(port_wwn, port_wwn_data);
if ((client_node = di_path_client_node(pnode)) ==
DI_NODE_NIL) {
(*failure_count)++;
di_devfs_path_free(node_path);
node_path = NULL;
pnode = di_path_next_client(fp_node, pnode);
continue;
}
if ((vhci_path = di_devfs_path(client_node)) == NULL) {
(*failure_count)++;
di_devfs_path_free(node_path);
node_path = NULL;
pnode = di_path_next_client(fp_node, pnode);
continue;
}
if ((ptr = strrchr(vhci_path, '@')) != NULL) {
*ptr = '\0';
}
if ((ptr = strrchr(vhci_path, '/')) == NULL) {
(*failure_count)++;
di_devfs_path_free(node_path);
node_path = NULL;
pnode = di_path_next_client(fp_node, pnode);
continue;
}
sprintf(pathname, "%s%s/%s@w%s,%x", DEVICES_DIR, node_path,
++ptr, port_wwn, *lunnump);
di_devfs_path_free(node_path);
di_devfs_path_free(vhci_path);
node_path = vhci_path = NULL;
if ((unusable_flag & FLAG_REMOVE_UNUSABLE_FCP_DEV) ==
FLAG_REMOVE_UNUSABLE_FCP_DEV) {
if (pnode->path_state == DI_PATH_STATE_OFFLINE) {
if (fp_rcm_offline(pathname, errstring,
flags) != 0) {
(*failure_count)++;
pnode = di_path_next_client(fp_node,
pnode);
continue;
} else if (lun_unconf(pathname, *lunnump,
xport_phys,dyncomp, errstring)
!= FPCFGA_OK) {
(void) fp_rcm_online(pathname,
NULL, flags);
(*failure_count)++;
pnode = di_path_next_client(fp_node,
pnode);
continue;
} else if (fp_rcm_remove(pathname, errstring,
flags) != 0) {
(void) fp_rcm_online(pathname,
NULL, flags);
(*failure_count)++;
pnode = di_path_next_client(fp_node,
pnode);
continue;
}
} else {
pnode = di_path_next(fp_node, pnode);
continue;
}
} else {
if (fp_rcm_offline(pathname, errstring, flags) != 0) {
(*failure_count)++;
pnode = di_path_next_client(fp_node, pnode);
continue;
} else if (lun_unconf(pathname, *lunnump, xport_phys,
dyncomp, errstring) != FPCFGA_OK) {
(void) fp_rcm_online(pathname, NULL, flags);
(*failure_count)++;
pnode = di_path_next_client(fp_node, pnode);
continue;
} else if (fp_rcm_remove(pathname, errstring,
flags) != 0) {
(void) fp_rcm_online(pathname, NULL, flags);
(*failure_count)++;
pnode = di_path_next_client(fp_node, pnode);
continue;
}
}
if ((update_str = calloc(1, strlen(xport_phys) +
strlen(DYN_SEP) +
strlen(port_wwn) + 1)) == NULL) {
cfga_err(errstring, errno, ERR_UNCONF_OK_UPD_REP, 0);
(*failure_count)++;
pnode = di_path_next_client(fp_node, pnode);
continue;
}
sprintf(update_str, "%s%s%s", xport_phys, DYN_SEP, port_wwn);
if (update_fabric_wwn_list(REMOVE_ENTRY, update_str,
errstring)) {
S_FREE(update_str);
cfga_err(errstring, errno,
ERR_UNCONF_OK_UPD_REP, 0);
(*failure_count)++;
pnode = di_path_next_client(fp_node, pnode);
continue;
}
S_FREE(update_str);
pnode = di_path_next_client(fp_node, pnode);
}
return (FPCFGA_OK);
}
static fpcfga_ret_t
unconf_non_vhci_nodes(di_node_t dnode, char *xport_phys, char *dyncomp,
int unusable_flag, int *num_devs, int *failure_count,
char **errstring, cfga_flags_t flags)
{
int ret1, ret2, *lunnump;
char pathname[MAXPATHLEN];
char *node_path, *update_str;
char port_wwn[WWN_SIZE*2+1];
uchar_t *port_wwn_data = NULL;
while (dnode != DI_NODE_NIL) {
(*num_devs)++;
if ((node_path = di_devfs_path(dnode)) == NULL) {
cfga_err(errstring, 0, ERRARG_DEVINFO, xport_phys, 0);
(*failure_count)++;
dnode = di_sibling_node(dnode);
continue;
}
ret1 = di_prop_lookup_ints(DDI_DEV_T_ANY, dnode,
LUN_PROP, &lunnump);
ret2 = di_prop_lookup_bytes(DDI_DEV_T_ANY, dnode,
PORT_WWN_PROP, &port_wwn_data);
if ((ret1 == -1) || (ret2 == -1)) {
cfga_err(errstring, 0,
ERRARG_DI_GET_PROP, node_path, 0);
di_devfs_path_free(node_path);
node_path = NULL;
(*failure_count)++;
dnode = di_sibling_node(dnode);
continue;
}
sprintf(pathname, "%s%s", DEVICES_DIR, node_path);
di_devfs_path_free(node_path);
node_path = NULL;
copy_pwwn_data_to_str(port_wwn, port_wwn_data);
if (strstr(pathname, "@w") == NULL) {
sprintf(&pathname[strlen(pathname)], "@w%s,%x",
port_wwn, *lunnump);
}
if ((unusable_flag & FLAG_REMOVE_UNUSABLE_FCP_DEV) ==
FLAG_REMOVE_UNUSABLE_FCP_DEV) {
if ((dnode->node_state == DI_DEVICE_OFFLINE) ||
(dnode->node_state == DI_DEVICE_DOWN)) {
if (fp_rcm_offline(pathname, errstring,
flags) != 0) {
(*failure_count)++;
dnode = di_sibling_node(dnode);
continue;
} else if (lun_unconf(pathname, *lunnump,
xport_phys,dyncomp, errstring)
!= FPCFGA_OK) {
(void) fp_rcm_online(pathname,
NULL, flags);
(*failure_count)++;
dnode = di_sibling_node(dnode);
continue;
} else if (fp_rcm_remove(pathname, errstring,
flags) != 0) {
(void) fp_rcm_online(pathname,
NULL, flags);
(*failure_count)++;
dnode = di_sibling_node(dnode);
continue;
}
} else {
dnode = di_sibling_node(dnode);
continue;
}
} else {
if (fp_rcm_offline(pathname, errstring, flags) != 0) {
(*failure_count)++;
dnode = di_sibling_node(dnode);
continue;
} else if (lun_unconf(pathname, *lunnump, xport_phys,
dyncomp, errstring) != FPCFGA_OK) {
(void) fp_rcm_online(pathname, NULL, flags);
(*failure_count)++;
dnode = di_sibling_node(dnode);
continue;
} else if (fp_rcm_remove(pathname, errstring,
flags) != 0) {
(void) fp_rcm_online(pathname, NULL, flags);
(*failure_count)++;
dnode = di_sibling_node(dnode);
continue;
}
}
if ((update_str = calloc(1, strlen(xport_phys) +
strlen(DYN_SEP) +
strlen(port_wwn) + 1)) == NULL) {
cfga_err(errstring, errno, ERR_UNCONF_OK_UPD_REP, 0);
(*failure_count)++;
dnode = di_sibling_node(dnode);
continue;
}
sprintf(update_str, "%s%s%s", xport_phys, DYN_SEP, port_wwn);
if (update_fabric_wwn_list(REMOVE_ENTRY, update_str,
errstring)) {
S_FREE(update_str);
cfga_err(errstring, errno, ERR_UNCONF_OK_UPD_REP, 0);
(*failure_count)++;
dnode = di_sibling_node(dnode);
continue;
}
S_FREE(update_str);
dnode = di_sibling_node(dnode);
}
return (FPCFGA_OK);
}
static fpcfga_ret_t
unconf_any_devinfo_nodes(apid_t *apidt, cfga_flags_t flags, char **errstring,
int *num_devs, int *failure_count)
{
char *node_path = NULL;
char pathname[MAXPATHLEN], *ptr;
di_node_t root_node, direct_node, fp_node;
di_path_t path_node = DI_PATH_NIL;
(void) strlcpy(pathname, apidt->xport_phys, MAXPATHLEN);
if ((ptr = strstr(pathname, MINOR_SEP)) != NULL)
*ptr = '\0';
if (strncmp(pathname, DEVICES_DIR, strlen(DEVICES_DIR))) {
cfga_err(errstring, 0, ERRARG_INVALID_PATH, pathname, 0);
return (FPCFGA_INVALID_PATH);
}
if ((root_node = di_init("/", DINFOCPYALL | DINFOPATH)) ==
DI_NODE_NIL) {
cfga_err(errstring, errno, ERRARG_DEVINFO,
apidt->xport_phys, 0);
return (FPCFGA_LIB_ERR);
}
if ((fp_node = di_drv_first_node("fp", root_node)) == DI_NODE_NIL) {
cfga_err(errstring, errno, ERRARG_DEVINFO,
apidt->xport_phys, 0);
di_fini(root_node);
return (FPCFGA_LIB_ERR);
}
ptr = pathname + strlen(DEVICES_DIR);
while (fp_node != DI_NODE_NIL) {
node_path = di_devfs_path(fp_node);
if (strcmp(node_path, ptr) == 0) {
di_devfs_path_free(node_path);
node_path = NULL;
break;
}
fp_node = di_drv_next_node(fp_node);
di_devfs_path_free(node_path);
}
if (fp_node == DI_NODE_NIL) {
cfga_err(errstring, 0, ERRARG_NOT_IN_DEVINFO,
apidt->xport_phys, 0);
di_fini(root_node);
return (FPCFGA_LIB_ERR);
}
direct_node = di_child_node(fp_node);
path_node = di_path_next_client(fp_node, path_node);
if ((direct_node == DI_NODE_NIL) && (path_node == DI_PATH_NIL)) {
di_fini(root_node);
return (FPCFGA_OK);
}
unconf_non_vhci_nodes(direct_node, apidt->xport_phys, apidt->dyncomp,
apidt->flags, num_devs, failure_count, errstring, flags);
unconf_vhci_nodes(path_node, fp_node, apidt->xport_phys, apidt->dyncomp,
apidt->flags, num_devs, failure_count, errstring, flags);
di_fini(root_node);
return (FPCFGA_OK);
}
static fpcfga_ret_t
handle_devs(cfga_cmd_t cmd, apid_t *apidt, cfga_flags_t flags,
char **errstring, HBA_HANDLE handle, int portIndex,
HBA_PORTATTRIBUTES portAttrs)
{
int num_devs = 0, dev_cs_failed = 0;
char port_wwn[WWN_S_LEN];
la_wwn_t pwwn;
apid_t my_apidt = {NULL};
char *my_apid;
HBA_PORTATTRIBUTES discPortAttrs;
int discIndex;
fpcfga_ret_t rval = FPCFGA_OK;
if ((my_apid = calloc(
1, strlen(apidt->xport_phys) + strlen(DYN_SEP) +
(2 * FC_WWN_SIZE) + 1)) == NULL) {
cfga_err(errstring, errno, ERR_MEM_ALLOC, 0);
return (FPCFGA_LIB_ERR);
}
num_devs = portAttrs.NumberofDiscoveredPorts;
for (discIndex = 0; discIndex < portAttrs.NumberofDiscoveredPorts;
discIndex++) {
if (getDiscPortAttrs(handle, portIndex,
discIndex, &discPortAttrs)) {
dev_cs_failed++;
continue;
}
(void) sprintf(port_wwn, "%016llx",
wwnConversion(discPortAttrs.PortWWN.wwn));
strcpy(my_apid, apidt->xport_phys);
strcat(my_apid, DYN_SEP);
strcat(my_apid, port_wwn);
if (apidt_create(my_apid, &my_apidt, errstring) != FPCFGA_OK) {
dev_cs_failed++;
continue;
}
my_apidt.flags = apidt->flags;
memcpy(&pwwn, &(discPortAttrs.PortWWN), sizeof (la_wwn_t));
if (dev_change_state(cmd, &my_apidt, &pwwn,
flags, errstring, handle, portAttrs) != FPCFGA_OK) {
dev_cs_failed++;
}
apidt_free(&my_apidt);
}
S_FREE(my_apid);
if (cmd == CFGA_CMD_UNCONFIGURE) {
rval = unconf_any_devinfo_nodes(apidt, flags, errstring,
&num_devs, &dev_cs_failed);
}
if (rval == FPCFGA_OK) {
if (dev_cs_failed == 0)
return (FPCFGA_OK);
if (dev_cs_failed == num_devs) {
cfga_err(errstring, 0,
((cmd == CFGA_CMD_CONFIGURE) ?
ERR_FCA_CONFIGURE : ERR_FCA_UNCONFIGURE), 0);
return (FPCFGA_LIB_ERR);
} else {
cfga_err(errstring, 0, ERR_PARTIAL_SUCCESS, 0);
return (FPCFGA_LIB_ERR);
}
} else {
if (dev_cs_failed == num_devs) {
cfga_err(errstring, 0,
((cmd == CFGA_CMD_CONFIGURE) ?
ERR_FCA_CONFIGURE : ERR_FCA_UNCONFIGURE), 0);
return (FPCFGA_LIB_ERR);
} else {
cfga_err(errstring, 0, ERR_PARTIAL_SUCCESS, 0);
return (FPCFGA_LIB_ERR);
}
}
}
fpcfga_ret_t
fca_change_state(cfga_cmd_t state_change_cmd, apid_t *apidt,
cfga_flags_t flags, char **errstring)
{
fpcfga_ret_t ret;
HBA_HANDLE handle;
HBA_PORTATTRIBUTES portAttrs;
int portIndex;
if ((ret = findMatchingAdapterPort(apidt->xport_phys, &handle,
&portIndex, &portAttrs, errstring)) != FPCFGA_OK) {
return (ret);
}
switch (state_change_cmd) {
case CFGA_CMD_CONFIGURE:
if (portAttrs.PortType != HBA_PORTTYPE_NLPORT &&
portAttrs.PortType != HBA_PORTTYPE_NPORT) {
HBA_CloseAdapter(handle);
HBA_FreeLibrary();
return (FPCFGA_OK);
}
break;
case CFGA_CMD_UNCONFIGURE:
if (portAttrs.PortType != HBA_PORTTYPE_NLPORT &&
portAttrs.PortType != HBA_PORTTYPE_NPORT) {
HBA_CloseAdapter(handle);
HBA_FreeLibrary();
return (FPCFGA_OPNOTSUPP);
}
break;
default:
HBA_CloseAdapter(handle);
HBA_FreeLibrary();
return (FPCFGA_LIB_ERR);
}
ret = (handle_devs(state_change_cmd, apidt, flags, errstring,
handle, portIndex, portAttrs));
HBA_CloseAdapter(handle);
HBA_FreeLibrary();
return (ret);
}