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