/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*LINTLIBRARY*/
/*
* I18N message number ranges
* This file: (not defined yet)
* 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 <fnmatch.h>
#include <l_common.h>
#include <stgcom.h>
#include <l_error.h>
#include <g_state.h>
#include <libdevinfo.h>
#include <libnvpair.h>
#include <errno.h>
/* Some forward declarations of static functions */
static int get_pathlist(char *, sv_iocdata_t *, int *);
static int stms_path_enable_disable(char *, char *, int);
static int stms_path_enable_disable_all(char *, int);
/*
* To get lun number of a given device pathname using driver ioctl.
* This interface is called directly by g_get_lun_number
*
* inputs;
* outputs:
* returns:
* 0 - success
* !0 - failure
*/
int
{
int fd = 0;
int retval = 0;
return (-1);
}
*char_ptr = '\0';
}
return (L_OPEN_PATH_FAIL);
}
/* Allocate memory for path info structs */
sizeof (sv_path_info_t));
/* Allocate memory for getting per path info properties */
for (i = 0; i < num_paths; i++) {
== NULL)) {
/* Free memory for per path info properties */
return (-1);
}
}
if (retval != 0) {
/* Free memory for per path info properties */
return (retval);
}
retval = 0;
} else {
retval = -1;
}
charptr1++;
}
}
/* Free memory for per path info properties */
return (retval);
}
/*
* To give the lun number of a given device pathname
*
* inputs: physical pathname beginning with /devices
* outputs: none
* returns: lun number (if available) or -1 (if not available or
* failure)
*/
int
{
int lunval = 0;
return (-1);
}
return (-1);
}
*charptr2 = '\0';
}
charptr1++;
if (*charptr1 != '0') {
} else {
return (0);
}
/* for the time being */
return (-1);
}
} else {
return (-1);
}
return (lunval);
}
/*
* Input - Space for client_path, phci_path and paddr fields of ioc structure
* need to be allocated by the caller of this routine.
*/
static int
{
int retval;
int fd;
int initial_path_count;
int current_path_count;
int i;
char *delimiter;
int malloc_error = 0;
int prop_buf_size;
int pathlist_retry_count = 0;
return (L_INVALID_PATH);
}
return (L_INVALID_PATH);
}
} else {
return (L_MALLOC_FAILED);
}
}
/* move beyond "/devices" prefix */
/* remove :c,raw suffix */
/* if we didn't find the ':' fine, else truncate */
}
/*
* We'll call ioctl SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO
* at least twice. The first time will get the path count
* and the size of the ioctl propoerty buffer. The second
* time will get the path_info for each path.
*
* It's possible that additional paths are added while this
* code is running. If the path count increases between the
* 2 ioctl's above, then we'll retry (and assume all is well).
*/
/* free physical path */
/* 0 buf_size asks driver to return actual size needed */
/* open the ioctl file descriptor */
return (L_OPEN_PATH_FAIL);
}
if (retval != 0) {
return (L_SCSI_VHCI_ERROR);
}
while (pathlist_retry_count <= RETRY_PATHLIST) {
/* Make driver put actual # paths in variable */
/*
* Allocate space for array of path_info structures.
* Allocate enough space for # paths from get_pathcount
*/
sizeof (sv_path_info_t));
return (L_MALLOC_FAILED);
}
/*
* Allocate space for path properties returned by driver
*/
malloc_error = 0;
for (i = 0; i < initial_path_count; i++) {
malloc_error = 1;
break;
}
malloc_error = 1;
break;
}
}
if (malloc_error == 1) {
for (i = 0; i < initial_path_count; i++) {
}
return (L_MALLOC_FAILED);
}
if (retval != 0) {
for (i = 0; i < initial_path_count; i++) {
}
return (L_SCSI_VHCI_ERROR);
}
if (initial_path_count < current_path_count) {
/* then a new path was added */
} else {
break;
}
}
/* we are done with ioctl's, lose the fd */
/*
* Compare the length num elements from the ioctl response
* and the caller's request - use smaller value.
*
* pathlist_p->path_count now has count returned from ioctl.
* ioc.buf_elem has the value the caller provided.
*/
if (initial_path_count < current_path_count) {
/* More paths exist than we allocated space for */
} else {
}
return (0);
}
/*
* To obtain pathlist of a given target device
*
* inputs:
* dev_path client device path
* outputs:
* pathlist_p pathlist structure containing pathinfo node data
* returns:
* 0 - success
* !0 - failure
*/
int
{
int num_paths_to_copy;
int i;
int prop_buf_size;
char *temp_addr;
!= 0) {
return (caller_ret);
}
sizeof (mp_pathinfo_t));
/* force the loop to not run so we free buffers and exit */
num_paths_to_copy = 0;
}
/* get ioctl reponse fields and copy them to caller's buffer */
for (i = 0; i < num_paths_to_copy; i++) {
DEV_PREFIX_LEN - 1);
/*
* Check for leading 'w'. The mpxio framework was
* incorrectly implemented to skip 'w' in mdi_pi_get_addr().
* Since the leading 'w' is fibre-channel specific, we
* do it here to remove fibre-channel specific behavior
* from the mpxio framework.
*/
if (*temp_addr == 'w') {
temp_addr++;
}
/* use nvlist_ calls to extract properties from retbuf */
prop_buf_size, &nvl, 0);
if (retval != 0) { /* ??? same retcode */
"UNKNOWN PROB");
} else {
if (retval != 0) {
"UNKNOWN");
} else {
}
}
}
/* free everything we alloced */
}
return (caller_ret);
}
/*
* To get the number of paths to a given device pathname using
* driver ioctl.
*
* inputs:
* dev path you would like to recieve mp count on
* outputs:
* returns:
* 0 - success
* -1 - bad device path
* -2 - open failure
* -3 - ioctl failure
*/
int
{
char *char_ptr;
int retval = 0;
char *physical_path;
/* translate device path to physical path */
/* ensure physical path is not NULL, or strcpy will core */
if (physical_path == NULL) {
return (-1);
}
/* copy physical path without /devices/ prefix */
*char_ptr = '\0';
}
/* prepare sv_iocdata_t structure */
return (-2);
}
/* Issue open to device to get multipath_info (ie. count) */
/* Check icotl status */
if (retval == 0) {
/* success */
} else {
/* failure */
return (-3);
}
}
/*
* Call driver to effect failover for a given pathclass
*
* inputs:
* outputs:
* returns:
* 0 - success
* !0 - failure
*/
int
{
return (L_INVALID_PATH);
}
*char_ptr_end = '\0';
}
return (L_OPEN_PATH_FAIL);
}
switch (errno) {
case EALREADY:
break;
case ENXIO:
break;
case EIO:
break;
case ENOTSUP:
break;
case EBUSY:
break;
case EFAULT:
default:
}
}
return (ret);
}
static void
{
int i = 0;
pi++;
}
}
/*
* Name: stms_path_enable_disable
*
* inputs:
*
* client_path client device path
*
* phci Controller device path
*
* request should be set to one of the following:
* SCSI_VHCI_PATH_DISABLE
* SCSI_VHCI_PATH_ENABLE
*
* returns:
* 0 for success
* non-zero otherwise
*/
static int
{
char *ioc_phci;
char *char_ptr_end;
int fd;
if (!client_path || !phci) {
return (EINVAL);
}
return (L_OPEN_PATH_FAIL);
}
/*
* translate device path to physical path
* Save off the ptr for use by free
*/
/* ensure physical path is not NULL, or strcpy will core */
if (client_physical_path == NULL) {
return (EINVAL);
}
/*
* Must be a scsi_vhci path
*/
return (L_INVALID_PATH);
}
/* physical path without /devices/ prefix */
*char_ptr_end = '\0';
}
/*
* If there is a '/devices', strip it, if not
* assume it is complete and correct
*/
} else {
}
/*
* Issue requested operation
*/
return (errno);
}
return (0);
}
int
{
}
int
{
}
/*
* Name: stms_path_enable_disable_all
*
* inputs:
*
* phci Controller device path
*
* request should be set to one of the following:
* SCSI_VHCI_PATH_DISABLE
* SCSI_VHCI_PATH_ENABLE
*
* returns:
* 0 for success
* non-zero otherwise
*/
static int
{
int fd;
char *ioc_phci;
if (!phci) {
return (EINVAL);
}
return (L_OPEN_PATH_FAIL);
}
/*
* If there is a '/devices', strip it, if not
* assume it is complete and correct
*/
} else {
}
/*
* Issue requested operation
*/
return (errno);
}
return (0);
}
int
{
/*
* issue disable on all clients for a phci
*/
}
int
{
/*
* issue enable on all clients for a phci
*/
}
/*
* Name: stms_get_path_state
*
* inputs:
*
* client_path client device path
*
* phci Controller device path
*
* outputs:
* state set to one of enum mdi_pathinfo_state_t in sunmdi.h
* MDI_PATHINFO_STATE_*
*
* ext_state set to one or more of the bits defined in mdi_impldefs.h
* MDI_PATHINFO_STATE_*
*
*
* returns:
* 0 for success
* non-zero otherwise
*/
int
{
int num_paths;
char *ioc_phci;
int i;
int found = 0;
int err;
if (!client_path || !phci) {
return (EINVAL);
}
/*
* Get all the paths for this client
*/
!= 0) {
return (err);
}
/*
* If there is a '/devices', strip it, if not
* assume it is complete and correct
*/
} else {
}
/*
* get ioctl response states
* for the requested client and phci
* and copy them to caller's buffers
*/
for (i = 0; i < num_paths; i++) {
found++;
break;
}
}
/* free everything we alloced */
}
if (found) {
return (0);
} else {
/* Requested path not found */
return (ENXIO);
}
}