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