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