xref: /onnv-gate/usr/src/lib/storage/libg_fc/common/hot.c (revision 7836:4e95154b5b7a)
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 /*
31*7836SJohn.Forte@Sun.COM  *	This module is part of fibre channel interface library.
32*7836SJohn.Forte@Sun.COM  */
33*7836SJohn.Forte@Sun.COM 
34*7836SJohn.Forte@Sun.COM /*
35*7836SJohn.Forte@Sun.COM  * I18N message number ranges
36*7836SJohn.Forte@Sun.COM  *  This file: 11000 - 11499
37*7836SJohn.Forte@Sun.COM  *  Shared common messages: 1 - 1999
38*7836SJohn.Forte@Sun.COM  */
39*7836SJohn.Forte@Sun.COM 
40*7836SJohn.Forte@Sun.COM /* #define		_POSIX_SOURCE 1 */
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/errno.h>
47*7836SJohn.Forte@Sun.COM #include	<sys/types.h>
48*7836SJohn.Forte@Sun.COM #include	<sys/param.h>
49*7836SJohn.Forte@Sun.COM #include	<sys/stat.h>
50*7836SJohn.Forte@Sun.COM #include	<fcntl.h>
51*7836SJohn.Forte@Sun.COM #include	<unistd.h>
52*7836SJohn.Forte@Sun.COM #include	<errno.h>
53*7836SJohn.Forte@Sun.COM #include	<string.h>
54*7836SJohn.Forte@Sun.COM #include	<strings.h>
55*7836SJohn.Forte@Sun.COM #include	<sys/sunddi.h>
56*7836SJohn.Forte@Sun.COM #include	<sys/scsi/scsi.h>
57*7836SJohn.Forte@Sun.COM #include	<nl_types.h>
58*7836SJohn.Forte@Sun.COM #include	<l_common.h>
59*7836SJohn.Forte@Sun.COM #include	<stgcom.h>
60*7836SJohn.Forte@Sun.COM #include	<l_error.h>
61*7836SJohn.Forte@Sun.COM #include	<g_state.h>
62*7836SJohn.Forte@Sun.COM 
63*7836SJohn.Forte@Sun.COM /* Forward declarations */
64*7836SJohn.Forte@Sun.COM static int issue_lip(char *, int);
65*7836SJohn.Forte@Sun.COM 
66*7836SJohn.Forte@Sun.COM 
67*7836SJohn.Forte@Sun.COM /*	Global variables	*/
68*7836SJohn.Forte@Sun.COM extern	uchar_t		g_switch_to_alpa[];
69*7836SJohn.Forte@Sun.COM extern	uchar_t		g_sf_alpa_to_switch[];
70*7836SJohn.Forte@Sun.COM 
71*7836SJohn.Forte@Sun.COM /*
72*7836SJohn.Forte@Sun.COM  * starts a device.
73*7836SJohn.Forte@Sun.COM  *
74*7836SJohn.Forte@Sun.COM  * RETURNS:
75*7836SJohn.Forte@Sun.COM  *	0	 if O.K.
76*7836SJohn.Forte@Sun.COM  *	non-zero otherwise
77*7836SJohn.Forte@Sun.COM  */
78*7836SJohn.Forte@Sun.COM int
g_dev_start(char * drv_path,int verbose)79*7836SJohn.Forte@Sun.COM g_dev_start(char *drv_path, int verbose)
80*7836SJohn.Forte@Sun.COM {
81*7836SJohn.Forte@Sun.COM int status;
82*7836SJohn.Forte@Sun.COM 
83*7836SJohn.Forte@Sun.COM 	if ((drv_path != NULL) && (*drv_path != '\0')) {
84*7836SJohn.Forte@Sun.COM 		if (status = g_start(drv_path)) {
85*7836SJohn.Forte@Sun.COM 			return (status);
86*7836SJohn.Forte@Sun.COM 		}
87*7836SJohn.Forte@Sun.COM 	}
88*7836SJohn.Forte@Sun.COM 	return (L_INVALID_PATH);
89*7836SJohn.Forte@Sun.COM }
90*7836SJohn.Forte@Sun.COM 
91*7836SJohn.Forte@Sun.COM 
92*7836SJohn.Forte@Sun.COM 
93*7836SJohn.Forte@Sun.COM /*
94*7836SJohn.Forte@Sun.COM  * stops a device. If the device was
95*7836SJohn.Forte@Sun.COM  * reserved by a host, it gets multiple
96*7836SJohn.Forte@Sun.COM  * paths to the device and try to stop the
97*7836SJohn.Forte@Sun.COM  * device using a different path.
98*7836SJohn.Forte@Sun.COM  *
99*7836SJohn.Forte@Sun.COM  * Returns:
100*7836SJohn.Forte@Sun.COM  *	0 if OK
101*7836SJohn.Forte@Sun.COM  *	-1 otherwise
102*7836SJohn.Forte@Sun.COM  */
103*7836SJohn.Forte@Sun.COM 
104*7836SJohn.Forte@Sun.COM int
g_dev_stop(char * drv_path,struct wwn_list_struct * wwn_list,int verbose)105*7836SJohn.Forte@Sun.COM g_dev_stop(char *drv_path, struct wwn_list_struct *wwn_list,
106*7836SJohn.Forte@Sun.COM 						int verbose)
107*7836SJohn.Forte@Sun.COM {
108*7836SJohn.Forte@Sun.COM int		status, err;
109*7836SJohn.Forte@Sun.COM char		*phys_path;
110*7836SJohn.Forte@Sun.COM struct dlist	*ml = NULL;
111*7836SJohn.Forte@Sun.COM 
112*7836SJohn.Forte@Sun.COM 
113*7836SJohn.Forte@Sun.COM 	/* stop the device */
114*7836SJohn.Forte@Sun.COM 	/* Make the stop NOT immediate, so we wait. */
115*7836SJohn.Forte@Sun.COM 	if ((drv_path == NULL) || (*drv_path == '\0')) {
116*7836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH);
117*7836SJohn.Forte@Sun.COM 	}
118*7836SJohn.Forte@Sun.COM 	if ((status = g_stop(drv_path, 0)) != 0) {
119*7836SJohn.Forte@Sun.COM 		/*
120*7836SJohn.Forte@Sun.COM 		 * In case of reservation conflict,
121*7836SJohn.Forte@Sun.COM 		 * get the multiple paths and try to
122*7836SJohn.Forte@Sun.COM 		 * stop the device through the path
123*7836SJohn.Forte@Sun.COM 		 * which held the reservations.
124*7836SJohn.Forte@Sun.COM 		 */
125*7836SJohn.Forte@Sun.COM 		if ((status & ~L_SCSI_ERROR) == STATUS_RESERVATION_CONFLICT) {
126*7836SJohn.Forte@Sun.COM 			if ((phys_path = g_get_physical_name(drv_path))
127*7836SJohn.Forte@Sun.COM 								== NULL) {
128*7836SJohn.Forte@Sun.COM 				return (L_INVALID_PATH);
129*7836SJohn.Forte@Sun.COM 			}
130*7836SJohn.Forte@Sun.COM 			if ((err = g_get_multipath(phys_path, &ml,
131*7836SJohn.Forte@Sun.COM 						wwn_list, verbose)) != 0) {
132*7836SJohn.Forte@Sun.COM 				return (err);
133*7836SJohn.Forte@Sun.COM 			}
134*7836SJohn.Forte@Sun.COM 			while (ml != NULL) {
135*7836SJohn.Forte@Sun.COM 				if (g_stop(ml->logical_path, 0) == 0) {
136*7836SJohn.Forte@Sun.COM 					(void) g_free_multipath(ml);
137*7836SJohn.Forte@Sun.COM 					goto done;
138*7836SJohn.Forte@Sun.COM 				}
139*7836SJohn.Forte@Sun.COM 				ml = ml->next;
140*7836SJohn.Forte@Sun.COM 			}
141*7836SJohn.Forte@Sun.COM 			(void) g_free_multipath(ml);
142*7836SJohn.Forte@Sun.COM 		}
143*7836SJohn.Forte@Sun.COM 		return (status);
144*7836SJohn.Forte@Sun.COM 	}
145*7836SJohn.Forte@Sun.COM done:
146*7836SJohn.Forte@Sun.COM 	return (0);
147*7836SJohn.Forte@Sun.COM }
148*7836SJohn.Forte@Sun.COM 
149*7836SJohn.Forte@Sun.COM /*
150*7836SJohn.Forte@Sun.COM  * This function is for Leadville devices only
151*7836SJohn.Forte@Sun.COM  * It takes as input the actual path on which to issue the LIP and issues it
152*7836SJohn.Forte@Sun.COM  *
153*7836SJohn.Forte@Sun.COM  * INPUT :
154*7836SJohn.Forte@Sun.COM  * Path to the FCA devctl node.
155*7836SJohn.Forte@Sun.COM  *
156*7836SJohn.Forte@Sun.COM  * For example,
157*7836SJohn.Forte@Sun.COM  * /devices/pci@6,2000/pci@2/SUNW,qlc@4/fp@0,0:devctl
158*7836SJohn.Forte@Sun.COM  *
159*7836SJohn.Forte@Sun.COM  * No SCSI_VHCI paths will work. No checks are done and we'll let the ioctl
160*7836SJohn.Forte@Sun.COM  * handle any failures if it is passed in.
161*7836SJohn.Forte@Sun.COM  *
162*7836SJohn.Forte@Sun.COM  * RETURNS:
163*7836SJohn.Forte@Sun.COM  * 0 on Success
164*7836SJohn.Forte@Sun.COM  * non-zero otherwise
165*7836SJohn.Forte@Sun.COM  */
166*7836SJohn.Forte@Sun.COM static int
issue_lip(char * fp_path,int verbose)167*7836SJohn.Forte@Sun.COM issue_lip(char *fp_path, int verbose)
168*7836SJohn.Forte@Sun.COM {
169*7836SJohn.Forte@Sun.COM 	int		fp_fd;
170*7836SJohn.Forte@Sun.COM 	la_wwn_t	wwn;
171*7836SJohn.Forte@Sun.COM 	fcio_t		fcio;
172*7836SJohn.Forte@Sun.COM 
173*7836SJohn.Forte@Sun.COM 	/*
174*7836SJohn.Forte@Sun.COM 	 * open fp path with exclusive path, otherwise,
175*7836SJohn.Forte@Sun.COM 	 * FCIO_RESET_LINK ioctl will fail with permission
176*7836SJohn.Forte@Sun.COM 	 * denied error.
177*7836SJohn.Forte@Sun.COM 	 */
178*7836SJohn.Forte@Sun.COM 	if ((fp_fd = g_object_open(fp_path, O_RDONLY | O_EXCL)) < 0) {
179*7836SJohn.Forte@Sun.COM 		return (L_OPEN_PATH_FAIL);
180*7836SJohn.Forte@Sun.COM 	}
181*7836SJohn.Forte@Sun.COM 
182*7836SJohn.Forte@Sun.COM 	if (verbose) {
183*7836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, MSGSTR(11001,
184*7836SJohn.Forte@Sun.COM 			" Reinitializing the loop at:  %s\n"), fp_path);
185*7836SJohn.Forte@Sun.COM 	}
186*7836SJohn.Forte@Sun.COM 
187*7836SJohn.Forte@Sun.COM 	fcio.fcio_cmd = FCIO_RESET_LINK;
188*7836SJohn.Forte@Sun.COM 	fcio.fcio_xfer = FCIO_XFER_WRITE;
189*7836SJohn.Forte@Sun.COM 	/*
190*7836SJohn.Forte@Sun.COM 	 * Reset the local loop here (fcio_ibuf = 0).
191*7836SJohn.Forte@Sun.COM 	 * Reset a remote loop on the Fabric by
192*7836SJohn.Forte@Sun.COM 	 * passing its node wwn (fcio_len = sizeof(nwwn)
193*7836SJohn.Forte@Sun.COM 	 * and fcio_ibuf = (caddr_t)&nwwn) to the port driver.
194*7836SJohn.Forte@Sun.COM 	 */
195*7836SJohn.Forte@Sun.COM 	(void) bzero((caddr_t)&wwn, sizeof (wwn));
196*7836SJohn.Forte@Sun.COM 	fcio.fcio_ilen = sizeof (wwn);
197*7836SJohn.Forte@Sun.COM 	fcio.fcio_ibuf = (caddr_t)&wwn;
198*7836SJohn.Forte@Sun.COM 	if (g_issue_fcio_ioctl(fp_fd, &fcio, verbose) != 0) {
199*7836SJohn.Forte@Sun.COM 		I_DPRINTF(" issue_lip: FCIO_RESET_LINK"
200*7836SJohn.Forte@Sun.COM 			" ioctl failed: %s\n", fp_path);
201*7836SJohn.Forte@Sun.COM 		(void) close(fp_fd);
202*7836SJohn.Forte@Sun.COM 		return (L_FCIO_RESET_LINK_FAIL);
203*7836SJohn.Forte@Sun.COM 	}
204*7836SJohn.Forte@Sun.COM 	(void) close(fp_fd);
205*7836SJohn.Forte@Sun.COM 	return (0);
206*7836SJohn.Forte@Sun.COM }
207*7836SJohn.Forte@Sun.COM 
208*7836SJohn.Forte@Sun.COM /*
209*7836SJohn.Forte@Sun.COM  * Issues the LIP (Loop Intialization Protocol)
210*7836SJohn.Forte@Sun.COM  * on a nexus path (in case of socal) or on an
211*7836SJohn.Forte@Sun.COM  * fp path (in case of fabric).
212*7836SJohn.Forte@Sun.COM  *
213*7836SJohn.Forte@Sun.COM  * RETURNS:
214*7836SJohn.Forte@Sun.COM  *	0	 O.K.
215*7836SJohn.Forte@Sun.COM  *	non-zero otherwise
216*7836SJohn.Forte@Sun.COM  */
217*7836SJohn.Forte@Sun.COM int
g_force_lip(char * path_phys,int verbose)218*7836SJohn.Forte@Sun.COM g_force_lip(char *path_phys, int verbose)
219*7836SJohn.Forte@Sun.COM {
220*7836SJohn.Forte@Sun.COM int		fd, err = 0, i = 0, pathcnt = 0;
221*7836SJohn.Forte@Sun.COM char		nexus_path[MAXPATHLEN], *nexus_path_ptr;
222*7836SJohn.Forte@Sun.COM char		*charPtr, fp_path[MAXPATHLEN];
223*7836SJohn.Forte@Sun.COM struct stat	stbuf;
224*7836SJohn.Forte@Sun.COM uint_t		dev_type;
225*7836SJohn.Forte@Sun.COM mp_pathlist_t	pathlist;
226*7836SJohn.Forte@Sun.COM mp_pathinfo_t	*pinfop;
227*7836SJohn.Forte@Sun.COM 
228*7836SJohn.Forte@Sun.COM 	/* return invalid path if path_phys NULL */
229*7836SJohn.Forte@Sun.COM 	if (path_phys == NULL) {
230*7836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH);
231*7836SJohn.Forte@Sun.COM 	}
232*7836SJohn.Forte@Sun.COM 
233*7836SJohn.Forte@Sun.COM 	/* Make a copy of the arg passed in ... we'll need it down */
234*7836SJohn.Forte@Sun.COM 	(void) strcpy(fp_path, path_phys);
235*7836SJohn.Forte@Sun.COM 
236*7836SJohn.Forte@Sun.COM 	if (strstr(path_phys, SCSI_VHCI) != NULL) {
237*7836SJohn.Forte@Sun.COM 
238*7836SJohn.Forte@Sun.COM 		/*
239*7836SJohn.Forte@Sun.COM 		 * Its an MPXIO device path
240*7836SJohn.Forte@Sun.COM 		 *
241*7836SJohn.Forte@Sun.COM 		 * First, Get a list of all the pHCI for the given vHCI
242*7836SJohn.Forte@Sun.COM 		 * Then issue a LIP on all the pHCI FCAs that are in the
243*7836SJohn.Forte@Sun.COM 		 * MDI_PATHINFO_STATE_ONLINE or MDI_PATHINFO_STATE_STANDBY
244*7836SJohn.Forte@Sun.COM 		 * states.
245*7836SJohn.Forte@Sun.COM 		 */
246*7836SJohn.Forte@Sun.COM 		if (g_get_pathlist(fp_path, &pathlist)) {
247*7836SJohn.Forte@Sun.COM 			return (L_INVALID_PATH);
248*7836SJohn.Forte@Sun.COM 		}
249*7836SJohn.Forte@Sun.COM 		for (i = 0; i < pathlist.path_count; i++) {
250*7836SJohn.Forte@Sun.COM 			pinfop = &pathlist.path_info[i];
251*7836SJohn.Forte@Sun.COM 			if ((pinfop->path_state ==
252*7836SJohn.Forte@Sun.COM 				MDI_PATHINFO_STATE_ONLINE) ||
253*7836SJohn.Forte@Sun.COM 				    (pinfop->path_state ==
254*7836SJohn.Forte@Sun.COM 					MDI_PATHINFO_STATE_STANDBY)) {
255*7836SJohn.Forte@Sun.COM 				pathcnt++;
256*7836SJohn.Forte@Sun.COM 				sprintf(fp_path, "%s%s",
257*7836SJohn.Forte@Sun.COM 						pinfop->path_hba, FC_CTLR);
258*7836SJohn.Forte@Sun.COM 				if (issue_lip(fp_path, verbose) != 0) {
259*7836SJohn.Forte@Sun.COM 					err++;
260*7836SJohn.Forte@Sun.COM 				}
261*7836SJohn.Forte@Sun.COM 			}
262*7836SJohn.Forte@Sun.COM 		}
263*7836SJohn.Forte@Sun.COM 		free(pathlist.path_info);
264*7836SJohn.Forte@Sun.COM 		if (err == 0)
265*7836SJohn.Forte@Sun.COM 			return (0);
266*7836SJohn.Forte@Sun.COM 		if (err == pathcnt)
267*7836SJohn.Forte@Sun.COM 			return (L_FCIO_FORCE_LIP_FAIL);
268*7836SJohn.Forte@Sun.COM 		return (L_FCIO_FORCE_LIP_PARTIAL_FAIL);
269*7836SJohn.Forte@Sun.COM 	}
270*7836SJohn.Forte@Sun.COM 
271*7836SJohn.Forte@Sun.COM 	/* Non-MPXIO case */
272*7836SJohn.Forte@Sun.COM 
273*7836SJohn.Forte@Sun.COM 	if ((dev_type = g_get_path_type(fp_path)) == 0) {
274*7836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH);
275*7836SJohn.Forte@Sun.COM 	}
276*7836SJohn.Forte@Sun.COM 
277*7836SJohn.Forte@Sun.COM 	if (dev_type & FC_FCA_MASK) {
278*7836SJohn.Forte@Sun.COM 		if (strstr(fp_path, DRV_NAME_SSD) ||
279*7836SJohn.Forte@Sun.COM 			strstr(fp_path, SES_NAME) ||
280*7836SJohn.Forte@Sun.COM 			strstr(fp_path, DRV_NAME_ST)) {
281*7836SJohn.Forte@Sun.COM 			if ((charPtr = strrchr(fp_path, '/')) == NULL) {
282*7836SJohn.Forte@Sun.COM 				return (L_INVALID_PATH);
283*7836SJohn.Forte@Sun.COM 			}
284*7836SJohn.Forte@Sun.COM 			*charPtr = '\0';
285*7836SJohn.Forte@Sun.COM 			/* append devctl to the path */
286*7836SJohn.Forte@Sun.COM 			(void) strcat(fp_path, FC_CTLR);
287*7836SJohn.Forte@Sun.COM 		} else {
288*7836SJohn.Forte@Sun.COM 			/* should have fp transport node to continue. */
289*7836SJohn.Forte@Sun.COM 			if (!(dev_type & FC_XPORT_MASK)) {
290*7836SJohn.Forte@Sun.COM 				return (L_INVALID_PATH_TYPE);
291*7836SJohn.Forte@Sun.COM 			}
292*7836SJohn.Forte@Sun.COM 			if (stat(fp_path, &stbuf) < 0) {
293*7836SJohn.Forte@Sun.COM 				return (L_LSTAT_ERROR);
294*7836SJohn.Forte@Sun.COM 			}
295*7836SJohn.Forte@Sun.COM 			if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
296*7836SJohn.Forte@Sun.COM 				/* append devctl to the path */
297*7836SJohn.Forte@Sun.COM 				(void) strcat(fp_path, FC_CTLR);
298*7836SJohn.Forte@Sun.COM 			}
299*7836SJohn.Forte@Sun.COM 		}
300*7836SJohn.Forte@Sun.COM 		return (issue_lip(fp_path, verbose));
301*7836SJohn.Forte@Sun.COM 
302*7836SJohn.Forte@Sun.COM 	} else {	/* for fc4 devices */
303*7836SJohn.Forte@Sun.COM 		if ((err = g_get_nexus_path(path_phys,
304*7836SJohn.Forte@Sun.COM 					&nexus_path_ptr)) != 0)
305*7836SJohn.Forte@Sun.COM 			return (err);
306*7836SJohn.Forte@Sun.COM 
307*7836SJohn.Forte@Sun.COM 		(void) strcpy(nexus_path, nexus_path_ptr);
308*7836SJohn.Forte@Sun.COM 		(void) g_destroy_data(nexus_path_ptr);
309*7836SJohn.Forte@Sun.COM 		P_DPRINTF("  g_force_lip: Force lip on:"
310*7836SJohn.Forte@Sun.COM 			" Path %s\n", nexus_path);
311*7836SJohn.Forte@Sun.COM 
312*7836SJohn.Forte@Sun.COM 		/* open driver */
313*7836SJohn.Forte@Sun.COM 		if ((fd = g_object_open(nexus_path,
314*7836SJohn.Forte@Sun.COM 				O_NDELAY | O_RDONLY)) == -1)
315*7836SJohn.Forte@Sun.COM 			return (L_OPEN_PATH_FAIL);
316*7836SJohn.Forte@Sun.COM 
317*7836SJohn.Forte@Sun.COM 		if (verbose) {
318*7836SJohn.Forte@Sun.COM 			(void) fprintf(stdout,
319*7836SJohn.Forte@Sun.COM 					MSGSTR(11000,
320*7836SJohn.Forte@Sun.COM 					"  Forcing lip (Loop Initialization "
321*7836SJohn.Forte@Sun.COM 					"Protocol)"
322*7836SJohn.Forte@Sun.COM 					"\n  on loop at: %s\n"), nexus_path);
323*7836SJohn.Forte@Sun.COM 		}
324*7836SJohn.Forte@Sun.COM 		if (ioctl(fd, FCIO_FORCE_LIP) != 0) {
325*7836SJohn.Forte@Sun.COM 			I_DPRINTF("  FCIO_FORCE_LIP ioctl failed.\n");
326*7836SJohn.Forte@Sun.COM 			(void) close(fd);
327*7836SJohn.Forte@Sun.COM 			return (L_FCIO_FORCE_LIP_FAIL);
328*7836SJohn.Forte@Sun.COM 		}
329*7836SJohn.Forte@Sun.COM 		(void) close(fd);
330*7836SJohn.Forte@Sun.COM 	}
331*7836SJohn.Forte@Sun.COM 	return (0);
332*7836SJohn.Forte@Sun.COM }
333*7836SJohn.Forte@Sun.COM 
334*7836SJohn.Forte@Sun.COM 
335*7836SJohn.Forte@Sun.COM 
336*7836SJohn.Forte@Sun.COM /*
337*7836SJohn.Forte@Sun.COM  * Takes one or more drives offline.
338*7836SJohn.Forte@Sun.COM  * If the force flag is supplied then: (1) don't pass the exclusive flag
339*7836SJohn.Forte@Sun.COM  * to the acquire routine and (2) allow the offline to fail
340*7836SJohn.Forte@Sun.COM  * If any acquire fails, print an error message and continue.
341*7836SJohn.Forte@Sun.COM  *
342*7836SJohn.Forte@Sun.COM  * RETURNS:
343*7836SJohn.Forte@Sun.COM  *	0		iff each offline succeeds
344*7836SJohn.Forte@Sun.COM  *	non-zero	otherwise
345*7836SJohn.Forte@Sun.COM  */
346*7836SJohn.Forte@Sun.COM int
g_offline_drive(struct dlist * dl,int force_flag)347*7836SJohn.Forte@Sun.COM g_offline_drive(struct dlist *dl, int force_flag)
348*7836SJohn.Forte@Sun.COM {
349*7836SJohn.Forte@Sun.COM devctl_hdl_t		devhdl;
350*7836SJohn.Forte@Sun.COM 
351*7836SJohn.Forte@Sun.COM 
352*7836SJohn.Forte@Sun.COM 	/* for each drive attempt to take it offline */
353*7836SJohn.Forte@Sun.COM 	for (; dl != NULL; dl = dl->next) {
354*7836SJohn.Forte@Sun.COM 
355*7836SJohn.Forte@Sun.COM 		/* attempt to acquire the device */
356*7836SJohn.Forte@Sun.COM 		if ((devhdl = devctl_device_acquire(dl->dev_path,
357*7836SJohn.Forte@Sun.COM 				force_flag ? 0 : DC_EXCL)) == NULL) {
358*7836SJohn.Forte@Sun.COM 			if (errno != EBUSY) {
359*7836SJohn.Forte@Sun.COM 				P_DPRINTF("%s: Could not acquire"
360*7836SJohn.Forte@Sun.COM 					" the device: %s\n\n",
361*7836SJohn.Forte@Sun.COM 					strerror(errno), dl->dev_path);
362*7836SJohn.Forte@Sun.COM 				continue;
363*7836SJohn.Forte@Sun.COM 			}
364*7836SJohn.Forte@Sun.COM 		}
365*7836SJohn.Forte@Sun.COM 		/* attempt to offline the drive */
366*7836SJohn.Forte@Sun.COM 		if ((devctl_device_offline(devhdl) != 0) && !force_flag) {
367*7836SJohn.Forte@Sun.COM 			(void) devctl_release(devhdl);
368*7836SJohn.Forte@Sun.COM 			return (L_DEV_BUSY);
369*7836SJohn.Forte@Sun.COM 		}
370*7836SJohn.Forte@Sun.COM 
371*7836SJohn.Forte@Sun.COM 		/* offline succeeded -- release handle acquired above */
372*7836SJohn.Forte@Sun.COM 		(void) devctl_release(devhdl);
373*7836SJohn.Forte@Sun.COM 	}
374*7836SJohn.Forte@Sun.COM 
375*7836SJohn.Forte@Sun.COM 	return (0);
376*7836SJohn.Forte@Sun.COM }
377*7836SJohn.Forte@Sun.COM 
378*7836SJohn.Forte@Sun.COM 
379*7836SJohn.Forte@Sun.COM 
380*7836SJohn.Forte@Sun.COM /*
381*7836SJohn.Forte@Sun.COM  * Brings one or more drives online.
382*7836SJohn.Forte@Sun.COM  * If the force flag is supplied then: (1) don't pass the exclusive
383*7836SJohn.Forte@Sun.COM  * flag to the acquire routine and (2) allow the offline to fail
384*7836SJohn.Forte@Sun.COM  * If any acquire fails, continue with the next device.
385*7836SJohn.Forte@Sun.COM  *
386*7836SJohn.Forte@Sun.COM  * RETURNS:
387*7836SJohn.Forte@Sun.COM  *	None.
388*7836SJohn.Forte@Sun.COM  */
389*7836SJohn.Forte@Sun.COM void
g_online_drive(struct dlist * dl,int force_flag)390*7836SJohn.Forte@Sun.COM g_online_drive(struct dlist *dl, int force_flag)
391*7836SJohn.Forte@Sun.COM {
392*7836SJohn.Forte@Sun.COM devctl_hdl_t		devhdl;
393*7836SJohn.Forte@Sun.COM 
394*7836SJohn.Forte@Sun.COM 
395*7836SJohn.Forte@Sun.COM 	while (dl != NULL) {
396*7836SJohn.Forte@Sun.COM 		if ((devhdl = devctl_device_acquire(dl->dev_path,
397*7836SJohn.Forte@Sun.COM 					force_flag ? 0 : DC_EXCL)) != NULL) {
398*7836SJohn.Forte@Sun.COM 			(void) devctl_device_online(devhdl);
399*7836SJohn.Forte@Sun.COM 			(void) devctl_release(devhdl);
400*7836SJohn.Forte@Sun.COM 		}
401*7836SJohn.Forte@Sun.COM 		dl = dl->next;
402*7836SJohn.Forte@Sun.COM 	}
403*7836SJohn.Forte@Sun.COM }
404*7836SJohn.Forte@Sun.COM 
405*7836SJohn.Forte@Sun.COM 
406*7836SJohn.Forte@Sun.COM 
407*7836SJohn.Forte@Sun.COM void
g_ll_to_str(uchar_t * wwn_ll,char * wwn_str)408*7836SJohn.Forte@Sun.COM g_ll_to_str(uchar_t *wwn_ll, char	*wwn_str)
409*7836SJohn.Forte@Sun.COM {
410*7836SJohn.Forte@Sun.COM int	j, k, fnib, snib;
411*7836SJohn.Forte@Sun.COM uchar_t	c;
412*7836SJohn.Forte@Sun.COM 
413*7836SJohn.Forte@Sun.COM 	for (j = 0, k = 0; j < 8; j++) {
414*7836SJohn.Forte@Sun.COM 		c = wwn_ll[j];
415*7836SJohn.Forte@Sun.COM 		fnib = ((int)(c & 0xf0) >> 4);
416*7836SJohn.Forte@Sun.COM 		snib = (c & 0x0f);
417*7836SJohn.Forte@Sun.COM 		if (fnib >= 0 && fnib <= 9)
418*7836SJohn.Forte@Sun.COM 			wwn_str[k++] = '0' + fnib;
419*7836SJohn.Forte@Sun.COM 		else if (fnib >= 10 && fnib <= 15)
420*7836SJohn.Forte@Sun.COM 			wwn_str[k++] = 'a' + fnib - 10;
421*7836SJohn.Forte@Sun.COM 		if (snib >= 0 && snib <= 9)
422*7836SJohn.Forte@Sun.COM 			wwn_str[k++] = '0' + snib;
423*7836SJohn.Forte@Sun.COM 		else if (snib >= 10 && snib <= 15)
424*7836SJohn.Forte@Sun.COM 			wwn_str[k++] = 'a' + snib - 10;
425*7836SJohn.Forte@Sun.COM 	}
426*7836SJohn.Forte@Sun.COM 	wwn_str[k] = '\0';
427*7836SJohn.Forte@Sun.COM }
428*7836SJohn.Forte@Sun.COM 
429*7836SJohn.Forte@Sun.COM 
430*7836SJohn.Forte@Sun.COM 
431*7836SJohn.Forte@Sun.COM /*
432*7836SJohn.Forte@Sun.COM  * Creates a list of nexus paths for each
433*7836SJohn.Forte@Sun.COM  * hotpluggable device and sends the list to g_force_lip(),
434*7836SJohn.Forte@Sun.COM  * which forces the LIP on each nexus path in the list.
435*7836SJohn.Forte@Sun.COM  *
436*7836SJohn.Forte@Sun.COM  * RETURNS:
437*7836SJohn.Forte@Sun.COM  *	None.
438*7836SJohn.Forte@Sun.COM  */
439*7836SJohn.Forte@Sun.COM int
g_forcelip_all(struct hotplug_disk_list * disk_list)440*7836SJohn.Forte@Sun.COM g_forcelip_all(struct hotplug_disk_list *disk_list)
441*7836SJohn.Forte@Sun.COM {
442*7836SJohn.Forte@Sun.COM char		*p;
443*7836SJohn.Forte@Sun.COM int		len, ndevs = 0, err = 0;
444*7836SJohn.Forte@Sun.COM struct	dlist	*dl;
445*7836SJohn.Forte@Sun.COM struct loop_list {	/* adp_name holds full dev path for MPXIO devices */
446*7836SJohn.Forte@Sun.COM 		char adp_name[MAXPATHLEN];
447*7836SJohn.Forte@Sun.COM 		struct loop_list *next;
448*7836SJohn.Forte@Sun.COM 		struct loop_list *prev;
449*7836SJohn.Forte@Sun.COM 	} *llist_head, *llist_tail, *llist, *llist1;
450*7836SJohn.Forte@Sun.COM 
451*7836SJohn.Forte@Sun.COM 	llist_head = llist_tail = NULL;
452*7836SJohn.Forte@Sun.COM 
453*7836SJohn.Forte@Sun.COM 	while (disk_list) {
454*7836SJohn.Forte@Sun.COM 		if (disk_list->dev_location == SENA) {
455*7836SJohn.Forte@Sun.COM 			dl = disk_list->seslist;
456*7836SJohn.Forte@Sun.COM 		} else {
457*7836SJohn.Forte@Sun.COM 			dl = disk_list->dlhead;
458*7836SJohn.Forte@Sun.COM 		}
459*7836SJohn.Forte@Sun.COM 		while (dl != NULL) {
460*7836SJohn.Forte@Sun.COM 			if (strstr(dl->dev_path, SCSI_VHCI) == NULL) {
461*7836SJohn.Forte@Sun.COM 				/* non-MPXIO device path */
462*7836SJohn.Forte@Sun.COM 				if (disk_list->dev_location == SENA) {
463*7836SJohn.Forte@Sun.COM 				    p = strstr(dl->dev_path, SLASH_SES);
464*7836SJohn.Forte@Sun.COM 				} else {
465*7836SJohn.Forte@Sun.COM 				    p = strstr(dl->dev_path, SLSH_DRV_NAME_SSD);
466*7836SJohn.Forte@Sun.COM 				    if (p == NULL) {
467*7836SJohn.Forte@Sun.COM 					p = strstr(dl->dev_path,
468*7836SJohn.Forte@Sun.COM 							SLSH_DRV_NAME_ST);
469*7836SJohn.Forte@Sun.COM 				    }
470*7836SJohn.Forte@Sun.COM 				}
471*7836SJohn.Forte@Sun.COM 				if (p == NULL) {
472*7836SJohn.Forte@Sun.COM 					P_DPRINTF(
473*7836SJohn.Forte@Sun.COM 					"  g_forcelip_all: Not able to do"
474*7836SJohn.Forte@Sun.COM 					" LIP on this path because path "
475*7836SJohn.Forte@Sun.COM 					"invalid.\n  Path: %s\n", dl->dev_path);
476*7836SJohn.Forte@Sun.COM 					dl = dl->next;
477*7836SJohn.Forte@Sun.COM 					continue;
478*7836SJohn.Forte@Sun.COM 				}
479*7836SJohn.Forte@Sun.COM 				len = strlen(dl->dev_path) - strlen(p);
480*7836SJohn.Forte@Sun.COM 			} else {
481*7836SJohn.Forte@Sun.COM 				/* MPXIO path */
482*7836SJohn.Forte@Sun.COM 				len = strlen(dl->dev_path);
483*7836SJohn.Forte@Sun.COM 			}
484*7836SJohn.Forte@Sun.COM 
485*7836SJohn.Forte@Sun.COM 			/*
486*7836SJohn.Forte@Sun.COM 			 * Avoid issuing forcelip
487*7836SJohn.Forte@Sun.COM 			 * on the same HA more than once
488*7836SJohn.Forte@Sun.COM 			 */
489*7836SJohn.Forte@Sun.COM 			if (llist_head != NULL) {
490*7836SJohn.Forte@Sun.COM 				for (llist1 = llist_head; llist1 != NULL;
491*7836SJohn.Forte@Sun.COM 						llist1 = llist1->next) {
492*7836SJohn.Forte@Sun.COM 					if (strncmp(llist1->adp_name,
493*7836SJohn.Forte@Sun.COM 						dl->dev_path, len) == 0) {
494*7836SJohn.Forte@Sun.COM 						break;
495*7836SJohn.Forte@Sun.COM 					}
496*7836SJohn.Forte@Sun.COM 				}
497*7836SJohn.Forte@Sun.COM 				if (llist1 != NULL) {
498*7836SJohn.Forte@Sun.COM 					dl = dl->next;
499*7836SJohn.Forte@Sun.COM 					continue;
500*7836SJohn.Forte@Sun.COM 				}
501*7836SJohn.Forte@Sun.COM 			}
502*7836SJohn.Forte@Sun.COM 			if ((llist = (struct loop_list *)
503*7836SJohn.Forte@Sun.COM 				g_zalloc(sizeof (struct loop_list))) == NULL)
504*7836SJohn.Forte@Sun.COM 				return (L_MALLOC_FAILED);
505*7836SJohn.Forte@Sun.COM 			(void) strncpy(llist->adp_name, dl->dev_path, len);
506*7836SJohn.Forte@Sun.COM 			llist->adp_name[len] = '\0';
507*7836SJohn.Forte@Sun.COM 			ndevs++;
508*7836SJohn.Forte@Sun.COM 
509*7836SJohn.Forte@Sun.COM 			if (llist_head == NULL) {
510*7836SJohn.Forte@Sun.COM 				llist_head = llist_tail = llist;
511*7836SJohn.Forte@Sun.COM 			} else {
512*7836SJohn.Forte@Sun.COM 				llist->prev = llist_tail;
513*7836SJohn.Forte@Sun.COM 				llist_tail = llist_tail->next = llist;
514*7836SJohn.Forte@Sun.COM 			}
515*7836SJohn.Forte@Sun.COM 			dl = dl->next;
516*7836SJohn.Forte@Sun.COM 		}
517*7836SJohn.Forte@Sun.COM 		disk_list = disk_list->next;
518*7836SJohn.Forte@Sun.COM 	}
519*7836SJohn.Forte@Sun.COM 
520*7836SJohn.Forte@Sun.COM 	while (llist_head) {
521*7836SJohn.Forte@Sun.COM 		if ((err = g_force_lip(llist_head->adp_name, 0)) != 0) {
522*7836SJohn.Forte@Sun.COM 			(void) g_destroy_data(llist);
523*7836SJohn.Forte@Sun.COM 			(void) g_destroy_data(llist_head);
524*7836SJohn.Forte@Sun.COM 			return (err);
525*7836SJohn.Forte@Sun.COM 		}
526*7836SJohn.Forte@Sun.COM 		llist = llist_head;
527*7836SJohn.Forte@Sun.COM 		llist_head = llist_head->next;
528*7836SJohn.Forte@Sun.COM 		(void) g_destroy_data((char *)llist);
529*7836SJohn.Forte@Sun.COM 	}
530*7836SJohn.Forte@Sun.COM 	(void) sleep(ndevs*10);
531*7836SJohn.Forte@Sun.COM 	return (0);
532*7836SJohn.Forte@Sun.COM }
533