#include <stdlib.h>
#include <stdio.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mkdev.h>
#include <sys/param.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/scsi/scsi.h>
#include <dirent.h>
#include <sys/vtoc.h>
#include <nl_types.h>
#include <strings.h>
#include <errno.h>
#include <sys/ddi.h>
#include <fnmatch.h>
#include <l_common.h>
#include <stgcom.h>
#include <l_error.h>
#include <g_state.h>
#include <g_scsi.h>
#include <sys/fibre-channel/ulp/fcp_util.h>
#include <sys/fibre-channel/impl/fc_error.h>
#include <sys/fibre-channel/impl/fcph.h>
#include <sys/socalio.h>
#include <libdevinfo.h>
#include <ctype.h>
#include <devid.h>
static int g_issue_fcp_ioctl(int, struct fcp_ioctl *, int);
static int g_set_port_state(char *, int);
static int g_dev_log_in_out(char *, la_wwn_t, uint16_t);
static int g_get_dev_port_state(char *, la_wwn_t, uint32_t *);
static void g_free_rls(AL_rls *);
static int g_scsi_inquiry_cmd80(int, uchar_t *, int);
static int get_fca_inq_dtype(char *, la_wwn_t, uchar_t *);
static int g_find_supported_inq_page(int, int);
static int wwn_list_name_compare(const void *, const void *);
static int devid_get_all(ddi_devid_t, di_node_t, char *,
struct mplist_struct **);
static int get_multipath(char *, struct dlist **,
struct wwn_list_struct *);
static int get_multipath_disk(char *, struct dlist **,
struct wwn_list_struct *);
static void mplist_free(struct mplist_struct *);
static int get_wwn_data(di_node_t, uchar_t **, uchar_t **);
static int get_dev_path(struct wwn_list_struct **, char *, char *);
static int insert_missing_pwwn(char *, struct wwn_list_struct **);
static int get_scsi_vhci_port_wwn(char *, uchar_t *);
static int search_wwn_entry(struct wwn_list_found_struct *, uchar_t *,
uchar_t *);
static int add_wwn_entry(struct wwn_list_found_struct **, uchar_t *,
uchar_t *);
static int string_to_wwn(uchar_t *, uchar_t *);
static int get_wwns(char *, uchar_t *, uchar_t *, int *,
struct wwn_list_found_struct **);
#define S_FREE(x) (((x) != NULL) ? (free(x), (x) = NULL) : (void *)0)
typedef struct impl_map_dev_prop {
char prop_name[MAXNAMELEN];
int prop_type;
int prop_size;
void *prop_data;
int prop_error;
struct impl_map_dev_prop *next;
} impl_map_dev_prop_t;
typedef struct impl_map_dev {
int flag;
uint_t topo;
impl_map_dev_prop_t *prop_list;
struct impl_map_dev *parent;
struct impl_map_dev *child;
struct impl_map_dev *next;
} impl_map_dev_t;
#define VERBPRINT if (verbose) (void) printf
#define DIR_MATCH_ST "*[0-9+]n"
#define DIR_MATCH_SSD "*s2"
#define PROP_NOEXIST 0
#define PROP_EXIST 1
static int create_map(char *, gfc_map_t *, int, int);
static char ctoi(char);
static int lilp_map_cmp(const void*, const void*);
static int devices_get_all(di_node_t, char *, char *,
struct wwn_list_struct **);
static char *my_devfs_path(di_node_t);
static void my_devfs_path_free(char *path);
static void copy_wwn_data_to_str(char *, const uchar_t *);
static void init_drv(char *, char *, char *);
static int update_map_dev_fc_prop(impl_map_dev_prop_t **, uint32_t,
uchar_t *, uchar_t *, int, int);
static int update_map_dev_FCP_prop(impl_map_dev_prop_t **, uchar_t *, int, int);
static int handle_map_dev_FCP_prop(minor_t, la_wwn_t, impl_map_dev_prop_t **);
static void free_prop_list(impl_map_dev_prop_t **);
static void free_child_list(impl_map_dev_t **);
static u_longlong_t wwnConversion(uchar_t *wwn);
uchar_t g_switch_to_alpa[] = {
0xef, 0xe8, 0xe4, 0xe2, 0xe1, 0xe0, 0xdc, 0xda, 0xd9, 0xd6,
0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xce, 0xcd, 0xcc, 0xcb, 0xca,
0xc9, 0xc7, 0xc6, 0xc5, 0xc3, 0xbc, 0xba, 0xb9, 0xb6, 0xb5,
0xb4, 0xb3, 0xb2, 0xb1, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9,
0xa7, 0xa6, 0xa5, 0xa3, 0x9f, 0x9e, 0x9d, 0x9b, 0x98, 0x97,
0x90, 0x8f, 0x88, 0x84, 0x82, 0x81, 0x80, 0x7c, 0x7a, 0x79,
0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x6e, 0x6d, 0x6c, 0x6b,
0x6a, 0x69, 0x67, 0x66, 0x65, 0x63, 0x5c, 0x5a, 0x59, 0x56,
0x55, 0x54, 0x53, 0x52, 0x51, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a,
0x49, 0x47, 0x46, 0x45, 0x43, 0x3c, 0x3a, 0x39, 0x36, 0x35,
0x34, 0x33, 0x32, 0x31, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29,
0x27, 0x26, 0x25, 0x23, 0x1f, 0x1e, 0x1d, 0x1b, 0x18, 0x17,
0x10, 0x0f, 0x08, 0x04, 0x02, 0x01
};
uchar_t g_sf_alpa_to_switch[] = {
0x00, 0x7d, 0x7c, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x7a, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x78, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x77, 0x76, 0x00, 0x00, 0x75, 0x00, 0x74,
0x73, 0x72, 0x00, 0x00, 0x00, 0x71, 0x00, 0x70, 0x6f, 0x6e,
0x00, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 0x00, 0x00, 0x67,
0x66, 0x65, 0x64, 0x63, 0x62, 0x00, 0x00, 0x61, 0x60, 0x00,
0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d,
0x5c, 0x5b, 0x00, 0x5a, 0x59, 0x58, 0x57, 0x56, 0x55, 0x00,
0x00, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4f, 0x00, 0x00, 0x4e,
0x4d, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b,
0x00, 0x4a, 0x49, 0x48, 0x00, 0x47, 0x46, 0x45, 0x44, 0x43,
0x42, 0x00, 0x00, 0x41, 0x40, 0x3f, 0x3e, 0x3d, 0x3c, 0x00,
0x00, 0x3b, 0x3a, 0x00, 0x39, 0x00, 0x00, 0x00, 0x38, 0x37,
0x36, 0x00, 0x35, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x33, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x31, 0x30, 0x00, 0x00, 0x2f, 0x00, 0x2e, 0x2d, 0x2c,
0x00, 0x00, 0x00, 0x2b, 0x00, 0x2a, 0x29, 0x28, 0x00, 0x27,
0x26, 0x25, 0x24, 0x23, 0x22, 0x00, 0x00, 0x21, 0x20, 0x1f,
0x1e, 0x1d, 0x1c, 0x00, 0x00, 0x1b, 0x1a, 0x00, 0x19, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x17, 0x16, 0x15,
0x00, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x00, 0x00, 0x0e,
0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x00, 0x00, 0x08, 0x07, 0x00,
0x06, 0x00, 0x00, 0x00, 0x05, 0x04, 0x03, 0x00, 0x02, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
int
g_device_in_map(gfc_map_t *map, int tid)
{
int i, j;
gfc_port_dev_info_t *dev_ptr;
dev_ptr = map->dev_addr;
if ((map->hba_addr.port_topology == FC_TOP_PUBLIC_LOOP) ||
(map->hba_addr.port_topology == FC_TOP_FABRIC)) {
for (i = 0; i < map->count; i++, dev_ptr++) {
if (dev_ptr->
gfc_port_dev.pub_port.dev_did.port_id == tid) {
for (j = 0; j < FC_WWN_SIZE; j++)
if (dev_ptr->gfc_port_dev.pub_port.
dev_pwwn.raw_wwn[j] != 0)
return (1);
}
}
} else {
for (i = 0; i < map->count; i++, dev_ptr++) {
if (dev_ptr->gfc_port_dev.priv_port.sf_al_pa ==
(int)g_switch_to_alpa[tid]) {
for (j = 0; j < WWN_SIZE; j++)
if (dev_ptr->gfc_port_dev.priv_port.
sf_port_wwn[j] != 0)
return (1);
}
}
}
return (0);
}
static int
insert_missing_pwwn(char *phys_path, struct wwn_list_struct **wwn_list_ptr)
{
mp_pathlist_t pathlist;
int i, pathcnt, match;
struct wwn_list_struct *new_wwn, *wwn_list_s, *wwn_list_found;
char pwwn1[WWN_S_LEN];
if (g_get_pathlist(phys_path, &pathlist)) {
S_FREE(pathlist.path_info);
return (L_INVALID_PATH);
}
pathcnt = pathlist.path_count;
for (i = 0; i < pathcnt; i++) {
if (pathlist.path_info[i].path_state ==
MDI_PATHINFO_STATE_ONLINE ||
pathlist.path_info[i].path_state ==
MDI_PATHINFO_STATE_STANDBY) {
(void) strncpy(pwwn1, pathlist.path_info[i].path_addr,
WWN_S_LEN - 1);
pwwn1[WWN_S_LEN - 1] = '\0';
match = 0;
for (wwn_list_s = *wwn_list_ptr; wwn_list_s != NULL;
wwn_list_s = wwn_list_s->wwn_next) {
if (strncmp(phys_path,
wwn_list_s->physical_path,
strlen(phys_path)) == 0) {
wwn_list_found = wwn_list_s;
if (strncmp(pwwn1,
wwn_list_s->port_wwn_s,
WWN_S_LEN) == 0) {
match++;
break;
}
}
}
if (match) {
continue;
} else {
if ((new_wwn = (struct wwn_list_struct *)
calloc(1,
sizeof (struct wwn_list_struct)))
== NULL) {
S_FREE(pathlist.path_info);
return (L_MALLOC_FAILED);
}
if ((new_wwn->physical_path = (char *)
calloc(1,
strlen(wwn_list_found->physical_path)
+ 1)) == NULL) {
S_FREE(pathlist.path_info);
return (L_MALLOC_FAILED);
}
if ((new_wwn->logical_path = (char *)
calloc(1,
strlen(wwn_list_found->logical_path)
+ 1)) == NULL) {
S_FREE(pathlist.path_info);
return (L_MALLOC_FAILED);
}
new_wwn->wwn_next = *wwn_list_ptr;
(*wwn_list_ptr)->wwn_prev = new_wwn;
*wwn_list_ptr = new_wwn;
memcpy(new_wwn->physical_path,
wwn_list_found->physical_path,
strlen(wwn_list_found->physical_path));
memcpy(new_wwn->logical_path,
wwn_list_found->logical_path,
strlen(wwn_list_found->logical_path));
memcpy(new_wwn->node_wwn_s,
wwn_list_found->node_wwn_s, WWN_S_LEN);
memcpy(new_wwn->w_node_wwn,
wwn_list_found->w_node_wwn, WWN_SIZE);
new_wwn->device_type =
wwn_list_found->device_type;
memcpy(new_wwn->port_wwn_s, pwwn1, WWN_S_LEN);
}
}
}
S_FREE(pathlist.path_info);
return (0);
}
static int
get_scsi_vhci_port_wwn(char *phys_path, uchar_t *port_wwn)
{
mp_pathlist_t pathlist;
int i, pathcnt, found;
char pwwn1[WWN_S_LEN];
if (g_get_pathlist(phys_path, &pathlist)) {
return (L_INVALID_PATH);
}
found = 0;
pathcnt = pathlist.path_count;
for (i = 0; found == 0 && i < pathcnt; i++) {
if (pathlist.path_info[i].path_state ==
MDI_PATHINFO_STATE_ONLINE) {
(void) strncpy(pwwn1, pathlist.path_info[i].path_addr,
WWN_S_LEN - 1);
pwwn1[WWN_S_LEN - 1] = '\0';
found++;
}
}
for (i = 0; found == 0 && i < pathcnt; i++) {
if (pathlist.path_info[i].path_state ==
MDI_PATHINFO_STATE_STANDBY) {
(void) strncpy(pwwn1, pathlist.path_info[i].path_addr,
WWN_S_LEN - 1);
pwwn1[WWN_S_LEN - 1] = '\0';
found++;
}
}
S_FREE(pathlist.path_info);
if (found) {
return (string_to_wwn((uchar_t *)pwwn1, port_wwn));
} else {
return (-1);
}
}
static int
search_wwn_entry(struct wwn_list_found_struct *wwn_list_found, uchar_t *pwwn,
uchar_t *nwwn)
{
struct wwn_list_found_struct *wwn_list_s;
for (wwn_list_s = wwn_list_found; wwn_list_s != NULL;
wwn_list_s = wwn_list_s->wwn_next) {
if (memcmp(pwwn, wwn_list_s->port_wwn, WWN_SIZE) == 0) {
memcpy(nwwn, wwn_list_s->node_wwn, WWN_SIZE);
return (0);
}
}
return (-1);
}
static int
add_wwn_entry(struct wwn_list_found_struct **wwn_list_found, uchar_t *pwwn,
uchar_t *nwwn)
{
struct wwn_list_found_struct *new_wwn, *temp_wwn_list_found = NULL;
if ((new_wwn = (struct wwn_list_found_struct *)
calloc(1, sizeof (struct wwn_list_found_struct))) == NULL) {
return (L_MALLOC_FAILED);
}
memcpy(new_wwn->node_wwn, nwwn, WWN_SIZE);
memcpy(new_wwn->port_wwn, pwwn, WWN_SIZE);
if (*wwn_list_found != NULL) {
temp_wwn_list_found = (*wwn_list_found)->wwn_next;
(*wwn_list_found)->wwn_next = new_wwn;
} else {
*wwn_list_found = new_wwn;
}
new_wwn->wwn_next = temp_wwn_list_found;
return (0);
}
int
g_get_wwn_list(struct wwn_list_struct **wwn_list_ptr, int verbose)
{
struct wwn_list_struct *wwn_list_p = NULL, *wwn_list_tmp_p = NULL;
struct wwn_list_found_struct *wwn_list_found = NULL;
int err;
int al_pa;
uchar_t node_wwn[WWN_SIZE], port_wwn[WWN_SIZE];
hrtime_t start_time, end_time;
char *env = NULL;
if (wwn_list_ptr == NULL) {
return (L_NULL_WWN_LIST);
}
if ((env = getenv("_LUX_T_DEBUG")) != NULL) {
start_time = gethrtime();
}
if ((err = g_devices_get_all(wwn_list_ptr)) != 0) {
return (err);
}
wwn_list_p = *wwn_list_ptr;
while (wwn_list_p != NULL) {
if (strstr(wwn_list_p->physical_path, SCSI_VHCI) != NULL) {
if ((get_scsi_vhci_port_wwn(wwn_list_p->physical_path,
port_wwn)) == 0) {
if ((search_wwn_entry(wwn_list_found, port_wwn,
node_wwn)) != 0) {
if ((err =
get_wwns(wwn_list_p->physical_path,
port_wwn,
node_wwn, &al_pa,
&wwn_list_found)) != 0) {
g_free_wwn_list_found(
&wwn_list_found);
return (err);
}
}
} else {
if ((err = g_get_wwn(wwn_list_p->physical_path,
port_wwn, node_wwn, &al_pa, 0)) != 0) {
if ((wwn_list_p->wwn_prev == NULL) &&
(wwn_list_p->wwn_next == NULL)) {
*wwn_list_ptr = NULL;
free(wwn_list_p);
g_free_wwn_list_found(
&wwn_list_found);
return (L_NO_DEVICES_FOUND);
} else if (
wwn_list_p->wwn_prev == NULL) {
*wwn_list_ptr =
wwn_list_p->wwn_next;
free(wwn_list_p);
wwn_list_p = *wwn_list_ptr;
wwn_list_p->wwn_prev = NULL;
} else if (
wwn_list_p->wwn_next == NULL) {
wwn_list_p->wwn_prev->wwn_next =
NULL;
free(wwn_list_p);
wwn_list_p = NULL;
} else {
wwn_list_tmp_p =
wwn_list_p->wwn_next;
wwn_list_p->wwn_prev->wwn_next =
wwn_list_p->wwn_next;
wwn_list_p->wwn_next->wwn_prev =
wwn_list_p->wwn_prev;
free(wwn_list_p);
wwn_list_p = wwn_list_tmp_p;
}
continue;
}
}
copy_wwn_data_to_str(wwn_list_p->node_wwn_s, node_wwn);
copy_wwn_data_to_str(wwn_list_p->port_wwn_s, port_wwn);
memcpy(wwn_list_p->w_node_wwn, node_wwn, WWN_SIZE);
}
wwn_list_p = wwn_list_p->wwn_next;
}
g_free_wwn_list_found(&wwn_list_found);
for (wwn_list_p = *wwn_list_ptr; wwn_list_p != NULL;
wwn_list_p = wwn_list_p->wwn_next) {
if (strstr(wwn_list_p->physical_path, SCSI_VHCI) != NULL) {
if ((err = insert_missing_pwwn(
wwn_list_p->physical_path, wwn_list_ptr)) != 0)
return (err);
}
}
if (env != NULL) {
end_time = gethrtime();
fprintf(stdout, " g_get_wwn_list: "
"\t\tTime = %lld millisec\n",
(end_time - start_time)/1000000);
}
return (0);
}
int
g_devices_get_all(struct wwn_list_struct **wwn_list_ptr)
{
struct wwn_list_struct *tape_ptr = NULL;
struct wwn_list_struct *tmp;
int err;
di_node_t root;
hrtime_t start_time, end_time;
char *env = NULL;
if ((env = getenv("_LUX_T_DEBUG")) != NULL) {
start_time = gethrtime();
}
init_drv(DEV_TAPE_DIR, DIR_MATCH_ST, SLSH_DRV_NAME_ST);
init_drv(DEV_RDIR, DIR_MATCH_SSD, SLSH_DRV_NAME_SSD);
if ((root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
return (L_DEV_SNAPSHOT_FAILED);
}
if (env != NULL) {
end_time = gethrtime();
fprintf(stdout, " di_init - /: "
"\t\tTime = %lld millisec\n",
(end_time - start_time)/1000000);
}
if (env != NULL) {
start_time = gethrtime();
}
if ((err = devices_get_all(root, SSD_DRVR_NAME, SSD_MINOR_NAME,
wwn_list_ptr)) != 0) {
if (err != L_NO_DEVICES_FOUND) {
di_fini(root);
g_free_wwn_list(&tape_ptr);
g_free_wwn_list(wwn_list_ptr);
return (err);
}
}
if (env != NULL) {
end_time = gethrtime();
fprintf(stdout, " devices_get_all - ssd: "
"\t\tTime = %lld millisec\n",
(end_time - start_time)/1000000);
}
if (env != NULL) {
start_time = gethrtime();
}
if ((err = devices_get_all(root, ST_DRVR_NAME, ST_MINOR_NAME,
&tape_ptr)) != 0) {
di_fini(root);
if (err != L_NO_DEVICES_FOUND) {
g_free_wwn_list(&tape_ptr);
g_free_wwn_list(wwn_list_ptr);
return (err);
} else {
if (*wwn_list_ptr != NULL) {
return (0);
} else {
g_free_wwn_list(&tape_ptr);
g_free_wwn_list(wwn_list_ptr);
return (err);
}
}
}
if (env != NULL) {
end_time = gethrtime();
fprintf(stdout, " devices_get_all - st: "
"\t\tTime = %lld millisec\n",
(end_time - start_time)/1000000);
}
if (*wwn_list_ptr != NULL) {
for (tmp = *wwn_list_ptr; tmp->wwn_next != NULL;
tmp = tmp->wwn_next)
;
tmp->wwn_next = tape_ptr;
tape_ptr->wwn_prev = tmp;
di_fini(root);
return (0);
}
*wwn_list_ptr = tape_ptr;
di_fini(root);
return (0);
}
void
g_free_wwn_list_found(struct wwn_list_found_struct **wwn_list_found)
{
WWN_list_found *next = NULL;
if (wwn_list_found == NULL) {
return;
}
for (; *wwn_list_found != NULL; *wwn_list_found = next) {
next = (*wwn_list_found)->wwn_next;
g_destroy_data(*wwn_list_found);
*wwn_list_found = NULL;
}
}
void
g_free_wwn_list(struct wwn_list_struct **wwn_list)
{
WWN_list *next = NULL;
if (wwn_list == NULL) {
return;
}
for (; *wwn_list != NULL; *wwn_list = next) {
next = (*wwn_list)->wwn_next;
if ((*wwn_list)->physical_path != NULL)
(void) g_destroy_data((*wwn_list)->physical_path);
if ((*wwn_list)->logical_path != NULL)
(void) g_destroy_data((*wwn_list)->logical_path);
(void) g_destroy_data(*wwn_list);
}
wwn_list = NULL;
}
void
g_sort_wwn_list(struct wwn_list_struct **wwn_list)
{
int i, n;
struct wwn_list_struct **wwn_list_array;
struct wwn_list_struct *wwn_list_ptr;
struct wwn_list_struct **wwn_list_array_ptr1;
struct wwn_list_struct **wwn_list_array_ptr2;
for (n = 0, wwn_list_ptr = *wwn_list;
wwn_list_ptr != NULL;
wwn_list_ptr = wwn_list_ptr->wwn_next) {
n++;
}
if (n <= 1) {
return;
}
wwn_list_array = (struct wwn_list_struct **)
g_zalloc((n+1) * sizeof (struct wwn_list_struct *));
wwn_list_array_ptr1 = wwn_list_array;
for (wwn_list_ptr = *wwn_list;
wwn_list_ptr != NULL;
wwn_list_ptr = wwn_list_ptr->wwn_next) {
*wwn_list_array_ptr1++ = wwn_list_ptr;
}
*wwn_list_array_ptr1 = NULL;
qsort((void *) wwn_list_array, n,
sizeof (struct wwn_list_struct *), wwn_list_name_compare);
wwn_list_array_ptr1 = wwn_list_array;
*wwn_list = *wwn_list_array_ptr1;
wwn_list_array_ptr2 = wwn_list_array_ptr1 + 1;
(*wwn_list_array_ptr1)->wwn_prev = NULL;
for (i = 0; i < n - 1; i++) {
(*wwn_list_array_ptr2)->wwn_prev = *wwn_list_array_ptr1;
(*wwn_list_array_ptr1++)->wwn_next = *wwn_list_array_ptr2++;
}
(*wwn_list_array_ptr1)->wwn_next = NULL;
(void) g_destroy_data((void *)wwn_list_array);
}
int
wwn_list_name_compare(const void *arg1, const void *arg2)
{
char *s1, *s2;
int n1, n2;
char *p1, *p2;
s1 = (*((struct wwn_list_struct **)arg1))->logical_path;
s2 = (*((struct wwn_list_struct **)arg2))->logical_path;
for (;;) {
if (*s1 == 0 || *s2 == 0)
break;
if ((isdigit(*s1) && isdigit(*s2))) {
n1 = strtol(s1, &p1, 10);
n2 = strtol(s2, &p2, 10);
if (n1 != n2) {
return (n1 - n2);
}
s1 = p1;
s2 = p2;
} else if (*s1 != *s2) {
break;
} else {
s1++;
s2++;
}
}
return (*s1 - *s2);
}
int
g_get_limited_map(char *path, struct lilpmap *map_ptr, int verbose)
{
int fd, i;
char drvr_path[MAXPATHLEN];
struct stat stbuf;
(void) memset(map_ptr, 0, sizeof (struct lilpmap));
(void) strcpy(drvr_path, path);
if (stat(drvr_path, &stbuf) < 0) {
return (L_LSTAT_ERROR);
}
if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
(void) strcat(drvr_path, ":0");
}
P_DPRINTF(" g_get_limited_map: Geting drive map from:"
" %s\n", drvr_path);
if ((fd = g_object_open(drvr_path, O_NDELAY | O_RDONLY)) == -1)
return (L_OPEN_PATH_FAIL);
if (ioctl(fd, FCIO_GETMAP, map_ptr) != 0) {
I_DPRINTF(" FCIO_GETMAP ioctl failed\n");
(void) close(fd);
return (L_FCIO_GETMAP_IOCTL_FAIL);
}
(void) close(fd);
if ((map_ptr->lilp_length > 126) || (map_ptr->lilp_magic != 0x1107)) {
return (L_INVALID_LOOP_MAP);
}
for (i = 0; i < (uint_t)map_ptr->lilp_length; i++) {
if (map_ptr->lilp_list[i] > 0xef) {
return (L_INVALID_LOOP_MAP);
}
}
return (0);
}
int
g_get_host_params(char *host_path, fc_port_dev_t *host_val, int verbose)
{
int err;
int fd;
int dev_type;
fcio_t fcio;
if (host_path == NULL) {
return (L_INVALID_PATH);
}
if (host_val == NULL) {
return (L_INVALID_ARG);
}
dev_type = g_get_path_type(host_path);
if ((dev_type == 0) || !(dev_type & FC_GEN_XPORT)) {
return (L_INVALID_PATH_TYPE);
}
if ((fd = g_object_open(host_path, O_NDELAY | O_RDONLY)) == -1) {
return (L_OPEN_PATH_FAIL);
}
(void) memset(host_val, 0, sizeof (struct fc_port_dev));
fcio.fcio_cmd = FCIO_GET_HOST_PARAMS;
fcio.fcio_xfer = FCIO_XFER_READ;
fcio.fcio_obuf = (caddr_t)host_val;
fcio.fcio_olen = sizeof (fc_port_dev_t);
if (g_issue_fcio_ioctl(fd, &fcio, verbose) != 0) {
I_DPRINTF(" FCIO_GET_HOST_PARAMS ioctl failed.\n");
(void) close(fd);
return (L_FCIO_GET_HOST_PARAMS_FAIL);
}
(void) close(fd);
if ((err = get_fca_inq_dtype(host_path, host_val->dev_pwwn,
&host_val->dev_dtype)) != 0) {
return (err);
}
return (0);
}
int
g_issue_fcio_ioctl(int fd, fcio_t *fcio, int verbose)
{
int ntries;
for (ntries = 0; ntries < RETRY_FCIO_IOCTL; ntries++) {
if (ioctl(fd, FCIO_CMD, fcio) != 0) {
if ((errno == EAGAIN) &&
(ntries+1 < RETRY_FCIO_IOCTL)) {
(void) usleep(WAIT_FCIO_IOCTL);
continue;
}
I_DPRINTF("FCIO ioctl failed.\n"
"Error: %s. fc_error = %d (0x%x)\n",
strerror(errno), fcio->fcio_errno,
fcio->fcio_errno);
if (errno == EINVAL) {
if (fcio->fcio_errno == FC_TOOMANY) {
return (L_INVALID_DEVICE_COUNT);
} else {
return (errno);
}
}
if (fcio->fcio_errno == FC_OFFLINE)
break;
return (-1);
}
break;
}
return (0);
}
static int
g_issue_fcp_ioctl(int fd, struct fcp_ioctl *fcp_data, int verbose)
{
int num_tries = 0;
struct device_data *dev_data = NULL;
while (num_tries++ < RETRY_FCP_IOCTL) {
if (ioctl(fd, FCP_TGT_INQUIRY, fcp_data) == -1) {
if (errno == EAGAIN) {
(void) usleep(WAIT_FCP_IOCTL);
continue;
} else {
break;
}
}
dev_data = (struct device_data *)((void *)(fcp_data->list));
if (dev_data->dev_status == 0) {
return (0);
}
if (dev_data->dev_status == EAGAIN) {
(void) usleep(WAIT_FCP_IOCTL);
continue;
} else {
dev_data->dev0_type = DTYPE_UNKNOWN;
return (0);
}
}
return (L_FCP_TGT_INQUIRY_FAIL);
}
int
g_get_dev_list(char *path, fc_port_dev_t **dev_list, int *ndevs)
{
int num_devices = 0;
int i, err, ulp_failure = 0, new_count = 0;
int dev_type;
int fd;
char fcapath[MAXPATHLEN];
char *char_ptr;
struct stat stbuf;
fcio_t fcio;
uint32_t port_top;
fc_port_dev_t *dlist;
*dev_list = dlist = NULL;
(void) strcpy(fcapath, path);
if (strstr(fcapath, DRV_NAME_SSD) || strstr(fcapath, SES_NAME)) {
if ((char_ptr = strrchr(fcapath, '/')) == NULL) {
return (L_INVALID_PATH);
}
*char_ptr = '\0';
(void) strcat(fcapath, FC_CTLR);
} else {
if (stat(fcapath, &stbuf) < 0) {
return (L_LSTAT_ERROR);
}
if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
(void) strcat(fcapath, FC_CTLR);
}
}
dev_type = g_get_path_type(fcapath);
if ((dev_type == 0) || !(dev_type & FC_GEN_XPORT)) {
return (L_INVALID_PATH_TYPE);
}
if ((fd = g_object_open(fcapath, O_NDELAY | O_RDONLY)) == -1) {
return (L_OPEN_PATH_FAIL);
}
fcio.fcio_cmd = FCIO_GET_NUM_DEVS;
fcio.fcio_olen = sizeof (num_devices);
fcio.fcio_xfer = FCIO_XFER_READ;
fcio.fcio_obuf = (caddr_t)&num_devices;
if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) {
I_DPRINTF(" FCIO_GET_NUM_DEVS ioctl failed.\n");
(void) close(fd);
return (L_FCIO_GET_NUM_DEVS_FAIL);
}
if (num_devices == 0) {
*ndevs = 0;
(void) close(fd);
return (L_NO_DEVICES_FOUND);
}
if ((dlist = (fc_port_dev_t *)calloc(num_devices,
sizeof (fc_port_dev_t))) == NULL) {
(void) close(fd);
return (L_MALLOC_FAILED);
}
bzero((caddr_t)&fcio, sizeof (fcio));
fcio.fcio_cmd = FCIO_GET_DEV_LIST;
fcio.fcio_xfer = FCIO_XFER_READ;
fcio.fcio_olen = num_devices * sizeof (fc_port_dev_t);
fcio.fcio_obuf = (caddr_t)dlist;
fcio.fcio_alen = sizeof (new_count);
fcio.fcio_abuf = (caddr_t)&new_count;
if ((err = g_issue_fcio_ioctl(fd, &fcio, 0)) != 0) {
if (err == L_INVALID_DEVICE_COUNT) {
free(dlist);
num_devices = new_count;
new_count = 0;
if ((dlist = (fc_port_dev_t *)calloc(num_devices,
sizeof (fc_port_dev_t))) == NULL) {
(void) close(fd);
return (L_MALLOC_FAILED);
}
fcio.fcio_cmd = FCIO_GET_DEV_LIST;
fcio.fcio_xfer = FCIO_XFER_READ;
fcio.fcio_obuf = (caddr_t)dlist;
fcio.fcio_olen = num_devices * sizeof (fc_port_dev_t);
fcio.fcio_alen = sizeof (new_count);
fcio.fcio_abuf = (caddr_t)&new_count;
if ((err = g_issue_fcio_ioctl(fd, &fcio, 0)) != 0) {
if (err == L_INVALID_DEVICE_COUNT) {
I_DPRINTF(" Device count was %d"
" should have been %d\n",
num_devices, new_count);
} else {
I_DPRINTF(
" FCIO_GET_DEV_LIST ioctl failed.");
err = L_FCIO_GET_DEV_LIST_FAIL;
}
free(dlist);
(void) close(fd);
return (err);
}
} else {
I_DPRINTF(" FCIO_GET_DEV_LIST ioctl failed.");
free(dlist);
(void) close(fd);
return (L_FCIO_GET_DEV_LIST_FAIL);
}
}
if (new_count < num_devices) {
if (new_count == 0) {
*ndevs = 0;
(void) close(fd);
S_FREE(dlist);
return (L_NO_DEVICES_FOUND);
}
num_devices = new_count;
if ((dlist = (fc_port_dev_t *)realloc(dlist,
(new_count * sizeof (fc_port_dev_t))))
== NULL) {
S_FREE(dlist);
(void) close(fd);
return (L_MALLOC_FAILED);
}
}
*dev_list = dlist;
*ndevs = num_devices;
(void) close(fd);
if ((err = g_get_fca_port_topology(fcapath, &port_top, 0)) != 0) {
free(*dev_list);
*dev_list = NULL;
return (err);
}
for (i = 0; i < num_devices; i++, dlist++) {
if ((err = g_get_inq_dtype(fcapath, dlist->dev_pwwn,
&dlist->dev_dtype)) != 0) {
if ((err == L_FCIO_DEV_LOGIN_FAIL) ||
(err == L_FCP_TGT_INQUIRY_FAIL)) {
ulp_failure = 1;
dlist->dev_dtype = GFC_ERR_INQ_DTYPE;
} else {
(void) free(*dev_list);
*dev_list = NULL;
return (err);
}
}
}
if (ulp_failure) {
return (L_GET_DEV_LIST_ULP_FAILURE);
} else {
return (0);
}
}
#define FCP_PATH "/devices/pseudo/fcp@0:fcp"
int
g_get_inq_dtype(char *fcapath, la_wwn_t pwwn, uchar_t *inq_dtype)
{
int dev_type, fd;
int err, fcp_fd;
uint32_t state;
uint32_t port_top = 0;
struct fcp_ioctl fcp_data;
struct device_data inq_data;
struct stat sbuf;
dev_type = g_get_path_type(fcapath);
if ((dev_type == 0) || !(dev_type & FC_GEN_XPORT)) {
return (L_INVALID_PATH_TYPE);
}
if ((err = g_get_fca_port_topology(fcapath, &port_top, 0)) != 0) {
return (err);
}
if ((port_top == FC_TOP_FABRIC) || (port_top == FC_TOP_PUBLIC_LOOP)) {
if (((err = g_get_dev_port_state(fcapath, pwwn, &state))
!= 0) || (state != PORT_DEVICE_LOGGED_IN)) {
if ((err = g_dev_login(fcapath, pwwn)) != 0) {
return (err);
}
}
}
if ((fd = g_object_open(fcapath, O_NDELAY | O_RDONLY)) == -1)
return (L_OPEN_PATH_FAIL);
if (fstat(fd, &sbuf) == -1) {
(void) close(fd);
return (L_FSTAT_ERROR);
}
if ((fcp_fd = g_object_open(FCP_PATH, O_RDONLY)) == -1) {
(void) close(fd);
return (L_OPEN_PATH_FAIL);
}
fcp_data.fp_minor = minor(sbuf.st_rdev);
fcp_data.listlen = 1;
inq_data.dev_pwwn = pwwn;
fcp_data.list = (caddr_t)&inq_data;
if (err = g_issue_fcp_ioctl(fcp_fd, &fcp_data, 0)) {
close(fd);
close(fcp_fd);
return (err);
}
*inq_dtype = inq_data.dev0_type;
close(fd);
close(fcp_fd);
return (err);
}
static int
get_fca_inq_dtype(char *fcapath, la_wwn_t pwwn, uchar_t *inq_dtype)
{
int dev_type, fd;
int err, fcp_fd;
struct fcp_ioctl fcp_data;
struct device_data inq_data;
struct stat sbuf;
dev_type = g_get_path_type(fcapath);
if ((dev_type == 0) || !(dev_type & FC_GEN_XPORT)) {
return (L_INVALID_PATH_TYPE);
}
if ((fd = g_object_open(fcapath, O_NDELAY | O_RDONLY)) == -1) {
return (L_OPEN_PATH_FAIL);
}
if (fstat(fd, &sbuf) == -1) {
(void) close(fd);
return (L_FSTAT_ERROR);
}
if ((fcp_fd = g_object_open(FCP_PATH, O_RDONLY)) == -1) {
(void) close(fd);
return (L_OPEN_PATH_FAIL);
}
fcp_data.fp_minor = minor(sbuf.st_rdev);
fcp_data.listlen = 1;
inq_data.dev_pwwn = pwwn;
fcp_data.list = (caddr_t)&inq_data;
if (err = g_issue_fcp_ioctl(fcp_fd, &fcp_data, 0)) {
close(fd);
close(fcp_fd);
return (err);
}
*inq_dtype = inq_data.dev0_type;
close(fd);
close(fcp_fd);
return (0);
}
int
g_get_dev_map(char *path, gfc_map_t *map_ptr, int verbose)
{
return (create_map(path, map_ptr, verbose, MAP_FORMAT_STANDARD));
}
int
g_get_lilp_map(char *path, gfc_map_t *map_ptr, int verbose)
{
return (create_map(path, map_ptr, verbose, MAP_FORMAT_LILP));
}
int
create_map(char *path, gfc_map_t *map_ptr, int verbose, int map_type)
{
int fd, i, j, num_devices = 0, err, pathcnt = 1;
char drvr_path[MAXPATHLEN], drvr_path0[MAXPATHLEN];
char *char_ptr;
struct stat stbuf;
fc_port_dev_t *dev_list, *dlistptr;
uint32_t hba_port_top = 0;
uint_t dev_type;
sf_al_map_t sf_map;
gfc_port_dev_info_t *dev_ptr;
fc_port_dev_t fp_hba_port;
mp_pathlist_t pathlist;
int p_on = 0, p_st = 0;
if (path == NULL) {
return (L_INVALID_PATH);
}
if (map_ptr == NULL) {
return (L_INVALID_ARG);
}
map_ptr->dev_addr = NULL;
map_ptr->count = 0;
(void) strcpy(drvr_path, path);
if (strstr(path, SCSI_VHCI)) {
(void) strcpy(drvr_path0, path);
if (g_get_pathlist(drvr_path0, &pathlist)) {
return (L_INVALID_PATH);
}
pathcnt = pathlist.path_count;
p_on = p_st = 0;
for (i = 0; i < pathcnt; i++) {
if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
if (pathlist.path_info[i].path_state ==
MDI_PATHINFO_STATE_ONLINE) {
p_on = i;
break;
} else if (pathlist.path_info[i].path_state ==
MDI_PATHINFO_STATE_STANDBY) {
p_st = i;
}
}
}
if (pathlist.path_info[p_on].path_state ==
MDI_PATHINFO_STATE_ONLINE) {
(void) strcpy(drvr_path,
pathlist.path_info[p_on].path_hba);
} else {
(void) strcpy(drvr_path,
pathlist.path_info[p_st].path_hba);
}
free(pathlist.path_info);
(void) strcat(drvr_path, FC_CTLR);
} else {
(void) strcpy(drvr_path, path);
if (strstr(drvr_path, DRV_NAME_SSD) ||
strstr(drvr_path, SES_NAME) ||
strstr(drvr_path, DRV_NAME_ST)) {
if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
return (L_INVALID_PATH);
}
*char_ptr = '\0';
(void) strcat(drvr_path, FC_CTLR);
} else {
if (stat(drvr_path, &stbuf) < 0) {
return (L_LSTAT_ERROR);
}
if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
(void) strcat(drvr_path, FC_CTLR);
}
}
}
P_DPRINTF(" g_get_dev_map: Geting drive map from:"
" %s\n", drvr_path);
dev_type = g_get_path_type(drvr_path);
if ((dev_type == 0) || !(dev_type & XPORT_MASK)) {
return (L_INVALID_PATH_TYPE);
}
if ((err = g_get_fca_port_topology(drvr_path,
&hba_port_top, verbose)) != 0) {
return (err);
}
if (dev_type & FC_FCA_MASK) {
if ((err = g_get_dev_list(drvr_path, &dev_list,
&num_devices)) != 0) {
if (err == L_GET_DEV_LIST_ULP_FAILURE) {
(void) free(dev_list);
}
if (err != L_NO_DEVICES_FOUND) {
return (err);
}
}
if ((err = g_get_host_params(drvr_path, &fp_hba_port,
verbose)) != 0) {
(void) free(dev_list);
if (num_devices == 0)
return (L_NO_DEVICES_FOUND);
else
return (err);
}
if (num_devices > 0) {
if (map_type == MAP_FORMAT_LILP) {
map_ptr->count = ++num_devices;
} else {
map_ptr->count = num_devices;
}
if ((map_ptr->dev_addr = (gfc_port_dev_info_t *)
calloc(map_ptr->count,
sizeof (gfc_port_dev_info_t))) == NULL) {
(void) free(dev_list);
return (L_MALLOC_FAILED);
}
}
if (map_type == MAP_FORMAT_LILP && num_devices > 0) {
if ((dev_list = (fc_port_dev_t *)realloc(dev_list,
(num_devices * sizeof (fc_port_dev_t))))
== NULL) {
S_FREE(dev_list);
(void) free(map_ptr->dev_addr);
map_ptr->dev_addr = NULL;
return (L_MALLOC_FAILED);
}
if (memcpy(dev_list+(num_devices-1), &fp_hba_port,
sizeof (fc_port_dev_t)) == NULL) {
(void) free(dev_list);
(void) free(map_ptr->dev_addr);
map_ptr->dev_addr = NULL;
return (L_MEMCPY_FAILED);
}
qsort((void*)dev_list, num_devices,
sizeof (fc_port_dev_t), lilp_map_cmp);
}
dlistptr = dev_list;
dev_ptr = map_ptr->dev_addr;
switch (hba_port_top) {
case FC_TOP_FABRIC:
case FC_TOP_PUBLIC_LOOP:
if (fp_hba_port.dev_did.port_id <= 0xffff) {
(void) free(dlistptr);
(void) free(map_ptr->dev_addr);
map_ptr->dev_addr = NULL;
return (L_INVALID_FABRIC_ADDRESS);
} else {
map_ptr->hba_addr.port_topology = hba_port_top;
map_ptr->hba_addr.gfc_port_dev.pub_port =
fp_hba_port;
}
for (i = 0; i < num_devices; i++, dev_ptr++,
dev_list++) {
if (dev_list->dev_did.port_id <= 0xffff) {
(void) free(dlistptr);
(void) free(map_ptr->dev_addr);
map_ptr->dev_addr = NULL;
return (L_INVALID_FABRIC_ADDRESS);
} else {
dev_ptr->port_topology = hba_port_top;
dev_ptr->gfc_port_dev.pub_port =
*dev_list;
}
}
break;
case FC_TOP_PRIVATE_LOOP:
if (fp_hba_port.dev_did.port_id > 0xff) {
(void) free(dlistptr);
(void) free(map_ptr->dev_addr);
map_ptr->dev_addr = NULL;
return (L_INVALID_PRIVATE_LOOP_ADDRESS);
} else {
map_ptr->hba_addr.port_topology = hba_port_top;
map_ptr->hba_addr.gfc_port_dev.
priv_port.sf_al_pa =
(uchar_t)fp_hba_port.dev_did.port_id;
map_ptr->hba_addr.gfc_port_dev.
priv_port.sf_hard_address = (uchar_t)
fp_hba_port.dev_hard_addr.hard_addr;
for (j = 0; j < FC_WWN_SIZE; j++) {
map_ptr->hba_addr.gfc_port_dev.
priv_port.sf_node_wwn[j] =
fp_hba_port.dev_nwwn.raw_wwn[j];
map_ptr->hba_addr.gfc_port_dev.
priv_port.sf_port_wwn[j] =
fp_hba_port.dev_pwwn.raw_wwn[j];
}
map_ptr->hba_addr.gfc_port_dev.
priv_port.sf_inq_dtype =
fp_hba_port.dev_dtype;
}
for (i = 0; (i < num_devices &&
i < SF_NUM_ENTRIES_IN_MAP);
i++, dev_ptr++, dev_list++) {
if (dev_list->dev_did.port_id > 0xff) {
(void) free(dlistptr);
(void) free(map_ptr->dev_addr);
map_ptr->dev_addr = NULL;
return (L_INVALID_PRIVATE_LOOP_ADDRESS);
}
dev_ptr->port_topology = hba_port_top;
dev_ptr->gfc_port_dev.priv_port.sf_al_pa
= (uchar_t)dev_list->dev_did.port_id;
dev_ptr->gfc_port_dev.priv_port.sf_hard_address
= (uchar_t)dev_list->dev_hard_addr.hard_addr;
for (j = 0; j < FC_WWN_SIZE; j++) {
dev_ptr->gfc_port_dev.priv_port.sf_node_wwn[j] =
dev_list->dev_nwwn.raw_wwn[j];
dev_ptr->gfc_port_dev.priv_port.sf_port_wwn[j] =
dev_list->dev_pwwn.raw_wwn[j];
}
dev_ptr->gfc_port_dev.priv_port.sf_inq_dtype =
dev_list->dev_dtype;
}
break;
case FC_TOP_PT_PT:
(void) free(dlistptr);
(void) free(map_ptr->dev_addr);
map_ptr->dev_addr = NULL;
return (L_PT_PT_FC_TOP_NOT_SUPPORTED);
default:
(void) free(dlistptr);
(void) free(map_ptr->dev_addr);
map_ptr->dev_addr = NULL;
return (L_UNEXPECTED_FC_TOPOLOGY);
}
(void) free(dlistptr);
} else {
if ((fd = g_object_open(drvr_path, O_NDELAY | O_RDONLY)) == -1)
return (errno);
(void) memset(&sf_map, 0, sizeof (struct sf_al_map));
if (ioctl(fd, SFIOCGMAP, &sf_map) != 0) {
I_DPRINTF(" SFIOCGMAP ioctl failed.\n");
(void) close(fd);
return (L_SFIOCGMAP_IOCTL_FAIL);
}
if ((sf_map.sf_count > 126) || (sf_map.sf_count < 0)) {
(void) close(fd);
return (L_INVALID_LOOP_MAP);
}
if (sf_map.sf_count == 0) {
(void) close(fd);
return (L_NO_DEVICES_FOUND);
}
map_ptr->count = sf_map.sf_count;
if ((map_ptr->dev_addr =
(gfc_port_dev_info_t *)calloc(map_ptr->count,
sizeof (gfc_port_dev_info_t))) == NULL) {
(void) close(fd);
return (L_MALLOC_FAILED);
}
dev_ptr = map_ptr->dev_addr;
for (i = 0; i < sf_map.sf_count; i++, dev_ptr++) {
if (sf_map.sf_addr_pair[i].sf_al_pa > 0xef) {
(void) free(map_ptr->dev_addr);
map_ptr->dev_addr = NULL;
(void) close(fd);
return (L_INVALID_LOOP_MAP);
}
dev_ptr->port_topology = hba_port_top;
dev_ptr->gfc_port_dev.priv_port =
sf_map.sf_addr_pair[i];
}
map_ptr->hba_addr.port_topology = hba_port_top;
map_ptr->hba_addr.gfc_port_dev.priv_port =
sf_map.sf_hba_addr;
(void) close(fd);
}
return (0);
}
static int
update_map_dev_fc_prop(impl_map_dev_prop_t **prop_list, uint32_t map_topo,
uchar_t *port_wwn, uchar_t *node_wwn, int port_addr, int hard_addr)
{
impl_map_dev_prop_t *prop_ptr, *pl_start = NULL, *pl_end = NULL;
uchar_t *port_wwn_data, *node_wwn_data;
int *port_addr_data, *hard_addr_data;
if ((map_topo == FC_TOP_FABRIC) || (map_topo == FC_TOP_PUBLIC_LOOP)) {
if (port_addr <= 0xffff) {
return (L_INVALID_FABRIC_ADDRESS);
}
} else if (map_topo == FC_TOP_PRIVATE_LOOP) {
if (port_addr > 0xff) {
return (L_INVALID_PRIVATE_LOOP_ADDRESS);
}
}
if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
1, sizeof (impl_map_dev_prop_t))) == NULL) {
return (L_MALLOC_FAILED);
}
(void) strncpy(prop_ptr->prop_name, PORT_ADDR_PROP,
strlen(PORT_ADDR_PROP));
prop_ptr->prop_type = GFC_PROP_TYPE_INT;
if ((port_addr_data = (int *)calloc(1, sizeof (int))) == NULL) {
free(prop_ptr);
return (L_MALLOC_FAILED);
}
*port_addr_data = port_addr;
prop_ptr->prop_data = port_addr_data;
pl_start = pl_end = prop_ptr;
if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
1, sizeof (impl_map_dev_prop_t))) == NULL) {
free_prop_list(&pl_start);
return (L_MALLOC_FAILED);
}
(void) strncpy(prop_ptr->prop_name, PORT_WWN_PROP,
strlen(PORT_WWN_PROP));
prop_ptr->prop_type = GFC_PROP_TYPE_BYTES;
if ((port_wwn_data = (uchar_t *)calloc(1, FC_WWN_SIZE)) == NULL) {
free_prop_list(&pl_start);
return (L_MALLOC_FAILED);
}
memcpy(port_wwn_data, port_wwn, FC_WWN_SIZE);
prop_ptr->prop_data = port_wwn_data;
prop_ptr->prop_size = FC_WWN_SIZE;
pl_end->next = prop_ptr;
pl_end = prop_ptr;
if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
1, sizeof (impl_map_dev_prop_t))) == NULL) {
free_prop_list(&pl_start);
return (L_MALLOC_FAILED);
}
(void) strncpy(prop_ptr->prop_name, NODE_WWN_PROP,
strlen(NODE_WWN_PROP));
prop_ptr->prop_type = GFC_PROP_TYPE_BYTES;
if ((node_wwn_data = (uchar_t *)calloc(
1, FC_WWN_SIZE)) == NULL) {
free_prop_list(&pl_start);
return (L_MALLOC_FAILED);
}
memcpy(node_wwn_data, node_wwn, FC_WWN_SIZE);
prop_ptr->prop_data = node_wwn_data;
prop_ptr->prop_size = FC_WWN_SIZE;
pl_end->next = prop_ptr;
pl_end = prop_ptr;
if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
1, sizeof (impl_map_dev_prop_t))) == NULL) {
free_prop_list(&pl_start);
return (L_MALLOC_FAILED);
}
(void) strncpy(prop_ptr->prop_name, HARD_ADDR_PROP,
strlen(HARD_ADDR_PROP));
prop_ptr->prop_type = GFC_PROP_TYPE_INT;
if ((hard_addr_data = (int *)calloc(1, sizeof (int))) == NULL) {
free_prop_list(&pl_start);
return (L_MALLOC_FAILED);
}
*hard_addr_data = hard_addr;
prop_ptr->prop_data = hard_addr_data;
pl_end->next = prop_ptr;
pl_end = prop_ptr;
if (*prop_list == NULL) {
*prop_list = pl_start;
} else {
pl_end->next = (*prop_list)->next;
*prop_list = pl_start;
}
return (0);
}
static int
update_map_dev_FCP_prop(impl_map_dev_prop_t **prop_list,
uchar_t *inq_dtype, int err, int exist)
{
impl_map_dev_prop_t *prop_ptr, *old_prop_ptr;
uchar_t *inq_dtype_data;
if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
1, sizeof (impl_map_dev_prop_t))) == NULL) {
return (L_MALLOC_FAILED);
}
(void) strncpy(prop_ptr->prop_name, INQ_DTYPE_PROP,
strlen(INQ_DTYPE_PROP));
if (inq_dtype == NULL) {
prop_ptr->prop_data = NULL;
prop_ptr->prop_error = err;
} else {
if ((inq_dtype_data = (uchar_t *)calloc(
1, sizeof (uchar_t))) == NULL) {
free(prop_ptr);
return (L_MALLOC_FAILED);
}
memcpy(inq_dtype_data, inq_dtype, sizeof (uchar_t));
prop_ptr->prop_data = inq_dtype_data;
prop_ptr->prop_type = GFC_PROP_TYPE_BYTES;
prop_ptr->prop_size = sizeof (uchar_t);
}
if (*prop_list == NULL) {
*prop_list = prop_ptr;
} else {
if (exist == PROP_EXIST) {
prop_ptr->next = (*prop_list)->next;
old_prop_ptr = *prop_list;
*prop_list = prop_ptr;
free((uchar_t *)(old_prop_ptr->prop_data));
old_prop_ptr->prop_data = NULL;
S_FREE(old_prop_ptr);
} else {
prop_ptr->next = *prop_list;
*prop_list = prop_ptr;
}
}
return (0);
}
static int
handle_map_dev_FCP_prop(minor_t fp_xport_minor, la_wwn_t port_wwn,
impl_map_dev_prop_t **prop_list)
{
struct device_data inq_data;
int fcp_fd, err;
struct fcp_ioctl fcp_data;
uchar_t inq_dtype;
if ((fcp_fd = g_object_open(FCP_PATH, O_RDONLY)) == -1) {
update_map_dev_FCP_prop(prop_list, NULL,
L_OPEN_PATH_FAIL, PROP_NOEXIST);
}
fcp_data.fp_minor = fp_xport_minor;
fcp_data.listlen = 1;
inq_data.dev_pwwn = port_wwn;
fcp_data.list = (caddr_t)&inq_data;
if (err = g_issue_fcp_ioctl(fcp_fd, &fcp_data, 0)) {
if ((err = update_map_dev_FCP_prop(
prop_list, NULL, err, PROP_NOEXIST)) != 0) {
return (err);
}
} else {
inq_dtype = inq_data.dev0_type;
if ((err = update_map_dev_FCP_prop(
prop_list, &inq_dtype, 0, PROP_NOEXIST)) != 0) {
return (err);
}
}
return (0);
}
gfc_dev_t
g_dev_map_init(char *path, int *l_err, int flag)
{
int fd, i, num_devices = 0, err, pathcnt = 1, new_count = 0;
char drvr_path[MAXPATHLEN], drvr_path0[MAXPATHLEN];
char *char_ptr, *nexus_path;
struct stat stbuf;
fc_port_dev_t *dev_list = NULL, *dlist;
uint32_t hba_port_top, state;
uint_t path_type;
sf_al_map_t sf_map;
fc_port_dev_t fp_hba_port;
mp_pathlist_t pathlist;
int p_on = 0, p_st = 0, hba_alpa_found = 0, nexus_fd;
fcio_t fcio;
struct lilpmap limited_map;
impl_map_dev_t *impl_map, *impl_dev;
impl_map_dev_t *mdl_start = NULL, *mdl_end = NULL;
struct stat sbuf;
if (l_err == NULL) {
return (NULL);
}
if (path == NULL) {
*l_err = L_INVALID_PATH;
return (NULL);
}
*l_err = 0;
(void) strcpy(drvr_path, path);
if (strstr(path, SCSI_VHCI)) {
(void) strcpy(drvr_path0, path);
if (g_get_pathlist(drvr_path0, &pathlist)) {
*l_err = L_INVALID_PATH;
return (NULL);
}
pathcnt = pathlist.path_count;
p_on = p_st = 0;
for (i = 0; i < pathcnt; i++) {
if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
if (pathlist.path_info[i].path_state ==
MDI_PATHINFO_STATE_ONLINE) {
p_on = i;
break;
} else if (pathlist.path_info[i].path_state ==
MDI_PATHINFO_STATE_STANDBY) {
p_st = i;
}
}
}
if (pathlist.path_info[p_on].path_state ==
MDI_PATHINFO_STATE_ONLINE) {
(void) strcpy(drvr_path,
pathlist.path_info[p_on].path_hba);
} else {
(void) strcpy(drvr_path,
pathlist.path_info[p_st].path_hba);
}
free(pathlist.path_info);
(void) strcat(drvr_path, FC_CTLR);
} else {
(void) strcpy(drvr_path, path);
if (strstr(drvr_path, DRV_NAME_SSD) ||
strstr(drvr_path, SES_NAME) ||
strstr(drvr_path, DRV_NAME_ST)) {
if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
*l_err = L_INVALID_PATH;
return (NULL);
}
*char_ptr = '\0';
(void) strcat(drvr_path, FC_CTLR);
} else {
if (stat(drvr_path, &stbuf) < 0) {
*l_err = L_LSTAT_ERROR;
return (NULL);
}
if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
(void) strcat(drvr_path, FC_CTLR);
}
}
}
P_DPRINTF(" g_dev_map_init: Geting drive map from:"
" %s\n", drvr_path);
path_type = g_get_path_type(drvr_path);
if ((path_type == 0) || !(path_type & XPORT_MASK)) {
*l_err = L_INVALID_PATH_TYPE;
return (NULL);
}
if ((err = g_get_fca_port_topology(drvr_path,
&hba_port_top, 0)) != 0) {
*l_err = err;
return (NULL);
}
if ((fd = g_object_open(drvr_path, O_NDELAY | O_RDONLY)) == -1) {
*l_err = errno;
return (NULL);
}
if (path_type & FC_FCA_MASK) {
fcio.fcio_cmd = FCIO_GET_NUM_DEVS;
fcio.fcio_olen = sizeof (num_devices);
fcio.fcio_xfer = FCIO_XFER_READ;
fcio.fcio_obuf = (caddr_t)&num_devices;
if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) {
I_DPRINTF(" FCIO_GET_NUM_DEVS ioctl failed.\n");
(void) close(fd);
*l_err = L_FCIO_GET_NUM_DEVS_FAIL;
return (NULL);
}
if (num_devices != 0) {
if ((dev_list = (fc_port_dev_t *)calloc(num_devices,
sizeof (fc_port_dev_t))) == NULL) {
(void) close(fd);
*l_err = L_MALLOC_FAILED;
return (NULL);
}
bzero((caddr_t)&fcio, sizeof (fcio));
fcio.fcio_cmd = FCIO_GET_DEV_LIST;
fcio.fcio_xfer = FCIO_XFER_READ;
fcio.fcio_olen = num_devices * sizeof (fc_port_dev_t);
fcio.fcio_obuf = (caddr_t)dev_list;
fcio.fcio_alen = sizeof (new_count);
fcio.fcio_abuf = (caddr_t)&new_count;
if ((err = g_issue_fcio_ioctl(fd, &fcio, 0)) != 0) {
if (err == L_INVALID_DEVICE_COUNT) {
free(dev_list);
num_devices = new_count;
new_count = 0;
if ((dev_list = (fc_port_dev_t *)
calloc(num_devices,
sizeof (fc_port_dev_t))) == NULL) {
(void) close(fd);
*l_err = L_MALLOC_FAILED;
return (NULL);
}
fcio.fcio_cmd = FCIO_GET_DEV_LIST;
fcio.fcio_xfer = FCIO_XFER_READ;
fcio.fcio_obuf = (caddr_t)dev_list;
fcio.fcio_olen = num_devices *
sizeof (fc_port_dev_t);
fcio.fcio_alen = sizeof (new_count);
fcio.fcio_abuf = (caddr_t)&new_count;
if ((err = g_issue_fcio_ioctl(fd, &fcio,
0)) != 0) {
if (err ==
L_INVALID_DEVICE_COUNT) {
I_DPRINTF(" Device"
" count was %d"
" should have been"
" %d\n",
num_devices,
new_count);
free(dev_list);
(void) close(fd);
*l_err = L_INVALID_DEVICE_COUNT;
return (NULL);
} else {
I_DPRINTF(" FCIO_GET_DEV_LIST ioctl failed.");
free(dev_list);
(void) close(fd);
*l_err = L_FCIO_GET_DEV_LIST_FAIL;
return (NULL);
}
}
}
}
}
if (new_count < num_devices) {
num_devices = new_count;
if (new_count > 0) {
if ((dev_list = (fc_port_dev_t *)
realloc(dev_list,
(new_count * sizeof (fc_port_dev_t))))
== NULL) {
S_FREE(dev_list);
(void) close(fd);
*l_err = L_MALLOC_FAILED;
return (NULL);
}
}
}
(void) memset(&fp_hba_port, 0, sizeof (struct fc_port_dev));
fcio.fcio_cmd = FCIO_GET_HOST_PARAMS;
fcio.fcio_xfer = FCIO_XFER_READ;
fcio.fcio_obuf = (caddr_t)&fp_hba_port;
fcio.fcio_olen = sizeof (fc_port_dev_t);
if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) {
I_DPRINTF(" FCIO_GET_HOST_PARAMS ioctl failed.\n");
(void) close(fd);
if (num_devices == 0) {
*l_err = L_NO_DEVICES_FOUND;
} else {
free(dev_list);
*l_err = L_FCIO_GET_HOST_PARAMS_FAIL;
}
(void) close(fd);
return (NULL);
}
if ((flag & MAP_FORMAT_LILP) == MAP_FORMAT_LILP) {
if (num_devices > 0) {
if ((dev_list = (fc_port_dev_t *)
realloc(dev_list,
(++num_devices *
sizeof (fc_port_dev_t)))) == NULL) {
(void) close(fd);
S_FREE(dev_list);
*l_err = L_MALLOC_FAILED;
return (NULL);
}
if (memcpy(dev_list+(num_devices-1),
&fp_hba_port,
sizeof (fc_port_dev_t)) == NULL) {
(void) free(dev_list);
(void) close(fd);
*l_err = L_MEMCPY_FAILED;
return (NULL);
}
qsort((void*)dev_list, num_devices,
sizeof (fc_port_dev_t), lilp_map_cmp);
}
}
if ((impl_map = (impl_map_dev_t *)calloc(
1, sizeof (impl_map_dev_t))) == NULL) {
(void) free(dev_list);
(void) close(fd);
*l_err = L_MALLOC_FAILED;
return (NULL);
}
impl_map->flag = flag;
impl_map->topo = hba_port_top;
if ((err = update_map_dev_fc_prop(&impl_map->prop_list,
hba_port_top, fp_hba_port.dev_pwwn.raw_wwn,
fp_hba_port.dev_nwwn.raw_wwn, fp_hba_port.dev_did.port_id,
fp_hba_port.dev_hard_addr.hard_addr)) != 0) {
(void) free(dev_list);
(void) close(fd);
g_dev_map_fini(impl_map);
*l_err = err;
return (NULL);
}
if ((flag & MAP_XPORT_PROP_ONLY) != MAP_XPORT_PROP_ONLY) {
if (fstat(fd, &sbuf) == -1) {
(void) free(dev_list);
(void) close(fd);
g_dev_map_fini(impl_map);
*l_err = L_FSTAT_ERROR;
return (NULL);
}
if ((err = handle_map_dev_FCP_prop(minor(sbuf.st_rdev),
fp_hba_port.dev_pwwn, &impl_map->prop_list)) != 0) {
(void) free(dev_list);
(void) close(fd);
g_dev_map_fini(impl_map);
*l_err = err;
return (NULL);
}
}
dlist = dev_list;
for (i = 0; i < num_devices; i++, dlist++) {
if ((impl_dev = (impl_map_dev_t *)calloc(
1, sizeof (impl_map_dev_t))) == NULL) {
(void) free(dev_list);
(void) close(fd);
g_dev_map_fini(impl_map);
*l_err = L_MALLOC_FAILED;
return (NULL);
}
impl_dev->parent = impl_map;
if ((err = update_map_dev_fc_prop(&impl_dev->prop_list,
hba_port_top, dlist->dev_pwwn.raw_wwn,
dlist->dev_nwwn.raw_wwn, dlist->dev_did.port_id,
dlist->dev_hard_addr.hard_addr)) != 0) {
(void) free(dev_list);
(void) close(fd);
g_dev_map_fini(impl_map);
*l_err = err;
return (NULL);
}
if (i == 0) {
mdl_start = mdl_end = impl_dev;
} else {
mdl_end->next = impl_dev;
mdl_end = impl_dev;
}
if ((flag & MAP_XPORT_PROP_ONLY) !=
MAP_XPORT_PROP_ONLY) {
if (((hba_port_top == FC_TOP_PUBLIC_LOOP) ||
(hba_port_top == FC_TOP_FABRIC)) &&
(memcmp(fp_hba_port.dev_pwwn.raw_wwn,
dlist->dev_pwwn.raw_wwn, FC_WWN_SIZE) != 0)) {
(void) memset(&fcio, 0, sizeof (fcio_t));
fcio.fcio_cmd = FCIO_GET_STATE;
fcio.fcio_ilen = sizeof (dlist->dev_pwwn);
fcio.fcio_ibuf = (caddr_t)&dlist->dev_pwwn;
fcio.fcio_xfer = FCIO_XFER_READ |
FCIO_XFER_WRITE;
fcio.fcio_olen = sizeof (uint32_t);
fcio.fcio_obuf = (caddr_t)&state;
fcio.fcio_alen = 0;
fcio.fcio_abuf = NULL;
if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) {
I_DPRINTF(
" FCIO_GET_STATE ioctl failed.\n");
if ((err = update_map_dev_FCP_prop(
&impl_dev->prop_list, NULL,
L_FCIO_GET_STATE_FAIL,
PROP_NOEXIST)) != 0) {
(void) free(dev_list);
(void) close(fd);
g_dev_map_fini(impl_map);
*l_err = err;
return (NULL);
}
}
if (state != PORT_DEVICE_LOGGED_IN) {
(void) close(fd);
if ((fd = g_object_open(drvr_path,
O_NDELAY | O_RDONLY | O_EXCL)) ==
-1) {
(void) free(dev_list);
g_dev_map_fini(impl_map);
*l_err = L_OPEN_PATH_FAIL;
return (NULL);
}
(void) memset(&fcio, 0,
sizeof (fcio_t));
fcio.fcio_cmd = FCIO_DEV_LOGIN;
fcio.fcio_ilen =
sizeof (dlist->dev_pwwn);
fcio.fcio_ibuf =
(caddr_t)&dlist->dev_pwwn;
fcio.fcio_xfer = FCIO_XFER_WRITE;
fcio.fcio_olen = fcio.fcio_alen = 0;
fcio.fcio_obuf = fcio.fcio_abuf = NULL;
if (g_issue_fcio_ioctl(fd, &fcio, 0) !=
0) {
I_DPRINTF(" FCIO_DEV_LOGIN ioctl failed.\n");
if ((err = update_map_dev_FCP_prop(
&impl_dev->prop_list, NULL,
L_FCIO_DEV_LOGIN_FAIL,
PROP_NOEXIST)) != 0) {
(void) free(dev_list);
(void) close(fd);
g_dev_map_fini(impl_map);
*l_err = err;
return (NULL);
}
continue;
}
}
}
if ((err = handle_map_dev_FCP_prop(
minor(sbuf.st_rdev),
dlist->dev_pwwn, &impl_dev->prop_list)) !=
0) {
(void) free(dev_list);
(void) close(fd);
g_dev_map_fini(impl_map);
*l_err = err;
return (NULL);
}
}
}
impl_map->child = mdl_start;
S_FREE(dev_list);
} else {
(void) memset(&sf_map, 0, sizeof (struct sf_al_map));
if (ioctl(fd, SFIOCGMAP, &sf_map) != 0) {
I_DPRINTF(" SFIOCGMAP ioctl failed.\n");
(void) close(fd);
*l_err = L_SFIOCGMAP_IOCTL_FAIL;
return (NULL);
}
if ((sf_map.sf_count > 126) || (sf_map.sf_count < 0)) {
(void) close(fd);
*l_err = L_INVALID_LOOP_MAP;
return (NULL);
}
if (sf_map.sf_count == 0) {
(void) close(fd);
*l_err = L_NO_DEVICES_FOUND;
return (NULL);
}
if ((err = g_get_nexus_path(drvr_path, &nexus_path)) != 0) {
(void) close(fd);
*l_err = err;
return (NULL);
}
if ((nexus_fd =
g_object_open(nexus_path, O_NDELAY | O_RDONLY)) == -1) {
(void) close(fd);
S_FREE(nexus_path);
*l_err = errno;
return (NULL);
}
if (ioctl(nexus_fd, FCIO_GETMAP, &limited_map) != 0) {
I_DPRINTF(" FCIO_GETMAP ioctl failed\n");
(void) close(fd);
(void) close(nexus_fd);
S_FREE(nexus_path);
*l_err = L_FCIO_GETMAP_IOCTL_FAIL;
return (NULL);
}
(void) close(nexus_fd);
S_FREE(nexus_path);
for (i = 0; i < sf_map.sf_count; i++) {
if (sf_map.sf_addr_pair[i].sf_al_pa ==
limited_map.lilp_myalpa) {
sf_map.sf_hba_addr = sf_map.sf_addr_pair[i];
hba_alpa_found = 1;
}
}
if (!(hba_alpa_found)) {
(void) close(fd);
*l_err = L_INVALID_LOOP_MAP;
return (NULL);
}
if ((impl_map = (impl_map_dev_t *)calloc(
1, sizeof (impl_map_dev_t))) == NULL) {
(void) close(fd);
*l_err = L_MALLOC_FAILED;
return (NULL);
}
impl_map->flag = flag;
impl_map->topo = hba_port_top;
if ((err = update_map_dev_fc_prop(&impl_map->prop_list,
hba_port_top, sf_map.sf_hba_addr.sf_port_wwn,
sf_map.sf_hba_addr.sf_node_wwn,
(int)sf_map.sf_hba_addr.sf_al_pa,
(int)sf_map.sf_hba_addr.sf_hard_address)) != 0) {
(void) close(fd);
g_dev_map_fini(impl_map);
*l_err = err;
return (NULL);
}
if ((flag & MAP_XPORT_PROP_ONLY) != MAP_XPORT_PROP_ONLY) {
if ((err = update_map_dev_FCP_prop(&impl_map->prop_list,
&sf_map.sf_hba_addr.sf_inq_dtype, 0,
PROP_NOEXIST)) != 0) {
(void) close(fd);
g_dev_map_fini(impl_map);
*l_err = err;
return (NULL);
}
}
for (i = 0; i < sf_map.sf_count; i++) {
if ((impl_dev = (impl_map_dev_t *)calloc(
1, sizeof (impl_map_dev_t))) == NULL) {
(void) close(fd);
g_dev_map_fini(impl_map);
*l_err = L_MALLOC_FAILED;
return (NULL);
}
impl_dev->parent = impl_map;
if ((err = update_map_dev_fc_prop(&impl_dev->prop_list,
hba_port_top, sf_map.sf_addr_pair[i].sf_port_wwn,
sf_map.sf_addr_pair[i].sf_node_wwn,
(int)(sf_map.sf_addr_pair[i].sf_al_pa),
(int)(sf_map.sf_addr_pair[i].sf_hard_address))) !=
0) {
(void) close(fd);
g_dev_map_fini(impl_map);
*l_err = err;
return (NULL);
}
if (i == 0) {
mdl_start = mdl_end = impl_dev;
} else {
mdl_end->next = impl_dev;
mdl_end = impl_dev;
}
if ((flag & MAP_XPORT_PROP_ONLY) !=
MAP_XPORT_PROP_ONLY) {
if ((err = update_map_dev_FCP_prop(
&impl_dev->prop_list,
&sf_map.sf_addr_pair[i].sf_inq_dtype, 0,
PROP_NOEXIST)) != 0) {
(void) close(fd);
g_dev_map_fini(impl_map);
*l_err = err;
return (NULL);
}
}
}
impl_map->child = mdl_start;
}
close(fd);
return ((gfc_dev_t)(impl_map));
}
static void
free_prop_list(impl_map_dev_prop_t **prop_list)
{
impl_map_dev_prop_t *lp, *olp;
lp = *prop_list;
while (lp != NULL) {
switch (lp->prop_type) {
case GFC_PROP_TYPE_BYTES:
free((uchar_t *)(lp->prop_data));
break;
case GFC_PROP_TYPE_INT:
free((int *)(lp->prop_data));
break;
case GFC_PROP_TYPE_STRING:
free((char *)(lp->prop_data));
break;
default:
break;
}
lp->prop_data = NULL;
olp = lp;
lp = olp->next;
S_FREE(olp);
}
*prop_list = NULL;
}
static void
free_child_list(impl_map_dev_t **dev_list)
{
impl_map_dev_t *lp, *olp;
lp = *dev_list;
while (lp != NULL) {
free_prop_list(&lp->prop_list);
olp = lp;
lp = olp->next;
S_FREE(olp);
}
*dev_list = NULL;
}
void
g_dev_map_fini(gfc_dev_t map)
{
impl_map_dev_t *impl_map;
impl_map = (impl_map_dev_t *)map;
if (impl_map != NULL) {
free_prop_list(&impl_map->prop_list);
free_child_list(&impl_map->child);
S_FREE(impl_map);
}
}
int
g_get_map_topology(gfc_dev_t map, uint_t *topology)
{
impl_map_dev_t *impl_map;
if (map == NULL) {
return (L_INVALID_MAP_DEV_ADDR);
}
if (topology == NULL) {
return (L_INVALID_ARG);
}
impl_map = (impl_map_dev_t *)map;
*topology = impl_map->topo;
return (0);
}
gfc_dev_t
g_get_first_dev(gfc_dev_t map, int *l_err)
{
impl_map_dev_t *impl_map;
if (l_err == NULL) {
return (NULL);
}
*l_err = 0;
if (map == NULL) {
*l_err = L_INVALID_MAP_DEV_ADDR;
return (NULL);
}
impl_map = (impl_map_dev_t *)map;
if (impl_map->child == NULL) {
*l_err = L_NO_SUCH_DEV_FOUND;
}
return ((gfc_dev_t)(impl_map->child));
}
gfc_dev_t
g_get_next_dev(gfc_dev_t map_dev, int *l_err)
{
impl_map_dev_t *impl_dev;
if (l_err == NULL) {
return (NULL);
}
*l_err = 0;
if (map_dev == NULL) {
*l_err = L_INVALID_MAP_DEV_ADDR;
return (NULL);
}
impl_dev = (impl_map_dev_t *)map_dev;
if (impl_dev->next == NULL) {
*l_err = L_NO_SUCH_DEV_FOUND;
}
return ((gfc_dev_t)(impl_dev->next));
}
int
g_dev_prop_lookup_bytes(gfc_dev_t map_dev, const char *prop_name,
int *prop_data_count, uchar_t **prop_data)
{
impl_map_dev_t *impl_dev;
impl_map_dev_prop_t *impl_prop;
int err;
if (map_dev == NULL) {
return (L_INVALID_MAP_DEV_ADDR);
}
if ((prop_name == NULL) || (prop_data == NULL) ||
(prop_data_count == NULL)) {
return (L_INVALID_ARG);
}
impl_dev = (impl_map_dev_t *)map_dev;
impl_prop = impl_dev->prop_list;
err = L_INVALID_MAP_DEV_PROP_NAME;
while (impl_prop) {
if (strncmp(impl_prop->prop_name, prop_name,
strlen(prop_name)) == 0) {
if (impl_prop->prop_type != GFC_PROP_TYPE_BYTES) {
err = L_INVALID_MAP_DEV_PROP_TYPE;
break;
}
if (impl_prop->prop_data) {
*prop_data = (uchar_t *)(impl_prop->prop_data);
*prop_data_count = impl_prop->prop_size;
return (0);
} else {
err = impl_prop->prop_error;
}
break;
}
impl_prop = impl_prop->next;
}
return (err);
}
int
g_dev_prop_lookup_ints(gfc_dev_t map_dev, const char *prop_name,
int **prop_data)
{
impl_map_dev_t *impl_dev;
impl_map_dev_prop_t *impl_prop;
int err;
if (map_dev == NULL) {
return (L_INVALID_MAP_DEV_ADDR);
}
if ((prop_name == NULL) || (prop_data == NULL)) {
return (L_INVALID_ARG);
}
impl_dev = (impl_map_dev_t *)map_dev;
impl_prop = impl_dev->prop_list;
err = L_INVALID_MAP_DEV_PROP_NAME;
while (impl_prop) {
if (strncmp(impl_prop->prop_name, prop_name,
strlen(prop_name)) == 0) {
if (impl_prop->prop_type != GFC_PROP_TYPE_INT) {
err = L_INVALID_MAP_DEV_PROP_TYPE;
break;
}
if (impl_prop->prop_data) {
*prop_data = (int *)(impl_prop->prop_data);
return (0);
} else {
err = impl_prop->prop_error;
}
break;
}
impl_prop = impl_prop->next;
}
return (err);
}
int
g_dev_prop_lookup_strings(gfc_dev_t map_dev, const char *prop_name,
char **prop_data)
{
impl_map_dev_t *impl_dev;
impl_map_dev_prop_t *impl_prop;
int err;
if (map_dev == NULL) {
return (L_INVALID_MAP_DEV_ADDR);
}
if ((prop_name == NULL) || (prop_data == NULL)) {
return (L_INVALID_ARG);
}
impl_dev = (impl_map_dev_t *)map_dev;
impl_prop = impl_dev->prop_list;
err = L_INVALID_MAP_DEV_PROP_NAME;
while (impl_prop) {
if (strncmp(impl_prop->prop_name, prop_name,
strlen(prop_name)) == 0) {
if (impl_prop->prop_type != GFC_PROP_TYPE_STRING) {
err = L_INVALID_MAP_DEV_PROP_TYPE;
break;
}
if (impl_prop->prop_data) {
*prop_data = (char *)(impl_prop->prop_data);
return (0);
} else {
err = impl_prop->prop_error;
}
break;
}
impl_prop = impl_prop->next;
}
return (err);
}
gfc_prop_t
g_get_first_dev_prop(gfc_dev_t map_dev, int *l_err)
{
impl_map_dev_t *impl_dev;
if (l_err == NULL) {
return (NULL);
}
*l_err = 0;
if (map_dev == NULL) {
*l_err = L_INVALID_MAP_DEV_ADDR;
return (NULL);
}
impl_dev = (impl_map_dev_t *)map_dev;
if (impl_dev->prop_list == NULL) {
*l_err = L_NO_SUCH_PROP_FOUND;
}
return ((gfc_prop_t)(impl_dev->prop_list));
}
gfc_prop_t
g_get_next_dev_prop(gfc_prop_t map_prop, int *l_err)
{
impl_map_dev_prop_t *impl_prop;
if (l_err == NULL) {
return (NULL);
}
*l_err = 0;
if (map_prop == NULL) {
*l_err = L_INVALID_MAP_DEV_PROP;
return (NULL);
}
impl_prop = (impl_map_dev_prop_t *)map_prop;
if (impl_prop->next == NULL) {
*l_err = L_NO_SUCH_PROP_FOUND;
}
return ((gfc_prop_t)(impl_prop->next));
}
char *
g_get_dev_prop_name(gfc_prop_t map_prop, int *l_err)
{
impl_map_dev_prop_t *impl_prop;
if (l_err == NULL) {
return (NULL);
}
*l_err = 0;
if (map_prop == NULL) {
*l_err = L_INVALID_MAP_DEV_PROP;
return (NULL);
}
impl_prop = (impl_map_dev_prop_t *)map_prop;
return (impl_prop->prop_name);
}
int
g_get_dev_prop_type(gfc_prop_t map_prop, int *l_err)
{
impl_map_dev_prop_t *impl_prop;
if (l_err != NULL) {
*l_err = 0;
} else {
return (L_INVALID_ARG);
}
if (map_prop == NULL) {
*l_err = L_INVALID_MAP_DEV_PROP;
return (GFC_PROP_TYPE_UNKNOWN);
}
impl_prop = (impl_map_dev_prop_t *)map_prop;
return (impl_prop->prop_type);
}
int
g_get_dev_prop_bytes(gfc_prop_t map_prop, int *prop_data_count,
uchar_t **prop_data)
{
impl_map_dev_prop_t *impl_prop;
if (map_prop == NULL) {
return (L_INVALID_MAP_DEV_ADDR);
}
if ((prop_data == NULL) || (prop_data_count == NULL)) {
return (L_INVALID_ARG);
}
impl_prop = (impl_map_dev_prop_t *)map_prop;
if (impl_prop->prop_type != GFC_PROP_TYPE_BYTES) {
return (L_INVALID_MAP_DEV_PROP_TYPE);
}
if (impl_prop->prop_data) {
*prop_data = (uchar_t *)(impl_prop->prop_data);
*prop_data_count = impl_prop->prop_size;
} else {
return (impl_prop->prop_error);
}
return (0);
}
int
g_get_dev_prop_ints(gfc_prop_t map_prop, int **prop_data)
{
impl_map_dev_prop_t *impl_prop;
if (map_prop == NULL) {
return (L_INVALID_MAP_DEV_ADDR);
}
if (prop_data == NULL) {
return (L_INVALID_ARG);
}
impl_prop = (impl_map_dev_prop_t *)map_prop;
if (impl_prop->prop_type != GFC_PROP_TYPE_INT) {
return (L_INVALID_MAP_DEV_PROP_TYPE);
}
if (impl_prop->prop_data) {
*prop_data = (int *)(impl_prop->prop_data);
} else {
return (impl_prop->prop_error);
}
return (0);
}
int
g_get_dev_prop_strings(gfc_prop_t map_prop, char **prop_data)
{
impl_map_dev_prop_t *impl_prop;
if (map_prop == NULL) {
return (L_INVALID_MAP_DEV_ADDR);
}
if (prop_data == NULL) {
return (L_INVALID_ARG);
}
impl_prop = (impl_map_dev_prop_t *)map_prop;
if (impl_prop->prop_type != GFC_PROP_TYPE_STRING) {
return (L_INVALID_MAP_DEV_PROP_TYPE);
}
if (impl_prop->prop_data) {
*prop_data = (char *)(impl_prop->prop_data);
} else {
return (impl_prop->prop_error);
}
return (0);
}
static void
g_free_rls(AL_rls *rlsptr)
{
AL_rls *trlsptr;
while (rlsptr != NULL) {
trlsptr = rlsptr->next;
free(rlsptr);
rlsptr = trlsptr;
}
}
int
g_rdls(char *path_phys, struct al_rls **rls_ptr, int verbose)
{
char nexus_path[MAXPATHLEN], *nexus_path_ptr;
int fd, fp_fd, err, length, exp_map_flag = 0, *port_addr;
struct lilpmap map;
AL_rls *rls, *c1 = NULL, *c2 = NULL;
uchar_t i, *port_wwn_byte;
la_wwn_t port_wwn;
sf_al_map_t exp_map;
char *charPtr, fp_path[MAXPATHLEN];
uint_t dev_type;
struct stat stbuf;
fcio_t fcio;
fc_portid_t rls_req;
fc_rls_acc_t rls_payload;
gfc_dev_t map_root, map_dev;
uint32_t hba_port_top, state;
int pathcnt = 1, count;
mp_pathlist_t pathlist;
int p_on = 0, p_st = 0;
if (path_phys == NULL) {
return (L_INVALID_PATH);
}
if (rls_ptr == NULL) {
return (L_INVALID_ARG);
}
*rls_ptr = rls = NULL;
if (strstr(path_phys, SCSI_VHCI) != NULL) {
(void) strcpy(fp_path, path_phys);
if (g_get_pathlist(fp_path, &pathlist)) {
return (L_INVALID_PATH);
}
pathcnt = pathlist.path_count;
p_on = p_st = 0;
for (i = 0; i < pathcnt; i++) {
if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
if (pathlist.path_info[i].path_state ==
MDI_PATHINFO_STATE_ONLINE) {
p_on = i;
break;
} else if (pathlist.path_info[i].path_state ==
MDI_PATHINFO_STATE_STANDBY) {
p_st = i;
}
}
}
if (pathlist.path_info[p_on].path_state ==
MDI_PATHINFO_STATE_ONLINE) {
(void) strcpy(fp_path,
pathlist.path_info[p_on].path_hba);
} else {
(void) strcpy(fp_path,
pathlist.path_info[p_st].path_hba);
}
free(pathlist.path_info);
} else {
(void) strcpy(fp_path, path_phys);
}
if ((dev_type = g_get_path_type(fp_path)) == 0) {
return (L_INVALID_PATH);
}
if (dev_type & FC_FCA_MASK) {
if (strstr(path_phys, SCSI_VHCI) != NULL) {
(void) strcat(fp_path, FC_CTLR);
} else if (strstr(fp_path, DRV_NAME_SSD) ||
strstr(fp_path, DRV_NAME_ST) ||
strstr(fp_path, SES_NAME)) {
if ((charPtr = strrchr(fp_path, '/')) == NULL) {
return (L_INVALID_PATH);
}
*charPtr = '\0';
(void) strcat(fp_path, FC_CTLR);
} else {
if (stat(fp_path, &stbuf) < 0) {
return (L_LSTAT_ERROR);
}
if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
(void) strcat(fp_path, FC_CTLR);
}
}
if ((map_root = g_dev_map_init(fp_path, &err,
MAP_XPORT_PROP_ONLY)) == NULL) {
return (err);
}
} else {
(void) memset(&map, 0, sizeof (struct lilpmap));
if ((err = g_get_nexus_path(path_phys,
&nexus_path_ptr)) != 0) {
return (err);
}
(void) strcpy(nexus_path, nexus_path_ptr);
g_destroy_data(nexus_path_ptr);
if ((fd = g_object_open(nexus_path,
O_NDELAY | O_RDONLY)) == -1)
return (errno);
if (ioctl(fd, FCIO_GETMAP, &map) != 0) {
I_DPRINTF(" FCIO_GETMAP ioctl failed.\n");
if (ioctl(fd, SFIOCGMAP, &exp_map) != 0) {
I_DPRINTF(" SFIOCGMAP ioctl failed.\n");
(void) close(fd);
return (L_SFIOCGMAP_IOCTL_FAIL);
}
if ((exp_map.sf_count > 126) ||
(exp_map.sf_count < 0)) {
(void) close(fd);
return (L_INVALID_LOOP_MAP);
}
for (i = 0; i < exp_map.sf_count; i++) {
if (exp_map.sf_addr_pair[i].sf_al_pa > 0xef) {
(void) close(fd);
return (L_INVALID_LOOP_MAP);
}
}
length = exp_map.sf_count;
exp_map_flag++;
} else {
I_DPRINTF(" g_rdls:"
" FCIO_GETMAP ioctl returned %d entries.\n",
map.lilp_length);
if (map.lilp_length > sizeof (map.lilp_list)) {
(void) close(fd);
return (L_FCIOGETMAP_INVLD_LEN);
}
length = map.lilp_length;
}
for (i = 0; i < length; i++) {
if ((c2 = (struct al_rls *)
g_zalloc(sizeof (struct al_rls))) == NULL) {
close(fd);
return (L_MALLOC_FAILED);
}
if (rls == NULL) {
c1 = rls = c2;
} else {
for (c1 = rls; c1->next; c1 = c1->next) {};
c1 = c1->next = c2;
}
(void) strcpy(c1->driver_path, nexus_path);
if (exp_map_flag) {
c1->payload.rls_portno = c1->al_ha =
exp_map.sf_addr_pair[i].sf_al_pa;
} else {
c1->payload.rls_portno = c1->al_ha =
map.lilp_list[i];
}
c1->payload.rls_linkfail =
(uint_t)0xff000000;
I_DPRINTF(" g_rdls:"
" al_pa 0x%x\n", c1->payload.rls_portno);
if (ioctl(fd, FCIO_LINKSTATUS, &c1->payload) != 0) {
if ((dev_type & FC4_PCI_FCA) &&
(errno == ENXIO)) {
c1->payload.rls_linkfail =
c1->payload.rls_syncfail =
c1->payload.rls_sigfail =
c1->payload.rls_primitiverr =
c1->payload.rls_invalidword =
c1->payload.rls_invalidcrc =
(uint_t)0xffffffff;
} else {
I_DPRINTF(" FCIO_LINKSTATUS ioctl"
" failed with errno %d.\n", errno);
g_free_rls(rls);
(void) close(fd);
return (L_FCIO_LINKSTATUS_FAILED);
}
}
I_DPRINTF(" g_rdls: al_pa returned by ioctl 0x%x\n",
c1->payload.rls_portno);
}
*rls_ptr = rls;
(void) close(fd);
return (0);
}
if ((err = g_get_map_topology(map_root, &hba_port_top)) != 0) {
g_dev_map_fini(map_root);
return (err);
}
if ((map_dev = g_get_first_dev(map_root, &err)) == NULL) {
g_dev_map_fini(map_root);
if (err != L_NO_SUCH_DEV_FOUND) {
return (err);
} else {
return (L_NO_DEVICES_FOUND);
}
}
while (map_dev) {
if ((err = g_dev_prop_lookup_ints(
map_dev, PORT_ADDR_PROP, &port_addr)) != 0) {
g_dev_map_fini(map_root);
g_free_rls(rls);
return (err);
}
if ((c2 = (struct al_rls *)
g_zalloc(sizeof (struct al_rls))) == NULL) {
g_dev_map_fini(map_root);
g_free_rls(rls);
close(fd);
return (L_MALLOC_FAILED);
}
if (rls == NULL) {
c1 = rls = c2;
} else {
for (c1 = rls; c1->next; c1 = c1->next) {};
c1 = c1->next = c2;
}
c1->al_ha = rls_req.port_id = *port_addr;
if ((hba_port_top == FC_TOP_FABRIC) ||
(hba_port_top == FC_TOP_PUBLIC_LOOP)) {
if ((err = g_dev_prop_lookup_bytes(
map_dev, PORT_WWN_PROP, &count,
&port_wwn_byte)) != 0) {
g_dev_map_fini(map_root);
g_free_rls(rls);
return (err);
}
memcpy(port_wwn.raw_wwn, port_wwn_byte, FC_WWN_SIZE);
if ((err = g_get_dev_port_state(
fp_path, port_wwn, &state)) == 0) {
if (state != PORT_DEVICE_LOGGED_IN) {
if ((err = g_dev_login(fp_path,
port_wwn)) != 0) {
c1->payload.rls_linkfail =
c1->payload.rls_syncfail =
c1->payload.rls_sigfail =
c1->payload.rls_primitiverr =
c1->payload.rls_invalidword =
c1->payload.rls_invalidcrc =
(uint_t)0xffffffff;
if (((map_dev =
g_get_next_dev(map_dev,
&err))
== NULL) &&
(err !=
L_NO_SUCH_DEV_FOUND)) {
g_dev_map_fini(
map_root);
g_free_rls(rls);
return (err);
}
continue;
}
}
}
}
fcio.fcio_cmd_flags = FCIO_CFLAGS_RLS_DEST_NPORT;
if ((fp_fd = g_object_open(fp_path, O_RDONLY | O_EXCL)) < 0) {
g_dev_map_fini(map_root);
g_free_rls(rls);
return (L_OPEN_PATH_FAIL);
}
fcio.fcio_cmd = FCIO_LINK_STATUS;
fcio.fcio_ibuf = (caddr_t)&rls_req;
fcio.fcio_ilen = sizeof (rls_req);
fcio.fcio_xfer = FCIO_XFER_RW;
fcio.fcio_flags = 0;
fcio.fcio_obuf = (caddr_t)&rls_payload;
fcio.fcio_olen = sizeof (rls_payload);
if (g_issue_fcio_ioctl(fp_fd, &fcio, verbose) != 0) {
c1->payload.rls_linkfail =
c1->payload.rls_syncfail =
c1->payload.rls_sigfail =
c1->payload.rls_primitiverr =
c1->payload.rls_invalidword =
c1->payload.rls_invalidcrc = (uint_t)0xffffffff;
} else {
c1->payload.rls_linkfail = rls_payload.rls_link_fail;
c1->payload.rls_syncfail = rls_payload.rls_sync_loss;
c1->payload.rls_sigfail = rls_payload.rls_sig_loss;
c1->payload.rls_primitiverr =
rls_payload.rls_prim_seq_err;
c1->payload.rls_invalidword =
rls_payload.rls_invalid_word;
c1->payload.rls_invalidcrc =
rls_payload.rls_invalid_crc;
}
(void) close(fp_fd);
if (((map_dev = g_get_next_dev(map_dev, &err)) == NULL) &&
(err != L_NO_SUCH_DEV_FOUND)) {
g_dev_map_fini(map_root);
g_free_rls(rls);
return (err);
}
}
if ((err = g_dev_prop_lookup_ints(
map_root, PORT_ADDR_PROP, &port_addr)) != 0) {
g_dev_map_fini(map_root);
g_free_rls(rls);
return (err);
}
if ((c2 = (struct al_rls *)
g_zalloc(sizeof (struct al_rls))) == NULL) {
g_dev_map_fini(map_root);
g_free_rls(rls);
return (L_MALLOC_FAILED);
}
if (rls == NULL) {
c1 = rls = c2;
} else {
for (c1 = rls; c1->next; c1 = c1->next) {};
c1 = c1->next = c2;
}
c1->al_ha = rls_req.port_id = *port_addr;
if ((fp_fd = g_object_open(fp_path, O_RDONLY | O_EXCL)) < 0) {
g_dev_map_fini(map_root);
g_free_rls(rls);
return (L_OPEN_PATH_FAIL);
}
fcio.fcio_cmd = FCIO_LINK_STATUS;
fcio.fcio_ibuf = (caddr_t)&rls_req;
fcio.fcio_ilen = sizeof (rls_req);
fcio.fcio_xfer = FCIO_XFER_RW;
fcio.fcio_flags = 0;
fcio.fcio_cmd_flags = FCIO_CFLAGS_RLS_DEST_NPORT;
fcio.fcio_obuf = (caddr_t)&rls_payload;
fcio.fcio_olen = sizeof (rls_payload);
if (g_issue_fcio_ioctl(fp_fd, &fcio, verbose) != 0) {
c1->payload.rls_linkfail =
c1->payload.rls_syncfail =
c1->payload.rls_sigfail =
c1->payload.rls_primitiverr =
c1->payload.rls_invalidword =
c1->payload.rls_invalidcrc = (uint_t)0xffffffff;
} else {
c1->payload.rls_linkfail = rls_payload.rls_link_fail;
c1->payload.rls_syncfail = rls_payload.rls_sync_loss;
c1->payload.rls_sigfail = rls_payload.rls_sig_loss;
c1->payload.rls_primitiverr = rls_payload.rls_prim_seq_err;
c1->payload.rls_invalidword = rls_payload.rls_invalid_word;
c1->payload.rls_invalidcrc = rls_payload.rls_invalid_crc;
(void) close(fp_fd);
}
(void) close(fp_fd);
*rls_ptr = rls;
g_dev_map_fini(map_root);
return (0);
}
static u_longlong_t wwnConversion(uchar_t *wwn)
{
u_longlong_t tmp;
memcpy(&tmp, wwn, sizeof (u_longlong_t));
return (tmp);
}
static int
get_wwns(char *path_phys, uchar_t port_wwn[], uchar_t node_wwn[], int *al_pa,
struct wwn_list_found_struct **wwn_list_found)
{
uint32_t hba_port_top;
int i, err, count;
char *char_ptr, *ptr;
int found = 0, pathcnt, *port_addr;
unsigned long long pwwn;
uchar_t *port_wwn_byte, *node_wwn_byte;
char drvr_path[MAXPATHLEN];
int p_on = 0, p_st = 0;
mp_pathlist_t pathlist;
char pwwn1[WWN_S_LEN];
gfc_dev_t map_root, map_dev;
hrtime_t start_time, end_time;
char *env = NULL;
P_DPRINTF(" g_get_wwn: Getting device WWN"
" and al_pa for device: %s\n",
path_phys);
if ((env = getenv("_LUX_T_DEBUG")) != NULL) {
start_time = gethrtime();
}
if ((char_ptr = strrchr(path_phys, '@')) == NULL) {
return (L_INVLD_PATH_NO_ATSIGN_FND);
}
char_ptr++;
(void) strcpy(drvr_path, path_phys);
if (strstr(drvr_path, SCSI_VHCI)) {
if (g_get_pathlist(drvr_path, &pathlist)) {
return (L_INVALID_PATH);
}
pathcnt = pathlist.path_count;
p_on = p_st = 0;
for (i = 0; i < pathcnt; i++) {
if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
if (pathlist.path_info[i].path_state ==
MDI_PATHINFO_STATE_ONLINE) {
p_on = i;
break;
} else if (pathlist.path_info[i].path_state ==
MDI_PATHINFO_STATE_STANDBY) {
p_st = i;
}
}
}
if (p_on == i) {
(void) strcpy(drvr_path,
pathlist.path_info[p_on].path_hba);
(void) strncpy(pwwn1,
pathlist.path_info[p_on].path_addr,
WWN_S_LEN - 1);
pwwn1[WWN_S_LEN - 1] = '\0';
} else {
(void) strcpy(drvr_path,
pathlist.path_info[p_st].path_hba);
(void) strncpy(pwwn1,
pathlist.path_info[p_st].path_addr,
WWN_S_LEN - 1);
pwwn1[WWN_S_LEN - 1] = '\0';
}
free(pathlist.path_info);
(void) strcat(drvr_path, FC_CTLR);
}
if ((map_root = g_dev_map_init(drvr_path, &err,
MAP_XPORT_PROP_ONLY)) == NULL) {
return (err);
}
if ((err = g_get_map_topology(map_root, &hba_port_top)) != 0) {
g_dev_map_fini(map_root);
return (err);
}
if (strstr(path_phys, SCSI_VHCI)) {
char_ptr = pwwn1;
} else {
if (*char_ptr != 'w') {
g_dev_map_fini(map_root);
return (L_INVLD_WWN_FORMAT);
}
char_ptr++;
}
pwwn = strtoull(char_ptr, &ptr, 16);
if (ptr == char_ptr) {
g_dev_map_fini(map_root);
return (L_NO_WWN_FOUND_IN_PATH);
}
P_DPRINTF(" g_get_wwn: Looking for WWN "
"0x%llx\n", pwwn);
if (((map_dev = g_get_first_dev(map_root, &err)) == NULL) &&
(err != L_NO_SUCH_DEV_FOUND)) {
g_dev_map_fini(map_root);
return (err);
}
while (map_dev) {
if ((err = g_dev_prop_lookup_bytes(map_dev,
PORT_WWN_PROP, &count, &port_wwn_byte)) != 0) {
g_dev_map_fini(map_root);
return (err);
}
if ((err = g_dev_prop_lookup_bytes(map_dev,
NODE_WWN_PROP, &count, &node_wwn_byte)) != 0) {
g_dev_map_fini(map_root);
return (err);
}
if (pwwn == wwnConversion(port_wwn_byte) && found != 1) {
found = 1;
memcpy(port_wwn, port_wwn_byte, FC_WWN_SIZE);
memcpy(node_wwn, node_wwn_byte, FC_WWN_SIZE);
if ((err = g_dev_prop_lookup_ints(
map_dev, PORT_ADDR_PROP, &port_addr)) != 0) {
g_dev_map_fini(map_root);
return (err);
}
*al_pa = *port_addr;
}
add_wwn_entry(wwn_list_found, port_wwn_byte,
node_wwn_byte);
if (((map_dev = g_get_next_dev(map_dev, &err)) == NULL) &&
(err != L_NO_SUCH_DEV_FOUND)) {
g_dev_map_fini(map_root);
return (err);
}
}
if (!found) {
g_dev_map_fini(map_root);
return (L_NO_LOOP_ADDRS_FOUND);
}
g_dev_map_fini(map_root);
if (env != NULL) {
end_time = gethrtime();
fprintf(stdout, " get_wwns: "
"\t\tTime = %lld millisec\n",
(end_time - start_time)/1000000);
}
return (0);
}
int
g_get_wwn(char *path_phys, uchar_t port_wwn[], uchar_t node_wwn[],
int *al_pa, int verbose)
{
struct wwn_list_found_struct *wwn_list_found = NULL;
int ret;
if (path_phys == NULL) {
return (L_INVALID_PATH);
}
if ((port_wwn == NULL) || (node_wwn == NULL) || (al_pa == NULL)) {
return (L_INVALID_ARG);
}
ret = get_wwns(path_phys, port_wwn, node_wwn, al_pa, &wwn_list_found);
g_free_wwn_list_found(&wwn_list_found);
return (ret);
}
int
g_get_serial_number(char *path, uchar_t *serial_number,
size_t *serial_number_len)
{
int fd, status = 0;
L_inquiry80 inq80;
if (path == NULL) {
return (L_INVALID_PATH);
}
if (serial_number == NULL) {
return (L_INVALID_ARG);
}
P_DPRINTF(" g_get_serial_number: path: %s\n", path);
if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1) {
return (L_OPEN_PATH_FAIL);
}
if ((g_find_supported_inq_page(fd, 0x80))) {
status = g_scsi_inquiry_cmd80(fd,
(uchar_t *)&inq80,
sizeof (struct l_inquiry80_struct));
if (status == 0) {
if (*serial_number_len > inq80.inq_page_len)
*serial_number_len = inq80.inq_page_len;
strncpy((char *)serial_number, (char *)inq80.inq_serial,
*serial_number_len);
} else {
char unavail[] = "Unavailable";
status = 0;
if (*serial_number_len > strlen(unavail))
*serial_number_len = strlen(unavail);
strncpy((char *)serial_number, unavail,
*serial_number_len);
}
} else {
char unsupp[] = "Unsupported";
if (*serial_number_len > strlen(unsupp))
*serial_number_len = strlen(unsupp);
strncpy((char *)serial_number, unsupp,
*serial_number_len);
}
(void) close(fd);
return (status);
}
int
g_get_inquiry(char *path, L_inquiry *l_inquiry)
{
int fd, status;
if (path == NULL) {
return (L_INVALID_PATH);
}
if (l_inquiry == NULL) {
return (L_INVALID_ARG);
}
P_DPRINTF(" g_get_inquiry: path: %s\n", path);
if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
return (L_OPEN_PATH_FAIL);
status = g_scsi_inquiry_cmd(fd,
(uchar_t *)l_inquiry, sizeof (struct l_inquiry_struct));
(void) close(fd);
return (status);
}
static int
g_scsi_inquiry_cmd80(int fd, uchar_t *buf_ptr, int buf_len)
{
struct uscsi_cmd ucmd;
my_cdb_g0 cdb = {SCMD_INQUIRY, 0x1, 0x80, 0, 0x10, 0};
struct scsi_extended_sense sense;
(void) memset(buf_ptr, 0, buf_len);
(void) memset((char *)&ucmd, 0, sizeof (ucmd));
cdb.count = (uchar_t)buf_len;
ucmd.uscsi_cdb = (caddr_t)&cdb;
ucmd.uscsi_cdblen = CDB_GROUP0;
ucmd.uscsi_bufaddr = (caddr_t)buf_ptr;
ucmd.uscsi_buflen = buf_len;
ucmd.uscsi_rqbuf = (caddr_t)&sense;
ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense);
ucmd.uscsi_timeout = 60;
return (cmd(fd, &ucmd, USCSI_READ | USCSI_SILENT));
}
static int
g_find_supported_inq_page(int fd, int page_num)
{
struct uscsi_cmd ucmd;
my_cdb_g0 cdb = {SCMD_INQUIRY, 0x1, 0, 0, 0xff, 0};
struct scsi_extended_sense sense;
L_inquiry00 inq00;
uchar_t *data;
int status = 0;
int index;
(void) memset((char *)&ucmd, 0, sizeof (ucmd));
cdb.count = (uchar_t)(sizeof (L_inquiry00));
ucmd.uscsi_cdb = (caddr_t)&cdb;
ucmd.uscsi_cdblen = CDB_GROUP0;
ucmd.uscsi_bufaddr = (caddr_t)&inq00;
ucmd.uscsi_buflen = sizeof (inq00);
ucmd.uscsi_rqbuf = (caddr_t)&sense;
ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense);
ucmd.uscsi_timeout = 60;
status = cmd(fd, &ucmd, USCSI_READ | USCSI_SILENT);
if (status) {
return (0);
}
data = (uchar_t *)&inq00;
for (index = 4; (index <= inq00.len+3)&&
(data[index] <= page_num); index ++) {
if (data[index] == page_num) {
return (1);
}
}
return (0);
}
int
g_get_perf_statistics(char *path, uchar_t *perf_ptr)
{
int fd;
P_DPRINTF(" g_get_perf_statistics: Get Performance Statistics:"
"\n Path:%s\n",
path);
(void) memset(perf_ptr, 0, sizeof (int));
if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
return (L_OPEN_PATH_FAIL);
(void) close(fd);
return (0);
}
int
g_start(char *path)
{
int status;
int fd;
P_DPRINTF(" g_start: Start: Path %s\n", path);
if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
return (L_OPEN_PATH_FAIL);
status = g_scsi_start_cmd(fd);
(void) close(fd);
return (status);
}
int
g_stop(char *path, int immediate_flag)
{
int status, fd;
P_DPRINTF(" g_stop: Stop: Path %s\n", path);
if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
return (errno);
status = g_scsi_stop_cmd(fd, immediate_flag);
(void) close(fd);
return (status);
}
int
g_reserve(char *path)
{
int fd, status;
P_DPRINTF(" g_reserve: Reserve: Path %s\n", path);
if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
return (L_OPEN_PATH_FAIL);
status = g_scsi_reserve_cmd(fd);
(void) close(fd);
return (status);
}
int
g_release(char *path)
{
int fd, status;
P_DPRINTF(" g_release: Release: Path %s\n", path);
if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
return (L_OPEN_PATH_FAIL);
status = g_scsi_release_cmd(fd);
(void) close(fd);
return (status);
}
static char
ctoi(char c)
{
if ((c >= '0') && (c <= '9'))
c -= '0';
else if ((c >= 'A') && (c <= 'F'))
c = c - 'A' + 10;
else if ((c >= 'a') && (c <= 'f'))
c = c - 'a' + 10;
else
c = -1;
return (c);
}
int
g_string_to_wwn(uchar_t *wwn, uchar_t *wwnp)
{
int i;
char c, c1;
*wwnp++ = 0;
*wwnp++ = 0;
for (i = 0; i < WWN_SIZE - 2; i++, wwnp++) {
c = ctoi(*wwn++);
c1 = ctoi(*wwn++);
if (c == -1 || c1 == -1)
return (-1);
*wwnp = ((c << 4) + c1);
}
return (0);
}
int
string_to_wwn(uchar_t *string, uchar_t *wwn)
{
int i;
char c, c1;
uchar_t *wwnp;
wwnp = wwn;
for (i = 0; i < WWN_SIZE; i++, wwnp++) {
c = ctoi(*string++);
c1 = ctoi(*string++);
if (c == -1 || c1 == -1)
return (-1);
*wwnp = ((c << 4) + c1);
}
return (0);
}
int
g_get_port_multipath(char *port_wwn_s, struct dlist **dlh, int verbose)
{
int err;
WWN_list *wwn_list, *wwn_list_ptr;
struct dlist *dlt, *dl;
dl = *dlh = dlt = (struct dlist *)NULL;
wwn_list = wwn_list_ptr = NULL;
H_DPRINTF(" g_get_port_multipath: Looking for multiple paths for"
" device with\n port WWW:"
"%s\n", port_wwn_s);
if (err = g_get_wwn_list(&wwn_list, verbose)) {
return (err);
}
for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL;
wwn_list_ptr = wwn_list_ptr->wwn_next) {
if (strcmp(port_wwn_s, wwn_list_ptr->port_wwn_s) == 0) {
if ((dl = (struct dlist *)
g_zalloc(sizeof (struct dlist))) == NULL) {
while (*dlh != NULL) {
dl = (*dlh)->next;
(void) g_destroy_data(*dlh);
*dlh = dl;
}
(void) g_free_wwn_list(&wwn_list);
return (L_MALLOC_FAILED);
}
H_DPRINTF(" g_get_port_multipath:"
" Found multipath:\n %s\n",
wwn_list_ptr->physical_path);
dl->dev_path = strdup(wwn_list_ptr->physical_path);
dl->logical_path = strdup(wwn_list_ptr->logical_path);
if (*dlh == NULL) {
*dlh = dlt = dl;
} else {
dlt->next = dl;
dl->prev = dlt;
dlt = dl;
}
}
}
(void) g_free_wwn_list(&wwn_list);
return (0);
}
int
g_get_multipath(char *devpath, struct dlist **multipath_list,
struct wwn_list_struct *wwn_list, int verbose)
{
int err;
H_DPRINTF(" g_get_multipath: Looking for multiple paths for"
" device at path: %s\n", devpath);
if (devpath == NULL) {
return (L_INVALID_PATH);
}
if ((multipath_list == NULL) || (wwn_list == NULL)) {
return (L_INVALID_ARG);
}
if (strstr(devpath, DRV_NAME_SSD) != NULL) {
err = get_multipath_disk(devpath, multipath_list, wwn_list);
} else {
err = get_multipath(devpath, multipath_list, wwn_list);
}
return (err);
}
int
get_multipath_disk(char *devpath, struct dlist **multipath_list,
struct wwn_list_struct *wwn_list)
{
WWN_list *wwn_list_ptr;
struct dlist *dl = NULL, *dlt = NULL;
ddi_devid_t devid = NULL;
int err;
di_node_t root;
struct mplist_struct *mplistp = NULL, *mplisth = NULL;
if (wwn_list == NULL || multipath_list == NULL || devpath == NULL) {
return (L_NULL_WWN_LIST);
}
if ((root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
return (L_DEV_SNAPSHOT_FAILED);
}
if ((err = g_devid_get(devpath, &devid, root, SSD_DRVR_NAME)) != 0) {
di_fini(root);
return (err);
}
*multipath_list = (struct dlist *)NULL;
if ((err = devid_get_all(devid, root, SSD_DRVR_NAME, &mplisth)) != 0) {
di_fini(root);
return (err);
}
if (mplisth == NULL) {
di_fini(root);
return (L_NULL_WWN_LIST);
}
for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL;
wwn_list_ptr = wwn_list_ptr->wwn_next) {
for (mplistp = mplisth; mplistp != NULL;
mplistp = mplistp->next) {
if (strncmp(mplistp->devpath,
wwn_list_ptr->physical_path,
strlen(mplistp->devpath)) == 0) {
if ((dl = (struct dlist *)
calloc(1, sizeof (struct dlist))) == NULL) {
while (*multipath_list != NULL) {
dl = dlt->next;
g_destroy_data(dlt);
dlt = dl;
}
di_fini(root);
return (L_MALLOC_FAILED);
}
H_DPRINTF(
" g_get_multipath: Found multipath=%s\n",
wwn_list_ptr->physical_path);
dl->logical_path =
strdup(wwn_list_ptr->logical_path);
dl->dev_path =
strdup(wwn_list_ptr->physical_path);
if (*multipath_list == NULL) {
*multipath_list = dlt = dl;
} else {
dlt->next = dl;
dl->prev = dlt;
dlt = dl;
}
}
}
}
di_fini(root);
mplist_free(mplisth);
return (0);
}
int
get_multipath(char *devpath, struct dlist **multipath_list,
struct wwn_list_struct *wwn_list)
{
WWN_list *wwn_list_ptr;
struct dlist *dl, *dlt;
char path[MAXPATHLEN], m_phys_path[MAXPATHLEN], *ptr;
int len;
int lun_a = -1;
char node_wwn_s[WWN_S_LEN];
if (devpath == NULL) {
return (L_INVALID_PATH);
}
if ((ptr = strrchr(devpath, ':')) != NULL) {
len = strlen(devpath) - strlen(ptr);
(void) strncpy(path, devpath, len);
path[len] = '\0';
} else {
(void) strcpy(path, devpath);
}
*multipath_list = dl = dlt = (struct dlist *)NULL;
if (wwn_list == NULL) {
return (L_NULL_WWN_LIST);
}
*node_wwn_s = '\0';
for (wwn_list_ptr = wwn_list;
wwn_list_ptr != NULL;
wwn_list_ptr = wwn_list_ptr->wwn_next) {
if ((ptr = strrchr(wwn_list_ptr->physical_path, ':')) != NULL) {
len = strlen(wwn_list_ptr->physical_path) - strlen(ptr);
(void) strncpy(m_phys_path, wwn_list_ptr->physical_path,
len);
m_phys_path[len] = '\0';
} else {
(void) strcpy(m_phys_path, wwn_list_ptr->physical_path);
}
if (strcasecmp(m_phys_path, path) == 0) {
(void) strcpy(node_wwn_s, wwn_list_ptr->node_wwn_s);
break;
}
}
if (*node_wwn_s == '\0') {
H_DPRINTF("node_wwn_s is not found!\n");
return (L_NO_NODE_WWN_IN_WWNLIST);
}
lun_a = g_get_lun_number(wwn_list_ptr->physical_path);
for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL;
wwn_list_ptr = wwn_list_ptr->wwn_next) {
if ((strcmp(node_wwn_s, wwn_list_ptr->node_wwn_s) == 0) &&
((lun_a < 0) || (lun_a ==
g_get_lun_number(wwn_list_ptr->physical_path)))) {
if ((dl = (struct dlist *)
g_zalloc(sizeof (struct dlist))) == NULL) {
while (*multipath_list != NULL) {
dl = dlt->next;
(void) g_destroy_data(dlt);
dlt = dl;
}
return (L_MALLOC_FAILED);
}
H_DPRINTF(" g_get_multipath: Found multipath=%s\n",
wwn_list_ptr->physical_path);
dl->dev_path = strdup(wwn_list_ptr->physical_path);
dl->logical_path = strdup(wwn_list_ptr->logical_path);
if (*multipath_list == NULL) {
*multipath_list = dlt = dl;
} else {
dlt->next = dl;
dl->prev = dlt;
dlt = dl;
}
}
}
return (0);
}
void
g_free_multipath(struct dlist *dlh)
{
struct dlist *dl;
while (dlh != NULL) {
dl = dlh->next;
if (dlh->dev_path != NULL)
(void) g_destroy_data(dlh->dev_path);
if (dlh->logical_path != NULL)
(void) g_destroy_data(dlh->logical_path);
(void) g_destroy_data(dlh);
dlh = dl;
}
}
int
g_get_nexus_path(char *path_phys, char **nexus_path)
{
uchar_t port = 0;
int port_flag = 0, i = 0, pathcnt = 1;
char *char_ptr;
char drvr_path[MAXPATHLEN];
char buf[MAXPATHLEN];
char temp_buf[MAXPATHLEN];
struct stat stbuf;
uint_t path_type;
mp_pathlist_t pathlist;
int p_on = 0, p_st = 0;
if (path_phys == NULL) {
return (L_INVALID_PATH);
}
*nexus_path = NULL;
(void) strcpy(drvr_path, path_phys);
if (strstr(path_phys, SCSI_VHCI)) {
if (g_get_pathlist(drvr_path, &pathlist)) {
return (L_INVALID_PATH);
}
pathcnt = pathlist.path_count;
p_on = p_st = 0;
for (i = 0; i < pathcnt; i++) {
if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
if (pathlist.path_info[i].path_state ==
MDI_PATHINFO_STATE_ONLINE) {
p_on = i;
break;
} else if (pathlist.path_info[i].path_state ==
MDI_PATHINFO_STATE_STANDBY) {
p_st = i;
}
}
}
if (pathlist.path_info[p_on].path_state ==
MDI_PATHINFO_STATE_ONLINE) {
(void) strcpy(drvr_path,
pathlist.path_info[p_on].path_hba);
} else {
(void) strcpy(drvr_path,
pathlist.path_info[p_st].path_hba);
}
free(pathlist.path_info);
(void) strcat(drvr_path, FC_CTLR);
} else {
if (strstr(drvr_path, DRV_NAME_SSD) || strstr(drvr_path,
DRV_NAME_ST) || strstr(drvr_path, SES_NAME)) {
if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
return (L_INVALID_PATH);
}
*char_ptr = '\0';
}
path_type = g_get_path_type(drvr_path);
if (path_type & FC4_SF_XPORT) {
if ((char_ptr = strstr(drvr_path, "sf@")) == NULL) {
return (L_INVALID_PATH);
}
port = atoi(char_ptr + 3);
if (port > 1) {
return (L_INVLD_PORT_IN_PATH);
}
if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
return (L_INVALID_PATH);
}
*char_ptr = '\0';
port_flag++;
L_DPRINTF(" g_get_nexus_path:"
" sf driver in path so use port #%d.\n",
port);
} else if (path_type & FC_GEN_XPORT) {
if ((path_type & FC_FCA_MASK) == FC_FCA_MASK) {
return (L_INVALID_PATH_TYPE);
}
if ((char_ptr = strstr(drvr_path, "/fp@")) == NULL) {
return (L_INVALID_PATH);
}
*char_ptr = '\0';
}
if (stat(drvr_path, &stbuf) != 0) {
return (L_LSTAT_ERROR);
}
if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
if (port_flag) {
(void) sprintf(buf, ":%d", port);
} else {
(void) sprintf(temp_buf, "%s:0", drvr_path);
if (stat(temp_buf, &stbuf) != 0) {
(void) sprintf(buf, ":devctl");
} else {
ER_DPRINTF("Since a complete path"
" was not supplied "
"a default path is being"
" used:\n %s\n",
temp_buf);
(void) sprintf(buf, ":0");
}
}
(void) strcat(drvr_path, buf);
}
}
*nexus_path = g_alloc_string(drvr_path);
L_DPRINTF(" g_get_nexus_path: Nexus path = %s\n", drvr_path);
return (0);
}
int
g_get_fca_port_topology(char *path, uint32_t *port_top, int verbose)
{
fcio_t fcio;
int fd, i = 0, pathcnt = 1;
char drvr_path[MAXPATHLEN];
char *char_ptr;
struct stat stbuf;
uint_t dev_type;
mp_pathlist_t pathlist;
int p_on = 0, p_st = 0;
if (path == NULL) {
return (L_INVALID_PATH);
}
if (port_top == NULL) {
return (L_INVALID_ARG);
}
(void) strcpy(drvr_path, path);
if (strstr(path, SCSI_VHCI)) {
if (g_get_pathlist(drvr_path, &pathlist)) {
return (L_INVALID_PATH);
}
pathcnt = pathlist.path_count;
p_on = p_st = 0;
for (i = 0; i < pathcnt; i++) {
if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
if (pathlist.path_info[i].path_state ==
MDI_PATHINFO_STATE_ONLINE) {
p_on = i;
break;
} else if (pathlist.path_info[i].path_state ==
MDI_PATHINFO_STATE_STANDBY) {
p_st = i;
}
}
}
if (pathlist.path_info[p_on].path_state ==
MDI_PATHINFO_STATE_ONLINE) {
(void) strcpy(drvr_path,
pathlist.path_info[p_on].path_hba);
} else {
(void) strcpy(drvr_path,
pathlist.path_info[p_st].path_hba);
}
free(pathlist.path_info);
(void) strcat(drvr_path, FC_CTLR);
} else {
if ((strstr(drvr_path, DRV_NAME_SSD) ||
strstr(drvr_path, SES_NAME)) ||
strstr(drvr_path, DRV_NAME_ST)) {
if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
return (L_INVALID_PATH);
}
*char_ptr = '\0';
(void) strcat(drvr_path, FC_CTLR);
} else {
if (stat(drvr_path, &stbuf) < 0) {
return (L_LSTAT_ERROR);
}
if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
(void) strcat(drvr_path, FC_CTLR);
}
}
}
if ((dev_type = g_get_path_type(drvr_path)) == 0) {
return (L_INVALID_PATH);
}
if ((dev_type & FC4_XPORT_MASK) || (dev_type & FC4_FCA_MASK)) {
*port_top = FC_TOP_PRIVATE_LOOP;
return (0);
}
if (!(dev_type & FC_XPORT_MASK)) {
return (L_INVALID_PATH);
}
if ((fd = g_object_open(drvr_path, O_NDELAY | O_RDONLY)) == -1)
return (errno);
P_DPRINTF(" g_get_fca_port_topology: Geting topology from:"
" %s\n", drvr_path);
fcio.fcio_cmd = FCIO_GET_TOPOLOGY;
fcio.fcio_olen = sizeof (uint32_t);
fcio.fcio_xfer = FCIO_XFER_READ;
fcio.fcio_obuf = (caddr_t)port_top;
if (g_issue_fcio_ioctl(fd, &fcio, verbose) != 0) {
I_DPRINTF(" FCIO_GET_TOPOLOGY ioctl failed.\n");
close(fd);
return (L_FCIO_GET_TOPOLOGY_FAIL);
}
close(fd);
return (0);
}
static int
g_set_port_state(char *nexus_port_ptr, int cmd)
{
int path_type, fd;
if ((path_type = g_get_path_type(nexus_port_ptr)) == 0) {
return (L_INVALID_PATH);
}
if ((fd = g_object_open(nexus_port_ptr, O_NDELAY|O_RDONLY)) == -1) {
return (L_OPEN_PATH_FAIL);
}
switch (cmd) {
case PORT_OFFLINE:
if (path_type & FC4_SOCAL_FCA) {
if (ioctl(fd, FCIO_LOOPBACK_INTERNAL,
NULL) == -1) {
close(fd);
return (L_PORT_OFFLINE_FAIL);
}
} else {
close(fd);
return (L_PORT_OFFLINE_UNSUPPORTED);
}
break;
case PORT_ONLINE:
if (path_type & FC4_SOCAL_FCA) {
if (ioctl(fd, FCIO_NO_LOOPBACK, NULL) == -1) {
close(fd);
return (L_PORT_ONLINE_FAIL);
}
} else {
close(fd);
return (L_PORT_ONLINE_UNSUPPORTED);
}
break;
default:
close(fd);
return (-1);
}
close(fd);
return (0);
}
int
g_port_offline(char *path)
{
return (g_set_port_state(path, PORT_OFFLINE));
}
int
g_port_online(char *path)
{
return (g_set_port_state(path, PORT_ONLINE));
}
int
g_loopback_mode(char *portpath, int cmd)
{
int path_type, fd;
if ((path_type = g_get_path_type(portpath)) == 0) {
return (L_INVALID_PATH);
}
if ((fd = g_object_open(portpath, O_NDELAY|O_RDONLY|O_EXCL)) == -1) {
return (L_OPEN_PATH_FAIL);
}
switch (cmd) {
case EXT_LPBACK:
if (path_type & FC4_SOCAL_FCA) {
if (ioctl(fd, FCIO_LOOPBACK_MANUAL,
NULL) == -1) {
if (errno != EALREADY) {
close(fd);
return (L_LOOPBACK_FAILED);
}
}
} else {
close(fd);
return (L_LOOPBACK_UNSUPPORTED);
}
break;
case NO_LPBACK:
if (path_type & FC4_SOCAL_FCA) {
if (ioctl(fd, FCIO_NO_LOOPBACK, NULL) == -1) {
close(fd);
return (L_LOOPBACK_FAILED);
}
} else {
close(fd);
return (L_LOOPBACK_UNSUPPORTED);
}
break;
case INT_LPBACK:
if (path_type & FC4_SOCAL_FCA) {
if (ioctl(fd, FCIO_LOOPBACK_INTERNAL,
NULL) == -1) {
if (errno != EALREADY) {
close(fd);
return (L_LOOPBACK_FAILED);
}
}
} else {
close(fd);
return (L_LOOPBACK_UNSUPPORTED);
}
break;
default:
close(fd);
return (L_LOOPBACK_UNSUPPORTED);
}
close(fd);
return (0);
}
int
g_get_port_state(char *portpath, int *portstate, int verbose)
{
int fd, err, num_devices = 0;
struct lilpmap map;
uint_t dev_type;
gfc_dev_t map_root;
(void) memset(&map, 0, sizeof (struct lilpmap));
if (portpath == NULL) {
return (L_INVALID_PATH);
}
if ((portpath == NULL) || (portstate == NULL)) {
return (L_INVALID_ARG);
}
if ((dev_type = g_get_path_type(portpath)) == 0) {
return (L_INVALID_PATH);
}
if (dev_type & FC_FCA_MASK) {
if ((map_root = g_dev_map_init(portpath, &err,
MAP_XPORT_PROP_ONLY)) == NULL) {
return (err);
}
if (g_get_first_dev(map_root, &err) == NULL) {
if (err == L_NO_SUCH_DEV_FOUND) {
*portstate = PORT_NOTCONNECTED;
}
g_dev_map_fini(map_root);
return (0);
} else {
*portstate = PORT_CONNECTED;
g_dev_map_fini(map_root);
}
} else {
if ((fd = g_object_open(portpath, O_NDELAY | O_RDONLY)) == -1) {
return (errno);
}
if (ioctl(fd, FCIO_GETMAP, &map) != 0) {
map.lilp_length = 0;
}
num_devices = map.lilp_length;
*portstate = (num_devices > 1) ? PORT_CONNECTED :
PORT_NOTCONNECTED;
(void) close(fd);
}
return (0);
}
int
g_dev_login(char *port_path, la_wwn_t port_wwn)
{
return (g_dev_log_in_out(port_path, port_wwn, FCIO_DEV_LOGIN));
}
int
g_dev_logout(char *port_path, la_wwn_t port_wwn)
{
return (g_dev_log_in_out(port_path, port_wwn, FCIO_DEV_LOGOUT));
}
static int
g_dev_log_in_out(char *port_path, la_wwn_t port_wwn, uint16_t cmd)
{
int fd, err;
uint32_t hba_port_top;
fcio_t fcio;
int verbose = 0;
if ((err = g_get_fca_port_topology(port_path,
&hba_port_top, verbose)) != 0) {
return (err);
}
if (!((hba_port_top == FC_TOP_PUBLIC_LOOP) ||
(hba_port_top == FC_TOP_FABRIC))) {
return (L_OPNOSUPP_ON_TOPOLOGY);
}
if ((fd = g_object_open(port_path, O_NDELAY | O_RDONLY | O_EXCL)) == -1)
return (L_OPEN_PATH_FAIL);
fcio.fcio_cmd = cmd;
fcio.fcio_ilen = sizeof (port_wwn);
fcio.fcio_ibuf = (caddr_t)&port_wwn;
fcio.fcio_xfer = FCIO_XFER_WRITE;
fcio.fcio_olen = fcio.fcio_alen = 0;
fcio.fcio_obuf = fcio.fcio_abuf = NULL;
if (g_issue_fcio_ioctl(fd, &fcio, verbose) != 0) {
I_DPRINTF((cmd == FCIO_DEV_LOGIN) ?
" FCIO_DEV_LOGIN ioctl failed.\n"
: " FCIO_DEV_LOGOUT ioctl failed.\n");
(void) close(fd);
return ((cmd == FCIO_DEV_LOGIN) ?
L_FCIO_DEV_LOGIN_FAIL
: L_FCIO_DEV_LOGOUT_FAIL);
} else {
(void) close(fd);
return (0);
}
}
int
g_wwn_in_dev_list(char *fca_path, la_wwn_t dev_wwn, int flag)
{
uint_t dev_type;
int i, err;
fc_port_dev_t *dev_list;
fc_port_dev_t *dev_list_save;
int num_devices = 0;
if ((dev_type = g_get_path_type(fca_path)) == 0) {
return (L_INVALID_PATH);
}
if (!(dev_type & FC_XPORT_MASK)) {
return (L_INVALID_PATH_TYPE);
}
if (((err = g_get_dev_list(fca_path, &dev_list, &num_devices))
!= 0) && (err != L_GET_DEV_LIST_ULP_FAILURE)) {
return (err);
}
dev_list_save = dev_list;
switch (flag) {
case MATCH_NODE_WWN:
for (i = 0; i < num_devices; i++, dev_list++) {
if (memcmp(dev_list->dev_nwwn.raw_wwn,
dev_wwn.raw_wwn, FC_WWN_SIZE) == 0) {
(void) free(dev_list_save);
return (0);
}
}
(void) free(dev_list_save);
return (L_WWN_NOT_FOUND_IN_DEV_LIST);
case MATCH_PORT_WWN:
for (i = 0; i < num_devices; i++, dev_list++) {
if (memcmp(dev_list->dev_pwwn.raw_wwn,
dev_wwn.raw_wwn, FC_WWN_SIZE) == 0) {
(void) free(dev_list_save);
return (0);
}
}
(void) free(dev_list_save);
return (L_WWN_NOT_FOUND_IN_DEV_LIST);
}
(void) free(dev_list_save);
return (-1);
}
static int
g_get_dev_port_state(char *fca_path, la_wwn_t port_wwn, uint32_t *state)
{
int fd;
int dev_type;
fcio_t fcio;
int verbose = 0;
if ((dev_type = g_get_path_type(fca_path)) == 0) {
return (L_INVALID_PATH);
}
if (!(dev_type & FC_XPORT_MASK)) {
return (L_INVALID_PATH_TYPE);
}
if ((fd = g_object_open(fca_path, O_NDELAY | O_RDONLY)) == -1)
return (L_OPEN_PATH_FAIL);
fcio.fcio_cmd = FCIO_GET_STATE;
fcio.fcio_ilen = sizeof (port_wwn);
fcio.fcio_ibuf = (caddr_t)&port_wwn;
fcio.fcio_xfer = FCIO_XFER_READ | FCIO_XFER_WRITE;
fcio.fcio_olen = sizeof (uint32_t);
fcio.fcio_obuf = (caddr_t)state;
fcio.fcio_alen = 0;
fcio.fcio_abuf = NULL;
if (g_issue_fcio_ioctl(fd, &fcio, verbose) != 0) {
I_DPRINTF(" FCIO_GET_STATE ioctl failed.\n");
(void) close(fd);
return (L_FCIO_GET_STATE_FAIL);
} else {
(void) close(fd);
return (0);
}
}
static int lilp_map_cmp(const void* dev1, const void* dev2) {
int i_dev1 = ((fc_port_dev_t *)dev1)->dev_did.priv_lilp_posit;
int i_dev2 = ((fc_port_dev_t *)dev2)->dev_did.priv_lilp_posit;
if (i_dev1 > i_dev2)
return (1);
if (i_dev1 < i_dev2)
return (-1);
return (0);
}
static int
devid_get_all(ddi_devid_t devid, di_node_t root, char *drvr_name,
struct mplist_struct **mplistp)
{
ddi_devid_t mydevid;
di_node_t node;
char *devfs_path = NULL;
struct mplist_struct *mpl, *mpln;
if (devid == NULL || root == NULL || drvr_name == NULL ||
mplistp == NULL ||
(strncmp(drvr_name, SSD_DRVR_NAME, strlen(SSD_DRVR_NAME))
!= 0)) {
return (EINVAL);
}
*mplistp = mpl = mpln = (struct mplist_struct *)NULL;
node = di_drv_first_node(drvr_name, root);
if (node == DI_NODE_NIL) {
return (L_NO_DRIVER_NODES_FOUND);
}
while (node != DI_NODE_NIL) {
if ((mydevid = di_devid(node)) != NULL) {
if (((devid_compare(mydevid, devid)) == 0)) {
if ((mpl = (struct mplist_struct *)
calloc(1, sizeof (struct mplist_struct)))
== NULL) {
mplist_free(*mplistp);
return (L_MALLOC_FAILED);
}
if ((devfs_path = my_devfs_path(node)) ==
NULL) {
node = di_drv_next_node(node);
S_FREE(mpl);
continue;
}
mpl->devpath = (char *)calloc(1,
strlen(devfs_path) +
strlen(SSD_MINOR_NAME) + 1);
if (mpl->devpath == NULL) {
S_FREE(mpl);
mplist_free(*mplistp);
my_devfs_path_free(devfs_path);
return (L_MALLOC_FAILED);
}
sprintf(mpl->devpath, "%s%s", devfs_path,
SSD_MINOR_NAME);
if (*mplistp == NULL) {
*mplistp = mpln = mpl;
} else {
mpln->next = mpl;
mpln = mpl;
}
my_devfs_path_free(devfs_path);
}
}
node = di_drv_next_node(node);
}
return (0);
}
static void
mplist_free(struct mplist_struct *mplistp)
{
struct mplist_struct *mplistn;
while (mplistp != NULL) {
mplistn = mplistp->next;
if (mplistp->devpath != NULL) {
free(mplistp->devpath);
mplistp->devpath = NULL;
}
free(mplistp);
mplistp = mplistn;
}
}
static int
devices_get_all(di_node_t root, char *drvr_name, char *minor_name,
struct wwn_list_struct **wwn_list_ptr)
{
di_node_t node;
char *devfs_path;
char devicepath[MAXPATHLEN];
uchar_t *nwwn = NULL, *pwwn = NULL;
uchar_t node_wwn[WWN_SIZE], port_wwn[WWN_SIZE];
WWN_list *wwn_list, *l1, *l2;
int scsi_vhci = 0;
int err, devtype;
if (root == DI_NODE_NIL || drvr_name == NULL ||
wwn_list_ptr == NULL) {
return (EINVAL);
}
wwn_list = *wwn_list_ptr = NULL;
memset(port_wwn, 0, sizeof (port_wwn));
memset(node_wwn, 0, sizeof (node_wwn));
if (strcmp(drvr_name, SSD_DRVR_NAME) == 0) {
devtype = DTYPE_DIRECT;
} else if (strcmp(drvr_name, ST_DRVR_NAME) == 0) {
devtype = DTYPE_SEQUENTIAL;
} else {
return (L_DRIVER_NOTSUPP);
}
node = di_drv_first_node(drvr_name, root);
if (node == DI_NODE_NIL) {
return (L_NO_DEVICES_FOUND);
}
while (node != DI_NODE_NIL) {
if ((devfs_path = my_devfs_path(node)) != NULL) {
if ((di_state(node) &
DI_DEVICE_OFFLINE) == DI_DEVICE_OFFLINE) {
my_devfs_path_free(devfs_path);
node = di_drv_next_node(node);
continue;
}
if (!strstr(devfs_path, SLSH_DRV_NAME_SSD) &&
!strstr(devfs_path, SLSH_DRV_NAME_ST)) {
my_devfs_path_free(devfs_path);
node = di_drv_next_node(node);
continue;
}
devicepath[0] = '\0';
sprintf(devicepath, "%s%s", devfs_path, minor_name);
if ((strstr(devicepath, SCSI_VHCI) == NULL)) {
if ((err = get_wwn_data(node, &nwwn, &pwwn)) !=
0) {
my_devfs_path_free(devfs_path);
return (err);
} else {
memcpy(node_wwn, nwwn,
sizeof (node_wwn));
memcpy(port_wwn, pwwn,
sizeof (port_wwn));
}
} else {
scsi_vhci++;
memset(port_wwn, 0, sizeof (port_wwn));
memset(node_wwn, 0, sizeof (node_wwn));
}
if ((l2 = (struct wwn_list_struct *)
calloc(1, sizeof (struct wwn_list_struct))) ==
NULL) {
my_devfs_path_free(devfs_path);
return (L_MALLOC_FAILED);
}
if ((l2->physical_path = (char *)
calloc(1, strlen(devicepath) +1)) == NULL) {
my_devfs_path_free(devfs_path);
return (L_MALLOC_FAILED);
}
memcpy(l2->w_node_wwn, node_wwn, WWN_SIZE);
if (scsi_vhci) {
strcpy(l2->node_wwn_s, MSGSTR(12000, "N/A"));
} else {
copy_wwn_data_to_str(l2->node_wwn_s, node_wwn);
copy_wwn_data_to_str(l2->port_wwn_s, port_wwn);
}
strcpy(l2->physical_path, devicepath);
l2->device_type = devtype;
if (wwn_list == NULL) {
l1 = wwn_list = l2;
} else {
l2->wwn_prev = l1;
l1 = l1->wwn_next = l2;
}
my_devfs_path_free(devfs_path);
scsi_vhci = 0;
}
node = di_drv_next_node(node);
}
*wwn_list_ptr = wwn_list;
if (*wwn_list_ptr == NULL) {
return (L_NO_DEVICES_FOUND);
} else {
if (strcmp(drvr_name, SSD_DRVR_NAME) == 0) {
if ((err = get_dev_path(wwn_list_ptr, DEV_RDIR,
DIR_MATCH_SSD)) != 0) {
g_free_wwn_list(wwn_list_ptr);
return (err);
}
} else if (strcmp(drvr_name, ST_DRVR_NAME) == 0) {
if ((err = get_dev_path(wwn_list_ptr, DEV_TAPE_DIR,
DIR_MATCH_ST)) != 0) {
g_free_wwn_list(wwn_list_ptr);
return (err);
}
}
return (0);
}
}
static int
get_wwn_data(di_node_t node, uchar_t **nwwn, uchar_t **pwwn)
{
if (di_prop_lookup_bytes(DDI_DEV_T_ANY, node, NODE_WWN_PROP,
nwwn) != WWN_SIZE) {
return (L_NO_WWN_PROP_FOUND);
}
if (di_prop_lookup_bytes(DDI_DEV_T_ANY, node, PORT_WWN_PROP,
pwwn) != WWN_SIZE) {
return (L_NO_WWN_PROP_FOUND);
}
return (0);
}
static int
get_dev_path(struct wwn_list_struct **wwn_list_ptr, char *dir_name,
char *pattern_match)
{
DIR *dirp;
struct dirent *entp;
char namebuf[MAXPATHLEN];
char *result = NULL;
WWN_list *wwn_list, *wwn_list_save;
char *env;
hrtime_t start_time, end_time;
if (wwn_list_ptr == NULL || *wwn_list_ptr == NULL ||
dir_name == NULL || pattern_match == NULL) {
return (EINVAL);
}
if ((env = getenv("_LUX_T_DEBUG")) != NULL) {
start_time = gethrtime();
}
wwn_list = *wwn_list_ptr;
if ((dirp = opendir(dir_name)) == NULL) {
P_DPRINTF(" get_dev_path: No devices found\n");
return (L_NO_DEVICES_FOUND);
}
while ((entp = readdir(dirp)) != NULL) {
if ((strcmp(entp->d_name, ".") == 0) ||
(strcmp(entp->d_name, "..") == 0) ||
(fnmatch(pattern_match, entp->d_name, 0) != 0))
continue;
memset(namebuf, 0, sizeof (namebuf));
sprintf(namebuf, "%s/%s", dir_name, entp->d_name);
if ((result = g_get_physical_name_from_link(namebuf)) == NULL) {
ER_DPRINTF(" Warning: Get physical name from"
" link failed. Link=%s\n", namebuf);
continue;
}
for (wwn_list = *wwn_list_ptr; wwn_list != NULL;
wwn_list = wwn_list->wwn_next) {
if (strcmp(wwn_list->physical_path, result) == 0) {
if ((wwn_list->logical_path = (char *)
calloc(1, strlen(namebuf) + 1)) == NULL) {
free(result);
return (L_MALLOC_FAILED);
}
strcpy(wwn_list->logical_path, namebuf);
break;
}
}
free(result);
}
closedir(dirp);
wwn_list = *wwn_list_ptr;
while (wwn_list != NULL) {
if (wwn_list->logical_path == NULL) {
free(wwn_list->physical_path);
wwn_list_save = wwn_list;
if (wwn_list->wwn_prev != NULL) {
wwn_list->wwn_prev->wwn_next =
wwn_list->wwn_next;
} else {
*wwn_list_ptr = wwn_list->wwn_next;
}
if (wwn_list->wwn_next != NULL) {
wwn_list->wwn_next->wwn_prev =
wwn_list->wwn_prev;
}
wwn_list = wwn_list->wwn_next;
free(wwn_list_save);
} else {
wwn_list = wwn_list->wwn_next;
}
}
if (env != NULL) {
end_time = gethrtime();
fprintf(stdout,
" get_dev_path %s: "
"\t\tTime = %lld millisec\n",
dir_name, (end_time - start_time)/1000000);
}
if (*wwn_list_ptr == NULL) {
return (L_NO_DEVICES_FOUND);
} else {
return (0);
}
}
static char *
my_devfs_path(di_node_t node)
{
uchar_t *pwwn = NULL;
char *interconnect = NULL;
char pwwns[WWN_SIZE*2+1];
char *mypath;
int scsi_vhci = 0;
int rval;
char *tptr = NULL, *lun_guid = NULL;
int *lunnump = NULL;
di_node_t parentnode;
if (node == DI_NODE_NIL) {
return (NULL);
}
if ((tptr = di_devfs_path(node)) == NULL) {
return (NULL);
}
parentnode = di_parent_node(node);
if ((mypath = (char *)calloc(1, MAXPATHLEN + 1)) == NULL) {
di_devfs_path_free(tptr);
return (NULL);
}
sprintf(mypath, "%s%s", DEVICES_DIR, tptr);
di_devfs_path_free(tptr);
if (strstr(mypath, SCSI_VHCI) == NULL) {
rval = di_prop_lookup_strings(DDI_DEV_T_ANY, parentnode,
"initiator-interconnect-type", &interconnect);
if ((rval <= 0) ||
((strcmp(interconnect, "FABRIC") != 0) &&
(strcmp(interconnect, "FIBRE") != 0))) {
free(mypath);
return (NULL);
}
} else {
scsi_vhci++;
}
if ((tptr = strrchr(mypath, '/')) == NULL) {
free(mypath);
return (NULL);
}
if (strchr(tptr, '@') != NULL) {
return (mypath);
}
if ((di_state(node) & DI_DRIVER_DETACHED) != DI_DRIVER_DETACHED) {
free(mypath);
return (NULL);
}
if (!scsi_vhci) {
copy_wwn_data_to_str(pwwns, pwwn);
di_prop_lookup_ints(DDI_DEV_T_ANY, node, LUN_PROP, &lunnump);
sprintf(&mypath[strlen(mypath)], "@w%s,%x", pwwn, *lunnump);
} else {
di_prop_lookup_strings(DDI_DEV_T_ANY, node,
LUN_GUID_PROP, &lun_guid);
sprintf(&mypath[strlen(mypath)], "@g%s", lun_guid);
}
return (mypath);
}
static void
my_devfs_path_free(char *path)
{
if (path != NULL) {
free(path);
}
}
static void
copy_wwn_data_to_str(char *to_ptr, const uchar_t *from_ptr)
{
if ((to_ptr == NULL) || (from_ptr == NULL))
return;
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 void
init_drv(char *dir_name, char *pattern_match, char *drvr_path)
{
DIR *dirp;
struct dirent *entp;
char namebuf[MAXPATHLEN];
char *result = NULL;
int fd;
if ((dirp = opendir(dir_name)) == NULL) {
return;
}
while ((entp = readdir(dirp)) != NULL) {
if ((strcmp(entp->d_name, ".") == 0) ||
(strcmp(entp->d_name, "..") == 0) ||
(fnmatch(pattern_match, entp->d_name, 0) != 0)) {
continue;
}
memset(namebuf, 0, sizeof (namebuf));
sprintf(namebuf, "%s/%s", dir_name, entp->d_name);
if ((result = g_get_physical_name_from_link(namebuf)) == NULL) {
ER_DPRINTF(" Warning: Get physical name from"
" link failed. Link=%s\n", namebuf);
continue;
}
if (strstr(result, drvr_path) == NULL) {
free(result);
result = NULL;
continue;
}
if ((fd = g_object_open(result, O_NDELAY | O_RDONLY)) != -1) {
close(fd);
break;
} else if (errno != EBUSY) {
free(result);
result = NULL;
continue;
} else {
break;
}
}
free(result);
closedir(dirp);
}