1fcf3ce44SJohn Forte /*
2fcf3ce44SJohn Forte  * CDDL HEADER START
3fcf3ce44SJohn Forte  *
4fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7fcf3ce44SJohn Forte  *
8fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11fcf3ce44SJohn Forte  * and limitations under the License.
12fcf3ce44SJohn Forte  *
13fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce44SJohn Forte  *
19fcf3ce44SJohn Forte  * CDDL HEADER END
20fcf3ce44SJohn Forte  */
21fcf3ce44SJohn Forte /*
22fcf3ce44SJohn Forte  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23fcf3ce44SJohn Forte  * Use is subject to license terms.
24fcf3ce44SJohn Forte  */
25fcf3ce44SJohn Forte 
26fcf3ce44SJohn Forte 
27fcf3ce44SJohn Forte /*LINTLIBRARY*/
28fcf3ce44SJohn Forte 
29fcf3ce44SJohn Forte /*
30fcf3ce44SJohn Forte  * I18N message number ranges
31fcf3ce44SJohn Forte  *  This file: (not defined yet)
32fcf3ce44SJohn Forte  *  Shared common messages: 1 - 1999
33fcf3ce44SJohn Forte  */
34fcf3ce44SJohn Forte 
35fcf3ce44SJohn Forte /*
36fcf3ce44SJohn Forte  *	This module is part of the Fibre Channel Interface library.
37fcf3ce44SJohn Forte  */
38fcf3ce44SJohn Forte 
39fcf3ce44SJohn Forte /* #define		_POSIX_SOURCE 1 */
40fcf3ce44SJohn Forte 
41fcf3ce44SJohn Forte 
42fcf3ce44SJohn Forte /*	Includes	*/
43fcf3ce44SJohn Forte #include	<stdlib.h>
44fcf3ce44SJohn Forte #include	<stdio.h>
45fcf3ce44SJohn Forte #include	<sys/file.h>
46fcf3ce44SJohn Forte #include	<sys/types.h>
47fcf3ce44SJohn Forte #include	<sys/stat.h>
48fcf3ce44SJohn Forte #include	<sys/mkdev.h>
49fcf3ce44SJohn Forte #include	<sys/param.h>
50fcf3ce44SJohn Forte #include	<fcntl.h>
51fcf3ce44SJohn Forte #include	<unistd.h>
52fcf3ce44SJohn Forte #include	<string.h>
53fcf3ce44SJohn Forte #include	<sys/scsi/scsi.h>
54fcf3ce44SJohn Forte #include	<dirent.h>		/* for DIR */
55fcf3ce44SJohn Forte #include	<sys/vtoc.h>
56fcf3ce44SJohn Forte #include	<nl_types.h>
57fcf3ce44SJohn Forte #include	<strings.h>
58fcf3ce44SJohn Forte #include	<sys/ddi.h>		/* for max */
59fcf3ce44SJohn Forte #include	<fnmatch.h>
60fcf3ce44SJohn Forte #include	<l_common.h>
61fcf3ce44SJohn Forte #include	<stgcom.h>
62fcf3ce44SJohn Forte #include	<l_error.h>
63fcf3ce44SJohn Forte #include	<g_state.h>
64fcf3ce44SJohn Forte #include	<sys/fibre-channel/ulp/fcp_util.h>
65fcf3ce44SJohn Forte #include	<sys/fibre-channel/impl/fc_error.h>
66fcf3ce44SJohn Forte #include	<sys/fibre-channel/impl/fcph.h>
67fcf3ce44SJohn Forte #include	<sys/socalio.h>
68fcf3ce44SJohn Forte #include	<libdevinfo.h>
69fcf3ce44SJohn Forte #include	<libnvpair.h>
70fcf3ce44SJohn Forte #include	<sys/scsi/adapters/scsi_vhci.h>
71fcf3ce44SJohn Forte #include	<errno.h>
72fcf3ce44SJohn Forte 
73fcf3ce44SJohn Forte /* Some forward declarations of static functions */
74fcf3ce44SJohn Forte static void g_free_pi_list(sv_path_info_t *, uint_t num_paths);
75fcf3ce44SJohn Forte static int get_pathlist(char *, sv_iocdata_t *, int *);
76fcf3ce44SJohn Forte static int stms_path_enable_disable(char *, char *, int);
77fcf3ce44SJohn Forte static int stms_path_enable_disable_all(char *, int);
78fcf3ce44SJohn Forte 
79fcf3ce44SJohn Forte /*
80fcf3ce44SJohn Forte  * To get lun number of a given device pathname using driver ioctl.
81fcf3ce44SJohn Forte  * This interface is called directly by g_get_lun_number
82fcf3ce44SJohn Forte  *
83fcf3ce44SJohn Forte  * inputs;
84fcf3ce44SJohn Forte  * outputs:
85fcf3ce44SJohn Forte  * returns:
86fcf3ce44SJohn Forte  *    0 - success
87fcf3ce44SJohn Forte  *   !0 - failure
88fcf3ce44SJohn Forte  */
89fcf3ce44SJohn Forte int
g_get_lun_str(char * dev_path,char lunstr[],int path_num)90fcf3ce44SJohn Forte g_get_lun_str(char *dev_path, char lunstr[], int path_num)
91fcf3ce44SJohn Forte {
92fcf3ce44SJohn Forte 	char		*char_ptr, *charptr1;
93fcf3ce44SJohn Forte 	int		fd = 0;
94fcf3ce44SJohn Forte 	sv_iocdata_t	ioc;
95fcf3ce44SJohn Forte 	char		phci_path[MAXPATHLEN];
96fcf3ce44SJohn Forte 	char		client_path[MAXPATHLEN];
97fcf3ce44SJohn Forte 	char		paddr[MAXNAMELEN];
98fcf3ce44SJohn Forte 	uint_t		num_elem = 0, i;
99fcf3ce44SJohn Forte 	sv_path_info_t	*pi = NULL;
100fcf3ce44SJohn Forte 	int		retval = 0;
101fcf3ce44SJohn Forte 	uint_t		num_paths;
102fcf3ce44SJohn Forte 
103fcf3ce44SJohn Forte 	if (strstr(dev_path, "/devices") == NULL) {
104fcf3ce44SJohn Forte 		return (-1);
105fcf3ce44SJohn Forte 	}
106fcf3ce44SJohn Forte 
107fcf3ce44SJohn Forte 	num_paths = path_num + 1;
108fcf3ce44SJohn Forte 	(void) strcpy(client_path, dev_path + DEV_PREFIX_LEN-1);
109fcf3ce44SJohn Forte 	if ((char_ptr = strrchr(client_path, ':')) != NULL) {
110fcf3ce44SJohn Forte 		*char_ptr = '\0';
111fcf3ce44SJohn Forte 	}
112fcf3ce44SJohn Forte 
113fcf3ce44SJohn Forte 	ioc.client	= client_path;
114fcf3ce44SJohn Forte 	ioc.phci	= phci_path;
115fcf3ce44SJohn Forte 	ioc.addr	= paddr;
116fcf3ce44SJohn Forte 	ioc.buf_elem	= 0;
117fcf3ce44SJohn Forte 	ioc.ret_buf	= NULL;
118fcf3ce44SJohn Forte 	ioc.ret_elem	= &num_elem;
119fcf3ce44SJohn Forte 
120fcf3ce44SJohn Forte 	if ((fd = g_object_open(VHCI_NODE, O_RDWR)) < 0) {
121fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
122fcf3ce44SJohn Forte 	}
123fcf3ce44SJohn Forte 
124fcf3ce44SJohn Forte 	/* Allocate memory for path info structs */
125fcf3ce44SJohn Forte 	pi = (sv_path_info_t *)calloc((size_t)num_paths,
126fcf3ce44SJohn Forte 		sizeof (sv_path_info_t));
127fcf3ce44SJohn Forte 	ioc.buf_elem = num_paths;
128fcf3ce44SJohn Forte 	ioc.ret_buf  = pi;
129fcf3ce44SJohn Forte 
130fcf3ce44SJohn Forte 	/* Allocate memory for getting per path info properties */
131fcf3ce44SJohn Forte 
132fcf3ce44SJohn Forte 	for (i = 0; i < num_paths; i++) {
133fcf3ce44SJohn Forte 		pi[i].ret_prop.buf_size = SV_PROP_MAX_BUF_SIZE;
134fcf3ce44SJohn Forte 		if (((pi[i].ret_prop.buf =
135fcf3ce44SJohn Forte 			malloc(SV_PROP_MAX_BUF_SIZE)) == NULL) ||
136fcf3ce44SJohn Forte 			((pi[i].ret_prop.ret_buf_size =
137fcf3ce44SJohn Forte 				malloc(sizeof (*pi[i].ret_prop.ret_buf_size)))
138fcf3ce44SJohn Forte 				    == NULL)) {
139fcf3ce44SJohn Forte 			/* Free memory for per path info properties */
140fcf3ce44SJohn Forte 			g_free_pi_list(pi, num_paths);
141fcf3ce44SJohn Forte 			(void) close(fd);
142fcf3ce44SJohn Forte 			return (-1);
143fcf3ce44SJohn Forte 		}
144fcf3ce44SJohn Forte 	}
145fcf3ce44SJohn Forte 
146fcf3ce44SJohn Forte 	retval = ioctl(fd, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO, &ioc);
147fcf3ce44SJohn Forte 	if (retval != 0) {
148fcf3ce44SJohn Forte 		/* Free memory for per path info properties */
149fcf3ce44SJohn Forte 		g_free_pi_list(pi, num_paths);
150fcf3ce44SJohn Forte 		(void) close(fd);
151fcf3ce44SJohn Forte 		return (retval);
152fcf3ce44SJohn Forte 	}
153fcf3ce44SJohn Forte 
154fcf3ce44SJohn Forte 	if (path_num < ioc.buf_elem) {
155fcf3ce44SJohn Forte 		charptr1 = strchr(pi[path_num].ret_addr, ',');
156fcf3ce44SJohn Forte 		retval = 0;
157fcf3ce44SJohn Forte 	} else {
158fcf3ce44SJohn Forte 		charptr1 = strchr(pi[0].ret_addr, ',');
159fcf3ce44SJohn Forte 		retval = -1;
160fcf3ce44SJohn Forte 	}
161fcf3ce44SJohn Forte 
162fcf3ce44SJohn Forte 	if (charptr1 != NULL) {
163fcf3ce44SJohn Forte 		charptr1++;
164fcf3ce44SJohn Forte 		if (charptr1 != NULL) {
165fcf3ce44SJohn Forte 			(void) strcpy(lunstr, charptr1);
166fcf3ce44SJohn Forte 		}
167fcf3ce44SJohn Forte 	}
168fcf3ce44SJohn Forte 
169fcf3ce44SJohn Forte 	/* Free memory for per path info properties */
170fcf3ce44SJohn Forte 	g_free_pi_list(pi, num_paths);
171fcf3ce44SJohn Forte 	(void) close(fd);
172fcf3ce44SJohn Forte 	return (retval);
173fcf3ce44SJohn Forte }
174fcf3ce44SJohn Forte 
175fcf3ce44SJohn Forte /*
176fcf3ce44SJohn Forte  * To give the lun number of a given device pathname
177fcf3ce44SJohn Forte  *
178fcf3ce44SJohn Forte  * inputs: physical pathname beginning with /devices
179fcf3ce44SJohn Forte  * outputs: none
180fcf3ce44SJohn Forte  * returns: lun number (if available) or -1 (if not available or
181fcf3ce44SJohn Forte  *          failure)
182fcf3ce44SJohn Forte  */
183fcf3ce44SJohn Forte int
g_get_lun_number(char * path_phys)184fcf3ce44SJohn Forte g_get_lun_number(char *path_phys)
185fcf3ce44SJohn Forte {
186fcf3ce44SJohn Forte 	char		path0[MAXPATHLEN], lunarr[MAXPATHLEN];
187fcf3ce44SJohn Forte 	char		*charptr1, *charptr2, *charptr3;
188fcf3ce44SJohn Forte 	int		lunval = 0;
189fcf3ce44SJohn Forte 
190fcf3ce44SJohn Forte 	if ((strstr(path_phys, "/devices")) == NULL) {
191fcf3ce44SJohn Forte 		return (-1);
192fcf3ce44SJohn Forte 	}
193fcf3ce44SJohn Forte 
194fcf3ce44SJohn Forte 	if (((charptr3 = strstr(path_phys, SLSH_DRV_NAME_SSD)) == NULL) &&
195fcf3ce44SJohn Forte 		((charptr3 = strstr(path_phys, SLSH_DRV_NAME_ST)) == NULL)) {
196fcf3ce44SJohn Forte 		return (-1);
197fcf3ce44SJohn Forte 	}
198fcf3ce44SJohn Forte 
199fcf3ce44SJohn Forte 	(void) strcpy(path0, charptr3);
200fcf3ce44SJohn Forte 
201fcf3ce44SJohn Forte 	if ((charptr2 = strrchr(path0, ':')) != NULL) {
202fcf3ce44SJohn Forte 		*charptr2 = '\0';
203fcf3ce44SJohn Forte 	}
204fcf3ce44SJohn Forte 
205fcf3ce44SJohn Forte 	if ((charptr1 = strchr(path0, ',')) != NULL) {
206fcf3ce44SJohn Forte 		charptr1++;
207fcf3ce44SJohn Forte 		if (*charptr1 != '0') {
208fcf3ce44SJohn Forte 			(void) strcpy(lunarr, charptr1);
209fcf3ce44SJohn Forte 		} else {
210fcf3ce44SJohn Forte 			return (0);
211fcf3ce44SJohn Forte 		}
212fcf3ce44SJohn Forte 	} else if (strstr(path_phys, SCSI_VHCI) != NULL) {
213fcf3ce44SJohn Forte 		/* for the time being */
214fcf3ce44SJohn Forte 		if (g_get_lun_str(path_phys, lunarr, 0) != 0) {
215fcf3ce44SJohn Forte 			return (-1);
216fcf3ce44SJohn Forte 		}
217fcf3ce44SJohn Forte 	} else {
218fcf3ce44SJohn Forte 		return (-1);
219fcf3ce44SJohn Forte 	}
220fcf3ce44SJohn Forte 
221fcf3ce44SJohn Forte 	lunval = (int)strtol(lunarr, NULL, 16);
222fcf3ce44SJohn Forte 
223fcf3ce44SJohn Forte 	return (lunval);
224fcf3ce44SJohn Forte }
225fcf3ce44SJohn Forte 
226fcf3ce44SJohn Forte /*
227fcf3ce44SJohn Forte  * Input - Space for client_path, phci_path and paddr fields of ioc structure
228fcf3ce44SJohn Forte  * need to be allocated by the caller of this routine.
229fcf3ce44SJohn Forte  */
230fcf3ce44SJohn Forte static int
get_pathlist(char * dev_path,sv_iocdata_t * ioc,int * num_paths_to_copy)231fcf3ce44SJohn Forte get_pathlist(char *dev_path, sv_iocdata_t *ioc, int *num_paths_to_copy)
232fcf3ce44SJohn Forte {
233fcf3ce44SJohn Forte 	char	*physical_path, *physical_path_s;
234fcf3ce44SJohn Forte 	int	retval;
235fcf3ce44SJohn Forte 	int	fd;
236fcf3ce44SJohn Forte 	int	initial_path_count;
237fcf3ce44SJohn Forte 	int	current_path_count;
238*926d645fSToomas Soome 	int	i;
239fcf3ce44SJohn Forte 	char	*delimiter;
240fcf3ce44SJohn Forte 	int	malloc_error = 0;
241*926d645fSToomas Soome 	int	prop_buf_size;
242fcf3ce44SJohn Forte 	int	pathlist_retry_count = 0;
243fcf3ce44SJohn Forte 
244*926d645fSToomas Soome 	if (strncmp(dev_path, SCSI_VHCI, strlen(SCSI_VHCI)) != 0) {
245fcf3ce44SJohn Forte 		if ((physical_path = g_get_physical_name(dev_path)) == NULL) {
246fcf3ce44SJohn Forte 			return (L_INVALID_PATH);
247fcf3ce44SJohn Forte 		}
248*926d645fSToomas Soome 		if (strncmp(physical_path, SCSI_VHCI, strlen(SCSI_VHCI)) != 0) {
249fcf3ce44SJohn Forte 			free(physical_path);
250fcf3ce44SJohn Forte 			return (L_INVALID_PATH);
251fcf3ce44SJohn Forte 		}
252fcf3ce44SJohn Forte 	} else {
253fcf3ce44SJohn Forte 		if ((physical_path = calloc(1, MAXPATHLEN)) == NULL) {
254fcf3ce44SJohn Forte 			return (L_MALLOC_FAILED);
255fcf3ce44SJohn Forte 		}
256fcf3ce44SJohn Forte 		(void) strcpy(physical_path, dev_path);
257fcf3ce44SJohn Forte 	}
258fcf3ce44SJohn Forte 	physical_path_s = physical_path;
259fcf3ce44SJohn Forte 
260fcf3ce44SJohn Forte 	/* move beyond "/devices" prefix */
261fcf3ce44SJohn Forte 	physical_path += DEV_PREFIX_LEN-1;
262fcf3ce44SJohn Forte 	/* remove  :c,raw suffix */
263fcf3ce44SJohn Forte 	delimiter = strrchr(physical_path, ':');
264fcf3ce44SJohn Forte 	/* if we didn't find the ':' fine, else truncate */
265fcf3ce44SJohn Forte 	if (delimiter != NULL) {
266*926d645fSToomas Soome 		*delimiter = '\0';
267fcf3ce44SJohn Forte 	}
268fcf3ce44SJohn Forte 
269fcf3ce44SJohn Forte 	/*
270fcf3ce44SJohn Forte 	 * We'll call ioctl SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO
271fcf3ce44SJohn Forte 	 * at least twice.  The first time will get the path count
272fcf3ce44SJohn Forte 	 * and the size of the ioctl propoerty buffer.  The second
273fcf3ce44SJohn Forte 	 * time will get the path_info for each path.
274fcf3ce44SJohn Forte 	 *
275fcf3ce44SJohn Forte 	 * It's possible that additional paths are added while this
276fcf3ce44SJohn Forte 	 * code is running.  If the path count increases between the
277fcf3ce44SJohn Forte 	 * 2 ioctl's above, then we'll retry (and assume all is well).
278fcf3ce44SJohn Forte 	 */
279fcf3ce44SJohn Forte 	(void) strcpy(ioc->client, physical_path);
280fcf3ce44SJohn Forte 	ioc->buf_elem = 1;
281fcf3ce44SJohn Forte 	ioc->ret_elem = (uint_t *)&(initial_path_count);
282fcf3ce44SJohn Forte 	ioc->ret_buf = NULL;
283fcf3ce44SJohn Forte 
284fcf3ce44SJohn Forte 	/* free physical path */
285fcf3ce44SJohn Forte 	free(physical_path_s);
286fcf3ce44SJohn Forte 
287fcf3ce44SJohn Forte 	/* 0 buf_size asks driver to return actual size needed */
288fcf3ce44SJohn Forte 	/* open the ioctl file descriptor */
289fcf3ce44SJohn Forte 	if ((fd = g_object_open(VHCI_NODE, O_RDWR)) < 0) {
290fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
291fcf3ce44SJohn Forte 	}
292fcf3ce44SJohn Forte 
293fcf3ce44SJohn Forte 	retval = ioctl(fd, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO, ioc);
294fcf3ce44SJohn Forte 	if (retval != 0) {
295fcf3ce44SJohn Forte 		close(fd);
296fcf3ce44SJohn Forte 		return (L_SCSI_VHCI_ERROR);
297fcf3ce44SJohn Forte 	}
298fcf3ce44SJohn Forte 	prop_buf_size = SV_PROP_MAX_BUF_SIZE;
299fcf3ce44SJohn Forte 
300fcf3ce44SJohn Forte 
301fcf3ce44SJohn Forte 	while (pathlist_retry_count <= RETRY_PATHLIST) {
302fcf3ce44SJohn Forte 		ioc->buf_elem = initial_path_count;
303fcf3ce44SJohn Forte 		/* Make driver put actual # paths in variable */
304fcf3ce44SJohn Forte 		ioc->ret_elem = (uint_t *)&(current_path_count);
305fcf3ce44SJohn Forte 
306fcf3ce44SJohn Forte 		/*
307fcf3ce44SJohn Forte 		 * Allocate space for array of path_info structures.
308fcf3ce44SJohn Forte 		 * Allocate enough space for # paths from get_pathcount
309fcf3ce44SJohn Forte 		 */
310fcf3ce44SJohn Forte 		ioc->ret_buf = (sv_path_info_t *)
311fcf3ce44SJohn Forte 				calloc(initial_path_count,
312fcf3ce44SJohn Forte 					sizeof (sv_path_info_t));
313fcf3ce44SJohn Forte 		if (ioc->ret_buf == NULL) {
314fcf3ce44SJohn Forte 			close(fd);
315fcf3ce44SJohn Forte 			return (L_MALLOC_FAILED);
316fcf3ce44SJohn Forte 		}
317fcf3ce44SJohn Forte 
318fcf3ce44SJohn Forte 		/*
319fcf3ce44SJohn Forte 		 * Allocate space for path properties returned by driver
320fcf3ce44SJohn Forte 		 */
321fcf3ce44SJohn Forte 		malloc_error = 0;
322fcf3ce44SJohn Forte 		for (i = 0; i < initial_path_count; i++) {
323fcf3ce44SJohn Forte 			ioc->ret_buf[i].ret_prop.buf_size = prop_buf_size;
324fcf3ce44SJohn Forte 			if ((ioc->ret_buf[i].ret_prop.buf =
325fcf3ce44SJohn Forte 			    (caddr_t)malloc(prop_buf_size)) == NULL) {
326fcf3ce44SJohn Forte 				malloc_error = 1;
327fcf3ce44SJohn Forte 				break;
328fcf3ce44SJohn Forte 			}
329fcf3ce44SJohn Forte 			if ((ioc->ret_buf[i].ret_prop.ret_buf_size =
330fcf3ce44SJohn Forte 				(uint_t *)malloc(sizeof (uint_t))) == NULL) {
331fcf3ce44SJohn Forte 				malloc_error = 1;
332fcf3ce44SJohn Forte 				break;
333fcf3ce44SJohn Forte 			}
334fcf3ce44SJohn Forte 		}
335fcf3ce44SJohn Forte 		if (malloc_error == 1) {
336fcf3ce44SJohn Forte 			for (i = 0; i < initial_path_count; i++) {
337fcf3ce44SJohn Forte 				free(ioc->ret_buf[i].ret_prop.buf);
338fcf3ce44SJohn Forte 				free(ioc->ret_buf[i].ret_prop.ret_buf_size);
339fcf3ce44SJohn Forte 			}
340fcf3ce44SJohn Forte 			free(ioc->ret_buf);
341fcf3ce44SJohn Forte 			close(fd);
342fcf3ce44SJohn Forte 			return (L_MALLOC_FAILED);
343fcf3ce44SJohn Forte 		}
344fcf3ce44SJohn Forte 
345fcf3ce44SJohn Forte 		retval = ioctl(fd, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO, ioc);
346fcf3ce44SJohn Forte 		if (retval != 0) {
347fcf3ce44SJohn Forte 			for (i = 0; i < initial_path_count; i++) {
348fcf3ce44SJohn Forte 				free(ioc->ret_buf[i].ret_prop.buf);
349fcf3ce44SJohn Forte 				free(ioc->ret_buf[i].ret_prop.ret_buf_size);
350fcf3ce44SJohn Forte 			}
351fcf3ce44SJohn Forte 			free(ioc->ret_buf);
352fcf3ce44SJohn Forte 			close(fd);
353fcf3ce44SJohn Forte 			return (L_SCSI_VHCI_ERROR);
354fcf3ce44SJohn Forte 		}
355fcf3ce44SJohn Forte 		if (initial_path_count < current_path_count) {
356fcf3ce44SJohn Forte 			/* then a new path was added */
357fcf3ce44SJohn Forte 			pathlist_retry_count++;
358fcf3ce44SJohn Forte 			initial_path_count = current_path_count;
359fcf3ce44SJohn Forte 		} else {
360fcf3ce44SJohn Forte 			break;
361fcf3ce44SJohn Forte 		}
362fcf3ce44SJohn Forte 	}
363fcf3ce44SJohn Forte 	/* we are done with ioctl's, lose the fd */
364fcf3ce44SJohn Forte 	close(fd);
365fcf3ce44SJohn Forte 
366fcf3ce44SJohn Forte 	/*
367fcf3ce44SJohn Forte 	 * Compare the length num elements from the ioctl response
368fcf3ce44SJohn Forte 	 *   and the caller's request - use smaller value.
369fcf3ce44SJohn Forte 	 *
370fcf3ce44SJohn Forte 	 * pathlist_p->path_count now has count returned from ioctl.
371fcf3ce44SJohn Forte 	 * ioc.buf_elem has the value the caller provided.
372fcf3ce44SJohn Forte 	 */
373fcf3ce44SJohn Forte 	if (initial_path_count < current_path_count) {
374fcf3ce44SJohn Forte 		/* More paths exist than we allocated space for */
375fcf3ce44SJohn Forte 		*num_paths_to_copy = initial_path_count;
376fcf3ce44SJohn Forte 	} else {
377fcf3ce44SJohn Forte 		*num_paths_to_copy = current_path_count;
378fcf3ce44SJohn Forte 	}
379fcf3ce44SJohn Forte return (0);
380fcf3ce44SJohn Forte }
381fcf3ce44SJohn Forte 
382fcf3ce44SJohn Forte /*
383fcf3ce44SJohn Forte  * To obtain pathlist of a given target device
384fcf3ce44SJohn Forte  *
385fcf3ce44SJohn Forte  * inputs:
386fcf3ce44SJohn Forte  *	dev_path client device path
387fcf3ce44SJohn Forte  *	example: /devices/scsi_vhci/ssd@g280000602200416d6257333030303261:c,raw
388fcf3ce44SJohn Forte  * outputs:
389*926d645fSToomas Soome  *	pathlist_p pathlist structure containing pathinfo node data
390fcf3ce44SJohn Forte  * returns:
391fcf3ce44SJohn Forte  *   0 - success
392fcf3ce44SJohn Forte  *  !0 - failure
393fcf3ce44SJohn Forte  */
394fcf3ce44SJohn Forte int
g_get_pathlist(char * dev_path,struct mp_pathlist * pathlist_p)395fcf3ce44SJohn Forte g_get_pathlist(char *dev_path, struct mp_pathlist *pathlist_p)
396fcf3ce44SJohn Forte {
397fcf3ce44SJohn Forte 
398fcf3ce44SJohn Forte 	sv_iocdata_t	ioc;
399fcf3ce44SJohn Forte 	int	retval, caller_ret = 0;
400fcf3ce44SJohn Forte 	int	num_paths_to_copy;
401*926d645fSToomas Soome 	int	i;
402*926d645fSToomas Soome 	int	prop_buf_size;
403fcf3ce44SJohn Forte 	char	*path_class_val = NULL;
404fcf3ce44SJohn Forte 	char	*temp_addr;
405fcf3ce44SJohn Forte 	char	phci_path[MAXPATHLEN];
406fcf3ce44SJohn Forte 	char	client_path[MAXPATHLEN];
407fcf3ce44SJohn Forte 	char	paddr[MAXNAMELEN];
408fcf3ce44SJohn Forte 
409fcf3ce44SJohn Forte 
410fcf3ce44SJohn Forte 	ioc.client = client_path;
411fcf3ce44SJohn Forte 	ioc.phci = phci_path;
412fcf3ce44SJohn Forte 	ioc.addr = paddr;
413fcf3ce44SJohn Forte 
414fcf3ce44SJohn Forte 	if ((caller_ret = get_pathlist(dev_path, &ioc, &num_paths_to_copy))
415fcf3ce44SJohn Forte 		!= 0) {
416fcf3ce44SJohn Forte 		return (caller_ret);
417fcf3ce44SJohn Forte 	}
418fcf3ce44SJohn Forte 
419fcf3ce44SJohn Forte 	pathlist_p->path_count = num_paths_to_copy;
420fcf3ce44SJohn Forte 	pathlist_p->path_info = calloc(num_paths_to_copy,
421fcf3ce44SJohn Forte 					sizeof (mp_pathinfo_t));
422fcf3ce44SJohn Forte 
423fcf3ce44SJohn Forte 	prop_buf_size = SV_PROP_MAX_BUF_SIZE;
424fcf3ce44SJohn Forte 
425fcf3ce44SJohn Forte 	if (pathlist_p->path_info == NULL) {
426fcf3ce44SJohn Forte 		caller_ret = L_MALLOC_FAILED;
427fcf3ce44SJohn Forte 		/* force the loop to not run so we free buffers and exit */
428fcf3ce44SJohn Forte 		num_paths_to_copy = 0;
429fcf3ce44SJohn Forte 	}
430fcf3ce44SJohn Forte 
431fcf3ce44SJohn Forte 	/* get ioctl reponse fields and copy them to caller's buffer */
432fcf3ce44SJohn Forte 	for (i = 0; i < num_paths_to_copy; i++) {
433fcf3ce44SJohn Forte 		nvlist_t *nvl;
434fcf3ce44SJohn Forte 
435fcf3ce44SJohn Forte 		pathlist_p->path_info[i].path_state =
436fcf3ce44SJohn Forte 			ioc.ret_buf[i].ret_state;
437fcf3ce44SJohn Forte 		(void) strncpy(pathlist_p->path_info[i].path_hba, DEV_PREFIX,
438fcf3ce44SJohn Forte 			DEV_PREFIX_LEN - 1);
439fcf3ce44SJohn Forte 		(void) strcat(pathlist_p->path_info[i].path_hba,
440fcf3ce44SJohn Forte 			ioc.ret_buf[i].device.ret_phci);
441fcf3ce44SJohn Forte 		(void) strcpy(pathlist_p->path_info[i].path_dev,
442fcf3ce44SJohn Forte 			ioc.client);
443fcf3ce44SJohn Forte 
444fcf3ce44SJohn Forte 		/*
445fcf3ce44SJohn Forte 		 * Check for leading 'w'. The mpxio framework was
446fcf3ce44SJohn Forte 		 * incorrectly implemented to skip 'w' in mdi_pi_get_addr().
447fcf3ce44SJohn Forte 		 * Since the leading 'w' is fibre-channel specific, we
448fcf3ce44SJohn Forte 		 * do it here to remove fibre-channel specific behavior
449fcf3ce44SJohn Forte 		 * from the mpxio framework.
450fcf3ce44SJohn Forte 		 */
451fcf3ce44SJohn Forte 		temp_addr = ioc.ret_buf[i].ret_addr;
452fcf3ce44SJohn Forte 		if (*temp_addr == 'w') {
453fcf3ce44SJohn Forte 			temp_addr++;
454fcf3ce44SJohn Forte 		}
455fcf3ce44SJohn Forte 		(void) strcpy(pathlist_p->path_info[i].path_addr, temp_addr);
456fcf3ce44SJohn Forte 
457fcf3ce44SJohn Forte 		/* use nvlist_ calls to extract properties from retbuf */
458fcf3ce44SJohn Forte 		retval = nvlist_unpack(ioc.ret_buf[i].ret_prop.buf,
459fcf3ce44SJohn Forte 					prop_buf_size, &nvl, 0);
460fcf3ce44SJohn Forte 		if (retval != 0) { /* ??? same retcode */
461fcf3ce44SJohn Forte 			(void) strcpy(pathlist_p->path_info[i].path_class,
462fcf3ce44SJohn Forte 				"UNKNOWN PROB");
463fcf3ce44SJohn Forte 		} else {
464fcf3ce44SJohn Forte 			retval = nvlist_lookup_string(nvl, "path-class",
465fcf3ce44SJohn Forte 				&path_class_val);
466fcf3ce44SJohn Forte 			if (retval != 0) {
467fcf3ce44SJohn Forte 			(void) strcpy(pathlist_p->path_info[i].path_class,
468fcf3ce44SJohn Forte 				"UNKNOWN");
469fcf3ce44SJohn Forte 			} else {
470fcf3ce44SJohn Forte 				(void) strcpy(pathlist_p->path_info[i].
471fcf3ce44SJohn Forte 					path_class,
472fcf3ce44SJohn Forte 					path_class_val);
473fcf3ce44SJohn Forte 			}
474fcf3ce44SJohn Forte 			nvlist_free(nvl);
475fcf3ce44SJohn Forte 		}
476fcf3ce44SJohn Forte 	}
477fcf3ce44SJohn Forte 
478fcf3ce44SJohn Forte 	/* free everything we alloced */
479fcf3ce44SJohn Forte 	for (i = 0; i < ioc.buf_elem; i++) {
480fcf3ce44SJohn Forte 		free(ioc.ret_buf[i].ret_prop.buf);
481fcf3ce44SJohn Forte 		free(ioc.ret_buf[i].ret_prop.ret_buf_size);
482fcf3ce44SJohn Forte 	}
483fcf3ce44SJohn Forte 	free(ioc.ret_buf);
484fcf3ce44SJohn Forte return (caller_ret);
485fcf3ce44SJohn Forte }
486fcf3ce44SJohn Forte 
487fcf3ce44SJohn Forte /*
488fcf3ce44SJohn Forte  * To get the number of paths to a given device pathname using
489fcf3ce44SJohn Forte  * driver ioctl.
490fcf3ce44SJohn Forte  *
491fcf3ce44SJohn Forte  * inputs:
492fcf3ce44SJohn Forte  *   dev path you would like to recieve mp count on
493fcf3ce44SJohn Forte  * outputs:
494fcf3ce44SJohn Forte  * returns:
495fcf3ce44SJohn Forte  *   0  - success
496fcf3ce44SJohn Forte  *   -1 - bad device path
497fcf3ce44SJohn Forte  *   -2 - open failure
498fcf3ce44SJohn Forte  *   -3 - ioctl failure
499fcf3ce44SJohn Forte  */
500fcf3ce44SJohn Forte int
g_get_pathcount(char * dev_path)501fcf3ce44SJohn Forte g_get_pathcount(char *dev_path)
502fcf3ce44SJohn Forte {
503fcf3ce44SJohn Forte 	char		*char_ptr;
504fcf3ce44SJohn Forte 	int		fd = -1;
505fcf3ce44SJohn Forte 	sv_iocdata_t	ioc;
506fcf3ce44SJohn Forte 	char		phci_path[MAXPATHLEN];
507fcf3ce44SJohn Forte 	char		client_path[MAXPATHLEN];
508fcf3ce44SJohn Forte 	char		paddr[MAXNAMELEN];
509fcf3ce44SJohn Forte 	uint_t		num_elem = 0;
510fcf3ce44SJohn Forte 	int		retval = 0;
511fcf3ce44SJohn Forte 	char		*physical_path;
512fcf3ce44SJohn Forte 
513fcf3ce44SJohn Forte 	/* translate device path to physical path */
514fcf3ce44SJohn Forte 	physical_path = g_get_physical_name(dev_path);
515fcf3ce44SJohn Forte 	/* ensure physical path is not NULL, or strcpy will core */
516fcf3ce44SJohn Forte 	if (physical_path == NULL) {
517fcf3ce44SJohn Forte 		return (-1);
518fcf3ce44SJohn Forte 	}
519fcf3ce44SJohn Forte 	/* copy physical path without /devices/ prefix */
520fcf3ce44SJohn Forte 	(void) strcpy(client_path, physical_path + DEV_PREFIX_LEN-1);
521fcf3ce44SJohn Forte 	free(physical_path);
522fcf3ce44SJohn Forte 
523fcf3ce44SJohn Forte 	if ((char_ptr = strrchr(client_path, ':')) != NULL) {
524fcf3ce44SJohn Forte 		*char_ptr = '\0';
525fcf3ce44SJohn Forte 	}
526fcf3ce44SJohn Forte 
527fcf3ce44SJohn Forte 	/* prepare sv_iocdata_t structure */
528fcf3ce44SJohn Forte 	ioc.client	= client_path;
529fcf3ce44SJohn Forte 	ioc.phci	= phci_path;
530fcf3ce44SJohn Forte 	ioc.addr	= paddr;
531fcf3ce44SJohn Forte 	ioc.buf_elem	= 0;
532fcf3ce44SJohn Forte 	ioc.ret_buf	= NULL;
533fcf3ce44SJohn Forte 	ioc.ret_elem	= &num_elem;
534fcf3ce44SJohn Forte 
535fcf3ce44SJohn Forte 	strcpy(ioc.phci, client_path);
536fcf3ce44SJohn Forte 
537fcf3ce44SJohn Forte 	/* Get file descr. for "/devices/scsi_vhci:devctl" */
538fcf3ce44SJohn Forte 	if ((fd = g_object_open(VHCI_NODE, O_RDWR)) < 0) {
539fcf3ce44SJohn Forte 		return (-2);
540fcf3ce44SJohn Forte 	}
541fcf3ce44SJohn Forte 
542fcf3ce44SJohn Forte 	/* Issue open to device to get multipath_info (ie. count) */
543fcf3ce44SJohn Forte 	retval = ioctl(fd, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO, &ioc);
544fcf3ce44SJohn Forte 	close(fd);
545fcf3ce44SJohn Forte 
546fcf3ce44SJohn Forte 	/* Check icotl status */
547fcf3ce44SJohn Forte 	if (retval == 0) {
548fcf3ce44SJohn Forte 		/* success */
549fcf3ce44SJohn Forte 		return (*ioc.ret_elem);
550fcf3ce44SJohn Forte 	} else {
551fcf3ce44SJohn Forte 		/* failure */
552fcf3ce44SJohn Forte 		return (-3);
553fcf3ce44SJohn Forte 	}
554fcf3ce44SJohn Forte 
555fcf3ce44SJohn Forte }
556fcf3ce44SJohn Forte 
557fcf3ce44SJohn Forte 
558fcf3ce44SJohn Forte /*
559fcf3ce44SJohn Forte  * Call driver to effect failover for a given pathclass
560fcf3ce44SJohn Forte  *
561fcf3ce44SJohn Forte  * inputs:
562fcf3ce44SJohn Forte  * outputs:
563fcf3ce44SJohn Forte  * returns:
564fcf3ce44SJohn Forte  *   0  - success
565fcf3ce44SJohn Forte  *   !0 - failure
566fcf3ce44SJohn Forte  */
567fcf3ce44SJohn Forte int
g_failover(char * dev_path,char * path_class)568fcf3ce44SJohn Forte g_failover(char *dev_path, char *path_class)
569fcf3ce44SJohn Forte {
570fcf3ce44SJohn Forte int		fd = 0, ret = 0;
571fcf3ce44SJohn Forte char		client_path[MAXPATHLEN];
572fcf3ce44SJohn Forte char		class[MAXNAMELEN];
573fcf3ce44SJohn Forte sv_switch_to_cntlr_iocdata_t	iocsc;
574fcf3ce44SJohn Forte 
575fcf3ce44SJohn Forte char		*char_ptr_start, *char_ptr_end;
576fcf3ce44SJohn Forte 
577fcf3ce44SJohn Forte 
578fcf3ce44SJohn Forte 	if (strstr(dev_path, SCSI_VHCI) == NULL) {
579fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
580fcf3ce44SJohn Forte 	}
581fcf3ce44SJohn Forte 
582fcf3ce44SJohn Forte 	char_ptr_start = dev_path + strlen("/devices");
583fcf3ce44SJohn Forte 	if ((char_ptr_end = strrchr(char_ptr_start, ':')) != NULL) {
584fcf3ce44SJohn Forte 		*char_ptr_end = '\0';
585fcf3ce44SJohn Forte 	}
586fcf3ce44SJohn Forte 
587fcf3ce44SJohn Forte 	if ((fd = g_object_open(VHCI_NODE, O_RDWR)) < 0) {
588fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
589fcf3ce44SJohn Forte 	}
590fcf3ce44SJohn Forte 
591fcf3ce44SJohn Forte 	iocsc.client = client_path;
592fcf3ce44SJohn Forte 	iocsc.class = class;
593fcf3ce44SJohn Forte 
594fcf3ce44SJohn Forte 	strcpy(iocsc.client, char_ptr_start);
595fcf3ce44SJohn Forte 	strcpy(iocsc.class, path_class);
596fcf3ce44SJohn Forte 
597fcf3ce44SJohn Forte 	if (ioctl(fd, SCSI_VHCI_SWITCH_TO_CNTLR, &iocsc) != 0) {
598fcf3ce44SJohn Forte 		switch (errno) {
599fcf3ce44SJohn Forte 			case EALREADY:
600fcf3ce44SJohn Forte 				ret = L_SCSI_VHCI_ALREADY_ACTIVE;
601fcf3ce44SJohn Forte 				break;
602fcf3ce44SJohn Forte 			case ENXIO:
603fcf3ce44SJohn Forte 				ret = L_INVALID_PATH;
604fcf3ce44SJohn Forte 				break;
605fcf3ce44SJohn Forte 			case EIO:
606fcf3ce44SJohn Forte 				ret = L_SCSI_VHCI_NO_STANDBY;
607fcf3ce44SJohn Forte 				break;
608fcf3ce44SJohn Forte 			case ENOTSUP:
609fcf3ce44SJohn Forte 				ret = L_SCSI_VHCI_FAILOVER_NOTSUP;
610fcf3ce44SJohn Forte 				break;
611fcf3ce44SJohn Forte 			case EBUSY:
612fcf3ce44SJohn Forte 				ret = L_SCSI_VHCI_FAILOVER_BUSY;
613fcf3ce44SJohn Forte 				break;
614fcf3ce44SJohn Forte 			case EFAULT:
615fcf3ce44SJohn Forte 			default:
616fcf3ce44SJohn Forte 				ret = L_SCSI_VHCI_ERROR;
617fcf3ce44SJohn Forte 		}
618fcf3ce44SJohn Forte 	}
619fcf3ce44SJohn Forte 
620fcf3ce44SJohn Forte 	close(fd);
621fcf3ce44SJohn Forte 	return (ret);
622fcf3ce44SJohn Forte }
623fcf3ce44SJohn Forte 
624fcf3ce44SJohn Forte static void
g_free_pi_list(sv_path_info_t * pi,uint_t num_paths)625fcf3ce44SJohn Forte g_free_pi_list(sv_path_info_t *pi, uint_t num_paths)
626fcf3ce44SJohn Forte {
627fcf3ce44SJohn Forte sv_path_info_t *pi_h = pi;
628fcf3ce44SJohn Forte int i = 0;
629fcf3ce44SJohn Forte 
630fcf3ce44SJohn Forte 	while (i++ < num_paths && pi != NULL) {
631fcf3ce44SJohn Forte 		free(pi->ret_prop.buf);
632fcf3ce44SJohn Forte 		free(pi->ret_prop.ret_buf_size);
633fcf3ce44SJohn Forte 		pi++;
634fcf3ce44SJohn Forte 	}
635fcf3ce44SJohn Forte 	free(pi_h);
636fcf3ce44SJohn Forte }
637fcf3ce44SJohn Forte 
638fcf3ce44SJohn Forte 
639fcf3ce44SJohn Forte /*
640fcf3ce44SJohn Forte  * Name: stms_path_enable_disable
641fcf3ce44SJohn Forte  *
642fcf3ce44SJohn Forte  * inputs:
643fcf3ce44SJohn Forte  *
644fcf3ce44SJohn Forte  * client_path	client device path
645fcf3ce44SJohn Forte  *	example: /devices/scsi_vhci/ssd@g280000602200416d6257333030303261:c,raw
646fcf3ce44SJohn Forte  *
647fcf3ce44SJohn Forte  * phci		Controller device path
648fcf3ce44SJohn Forte  *	example: /devices/pci@4,4000/SUNW,qlc@4/fp@0,0
649fcf3ce44SJohn Forte  *
650fcf3ce44SJohn Forte  * request should be set to one of the following:
651fcf3ce44SJohn Forte  *	SCSI_VHCI_PATH_DISABLE
652fcf3ce44SJohn Forte  *	SCSI_VHCI_PATH_ENABLE
653fcf3ce44SJohn Forte  *
654fcf3ce44SJohn Forte  * returns:
655fcf3ce44SJohn Forte  *	0 for success
656fcf3ce44SJohn Forte  *	non-zero otherwise
657fcf3ce44SJohn Forte  */
658fcf3ce44SJohn Forte static int
stms_path_enable_disable(char * client_path,char * phci,int request)659fcf3ce44SJohn Forte stms_path_enable_disable(char *client_path, char *phci, int request)
660fcf3ce44SJohn Forte {
661fcf3ce44SJohn Forte 	char *ioc_phci;
662fcf3ce44SJohn Forte 	char *char_ptr_end;
663fcf3ce44SJohn Forte 	char *client_physical_path, *client_path_ptr;
664fcf3ce44SJohn Forte 	int fd;
665fcf3ce44SJohn Forte 	sv_iocdata_t	ioc;
666fcf3ce44SJohn Forte 
667fcf3ce44SJohn Forte 	if (!client_path || !phci) {
668fcf3ce44SJohn Forte 		return (EINVAL);
669fcf3ce44SJohn Forte 	}
670fcf3ce44SJohn Forte 
671fcf3ce44SJohn Forte 	if ((fd = g_object_open(VHCI_NODE, O_RDWR)) < 0) {
672fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
673fcf3ce44SJohn Forte 	}
674fcf3ce44SJohn Forte 
675fcf3ce44SJohn Forte 	/*
676fcf3ce44SJohn Forte 	 * translate device path to physical path
677fcf3ce44SJohn Forte 	 * Save off the ptr for use by free
678fcf3ce44SJohn Forte 	 */
679fcf3ce44SJohn Forte 	client_path_ptr = client_physical_path =
680fcf3ce44SJohn Forte 		g_get_physical_name(client_path);
681fcf3ce44SJohn Forte 
682fcf3ce44SJohn Forte 	/* ensure physical path is not NULL, or strcpy will core */
683fcf3ce44SJohn Forte 	if (client_physical_path == NULL) {
684fcf3ce44SJohn Forte 		return (EINVAL);
685fcf3ce44SJohn Forte 	}
686fcf3ce44SJohn Forte 
687fcf3ce44SJohn Forte 	/*
688fcf3ce44SJohn Forte 	 * Must be a scsi_vhci path
689fcf3ce44SJohn Forte 	 */
690fcf3ce44SJohn Forte 	if (strstr(client_physical_path, SCSI_VHCI) == NULL) {
691fcf3ce44SJohn Forte 		free(client_path_ptr);
692fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
693fcf3ce44SJohn Forte 	}
694fcf3ce44SJohn Forte 
695fcf3ce44SJohn Forte 	/* physical path without /devices/ prefix */
696fcf3ce44SJohn Forte 	client_physical_path += DEV_PREFIX_LEN - 1;
697fcf3ce44SJohn Forte 
698fcf3ce44SJohn Forte 	if ((char_ptr_end = strrchr(client_physical_path, ':')) != NULL) {
699fcf3ce44SJohn Forte 		*char_ptr_end = '\0';
700fcf3ce44SJohn Forte 	}
701fcf3ce44SJohn Forte 
702fcf3ce44SJohn Forte 	/*
703fcf3ce44SJohn Forte 	 * If there is a '/devices', strip it, if not
704fcf3ce44SJohn Forte 	 * assume it is complete and correct
705fcf3ce44SJohn Forte 	 */
706fcf3ce44SJohn Forte 	if (strncmp(phci, DEV_PREFIX, DEV_PREFIX_LEN) == 0) {
707fcf3ce44SJohn Forte 		ioc_phci = phci + DEV_PREFIX_LEN - 1;
708fcf3ce44SJohn Forte 	} else {
709fcf3ce44SJohn Forte 		ioc_phci = phci;
710fcf3ce44SJohn Forte 	}
711fcf3ce44SJohn Forte 
712fcf3ce44SJohn Forte 	memset(&ioc, 0, sizeof (ioc));
713fcf3ce44SJohn Forte 
714fcf3ce44SJohn Forte 	ioc.client = client_physical_path;
715fcf3ce44SJohn Forte 	ioc.phci = ioc_phci;
716fcf3ce44SJohn Forte 
717fcf3ce44SJohn Forte 	/*
718fcf3ce44SJohn Forte 	 * Issue requested operation
719fcf3ce44SJohn Forte 	 */
720fcf3ce44SJohn Forte 	if (ioctl(fd, request, &ioc) != 0) {
721fcf3ce44SJohn Forte 		free(client_path_ptr);
722fcf3ce44SJohn Forte 		return (errno);
723fcf3ce44SJohn Forte 	}
724fcf3ce44SJohn Forte 	free(client_path_ptr);
725fcf3ce44SJohn Forte 	return (0);
726fcf3ce44SJohn Forte }
727fcf3ce44SJohn Forte 
728fcf3ce44SJohn Forte int
g_stms_path_disable(char * client_path,char * phci)729fcf3ce44SJohn Forte g_stms_path_disable(char *client_path, char *phci)
730fcf3ce44SJohn Forte {
731fcf3ce44SJohn Forte 	return (stms_path_enable_disable(client_path, phci,
732fcf3ce44SJohn Forte 		SCSI_VHCI_PATH_DISABLE));
733fcf3ce44SJohn Forte }
734fcf3ce44SJohn Forte 
735fcf3ce44SJohn Forte int
g_stms_path_enable(char * client_path,char * phci)736fcf3ce44SJohn Forte g_stms_path_enable(char *client_path, char *phci)
737fcf3ce44SJohn Forte {
738fcf3ce44SJohn Forte 	return (stms_path_enable_disable(client_path, phci,
739fcf3ce44SJohn Forte 		SCSI_VHCI_PATH_ENABLE));
740fcf3ce44SJohn Forte }
741fcf3ce44SJohn Forte 
742fcf3ce44SJohn Forte /*
743fcf3ce44SJohn Forte  * Name: stms_path_enable_disable_all
744fcf3ce44SJohn Forte  *
745fcf3ce44SJohn Forte  * inputs:
746fcf3ce44SJohn Forte  *
747fcf3ce44SJohn Forte  * phci		Controller device path
748fcf3ce44SJohn Forte  *	example: /devices/pci@4,4000/SUNW,qlc@4/fp@0,0
749fcf3ce44SJohn Forte  *
750fcf3ce44SJohn Forte  * request should be set to one of the following:
751fcf3ce44SJohn Forte  *	SCSI_VHCI_PATH_DISABLE
752fcf3ce44SJohn Forte  *	SCSI_VHCI_PATH_ENABLE
753fcf3ce44SJohn Forte  *
754fcf3ce44SJohn Forte  * returns:
755fcf3ce44SJohn Forte  *	0 for success
756fcf3ce44SJohn Forte  *	non-zero otherwise
757fcf3ce44SJohn Forte  */
758fcf3ce44SJohn Forte 
759fcf3ce44SJohn Forte static int
stms_path_enable_disable_all(char * phci,int request)760fcf3ce44SJohn Forte stms_path_enable_disable_all(char *phci, int request)
761fcf3ce44SJohn Forte {
762fcf3ce44SJohn Forte 	int fd;
763fcf3ce44SJohn Forte 	char *ioc_phci;
764fcf3ce44SJohn Forte 	sv_iocdata_t ioc;
765fcf3ce44SJohn Forte 
766fcf3ce44SJohn Forte 	if (!phci) {
767fcf3ce44SJohn Forte 		return (EINVAL);
768fcf3ce44SJohn Forte 	}
769fcf3ce44SJohn Forte 
770fcf3ce44SJohn Forte 	if ((fd = g_object_open(VHCI_NODE, O_RDWR)) < 0) {
771fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
772fcf3ce44SJohn Forte 	}
773fcf3ce44SJohn Forte 
774fcf3ce44SJohn Forte 	memset(&ioc, 0, sizeof (ioc));
775fcf3ce44SJohn Forte 
776fcf3ce44SJohn Forte 	/*
777fcf3ce44SJohn Forte 	 * If there is a '/devices', strip it, if not
778fcf3ce44SJohn Forte 	 * assume it is complete and correct
779fcf3ce44SJohn Forte 	 */
780fcf3ce44SJohn Forte 	if (strncmp(phci, DEV_PREFIX, DEV_PREFIX_LEN) == 0) {
781fcf3ce44SJohn Forte 		ioc_phci = phci + DEV_PREFIX_LEN - 1;
782fcf3ce44SJohn Forte 	} else {
783fcf3ce44SJohn Forte 		ioc_phci = phci;
784fcf3ce44SJohn Forte 	}
785fcf3ce44SJohn Forte 
786fcf3ce44SJohn Forte 	ioc.client = "/scsi_vhci";
787fcf3ce44SJohn Forte 	ioc.phci = ioc_phci;
788fcf3ce44SJohn Forte 
789fcf3ce44SJohn Forte 	/*
790fcf3ce44SJohn Forte 	 * Issue requested operation
791fcf3ce44SJohn Forte 	 */
792fcf3ce44SJohn Forte 	if (ioctl(fd, request, &ioc) != 0) {
793fcf3ce44SJohn Forte 		return (errno);
794fcf3ce44SJohn Forte 	}
795fcf3ce44SJohn Forte 	return (0);
796fcf3ce44SJohn Forte }
797fcf3ce44SJohn Forte 
798fcf3ce44SJohn Forte int
g_stms_path_disable_all(char * phci)799fcf3ce44SJohn Forte g_stms_path_disable_all(char *phci)
800fcf3ce44SJohn Forte {
801fcf3ce44SJohn Forte 	/*
802fcf3ce44SJohn Forte 	 * issue disable on all clients for a phci
803fcf3ce44SJohn Forte 	 */
804fcf3ce44SJohn Forte 	return (stms_path_enable_disable_all(phci, SCSI_VHCI_PATH_DISABLE));
805fcf3ce44SJohn Forte }
806fcf3ce44SJohn Forte 
807fcf3ce44SJohn Forte int
g_stms_path_enable_all(char * phci)808fcf3ce44SJohn Forte g_stms_path_enable_all(char *phci)
809fcf3ce44SJohn Forte {
810fcf3ce44SJohn Forte 	/*
811fcf3ce44SJohn Forte 	 * issue enable on all clients for a phci
812fcf3ce44SJohn Forte 	 */
813fcf3ce44SJohn Forte 	return (stms_path_enable_disable_all(phci, SCSI_VHCI_PATH_ENABLE));
814fcf3ce44SJohn Forte }
815fcf3ce44SJohn Forte 
816fcf3ce44SJohn Forte /*
817fcf3ce44SJohn Forte  * Name: stms_get_path_state
818fcf3ce44SJohn Forte  *
819fcf3ce44SJohn Forte  * inputs:
820fcf3ce44SJohn Forte  *
821fcf3ce44SJohn Forte  * client_path	client device path
822fcf3ce44SJohn Forte  *	example: /devices/scsi_vhci/ssd@g280000602200416d6257333030303261:c,raw
823fcf3ce44SJohn Forte  *
824fcf3ce44SJohn Forte  * phci		Controller device path
825fcf3ce44SJohn Forte  *	example: /devices/pci@4,4000/SUNW,qlc@4/fp@0,0
826fcf3ce44SJohn Forte  *
827fcf3ce44SJohn Forte  * outputs:
828fcf3ce44SJohn Forte  * state set to one of enum mdi_pathinfo_state_t in sunmdi.h
829fcf3ce44SJohn Forte  *	MDI_PATHINFO_STATE_*
830fcf3ce44SJohn Forte  *
831fcf3ce44SJohn Forte  * ext_state set to one or more of the bits defined in mdi_impldefs.h
832fcf3ce44SJohn Forte  *	MDI_PATHINFO_STATE_*
833fcf3ce44SJohn Forte  *
834fcf3ce44SJohn Forte  *
835fcf3ce44SJohn Forte  * returns:
836fcf3ce44SJohn Forte  *	0 for success
837fcf3ce44SJohn Forte  *	non-zero otherwise
838fcf3ce44SJohn Forte  */
839fcf3ce44SJohn Forte int
g_stms_get_path_state(char * client_path,char * phci,int * state,int * ext_state)840fcf3ce44SJohn Forte g_stms_get_path_state(char *client_path, char *phci, int *state, int *ext_state)
841fcf3ce44SJohn Forte {
842fcf3ce44SJohn Forte 	sv_iocdata_t ioc;
843fcf3ce44SJohn Forte 	int num_paths;
844fcf3ce44SJohn Forte 	char *ioc_phci;
845fcf3ce44SJohn Forte 	int i;
846fcf3ce44SJohn Forte 	int found = 0;
847fcf3ce44SJohn Forte 	int err;
848fcf3ce44SJohn Forte 	char	phci_path[MAXPATHLEN];
849fcf3ce44SJohn Forte 	char	cpath[MAXPATHLEN];
850fcf3ce44SJohn Forte 	char	paddr[MAXNAMELEN];
851fcf3ce44SJohn Forte 
852fcf3ce44SJohn Forte 
853fcf3ce44SJohn Forte 	if (!client_path || !phci) {
854fcf3ce44SJohn Forte 		return (EINVAL);
855fcf3ce44SJohn Forte 	}
856fcf3ce44SJohn Forte 
857fcf3ce44SJohn Forte 	ioc.client = cpath;
858fcf3ce44SJohn Forte 	ioc.phci = phci_path;
859fcf3ce44SJohn Forte 	ioc.addr = paddr;
860fcf3ce44SJohn Forte 
861fcf3ce44SJohn Forte 	/*
862fcf3ce44SJohn Forte 	 * Get all the paths for this client
863fcf3ce44SJohn Forte 	 */
864fcf3ce44SJohn Forte 	if ((err = get_pathlist(client_path, &ioc, &num_paths))
865fcf3ce44SJohn Forte 		!= 0) {
866fcf3ce44SJohn Forte 		return (err);
867fcf3ce44SJohn Forte 	}
868fcf3ce44SJohn Forte 
869fcf3ce44SJohn Forte 	/*
870fcf3ce44SJohn Forte 	 * If there is a '/devices', strip it, if not
871fcf3ce44SJohn Forte 	 * assume it is complete and correct
872fcf3ce44SJohn Forte 	 */
873fcf3ce44SJohn Forte 	if (strncmp(phci, DEV_PREFIX, DEV_PREFIX_LEN) == 0) {
874fcf3ce44SJohn Forte 		ioc_phci = phci + DEV_PREFIX_LEN - 1;
875fcf3ce44SJohn Forte 	} else {
876fcf3ce44SJohn Forte 		ioc_phci = phci;
877fcf3ce44SJohn Forte 	}
878fcf3ce44SJohn Forte 
879fcf3ce44SJohn Forte 	/*
880fcf3ce44SJohn Forte 	 * get ioctl response states
881fcf3ce44SJohn Forte 	 * for the requested client and phci
882fcf3ce44SJohn Forte 	 * and copy them to caller's buffers
883fcf3ce44SJohn Forte 	 */
884fcf3ce44SJohn Forte 	for (i = 0; i < num_paths; i++) {
885fcf3ce44SJohn Forte 		if (strncmp(ioc_phci, ioc.ret_buf[i].device.ret_phci,
886fcf3ce44SJohn Forte 			strlen(ioc_phci)) == 0) {
887fcf3ce44SJohn Forte 			found++;
888fcf3ce44SJohn Forte 			*state = ioc.ret_buf[i].ret_state;
889fcf3ce44SJohn Forte 			*ext_state = ioc.ret_buf[i].ret_ext_state;
890fcf3ce44SJohn Forte 			break;
891fcf3ce44SJohn Forte 		}
892fcf3ce44SJohn Forte 	}
893fcf3ce44SJohn Forte 
894fcf3ce44SJohn Forte 	/* free everything we alloced */
895fcf3ce44SJohn Forte 	for (i = 0; i < ioc.buf_elem; i++) {
896fcf3ce44SJohn Forte 		free(ioc.ret_buf[i].ret_prop.buf);
897fcf3ce44SJohn Forte 		free(ioc.ret_buf[i].ret_prop.ret_buf_size);
898fcf3ce44SJohn Forte 	}
899fcf3ce44SJohn Forte 	free(ioc.ret_buf);
900fcf3ce44SJohn Forte 
901fcf3ce44SJohn Forte 	if (found) {
902fcf3ce44SJohn Forte 		return (0);
903fcf3ce44SJohn Forte 	} else {
904fcf3ce44SJohn Forte 		/* Requested path not found */
905fcf3ce44SJohn Forte 		return (ENXIO);
906fcf3ce44SJohn Forte 	}
907fcf3ce44SJohn Forte }