/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
/*LINTLIBRARY*/
/*
* I18N message number ranges
* This file: 12000 - 12499
* Shared common messages: 1 - 1999
*/
/*
* This module is part of the Fibre Channel Interface library.
*/
/* #define _POSIX_SOURCE 1 */
/* Includes */
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h> /* for DIR */
#include <nl_types.h>
#include <strings.h>
#include <errno.h>
#include <fnmatch.h>
#include <l_common.h>
#include <stgcom.h>
#include <l_error.h>
#include <g_state.h>
#include <g_scsi.h>
#include <libdevinfo.h>
#include <ctype.h>
#include <devid.h>
/* Some forward declarations of static functions */
/*
* becomes extern interface for Tapestry.
* static int g_get_inq_dtype(char *, la_wwn_t, uchar_t *);
* static int g_get_dev_list(char *, fc_port_dev_t **, int *, int);
*/
static int g_issue_fcp_ioctl(int, struct fcp_ioctl *, int);
static int g_set_port_state(char *, int);
static void g_free_rls(AL_rls *);
static int g_scsi_inquiry_cmd80(int, uchar_t *, int);
static int g_find_supported_inq_page(int, int);
static int wwn_list_name_compare(const void *, const void *);
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_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 *);
uchar_t *);
uchar_t *);
struct wwn_list_found_struct **);
/* type for g_dev_map_init related routines */
typedef struct impl_map_dev_prop {
int prop_type;
int prop_size;
void *prop_data;
int prop_error;
typedef struct impl_map_dev {
int flag;
/* Defines */
#define PROP_NOEXIST 0
/* Prototypes */
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 for g_dev_map_init related routines */
static void free_prop_list(impl_map_dev_prop_t **);
static void free_child_list(impl_map_dev_t **);
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
};
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
};
/*
* Check if device is in the map.
*
* PARAMS:
* map - loop map returned from fc port
* tid - device ID for private map or 24-bit alpa for fabric map
*
* RETURNS:
* 1 if device present in the map.
* 0 otherwise.
*
*/
int
{
int i, j;
if (dev_ptr->
/* Does not count if WWN == 0 */
for (j = 0; j < FC_WWN_SIZE; j++)
return (1);
}
}
} else {
(int)g_switch_to_alpa[tid]) {
/* Does not count if WWN == 0 */
for (j = 0; j < WWN_SIZE; j++)
sf_port_wwn[j] != 0)
return (1);
}
}
}
return (0);
}
/*
* Inserts any missing port wwns for mpxio device paths
* which are in ONLINE or STANDBY state.
*/
static int
{
/*
* Now check each scsi_vhci device path to find any missed
* port wwns and insert a new wwn list entry for the missed
* port wwn
*/
/* Free memory for pathlist before return */
return (L_INVALID_PATH);
}
for (i = 0; i < pathcnt; i++) {
/*
* Just search for ONLINE and STANDBY paths as
* those should be the only missing wwn entries.
* There is a very small window for an offline
* to have occurred between the time we retrieved
* the device list and a call to this function.
* If that happens, we just won't add it to
* the list which is probably a good thing.
*/
WWN_S_LEN - 1);
/*
* Now search through wwn list for matching
* device path AND pwwn
* If it's found, continue to next path.
* If it's not found, add it the wwn list.
*/
match = 0;
WWN_S_LEN) == 0) {
match++;
break;
}
}
}
if (match) {
continue;
} else {
/*
* didn't find a match but the mpxio
* device is in the list. Retrieve
* the info from the wwn_list_found
* and add it to the list.
*/
if ((new_wwn = (struct wwn_list_struct *)
calloc(1,
sizeof (struct wwn_list_struct)))
== NULL) {
return (L_MALLOC_FAILED);
}
if ((new_wwn->physical_path = (char *)
calloc(1,
+ 1)) == NULL) {
return (L_MALLOC_FAILED);
}
if ((new_wwn->logical_path = (char *)
calloc(1,
+ 1)) == NULL) {
return (L_MALLOC_FAILED);
}
/*
* Insert new_wwn at the beginning of the list.
*/
/* set new starting ptr */
*wwn_list_ptr = new_wwn;
/*
* Copy found node wwn data to this new entry
* Node wwn is required for the wwn_list
* however for mpxio devices it is not
* relevant as it may apply to multiple
* target controllers, so just use what
* we already have in wwn_list_found.
*/
}
}
}
return (0);
}
/*
* gets the port wwn for a scsi_vhci device using ONLINE path priority
*/
static int
{
return (L_INVALID_PATH);
}
found = 0;
/*
* Look for an ONLINE path first.
* If that fails, get the STANDBY path port WWN
* If that fails, give up
*/
WWN_S_LEN - 1);
found++;
}
}
WWN_S_LEN - 1);
found++;
}
}
if (found) {
} else {
return (-1);
}
}
/*
* searches wwn_list_found for the pwwn passed in
* and sets the corresponding nwwn on return.
* If no match is found, -1 is returned and nwwn is not set.
*/
static int
{
return (0);
}
}
return (-1);
}
/*
* adds a nwwn, pwwn entry to the next entry in wwn_list_found list
*/
static int
{
/* Got wwns, load data in list */
if ((new_wwn = (struct wwn_list_found_struct *)
return (L_MALLOC_FAILED);
}
/*
* Insert new_wwn in the list
*/
if (*wwn_list_found != NULL) {
} else {
}
return (0);
}
/*
* Create a linked list of all the WWN's for all FC_AL disks and
* tapes that are attached to this host.
*
* RETURN VALUES: 0 O.K.
*
* wwn_list pointer:
* NULL: No devices found.
* !NULL: Devices found
* wwn_list points to a linked list of wwn's.
*/
int
{
int err;
int al_pa;
/* return L_NULL_WWN_LIST if wwn_list_ptr is NULL */
if (wwn_list_ptr == NULL) {
return (L_NULL_WWN_LIST);
}
start_time = gethrtime();
}
return (err);
}
/*
* retain backward compatibility with g_get_wwn_list
* and retrieve the WWN for scsi_vhci devices in the
* same fashion
* Note that for scsi_vhci devices, the wwn fields are
* not relevant but in the previous versions
* we loaded the wwns so...
*/
while (wwn_list_p != NULL) {
/* get port wwn of first ONLINE, STANDBY */
port_wwn)) == 0) {
node_wwn)) != 0) {
if ((err =
&wwn_list_found)) != 0) {
return (err);
}
}
} else {
/* Use g_get_wwn as a last resort */
/*
* this is a bad WWN.
* remove it from the wwn_list.
*
* After removing the bad WWN,
* wwn_list_p should point to the next
* node in the list.
*/
*wwn_list_ptr = NULL;
return (L_NO_DEVICES_FOUND);
} else if (
*wwn_list_ptr =
} else if (
NULL;
wwn_list_p = NULL;
} else {
}
continue;
}
}
}
}
/*
* Now go through the list one more time to add entries for
* any missing port wwns.
* This allows a search on port wwn for any paths which are
* ONLINE or STANDBY. We don't care about OFFLINE as those won't
* and should not show up in the list
*/
if ((err = insert_missing_pwwn(
return (err);
}
}
"\t\tTime = %lld millisec\n",
}
return (0);
}
int
{
int err;
start_time = gethrtime();
}
/*
* Try to prime di_drv_first_node()
* If there are no nodes bound, di_drv_first_node()
* will return nothing.
*/
return (L_DEV_SNAPSHOT_FAILED);
}
"\t\tTime = %lld millisec\n",
}
start_time = gethrtime();
}
wwn_list_ptr)) != 0) {
if (err != L_NO_DEVICES_FOUND) {
return (err);
}
}
"\t\tTime = %lld millisec\n",
}
start_time = gethrtime();
}
&tape_ptr)) != 0) {
if (err != L_NO_DEVICES_FOUND) {
return (err);
} else {
/*
* if *wwn_list_ptr == NULL
* we have disks but no tapes
* Just return
*/
if (*wwn_list_ptr != NULL) {
return (0);
} else {
/*
* No disks or tapes
*/
return (err);
}
}
}
"\t\tTime = %lld millisec\n",
}
/* Now link the two together */
/* Walk to the end of it */
;
return (0);
}
/* else we have no disks */
*wwn_list_ptr = tape_ptr;
return (0);
}
void
/* return if wwn_list_found is NULL */
if (wwn_list_found == NULL) {
return;
}
*wwn_list_found = NULL;
}
}
void
{
/* return if wwn_list is NULL */
return;
}
(void) g_destroy_data(*wwn_list);
}
}
void
{
int i, n;
/*
* Count the number of wwn_list in the list
*/
for (n = 0, wwn_list_ptr = *wwn_list;
wwn_list_ptr != NULL;
n++;
}
if (n <= 1) {
return;
}
/*
* Allocate a simple wwn_list array and fill it in
*/
wwn_list_array = (struct wwn_list_struct **)
for (wwn_list_ptr = *wwn_list;
wwn_list_ptr != NULL;
}
/*
* Sort the wwn_list array
*/
qsort((void *) wwn_list_array, n,
sizeof (struct wwn_list_struct *), wwn_list_name_compare);
/*
* Rebuild the linked list wwn_list structure
*/
for (i = 0; i < n - 1; i++) {
}
/*
* Clean up
*/
(void) g_destroy_data((void *)wwn_list_array);
}
int
{
for (;;) {
break;
}
break;
} else {
s1++;
s2++;
}
}
}
/*
* Get the limited map for FC4 devices.
* This function is specific to FC4
* devices and doesn't work for FC (leadville) devices.
*
* RETURN VALUES:
* 0 O.K.
* non-zero otherwise
*
* lilpmap *map_ptr:
* NULL: No devices found
* !NULL: if devices found
*/
int
{
int fd, i;
/* initialize map */
/*
* Get the path to the :devctl driver
*
* This assumes the path looks something like this:
* or
* or
* a 1 level PCI type driver
*/
return (L_LSTAT_ERROR);
}
/* append a port. Just try 0 since they did not give us one */
}
P_DPRINTF(" g_get_limited_map: Geting drive map from:"
" %s\n", drvr_path);
/* open controller */
return (L_OPEN_PATH_FAIL);
I_DPRINTF(" FCIO_GETMAP ioctl failed\n");
return (L_FCIO_GETMAP_IOCTL_FAIL);
}
/*
* Check for reasonableness.
*/
return (L_INVALID_LOOP_MAP);
}
return (L_INVALID_LOOP_MAP);
}
}
return (0);
}
/*
* For leadville specific HBA's ONLY.
* Get the host specific parameters,
*
* OUTPUT:
* fc_port_dev_t structure.
*
* RETURNS:
* 0 if OK
* non-zero in case of error.
*/
int
{
int err;
int fd;
int dev_type;
/* return invalid path if host_path is NULL */
return (L_INVALID_PATH);
}
/* return invalid arg if host_val is NULL */
return (L_INVALID_ARG);
}
return (L_INVALID_PATH_TYPE);
}
return (L_OPEN_PATH_FAIL);
}
/* initialize structure */
I_DPRINTF(" FCIO_GET_HOST_PARAMS ioctl failed.\n");
return (L_FCIO_GET_HOST_PARAMS_FAIL);
}
/* get the inquiry information for the leadville HBA. */
return (err);
}
return (0);
}
/*
* Issue FCIO ioctls to the port(fp) driver.
* FCIO ioctl needs to be retried when it
* is returned with an EINVAL error, wait
* time between retries should be atleast
* WAIT_FCIO_IOCTL (too much of a time to wait!!)
*
* OUTPUT:
* fcio_t structure
*
* RETURNS:
* 0 if O.K.
* non-zero otherwise.
*/
int
{
int ntries;
/* wait WAIT_FCIO_IOCTL */
(void) usleep(WAIT_FCIO_IOCTL);
continue;
}
I_DPRINTF("FCIO ioctl failed.\n"
"Error: %s. fc_error = %d (0x%x)\n",
fcio->fcio_errno);
return (L_INVALID_DEVICE_COUNT);
} else {
return (errno);
}
}
/*
* When port is offlined, qlc
* returns the FC_OFFLINE error and errno
* is set to EIO.
* We do want to ignore this error,
* especially when an enclosure is
* removed from the loop.
*/
break;
return (-1);
}
break;
}
return (0);
}
/*
* This function issues the FCP_TGT_INQUIRY ioctl to
* the fcp module
*
* OUTPUT:
* fcp_ioctl structure in fcp_data is filled in by fcp
*
* RETURN VALUES :
* 0 on Success
* Non-zero otherwise
*/
static int
{
int num_tries = 0;
/*
* Issue the ioctl to FCP
* The retries are required because the driver may
* need some time to respond at times.
*/
while (num_tries++ < RETRY_FCP_IOCTL) {
/* if ioctl fails it is an error from Solaris operation. */
(void) usleep(WAIT_FCP_IOCTL);
continue;
} else {
break;
}
}
if (dev_data->dev_status == 0) {
return (0);
}
(void) usleep(WAIT_FCP_IOCTL);
continue;
} else {
return (0);
}
}
return (L_FCP_TGT_INQUIRY_FAIL);
}
/*
* Get the number of devices and also
* a list of devices accessible through
* the device's port as specified by path.
* The calling function * is responsible for freeing the dev_list.
*
* Acquires inq_dtype from g_get_inq_dtype() and
* stores into dev_dtype field of fc_port_dev.
*
* For fabric devices call FCIO_DEV_LOGIN (if necessary) to execute port login
* and get inq dtype.
*
* dev_list:
* NULL: No devices found, in case of an error
* Non-NULL: Devices found.
* ndevs:
* set to the number of devices
* accessible through the port.
*
* RETURNS:
* 0 if O.K.
* non-zero otherwise
*/
int
{
int num_devices = 0;
int dev_type;
int fd;
char *char_ptr;
/*
* Get the path to the :devctl driver
*
* This assumes the path looks something like this:
* or
* or
* or
* a 1 level PCI type driver but still :devctl
*/
return (L_INVALID_PATH);
}
/* append controller */
} else {
return (L_LSTAT_ERROR);
}
/* append controller */
}
}
return (L_INVALID_PATH_TYPE);
}
return (L_OPEN_PATH_FAIL);
}
/*
* Get the device list from port driver
*/
I_DPRINTF(" FCIO_GET_NUM_DEVS ioctl failed.\n");
return (L_FCIO_GET_NUM_DEVS_FAIL);
}
if (num_devices == 0) {
*ndevs = 0;
return (L_NO_DEVICES_FOUND);
}
sizeof (fc_port_dev_t))) == NULL) {
return (L_MALLOC_FAILED);
}
/* Get the device list */
/* Information read operation */
/* new device count */
if (err == L_INVALID_DEVICE_COUNT) {
/*
* original buffer was small so allocate buffer
* with a new count and retry.
*/
new_count = 0;
sizeof (fc_port_dev_t))) == NULL) {
return (L_MALLOC_FAILED);
}
/* Information read operation */
/* new device count */
if (err == L_INVALID_DEVICE_COUNT) {
/*
* No more retry. There may be severe
* hardware problem so return error
* here.
*/
I_DPRINTF(" Device count was %d"
" should have been %d\n",
} else {
" FCIO_GET_DEV_LIST ioctl failed.");
}
return (err);
}
} else {
I_DPRINTF(" FCIO_GET_DEV_LIST ioctl failed.");
return (L_FCIO_GET_DEV_LIST_FAIL);
}
}
/*
* if new count is smaller than the original number from
* FCIO_GET_NUM_DEVS, adjust new count and buffer size
* and continue.
*/
if (new_count < num_devices) {
if (new_count == 0) {
*ndevs = 0;
return (L_NO_DEVICES_FOUND);
}
(new_count * sizeof (fc_port_dev_t))))
== NULL) {
return (L_MALLOC_FAILED);
}
}
*ndevs = num_devices;
/* close here since fcapath will be passed to other routines. */
return (err);
}
/* Get the inq_dtype for each device on dev list. */
for (i = 0; i < num_devices; i++, dlist++) {
/* Get the inq_dtype for each device. */
/*
* if g_get_inq_dtype failed on g_dev_login
* or g_issue_fcp_ioctl, continue to the next
* dev on dlist.
* L_GET_DEV_LIST_ULP_FAILURE is returned
* after processing the whole dlist.
*/
if ((err == L_FCIO_DEV_LOGIN_FAIL) ||
(err == L_FCP_TGT_INQUIRY_FAIL)) {
ulp_failure = 1;
} else {
return (err);
}
}
}
if (ulp_failure) {
return (L_GET_DEV_LIST_ULP_FAILURE);
} else {
return (0);
}
}
/* Constant used by g_get_inq_dtype() */
/*
* Gets the inq_dtype for devices on the fabric FC driver
* through an ioctl to the FCP module.
*
* OUTPUT:
* inq_dtype is set to the dtype on success
*
* RETURN VALUES:
* 0 on Success
* Non-zero on error
*/
int
{
return (L_INVALID_PATH_TYPE);
}
return (err);
}
/*
* if there is an error on getting port state we will
* continue to login.
* state can be either of
* PORT_DEVICE_INVALID, PORT_DEVICE_VALID,
* PORT_DEVICE_LOGGED_IN. Trying port login
* unless already logged in.
* It will be examined if there is an adverse
* effect on invalid state device.
*/
!= 0) || (state != PORT_DEVICE_LOGGED_IN)) {
/* do port login to fabric device. */
return (err);
}
}
}
return (L_OPEN_PATH_FAIL);
return (L_FSTAT_ERROR);
}
return (L_OPEN_PATH_FAIL);
}
/* Get the minor number for an fp instance */
return (err);
}
return (err);
}
/*
* Gets the inq_dtype for devices on the fabric FC driver
* through an ioctl to the FCP module.
*
* This is exactly same as g_get_inq_dtype except that it does not do
* g_dev_login(). That is for the case when the FCA tries to get its own
* inq_dtype and in such a case, it cannot PLOGI into itself.
*
* OUTPUT:
* inq_dtype is set to the dtype on success
*
* RETURN VALUES:
* 0 on Success
* Non-zero on error
*/
static int
{
return (L_INVALID_PATH_TYPE);
}
return (L_OPEN_PATH_FAIL);
}
return (L_FSTAT_ERROR);
}
return (L_OPEN_PATH_FAIL);
}
/* Get the minor number for an fp instance */
return (err);
}
return (0);
}
/*
* This function returns the traditional g_get_dev_map. Device list
* and local hba separate.
*/
int
{
}
/*
* This function returns the device map with local hba in physical
* order. Note: Physical order is only returned properly for
* private loop. local hba is also included separate
*/
int
{
}
/*
* Gets device map from nexus driver
*
* PARAMS:
* path - must be the physical path to a device
* map - loop map returned from fc port.
* verbose - options.
*
* LOGIC:
* 1. check the validity of path via g_get_path_type.
* 2. If FC path, get the topology of the path via
* g_get_fca_port_topology.
*
* 3. If FC type(Leadville statck)
* g_get_dev_list to get the device node list of fc_port_dev_t.
* g_get_host_params to get the fca port node of fc_port_dev_t.
*
* Case of fabric or public loop topology
* Check if the port id > 0xffff.
* Move device node and fca port node to
* gfc_map structure via gfc_port_dev_info_t
* pub_port union.
* Issue g_get_inq_dtype to get FCP inquiry data
* and store it into gfc_port_dev_info_t.
*
* Case of private loop topology
* Check if the port id < 0xff.
* Move device node and fca port node to
* gfc_map structure via gfc_port_dev_info_t
* priv_port union.
* Issue g_get_inq_dtype to get FCP inquiry data
* and store it into gfc_port_dev_info_t.
*
* SFIOCGMAP ioctl to get the device and hba nodes of
* sf_addr_pair_t.
*
*
* RETURNS:
* 0 : if OK
* non-zero: otherwise
*/
int
{
char *char_ptr;
/* return invalid path if path is NULL */
return (L_INVALID_PATH);
}
/* return invalid arg if map_ptr is NULL */
return (L_INVALID_ARG);
}
/*
* Get the path to the :devctl driver
*
* This assumes the path looks something like this:
* or
* or
* or
* a 1 level PCI type driver but still :devctl
*/
return (L_INVALID_PATH);
}
for (i = 0; i < pathcnt; i++) {
p_on = i;
break;
p_st = i;
}
}
}
/* on_line path */
} else {
/* standby or path0 */
}
} else {
return (L_INVALID_PATH);
}
/* append controller */
} else {
return (L_LSTAT_ERROR);
}
/* append controller */
}
}
}
P_DPRINTF(" g_get_dev_map: Geting drive map from:"
" %s\n", drvr_path);
return (L_INVALID_PATH_TYPE);
}
/* get fiber topology */
&hba_port_top, verbose)) != 0) {
return (err);
}
/* for FC devices. */
if (dev_type & FC_FCA_MASK) {
/*
* if g_get_dev_list fails with L_NO_DEVICES_FOUND
* we still want to call g_get_host_params to try to find the
* HBA. If we do not see any HBAs on the loop, the
* g_get_host_params will fail when it trys to issue the target
* inquiry ioctl. In this case, we would still like to return
* L_NO_DEVICES_FOUND.
*
* If g_get_dev_list fails with L_NO_DEVICES_FOUND and
* g_get_host_params fails, the function returns
* L_NO_DEVICES_FOUND
*/
&num_devices)) != 0) {
/*
* g_get_dev_map doesn't allow ulp failure
* to continue thus we need to free dev_list
* here.
*/
if (err == L_GET_DEV_LIST_ULP_FAILURE) {
}
if (err != L_NO_DEVICES_FOUND) {
return (err);
}
}
/* Get local HBA information */
verbose)) != 0) {
if (num_devices == 0)
return (L_NO_DEVICES_FOUND);
else
return (err);
}
/* If devices, other than local HBA are found */
/* allocate space for them in the gfc_map. */
if (num_devices > 0) {
/* If map type is on MAP_FORMAT_LILP we need */
/* to add space for the local HBA */
if (map_type == MAP_FORMAT_LILP) {
} else {
}
sizeof (gfc_port_dev_info_t))) == NULL) {
return (L_MALLOC_FAILED);
}
}
/* If we want the lilp map then we need to do a little */
/* work here. The lilp map contains the local hba in */
/* the dev_addr. Once this has been added qsort the */
/* dev_addr array so it's in physical order. */
/* The lilp map will contain the local hba in the */
/* dev_addr array only when num_devices > 0 */
/* First we need to allocate one additional */
/* device to the dev_addr structure, for the */
/* local hba */
(num_devices * sizeof (fc_port_dev_t))))
== NULL) {
return (L_MALLOC_FAILED);
}
/* Next, copy the local hba into this new loc. */
sizeof (fc_port_dev_t)) == NULL) {
return (L_MEMCPY_FAILED);
}
/* Now sort by physical location */
sizeof (fc_port_dev_t), lilp_map_cmp);
}
switch (hba_port_top) {
case FC_TOP_FABRIC:
case FC_TOP_PUBLIC_LOOP:
return (L_INVALID_FABRIC_ADDRESS);
} else {
}
for (i = 0; i < num_devices; i++, dev_ptr++,
dev_list++) {
return (L_INVALID_FABRIC_ADDRESS);
} else {
*dev_list;
}
}
break;
case FC_TOP_PRIVATE_LOOP:
/*
* Map the (new->old) structures here.
* Checking (i < SF_NUM_ENTRIES_IN_MAP) just to
* make sure that we don't overrun the map structure
* since it can hold data for upto 126 devices.
*/
return (L_INVALID_PRIVATE_LOOP_ADDRESS);
} else {
for (j = 0; j < FC_WWN_SIZE; j++) {
priv_port.sf_node_wwn[j] =
priv_port.sf_port_wwn[j] =
}
}
for (i = 0; (i < num_devices &&
i < SF_NUM_ENTRIES_IN_MAP);
/*
* Out of 24 bits of port_id, copy only
* 8 bits to al_pa. This works okay for
* devices that're on a private loop.
*/
return (L_INVALID_PRIVATE_LOOP_ADDRESS);
}
/* Code refactorization is needed for C style */
for (j = 0; j < FC_WWN_SIZE; j++) {
}
}
break;
case FC_TOP_PT_PT:
return (L_PT_PT_FC_TOP_NOT_SUPPORTED);
default:
return (L_UNEXPECTED_FC_TOPOLOGY);
} /* End of switch on port_topology */
return (errno);
/* initialize map */
I_DPRINTF(" SFIOCGMAP ioctl failed.\n");
return (L_SFIOCGMAP_IOCTL_FAIL);
}
/* Check for reasonableness. */
return (L_INVALID_LOOP_MAP);
}
return (L_NO_DEVICES_FOUND);
}
sizeof (gfc_port_dev_info_t))) == NULL) {
return (L_MALLOC_FAILED);
}
return (L_INVALID_LOOP_MAP);
}
sf_map.sf_addr_pair[i];
}
}
return (0);
}
/*
* This function consturct FC proerty list using map_dev_fc_prop_list.
*
* port WWN, node WWN, port addr and hard addr properties is constructed.
*
* return 0 if OK.
* otherwise returns error code.
*/
static int
{
/* consrtruct port addr property. */
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);
}
}
return (L_MALLOC_FAILED);
}
return (L_MALLOC_FAILED);
}
/* consrtruct port WWN property. */
return (L_MALLOC_FAILED);
}
return (L_MALLOC_FAILED);
}
/* consrtruct node WWN property. */
return (L_MALLOC_FAILED);
}
return (L_MALLOC_FAILED);
}
/* consrtruct hard addr property. */
return (L_MALLOC_FAILED);
}
return (L_MALLOC_FAILED);
}
} else {
}
return (0);
}
/*
* This function consturct FCP inq dtype propery.
* if inq_dtype is null the property is constrcted with err info.
*
* L_MALLOC_FAILED is the only possible error.
*/
static int
{
return (L_MALLOC_FAILED);
}
} else {
return (L_MALLOC_FAILED);
}
}
} else {
if (exist == PROP_EXIST) {
} else {
}
}
return (0);
}
/*
* This function calls FCP_TGT_INQUIRY via g_issue_fcp_ioctl()
* to get the inq_dtype of input device and calls update_map_dev_FCP_prop().
* inq_dtype is set to NULL and pass error code if inq_dtype data is not
* requried.
*
* return error from update_map_dev_FCP_prop().
*/
static int
{
}
/* Get the minor number for an fp instance */
/* Get FCP prop for the hba first. */
/* if ioctl error then set the prop_error. */
if ((err = update_map_dev_FCP_prop(
return (err);
}
} else {
if ((err = update_map_dev_FCP_prop(
return (err);
}
}
return (0);
}
/*
* Construct device map tree from nexus driver
*
* PARAMS:
* path - must be the physical path to a device
* l_err - ptr to an error code. Set when NULL is returned.
* flag - device map fomat and property type.
*
* LOGIC:
* 1. check the validity of path via g_get_path_type.
* 2. If FC path, get the topology of the path via
* g_get_fca_port_topology.
*
* 3. If FC type(Leadville statck)
* FCIO_GET_DEV_LIST to get the device node list of fc_port_dev_t.
* FCIO_GET_HOST_PARAMS to get the fca port node of fc_port_dev_t.
*
* root of tree is set with host_params info
* FC propery is set.
* FCP property is set if reqyested through flag.
* Issue g_issue_fcp_ioctl to get FCP inquiry data
* consruruct list of children via dev_list.
* FC property is set.
* FCP property is set if reqyested through flag.
* Issue FCIO_DEV_LOGIN if it is fabric device.
* Issue g_issue_fcp_ioctl to get FCP inquiry data.
*
* SFIOCGMAP ioctl to get the device and hba nodes of
* sf_addr_pair_t.
* FCIO_GETMAP ioctl to get hba port info.
* consturct map and child tree list and
* set the properties as private loop devices.
*
* RETURNS:
* ptr to map is returned if OK.
* NULL and l_err is set otherwise.
*/
{
return (NULL);
}
*l_err = L_INVALID_PATH;
return (NULL);
}
*l_err = 0;
/*
* Get the path to the :devctl driver
*
* This assumes the path looks something like this:
* or
* or
* or
* a 1 level PCI type driver but still :devctl
*/
*l_err = L_INVALID_PATH;
return (NULL);
}
for (i = 0; i < pathcnt; i++) {
p_on = i;
break;
p_st = i;
}
}
}
/* on_line path */
} else {
/* standby or path0 */
}
} else {
*l_err = L_INVALID_PATH;
return (NULL);
}
/* append controller */
} else {
*l_err = L_LSTAT_ERROR;
return (NULL);
}
/* append controller */
}
}
}
P_DPRINTF(" g_dev_map_init: Geting drive map from:"
" %s\n", drvr_path);
return (NULL);
}
/* get fiber topology */
&hba_port_top, 0)) != 0) {
return (NULL);
}
return (NULL);
}
/* for FC devices. */
if (path_type & FC_FCA_MASK) {
/* get the number of device first. */
I_DPRINTF(" FCIO_GET_NUM_DEVS ioctl failed.\n");
return (NULL);
}
if (num_devices != 0) {
sizeof (fc_port_dev_t))) == NULL) {
*l_err = L_MALLOC_FAILED;
return (NULL);
}
/* Get the device list */
/* Information read operation */
/* new device count */
if (err == L_INVALID_DEVICE_COUNT) {
/*
* original buffer was small so allocate
* buffer with a new count and retry.
*/
new_count = 0;
if ((dev_list = (fc_port_dev_t *)
sizeof (fc_port_dev_t))) == NULL) {
*l_err = L_MALLOC_FAILED;
return (NULL);
}
/* Information read operation */
sizeof (fc_port_dev_t);
/* new device count */
0)) != 0) {
if (err ==
/*
* No more retry. There
* may be severe
* hardware problem so
* return error here.
*/
I_DPRINTF(" Device"
" count was %d"
" should have been"
" %d\n",
return (NULL);
} else {
/* Code refactorization is needed for C style */
I_DPRINTF(" FCIO_GET_DEV_LIST ioctl failed.");
return (NULL);
}
}
}
}
}
/*
* if new count is smaller than the original number from
* FCIO_GET_NUM_DEVS, adjust new count and buffer size
* and continue.
*/
if (new_count < num_devices) {
if (new_count > 0) {
if ((dev_list = (fc_port_dev_t *)
(new_count * sizeof (fc_port_dev_t))))
== NULL) {
*l_err = L_MALLOC_FAILED;
return (NULL);
}
}
}
/* get the host param info */
I_DPRINTF(" FCIO_GET_HOST_PARAMS ioctl failed.\n");
if (num_devices == 0) {
} else {
}
return (NULL);
}
/* If we want the lilp map then we need to do a little */
/* work here. The lilp map contains the local hba in */
/* the dev_addr. Once this has been added qsort the */
/* dev_addr array so it's in physical order. */
/* First we need to allocate one additional */
/* device to the dev_addr structure, for the */
/* local hba */
if (num_devices > 0) {
if ((dev_list = (fc_port_dev_t *)
(++num_devices *
sizeof (fc_port_dev_t)))) == NULL) {
/*
* In case dev_list is not null free
* it.
*/
*l_err = L_MALLOC_FAILED;
return (NULL);
}
/*
* Next, copy the local hba into this new
* loc.
*/
sizeof (fc_port_dev_t)) == NULL) {
*l_err = L_MEMCPY_FAILED;
return (NULL);
}
/* Now sort by physical location */
sizeof (fc_port_dev_t), lilp_map_cmp);
}
}
/* We have dev list info and host param info. */
/* Now constructs map tree with these info. */
/* First consturct the root of the map tree */
/* with host param. */
*l_err = L_MALLOC_FAILED;
return (NULL);
}
/* consturct hba property list. */
return (NULL);
}
*l_err = L_FSTAT_ERROR;
return (NULL);
}
return (NULL);
}
}
/* consturct child for each device and */
/* set device property list. */
for (i = 0; i < num_devices; i++, dlist++) {
*l_err = L_MALLOC_FAILED;
return (NULL);
}
/* set the map as parent */
return (NULL);
}
if (i == 0) {
} else {
}
if ((flag & MAP_XPORT_PROP_ONLY) !=
if (((hba_port_top == FC_TOP_PUBLIC_LOOP) ||
(hba_port_top == FC_TOP_FABRIC)) &&
" FCIO_GET_STATE ioctl failed.\n");
if ((err = update_map_dev_FCP_prop(
PROP_NOEXIST)) != 0) {
return (NULL);
}
}
if (state != PORT_DEVICE_LOGGED_IN) {
-1) {
return (NULL);
}
sizeof (fcio_t));
0) {
/* Code refactorization is needed for C style */
I_DPRINTF(" FCIO_DEV_LOGIN ioctl failed.\n");
if ((err = update_map_dev_FCP_prop(
PROP_NOEXIST)) != 0) {
return (NULL);
}
/*
* plogi failed continue
* to next dev
*/
continue;
}
}
}
/* sbuf should be set from hba_port handling. */
if ((err = handle_map_dev_FCP_prop(
0) {
return (NULL);
}
}
}
/* connect the children to to map. */
/* initialize map */
I_DPRINTF(" SFIOCGMAP ioctl failed.\n");
return (NULL);
}
/* Check for reasonableness. */
return (NULL);
}
return (NULL);
}
return (NULL);
}
if ((nexus_fd =
return (NULL);
}
/* get limited map to get hba param info */
I_DPRINTF(" FCIO_GETMAP ioctl failed\n");
return (NULL);
}
hba_alpa_found = 1;
}
}
if (!(hba_alpa_found)) {
return (NULL);
}
/* We have dev list info and host param info. */
/* Now constructs map tree with these info. */
/* First consturct the root of the map tree */
/* with host param. */
*l_err = L_MALLOC_FAILED;
return (NULL);
}
/* consturct hba property list. */
return (NULL);
}
PROP_NOEXIST)) != 0) {
return (NULL);
}
}
*l_err = L_MALLOC_FAILED;
return (NULL);
}
/* set the map as parent */
0) {
return (NULL);
}
if (i == 0) {
} else {
}
if ((flag & MAP_XPORT_PROP_ONLY) !=
if ((err = update_map_dev_FCP_prop(
PROP_NOEXIST)) != 0) {
return (NULL);
}
}
} /* end of for loop */
} /* end of else */
}
/*
* This function deallocates memory for propery list.
*/
static void
{
case GFC_PROP_TYPE_BYTES:
break;
case GFC_PROP_TYPE_INT:
break;
case GFC_PROP_TYPE_STRING:
break;
default:
break;
}
}
}
/*
* This function deallocates memory for children list.
*/
static void
{
}
}
/*
* This function deallocates memory for the whole map.
*/
void
{
}
}
/*
* This function passes back topology of the input map.
* input should be a handle form g_dev_map_init().
*
* return 0 if OK.
* return error code otherwise.
*/
int
{
return (L_INVALID_MAP_DEV_ADDR);
}
return (L_INVALID_ARG);
}
return (0);
}
/*
* This function returns the first device handle of the input map.
* map input should be a handle form g_dev_map_init().
*
* l_err set to 0 if OK.
* l_err set to error code otherwise.
*/
{
return (NULL);
}
*l_err = 0;
return (NULL);
}
}
}
/*
* This function returns the next device handle of the input map.
* map_dev input should be a handle for device.
*
* l_err set to 0 if OK.
* l_err set to error code otherwise.
*/
{
return (NULL);
}
*l_err = 0;
return (NULL);
}
}
}
/*
* This function passes back uchar_t type property and its count.
* map_dev input should be a handle for device.
*
* return 0 if OK.
* return error code otherwise.
*/
int
{
int err;
return (L_INVALID_MAP_DEV_ADDR);
}
(prop_data_count == NULL)) {
return (L_INVALID_ARG);
}
while (impl_prop) {
break;
}
return (0);
} else {
}
break;
}
}
return (err);
}
/*
* This function passes back int type property.
* map_dev input should be a handle for device.
*
* return 0 if OK.
* return error code otherwise.
*/
int
int **prop_data)
{
int err;
return (L_INVALID_MAP_DEV_ADDR);
}
return (L_INVALID_ARG);
}
while (impl_prop) {
break;
}
return (0);
} else {
}
break;
}
}
return (err);
}
/*
* This function passes back int type property.
* map_dev input should be a handle for device.
*
* return 0 if OK.
* return error code otherwise.
*/
int
char **prop_data)
{
int err;
return (L_INVALID_MAP_DEV_ADDR);
}
return (L_INVALID_ARG);
}
while (impl_prop) {
break;
}
return (0);
} else {
}
break;
}
}
return (err);
}
/*
* This function returns the handle for the first property of the input device.
* map_dev input should be a handle form a device.
*
* l_err set to 0 if OK.
* l_err set to error code otherwise.
*/
{
return (NULL);
}
*l_err = 0;
return (NULL);
}
}
}
/*
* This function returns the handle for next property handle of the input prop.
* map_prop input should be a handle for property.
*
* l_err set to 0 if OK.
* l_err set to error code otherwise.
*/
{
return (NULL);
}
*l_err = 0;
return (NULL);
}
}
}
/*
* This function returns the name of the property of the input prop.
* map_prop input should be a handle for property.
*
* return name string if OK.
* returns NULL and l_err set to error code otherwise.
*/
char *
{
return (NULL);
}
*l_err = 0;
return (NULL);
}
}
/*
* This function returns the type of the property of the input prop.
* map_prop input should be a handle for property.
*
* return type if OK.
* returns GFC_PROP_TYPE_UNKNOWN and l_err set to error code otherwise.
*/
int
{
*l_err = 0;
} else {
return (L_INVALID_ARG);
}
return (GFC_PROP_TYPE_UNKNOWN);
}
}
/*
* This function passes back uchar_t type property and its count.
* map_prop input should be a handle for property.
*
* return 0 if OK.
* return error code otherwise.
*/
int
{
return (L_INVALID_MAP_DEV_ADDR);
}
return (L_INVALID_ARG);
}
return (L_INVALID_MAP_DEV_PROP_TYPE);
}
} else {
return (impl_prop->prop_error);
}
return (0);
}
/*
* This function passes back int type property.
* map_prop input should be a handle for property.
*
* return 0 if OK.
* return error code otherwise.
*/
int
{
return (L_INVALID_MAP_DEV_ADDR);
}
return (L_INVALID_ARG);
}
return (L_INVALID_MAP_DEV_PROP_TYPE);
}
} else {
return (impl_prop->prop_error);
}
return (0);
}
/*
* This function passes back string type property.
* map_prop input should be a handle for property.
*
* return 0 if OK.
* return error code otherwise.
*/
int
{
return (L_INVALID_MAP_DEV_ADDR);
}
return (L_INVALID_ARG);
}
return (L_INVALID_MAP_DEV_PROP_TYPE);
}
} else {
return (impl_prop->prop_error);
}
return (0);
}
/*
* Free the linked list allocated by g_rdls()
*/
static void
{
}
}
/*
* Read the extended link error status block
* from the specified device and Host Adapter.
*
* PARAMS:
* path_phys - physical path to an FC device
* rls_ptr - pointer to read link state structure
*
* RETURNS:
* 0 : if OK
* non-zero: otherwise
*/
int
{
/* return invalid path if path_phys is NULL */
return (L_INVALID_PATH);
}
/* return invalid arg if rls_ptr is NULL */
return (L_INVALID_ARG);
}
return (L_INVALID_PATH);
}
for (i = 0; i < pathcnt; i++) {
p_on = i;
break;
p_st = i;
}
}
}
/* on_line path */
} else {
/* standby or path0 */
}
} else {
}
/* Get map of devices on this loop. */
return (L_INVALID_PATH);
}
if (dev_type & FC_FCA_MASK) {
return (L_INVALID_PATH);
}
*charPtr = '\0';
/* append devctl to the path */
} else {
return (L_LSTAT_ERROR);
}
/* append devctl to the path */
}
}
MAP_XPORT_PROP_ONLY)) == NULL) {
return (err);
}
} else { /* FC4_FCA_MASK type path */
&nexus_path_ptr)) != 0) {
return (err);
}
/* open driver */
return (errno);
/*
* First try using the socal version of the map.
* If that fails get the expanded vesion.
*/
I_DPRINTF(" FCIO_GETMAP ioctl failed.\n");
I_DPRINTF(" SFIOCGMAP ioctl failed.\n");
return (L_SFIOCGMAP_IOCTL_FAIL);
}
/* Check for reasonableness. */
return (L_INVALID_LOOP_MAP);
}
return (L_INVALID_LOOP_MAP);
}
}
exp_map_flag++;
} else {
I_DPRINTF(" g_rdls:"
" FCIO_GETMAP ioctl returned %d entries.\n",
/* Check for reasonableness. */
return (L_FCIOGETMAP_INVLD_LEN);
}
}
for (i = 0; i < length; i++) {
return (L_MALLOC_FAILED);
}
} else {
}
if (exp_map_flag) {
} else {
}
I_DPRINTF(" g_rdls:"
/*
* The ifp driver will return ENXIO when rls
* is issued for same initiator on loop when
* there is more than one on the loop.
* Rather than completely fail, continue on.
* Set values in the payload struct to -1 as
* this is what socal is currently doing for
* the case of same initiator rls.
*/
if ((dev_type & FC4_PCI_FCA) &&
(uint_t)0xffffffff;
} else {
I_DPRINTF(" FCIO_LINKSTATUS ioctl"
" failed with errno %d.\n", errno);
return (L_FCIO_LINKSTATUS_FAILED);
}
}
I_DPRINTF(" g_rdls: al_pa returned by ioctl 0x%x\n",
}
return (0);
}
/* Now we need to take care of FC_FCA_MASK case. */
/* we have map created already via g_dev_map_init. */
return (err);
}
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(
return (err);
}
return (L_MALLOC_FAILED);
}
} else {
}
/* Set the al_ha here */
/*
* rls. Load the values returned for the fp ioctl
* into the structure passed back to the caller
* Note: There is no reason for the path
* above.
*/
if ((hba_port_top == FC_TOP_FABRIC) ||
(hba_port_top == FC_TOP_PUBLIC_LOOP)) {
if ((err = g_dev_prop_lookup_bytes(
&port_wwn_byte)) != 0) {
return (err);
}
if ((err = g_get_dev_port_state(
if (state != PORT_DEVICE_LOGGED_IN) {
port_wwn)) != 0) {
(uint_t)0xffffffff;
if (((map_dev =
&err))
== NULL) &&
(err !=
map_root);
return (err);
}
continue;
}
}
} /* if g_get_dev_port_state fails proceed. */
}
return (L_OPEN_PATH_FAIL);
}
fcio.fcio_flags = 0;
} else {
/*
* Load the values into the struct passed
* back to the caller
*/
}
(err != L_NO_SUCH_DEV_FOUND)) {
return (err);
}
}
/* for Leadville issue a final call for the initiator */
if ((err = g_dev_prop_lookup_ints(
return (err);
}
return (L_MALLOC_FAILED);
}
} else {
}
return (L_OPEN_PATH_FAIL);
}
fcio.fcio_flags = 0;
} else {
/*
* Load the values into the struct passed
* back to the caller
*/
}
return (0);
}
{
return (tmp);
}
/*
* Get device World Wide Name (port and node) for device at path
* and add all WWNs to the wwn_list_found list.
*
* RETURN: 0 O.K.
*
* INPUTS:
* - path_phys must be of a device, either an IB or disk.
*/
static int
struct wwn_list_found_struct **wwn_list_found)
{
unsigned long long pwwn;
P_DPRINTF(" g_get_wwn: Getting device WWN"
" and al_pa for device: %s\n",
start_time = gethrtime();
}
/*
* Get the loop identifier (switch setting) from the path.
*
* This assumes the path looks something like this:
* /devices/.../SUNW,socal@3,0/SUNW,sf@0,0/SUNW,ssd@x,0
* or
* /devices/.../SUNW,qlc@5/SUNW,fp@0,0/SUNW,ssd@x,0
*/
return (L_INVLD_PATH_NO_ATSIGN_FND);
}
char_ptr++; /* point to the loop identifier or WWN */
/* This function allocs mem for map.dev_addr on success */
return (L_INVALID_PATH);
}
for (i = 0; i < pathcnt; i++) {
p_on = i;
break;
p_st = i;
}
}
}
if (p_on == i) {
/* on_line path */
WWN_S_LEN - 1);
} else {
/* standby or path0 */
WWN_S_LEN - 1);
}
}
MAP_XPORT_PROP_ONLY)) == NULL) {
return (err);
}
return (err);
}
} else {
/*
* Format of WWN is
* ssd@w2200002037000f96,0:a,raw
*/
if (*char_ptr != 'w') {
return (L_INVLD_WWN_FORMAT);
}
char_ptr++;
}
return (L_NO_WWN_FOUND_IN_PATH);
}
P_DPRINTF(" g_get_wwn: Looking for WWN "
"0x%llx\n", pwwn);
(err != L_NO_SUCH_DEV_FOUND)) {
return (err);
}
while (map_dev) {
return (err);
}
return (err);
}
found = 1;
if ((err = g_dev_prop_lookup_ints(
return (err);
}
}
(err != L_NO_SUCH_DEV_FOUND)) {
return (err);
}
}
if (!found) {
return (L_NO_LOOP_ADDRS_FOUND);
}
"\t\tTime = %lld millisec\n",
}
return (0);
}
/*
* Get device World Wide Name and AL_PA for device at path
*
* RETURN: 0 O.K.
*
* INPUTS:
* - path_phys must be of a device, either an IB or disk.
*/
int
{
int ret;
/* return invalid path if the argument is NULL */
return (L_INVALID_PATH);
}
/* return invalid arg if the argument is NULL */
return (L_INVALID_ARG);
}
return (ret);
}
int
{
/* return invalid path if path is NULL */
return (L_INVALID_PATH);
}
/* return invalid arg if serial_number is NULL */
if (serial_number == NULL) {
return (L_INVALID_ARG);
}
return (L_OPEN_PATH_FAIL);
}
/*
* Call the inquiry cmd on page 0x80 only if the vendor
* supports page 0x80.
*/
/*
* Let's retrieve the serial number from page 0x80
* and store it in the inquiry structure
*/
sizeof (struct l_inquiry80_struct));
if (status == 0) {
} else {
status = 0;
}
} else {
/*
* page 0x80 is not supported, so print the
* appropriate message.
*/
}
return (status);
}
int
{
/* return invalid path if path is NULL */
return (L_INVALID_PATH);
}
/* return invalid arg if l_inquiry is NULL */
return (L_INVALID_ARG);
}
return (L_OPEN_PATH_FAIL);
return (status);
}
/*
* Function to retrieve inquiry page 0x80 from the device
*/
static int
{
}
/*
* Function to determine if the given page is supported by vendor.
*/
static int
{
int status = 0;
int index;
if (status) {
return (0);
}
return (1);
}
}
return (0);
}
int
{
int fd;
P_DPRINTF(" g_get_perf_statistics: Get Performance Statistics:"
"\n Path:%s\n",
path);
/* initialize tables */
/* open controller */
return (L_OPEN_PATH_FAIL);
/* update parameters in the performance table */
/* get the period in seconds */
return (0);
}
int
{
int status;
int fd;
return (L_OPEN_PATH_FAIL);
return (status);
}
int
{
return (errno);
return (status);
}
int
{
return (L_OPEN_PATH_FAIL);
return (status);
}
int
{
return (L_OPEN_PATH_FAIL);
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
{
int i;
char c, c1;
*wwnp++ = 0;
*wwnp++ = 0;
return (-1);
}
return (0);
}
/*
* Converts a string of WWN ASCII characters to a
* binary representation.
*
* Input: string - pointer to uchar_t array
* WWN in ASCII
* length: 16 bytes
* Output: wwn - pointer to uchar_t array
* containing WWN result
* length: 8 bytes
* Returns:
* non-zero on error
* zero on success
*/
int
{
int i;
char c, c1;
return (-1);
}
return (0);
}
/*
* Get multiple paths to a given device port.
* INPUTS:
* port WWN string.
*/
int
{
int err;
/* Initialize list structures. */
H_DPRINTF(" g_get_port_multipath: Looking for multiple paths for"
" device with\n port WWW:"
"%s\n", port_wwn_s);
return (err);
}
(void) g_destroy_data(*dlh);
}
(void) g_free_wwn_list(&wwn_list);
return (L_MALLOC_FAILED);
}
H_DPRINTF(" g_get_port_multipath:"
" Found multipath:\n %s\n",
} else {
}
}
}
(void) g_free_wwn_list(&wwn_list);
return (0);
}
/*
* The arg: devpath should be the physical path to device.
*
* OUTPUT:
* multipath_list points to a list of multiple paths to the device.
* NOTE: The caller must free the allocated list (dlist).
*
* RETURNS:
* 0 if O.K.
* non-zero otherwise
*/
int
{
int err;
H_DPRINTF(" g_get_multipath: Looking for multiple paths for"
" device at path: %s\n", devpath);
/* return invalid path if devpath is NULL */
return (L_INVALID_PATH);
}
/* return invalid arg if argument is NULL */
return (L_INVALID_ARG);
}
} else {
}
return (err);
}
/*
* Returns multipath information for a ssd device.
* Inputs:
* devpath: device path to for requested multipath info
* wwn_list: returned from g_get_wwn_list or devices_get_all
* Output:
* multipath_list: dlist list of paths
* Returns:
* 0 on success
* non-zero on failure
*/
int
struct wwn_list_struct *wwn_list)
{
int err;
return (L_NULL_WWN_LIST);
}
return (L_DEV_SNAPSHOT_FAILED);
}
return (err);
}
return (err);
}
return (L_NULL_WWN_LIST);
}
/*
* When a path is found from the list, load the logical
* and physical dev path
*/
/* Load multipath list */
while (*multipath_list != NULL) {
}
return (L_MALLOC_FAILED);
}
" g_get_multipath: Found multipath=%s\n",
dl->logical_path =
if (*multipath_list == NULL) {
} else {
}
}
}
}
return (0);
}
int
struct wwn_list_struct *wwn_list)
{
int len;
return (L_INVALID_PATH);
}
/* Strip partition information. */
} else {
}
return (L_NULL_WWN_LIST);
}
wwn_list_ptr != NULL;
len);
} else {
}
break;
}
}
if (*node_wwn_s == NULL) {
H_DPRINTF("node_wwn_s is NULL!\n");
return (L_NO_NODE_WWN_IN_WWNLIST);
}
while (*multipath_list != NULL) {
(void) g_destroy_data(dlt);
}
return (L_MALLOC_FAILED);
}
H_DPRINTF(" g_get_multipath: Found multipath=%s\n",
if (*multipath_list == NULL) {
} else {
}
}
}
return (0);
}
/*
* Free a multipath list
*
*/
void
{
(void) g_destroy_data(dlh);
}
}
/*
* Get the path to the nexus (HBA) driver.
* This assumes the path looks something like this:
* or maybe this
* or
* or
* or
* (or "qlc" instead of "socal" and "fp" for "sf")
*
* Which should resolve to a path like this:
* or
*
* or
* which should resolve to
*/
int
{
char *char_ptr;
/* return invalid path if the path_phys is NULL */
return (L_INVALID_PATH);
}
*nexus_path = NULL;
return (L_INVALID_PATH);
}
for (i = 0; i < pathcnt; i++) {
p_on = i;
break;
p_st = i;
}
}
}
/* on_line path */
} else {
/* standby or path0 */
}
} else {
return (L_INVALID_PATH);
}
}
if (path_type & FC4_SF_XPORT) {
/* sf driver in path so capture the port # */
return (L_INVALID_PATH);
}
if (port > 1) {
return (L_INVLD_PORT_IN_PATH);
}
return (L_INVALID_PATH);
}
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) {
/*
* check to see if it 3rd party vendor FCA.
* if it is return error for this operation since
* we don't know how they creates FCA port related minor node.
*
* As of now there is no supported operation on FCA node so
* this should be okay.
*/
return (L_INVALID_PATH_TYPE);
}
/*
* For current Sun FCA driver, appending
* port # doesn't work. Just remove transport layer from
* input path.
*/
return (L_INVALID_PATH);
}
}
return (L_LSTAT_ERROR);
}
/*
* Found a directory.
* Now append a port number or devctl to the path.
*/
if (port_flag) {
/* append port */
} else {
/* Try adding port 0 and see if node exists. */
/*
* Path we guessed at does not
* exist so it may be a driver
* that ends in :devctl.
*/
} else {
/*
* The path that was entered
* did not include a port number
* so the port was set to zero, and
* then checked. The default path
* did exist.
*/
ER_DPRINTF("Since a complete path"
" was not supplied "
"a default path is being"
" used:\n %s\n",
temp_buf);
}
}
}
}
return (0);
}
/*
* Get the FC topology for the input device or nexus(HBA) path.
*
* The routine calls g_get_path_type to determine the stack of
* the input path.
*
* If it a socal path
* it returns FC_TOP_PRIVATE_LOOP
* else
* calls fc_get_topology ioctl to
* get the fp topolgy from the driver.
*
* INPUTS:
* path - a string of device path, transport path.
* NOTE: "path" SHOULD NOT BE OPEN BEFORE CALLING
* THIS FUNCTION BECAUSE THIS FUNCTION DOES
* AN "O_EXCL" OPEN.
* port_top - a pointer to the toplogy type.
*
* RETURNS:
* 0 if there is no error.
* error code.
*
* The input path is expected to be something like below:
* 1)
* (or "qlc" instead of "socal" and "fp" for "sf")
*
* Which should resolve to a path like this:
*
* 2)
* which should resolve to
*
* 3) The nexus(hba or nexus) path will get an error only for qlc
* since the routine need to open fp :devctl node for fcio ioctl.
*/
int
{
char *char_ptr;
/* return invalid path if the path is NULL */
return (L_INVALID_PATH);
}
/* return invalid arg if the argument is NULL */
return (L_INVALID_ARG);
}
return (L_INVALID_PATH);
}
for (i = 0; i < pathcnt; i++) {
p_on = i;
break;
p_st = i;
}
}
}
/* on_line path */
} else {
/* standby or path0 */
}
} else {
/*
* Get the path to the :devctl driver
*
* This assumes the path looks something like this:
* or
* or
* or
* a 1 level PCI type driver but still :devctl
* (or "qlc" in the place of "socal" and "fp" for "sf")
*
* The dir below doesn't have corresponding :devctl node.
*
*/
return (L_INVALID_PATH);
}
/* append controller */
} else {
return (L_LSTAT_ERROR);
}
/* append controller */
}
}
}
return (L_INVALID_PATH);
}
return (0);
}
/* To contiue the path type should be fp :devctl node */
if (!(dev_type & FC_XPORT_MASK)) {
return (L_INVALID_PATH);
}
return (errno);
P_DPRINTF(" g_get_fca_port_topology: Geting topology from:"
" %s\n", drvr_path);
I_DPRINTF(" FCIO_GET_TOPOLOGY ioctl failed.\n");
return (L_FCIO_GET_TOPOLOGY_FAIL);
}
return (0);
}
/*
* This functions enables or disables a FCA port depending on the
* argument, cmd, passed to it. If cmd is PORT_OFFLINE, the function
* tries to disable the port specified by the argument 'phys_path'. If
* cmd is PORT_ONLINE, the function tries to enable the port specified
* by the argument 'phys_path'.
* INPUTS :
* nexus_port_ptr - Pointer to the nexus path of the FCA port to
* operate on
* cmd - PORT_OFFLINE or PORT_ONLINE
* RETURNS :
* 0 on success and non-zero otherwise
*/
static int
{
return (L_INVALID_PATH);
}
return (L_OPEN_PATH_FAIL);
}
switch (cmd) {
case PORT_OFFLINE:
if (path_type & FC4_SOCAL_FCA) {
/*
* The socal driver currently returns EFAULT
* even if the ioctl has completed successfully.
*/
NULL) == -1) {
return (L_PORT_OFFLINE_FAIL);
}
} else {
/*
* QLogic card -
* Can't do much here since the driver currently
* doesn't support this feature. We'll just fail
* for now. Support can be added when the driver
* is enabled with the feature at a later date.
*/
return (L_PORT_OFFLINE_UNSUPPORTED);
}
break;
case PORT_ONLINE:
if (path_type & FC4_SOCAL_FCA) {
/*
* The socal driver currently returns EFAULT
* even if the ioctl has completed successfully.
*/
return (L_PORT_ONLINE_FAIL);
}
} else {
/*
* QLogic card -
* Can't do much here since the driver currently
* doesn't support this feature. We'll just fail
* for now. Support can be added when the driver
* is enabled with the feature at a later date.
*/
return (L_PORT_ONLINE_UNSUPPORTED);
}
break;
default:
return (-1);
}
return (0);
}
/*
* The interfaces defined below (g_port_offline() and g_port_online())
* are what will be exposed to applications. We will hide g_set_port_state().
* They have to be functions (as against macros) because making them
* macros will mean exposing g_set_port_state() and we dont want to do that
*/
int
{
}
int
{
}
/*
* This function sets the loopback mode for a port on a HBA
* INPUTS :
* portpath - Pointer to the path of the FCA port on which to
* set the loopback mode
* cmd - EXT_LPBACK
* INT_LPBACK
* NO_LPBACK
* RETURNS :
* 0 on success and non-zero otherwise
*/
int
{
return (L_INVALID_PATH);
}
return (L_OPEN_PATH_FAIL);
}
/*
* The loopback calls are currently not fully supported
* via fp.
*
* A fp based general solution is required to support Leadville FCAs
* including Qlgc and 3rd party FCA. As of now qlgc provides
* some diag functions like echo through qlc private ioctl
* which is not supproted by luxadm and libraries.
*/
switch (cmd) {
case EXT_LPBACK:
if (path_type & FC4_SOCAL_FCA) {
NULL) == -1) {
/* Check for previous mode set */
return (L_LOOPBACK_FAILED);
}
}
} else {
/*
* Well, it wasn't one of the above cards so..
*/
return (L_LOOPBACK_UNSUPPORTED);
}
break;
case NO_LPBACK:
if (path_type & FC4_SOCAL_FCA) {
return (L_LOOPBACK_FAILED);
}
} else {
/*
* Well, it wasn't one of the above cards so..
*/
return (L_LOOPBACK_UNSUPPORTED);
}
break;
case INT_LPBACK:
if (path_type & FC4_SOCAL_FCA) {
NULL) == -1) {
/* Check for previous mode set */
return (L_LOOPBACK_FAILED);
}
}
} else {
/*
* Well, it wasn't one of the above cards so..
*/
return (L_LOOPBACK_UNSUPPORTED);
}
break;
default:
return (L_LOOPBACK_UNSUPPORTED);
}
return (0);
}
/*
* g_get_port_state(char *portpath, int port_state)
* Purpose: Get port state for a path
* Input: portpath
* set to path of port
* Output: port_state
* Set to one of the following:
* PORT_CONNECTED
* PORT_NOTCONNECTED
* Returns: 0 on success
* non-zero on failure
*/
int
{
/* return invalid path if portpath is NULL */
return (L_INVALID_PATH);
}
/* return invalid arg if argument is NULL */
return (L_INVALID_ARG);
}
return (L_INVALID_PATH);
}
/*
* FCIO_GETMAP returns error when there are * no devices attached.
* ENOMEM is returned when no devices are attached.
* g_get_first_dev returns NULL without error when there is no
* devices are attached.
*/
if (dev_type & FC_FCA_MASK) {
MAP_XPORT_PROP_ONLY)) == NULL) {
return (err);
}
/* no device is found if err == 0 */
if (err == L_NO_SUCH_DEV_FOUND) {
}
return (0);
} else {
/* Device found okay */
}
} else {
/* open controller */
return (errno);
}
/*
* Note: There is only one error returned by this ioctl. ENOMEM.
* Hence the lack of return on error.
*/
map.lilp_length = 0;
}
/* Non-Leadville stacks report the FCA in the count */
}
return (0);
}
/*
* g_dev_login(char *port_path, la_wwn_t port_wwn)
* Purpose: port login via g_dev_log_in_out()
* Input: port_path
* port_wwn
* port wwn of device node to login
*
* Returns: return code from g_dev_log_in_out()
*/
int
{
}
/*
* g_dev_logout(char *port_path, la_wwn_t port_wwn)
* Purpose: port login via g_dev_log_in_out()
* Input: port_path
* port_wwn
* port wwn of device node to logout
*
* Returns: return code from g_dev_log_in_out()
*/
int
{
}
/*
* g_dev_log_in_out(char *port_path, la_wwn_t port_wwn, uint16_t cmd)
* Purpose: port login via FCIO_DEV_LOGOUT and port logout via FCIO_DEV_LOGOUT
* IOCTL requires EXCLUSIVE open.
* Input: port_path
* port_wwn
* port wwn of device node to logout
* cmd
* FCIO_DEV_LOGON or FCIO_DEV_LOGOUT
*
* Returns: 0 on success
* non-zero on failure
*/
static int
{
int verbose = 0;
&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);
}
/* open controller */
return (L_OPEN_PATH_FAIL);
/*
* stores port_wwn to la_wwn_t raw_wwn field
* and construct fcio structures for FCIO_DEV_LOGIN.
*/
" FCIO_DEV_LOGIN ioctl failed.\n"
: " FCIO_DEV_LOGOUT ioctl failed.\n");
return ((cmd == FCIO_DEV_LOGIN) ?
} else {
return (0);
}
}
/*
* This function will verify if a FC device (represented by input WWN
* is connected on a FCA port by searching the device list from
* g_get_dev_list() for a WWN match.
*
* input:
* fca_path: pointer to the physical path string, path to a fp node.
* possible forms are
* dev_wwn: WWN string
* flag: indicate that the input WWN is node or port
*
* returned values
* 0: if a match is found.
* L_WWN_NOT_FOUND_IN_DEV_LIST: if no match found
* L_UNEXPECTED_FC_TOPOLOGY: existing error code for an error
* from the topology checking of the input fca path.
* L_MALLOC_FAILED: existing error code for allocation eror from the
* g_get_dev_list().
* L_FCIO_GETMAP_IOCTL_FAIL: existing error code for an error from the
* FCIO ioctl called by the g_get_dev_list()
* -1: other failure
*
*/
int
{
int i, err;
int num_devices = 0;
return (L_INVALID_PATH);
}
if (!(dev_type & FC_XPORT_MASK)) {
return (L_INVALID_PATH_TYPE);
}
!= 0) && (err != L_GET_DEV_LIST_ULP_FAILURE)) {
return (err);
}
switch (flag) {
case MATCH_NODE_WWN:
for (i = 0; i < num_devices; i++, dev_list++) {
(void) free(dev_list_save);
return (0);
}
}
(void) free(dev_list_save);
/* consider a new error code for not found. */
return (L_WWN_NOT_FOUND_IN_DEV_LIST);
case MATCH_PORT_WWN:
for (i = 0; i < num_devices; i++, dev_list++) {
(void) free(dev_list_save);
return (0);
}
}
(void) free(dev_list_save);
/* consider a new error code for not found. */
return (L_WWN_NOT_FOUND_IN_DEV_LIST);
}
(void) free(dev_list_save);
return (-1);
}
/*
* g_get_dev_port_state(char *fca_path, la_wwn_t port_wwn, uint32_t *state)
* Purpose: get the state of device port login via FCIO_GET_STATE ioctl.
*
* Input: fca_path
* port_wwn
* port wwn of device node to logout
* state
* port login or not
*
* Returns: 0 on success
* non-zero on failure
*/
static int
{
int fd;
int dev_type;
int verbose = 0;
return (L_INVALID_PATH);
}
if (!(dev_type & FC_XPORT_MASK)) {
return (L_INVALID_PATH_TYPE);
}
/* open controller */
return (L_OPEN_PATH_FAIL);
/*
* stores port_wwn to la_wwn_t raw_wwn field
* and construct fcio structures for FCIO_DEV_LOGIN.
*/
I_DPRINTF(" FCIO_GET_STATE ioctl failed.\n");
return (L_FCIO_GET_STATE_FAIL);
} else {
return (0);
}
}
/*
* Name: lilp_map_cmp
*
* Description: This function is used to compare the physical location
* of to fc devices in a gfc_map_t.dev_addr arrary.
*
* Params:
* First device to compare
* Second device to compare
*
* Return:
* 0 = Devices at equal phyiscal location, How did this happen?
* >0 = First device have a higher physical location than second
* <0 = Second device have a higher physical location than first
*/
return (1);
return (-1);
return (0);
}
/*
* Description:
* Retrieves multiple paths to a device based on devid
* Caller must use mplist_free to free mplist structure
* This currently only supports ssd devices.
* The st driver does not register a device id.
*
* Input Values:
*
* devid: ptr to valid ddi_devid_t struct
* root: root handle to device tree snapshot
* drvr_name: driver name to start the node tree search
*
* Return Value:
* 0 on success
* non-zero on failure
*/
static int
struct mplist_struct **mplistp)
{
!= 0)) {
return (EINVAL);
}
/* point to first node which matches portdrvr */
if (node == DI_NODE_NIL) {
return (L_NO_DRIVER_NODES_FOUND);
}
while (node != DI_NODE_NIL) {
/* Load multipath list */
if ((mpl = (struct mplist_struct *)
== NULL) {
return (L_MALLOC_FAILED);
}
NULL) {
continue;
}
strlen(devfs_path) +
return (L_MALLOC_FAILED);
}
} else {
}
}
}
}
return (0);
}
/*
* Frees a previously allocated mplist_struct
*/
static void
{
}
}
}
/*
* Description
* Retrieves all device nodes based on drvr_name
* Currently supports SSD_DRVR_NAME, ST_DRVR_NAME
* There will be a device node in the libdevinfo
* snapshot only if there is at least one node bound.
*
* Input values:
* root valid snapshot handle from di_init(3DEVINFO)
* drvr_name name of driver to start node search
* wwn_list_ptr ptr to ptr to WWN_list struct
*
*
*/
static int
struct wwn_list_struct **wwn_list_ptr)
{
char *devfs_path;
int scsi_vhci = 0;
wwn_list_ptr == NULL) {
return (EINVAL);
}
} else {
/*
* An unsupported driver name was passed in
*/
return (L_DRIVER_NOTSUPP);
}
/* point to first node which matches portdrvr */
if (node == DI_NODE_NIL) {
return (L_NO_DEVICES_FOUND);
}
while (node != DI_NODE_NIL) {
/*
* Check for offline state
*/
continue;
}
/*
* Only support st, ssd nodes
*/
continue;
}
devicepath[0] = '\0';
/*
* form device path
*/
0) {
return (err);
} else {
sizeof (node_wwn));
sizeof (port_wwn));
}
} else {
/*
* Clear values for SCSI VHCI devices.
* node wwn, port wwn are irrevelant at
* the SCSI VHCI level
*/
scsi_vhci++;
}
/* Got wwns, load data in list */
if ((l2 = (struct wwn_list_struct *)
NULL) {
return (L_MALLOC_FAILED);
}
if ((l2->physical_path = (char *)
return (L_MALLOC_FAILED);
}
if (scsi_vhci) {
} else {
}
} else {
}
scsi_vhci = 0;
}
}
if (*wwn_list_ptr == NULL) {
return (L_NO_DEVICES_FOUND);
} else {
/*
* Now load the /dev/ paths
*/
DIR_MATCH_SSD)) != 0) {
return (err);
}
DIR_MATCH_ST)) != 0) {
return (err);
}
}
return (0);
}
}
/*
* Access the properties for the node to get the node-wwn, port-wwn property
* On error, contents of nwwn, pwwn are unspecified.
* On successful return nwwn and pwwn are WWN_SIZE bytes.
*/
static int
{
/* If we didn't get back the right count, return error */
return (L_NO_WWN_PROP_FOUND);
}
/* If we didn't get back the right count, return error */
return (L_NO_WWN_PROP_FOUND);
}
return (0);
}
/*
* Description
* retrieves the /dev logical path for a WWN_list of devices.
* Input values
* wwn_list_ptr ptr to list returned by devices_get_all
* dir_name /dev/ directory to search
*
*/
static int
char *pattern_match)
{
char *env;
return (EINVAL);
}
start_time = gethrtime();
}
wwn_list = *wwn_list_ptr;
P_DPRINTF(" get_dev_path: No devices found\n");
return (L_NO_DEVICES_FOUND);
}
/*
* Ignore current directory and parent directory
* entries.
*/
continue;
ER_DPRINTF(" Warning: Get physical name from"
" link failed. Link=%s\n", namebuf);
continue;
}
/*
* Add information to the list.
*/
if ((wwn_list->logical_path = (char *)
return (L_MALLOC_FAILED);
}
break;
}
}
}
/*
* Did we load all of the paths?
* Note: if there is a missing entry in /dev then
* the user probably did a cleanup of /dev.
* Whatever the case, remove the entry as it
* is invalid.
*/
wwn_list = *wwn_list_ptr;
} else {
/*
* No previous entries
*/
}
}
} else {
}
}
" get_dev_path %s: "
"\t\tTime = %lld millisec\n",
}
if (*wwn_list_ptr == NULL) {
return (L_NO_DEVICES_FOUND);
} else {
return (0);
}
}
/*
* This functions calls di_devfs_path and gets the path associated with a
* given devinfo node. If the path returned does not have a '@' in it, it
* checks if the driver is detached and creates a path after looking at the
* driver properties.
*
* di_devfs_path_free is called internally.
*
* The argument 'path' points to the final value upon return.
* Caller must use my_devfs_path_free on returned char *
* for FC check for initiator-interconnect-type prop
*
*/
static char *
{
char *mypath;
int scsi_vhci = 0;
int rval;
/* sanity check */
if (node == DI_NODE_NIL) {
return (NULL);
}
/* Now go get the path for this node */
return (NULL);
}
return (NULL);
}
/* Prepend "/devices" to libdevinfo-returned paths */
/*
* Is this a FC device?
* Check initiator-interconnect-type property
*/
"initiator-interconnect-type", &interconnect);
/* Check for INTERCONNECT_FABRIC_STR & INTERCONNECT_FIBRE_STR */
if ((rval <= 0) ||
/* Not a FC device. Free path and return */
return (NULL);
}
} else {
scsi_vhci++;
}
return (NULL);
}
return (mypath);
}
/*
* No '@' in path. This can happen when driver is detached.
* We'll check if the state is detached and if it is, we'll construct
* the path by looking at the properties.
*/
/*
* Driver is not detached and no '@' in path.
* Can't handle it.
*/
return (NULL);
}
if (!scsi_vhci) {
&pwwn);
if (rval <= 0) {
/* Something unexpected happened. */
return (NULL);
}
} else {
}
return (mypath);
}
static void
{
}
}
/*
* from_ptr: ptr to uchar_t array of size WWN_SIZE
* to_ptr: char ptr to string of size WWN_SIZE*2+1
*/
static void
{
return;
}
/*
* Open the requested directory and get one valid open.
* If a device is busy, return.
* Only need to open one device since
* that implies there will be a node returned from
* di_drv_first_node()
* dir_name: logical device name directory
* (DEV_TAPE_DIR, DEV_RDIR)
* pattern_match: used by fnmatch on directory entry
* (DIR_MATCH_SSD, DIR_MATCH_ST)
* drvr_path: path type to verify ("/ssd@", "/st@")
* (SLSH_DRV_NAME_ST, SLSH_DRV_NAME_SSD)
*
* Returns: None
*/
static void
{
int fd;
return;
}
/*
* Ignore current directory and parent directory
* entries.
*/
continue;
}
ER_DPRINTF(" Warning: Get physical name from"
" link failed. Link=%s\n", namebuf);
continue;
}
continue;
}
break;
continue;
} else {
break;
}
}
}