xref: /titanic_44/usr/src/cmd/luxadm/x86_adm.c (revision a6a911618075176ed839dbe7f7c90604d0954b46)
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 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <hbaapi.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <string.h>
34 #include <sys/fibre-channel/fcio.h>
35 #include <sys/fibre-channel/impl/fc_error.h>
36 #include <sys/scsi/adapters/scsi_vhci.h>
37 #include "common.h"
38 #include "errorcodes.h"
39 #include <locale.h>
40 
41 /* The i18n catalog */
42 nl_catd l_catd;
43 
44 void
45 i18n_catopen() {
46 	static int fileopen = 0;
47 
48 	if (setlocale(LC_ALL, "") == NULL) {
49 		(void) fprintf(stderr,
50 		"Cannot operate in the locale requested. "
51 		"Continuing in the default C locale\n");
52 	}
53 	if (!fileopen) {
54 		l_catd = catopen("a5k_g_fc_i18n_cat", NL_CAT_LOCALE);
55 		if (l_catd == (nl_catd)-1) {
56 			return;
57 		}
58 		fileopen = 1;
59 	}
60 	return;
61 
62 }
63 
64 /*
65  * Given an error number, this functions
66  * calls the get_errString() to print a
67  * corresponding error message to the stderr.
68  * get_errString() always returns an error
69  * message, even in case of undefined error number.
70  * So, there is no need to check for a NULL pointer
71  * while printing the error message to the stdout.
72  *
73  * RETURNS: N/A
74  *
75  */
76 void
77 print_errString(int errnum, char *devpath)
78 {
79 
80 char	*errStr;
81 
82 	errStr = get_errString(errnum);
83 
84 	if (devpath == NULL) {
85 		(void) fprintf(stderr,
86 				"%s \n\n", errStr);
87 	} else {
88 		(void) fprintf(stderr,
89 				"%s - %s.\n\n", errStr, devpath);
90 	}
91 
92 	/* free the allocated memory for error string */
93 	if (errStr != NULL)
94 		(void) free(errStr);
95 }
96 
97 static void terminate() {
98 	fprintf(stdout, MSGSTR(2506, "Unsupported"));
99 	fprintf(stdout, "\n");
100 	exit(1);
101 }
102 
103 /*ARGSUSED*/
104 int adm_display_config(char **a) {
105 	terminate();
106 	return (1);
107 }
108 
109 /*ARGSUSED*/
110 void adm_download(char **a, char *b) {
111 	terminate();
112 }
113 
114 /*ARGSUSED*/
115 void up_encl_name(char **a, int b) {
116 	terminate();
117 }
118 
119 void adm_failover(char **argv) {
120 	int		path_index = 0, err = 0, fd;
121 	char		path_class[MAXNAMELEN];
122 	char		client_path[MAXPATHLEN];
123 	char		*path_phys = NULL, *trailingMinor;
124 	sv_switch_to_cntlr_iocdata_t	iocsc;
125 
126 	(void) memset(path_class, 0, sizeof (path_class));
127 	(void) strcpy(path_class, argv[path_index++]);
128 	if ((strcmp(path_class, "primary") != 0) &&
129 		(strcmp(path_class, "secondary") != 0)) {
130 			(void) fprintf(stderr,
131 			MSGSTR(2300, "Incorrect pathclass\n"));
132 			exit(-1);
133 	}
134 
135 	if ((fd = open("/devices/scsi_vhci:devctl", O_RDWR)) < 0) {
136 	    print_errString(L_OPEN_PATH_FAIL, "/devices/scsi_vhci:devctl");
137 	    exit(-1);
138 	}
139 
140 	iocsc.client = client_path;
141 	iocsc.class = path_class;
142 
143 	while (argv[path_index] != NULL) {
144 		path_phys =
145 		    get_slash_devices_from_osDevName(argv[path_index++],
146 			STANDARD_DEVNAME_HANDLING);
147 		if ((path_phys == NULL) ||
148 			(strstr(path_phys, "/devices/scsi_vhci") == NULL)) {
149 				(void) fprintf(stderr,
150 				MSGSTR(2301, "Incorrect pathname\n"));
151 				close(fd);
152 				exit(-1);
153 		}
154 
155 		strcpy(iocsc.client, path_phys + strlen("/devices"));
156 
157 		/* Now chop off the trailing ":xxx" portion if present */
158 		if ((trailingMinor = strrchr(iocsc.client, ':')) != NULL) {
159 			trailingMinor[0] = '\0';
160 		}
161 
162 		if (ioctl(fd, SCSI_VHCI_SWITCH_TO_CNTLR, &iocsc) != 0) {
163 		    switch (errno) {
164 			case EALREADY:
165 				err = L_SCSI_VHCI_ALREADY_ACTIVE;
166 				break;
167 			case ENXIO:
168 				err = L_INVALID_PATH;
169 				break;
170 			case EIO:
171 				err = L_SCSI_VHCI_NO_STANDBY;
172 				break;
173 			case ENOTSUP:
174 				err = L_SCSI_VHCI_FAILOVER_NOTSUP;
175 				break;
176 			case EBUSY:
177 				err = L_SCSI_VHCI_FAILOVER_BUSY;
178 				break;
179 			case EFAULT:
180 			default:
181 				err = L_SCSI_VHCI_ERROR;
182 		    }
183 		}
184 
185 		if (err != 0) {
186 		    close(fd);
187 		    print_errString(err, path_phys);
188 		    exit(-1);
189 		}
190 	}
191 
192 	close(fd);
193 }
194 
195 /*ARGSUSED*/
196 int adm_inquiry(char **a) {
197 	terminate();
198 	return (1);
199 }
200 
201 /*ARGSUSED*/
202 void pho_probe() {
203 	terminate();
204 }
205 
206 /*ARGSUSED*/
207 void non_encl_probe() {
208 	terminate();
209 }
210 
211 /*ARGSUSED*/
212 void adm_led(char **a, int b) {
213 	terminate();
214 }
215 
216 /*ARGSUSED*/
217 void up_password(char **a) {
218 	terminate();
219 }
220 
221 /*ARGSUSED*/
222 int adm_reserve(char *path) {
223 	terminate();
224 	return (1);
225 }
226 
227 /*ARGSUSED*/
228 int adm_release(char *path) {
229 	terminate();
230 	return (1);
231 }
232 
233 /*ARGSUSED*/
234 int adm_start(char **a) {
235 	terminate();
236 	return (1);
237 }
238 
239 /*ARGSUSED*/
240 int adm_stop(char **a) {
241 	terminate();
242 	return (1);
243 }
244 
245 /*ARGSUSED*/
246 int adm_power_off(char **a, int b) {
247 	terminate();
248 	return (1);
249 }
250 
251 int
252 adm_forcelip(char **argv)
253 {
254 	int		path_index = 0, fd;
255 	uint64_t	wwn;
256 	fcio_t		fcio;
257 	HBA_HANDLE handle;
258 	HBA_ADAPTERATTRIBUTES hbaAttrs;
259 	HBA_PORTATTRIBUTES portAttrs;
260 	HBA_FCPTARGETMAPPINGV2    *map;
261 	HBA_STATUS status;
262 	int count, adapterIndex, portIndex, mapIndex;
263 	char name[256];
264 	int		matched, ret = 0, wwnCompare = 0, ntries;
265 	char	    *physical = NULL, *slash_OSDeviceName = NULL;
266 
267 	if ((status = loadLibrary())) {
268 	    /* loadLibrary print out error msg */
269 	    return (ret++);
270 	}
271 	for (path_index = 0; argv[path_index] != NULL; path_index++) {
272 
273 	    if (is_wwn(argv[path_index])) {
274 		(void) sscanf(argv[path_index], "%016llx", &wwn);
275 		wwnCompare = 1;
276 	    } else if (!is_path(argv[path_index])) {
277 		print_errString(L_INVALID_PATH, argv[path_index]);
278 		ret++;
279 		continue;
280 	    }
281 	    if (!wwnCompare) {
282 		/* Convert the paths to phsyical paths */
283 		physical = get_slash_devices_from_osDevName(argv[path_index],
284 			STANDARD_DEVNAME_HANDLING);
285 		if (!physical) {
286 		    print_errString(L_INVALID_PATH, argv[path_index]);
287 		    ret++;
288 		    continue;
289 		}
290 	    }
291 
292 	    count = getNumberOfAdapters();
293 
294 	    matched = 0;
295 	    for (adapterIndex = 0; adapterIndex < count; adapterIndex ++) {
296 		status = HBA_GetAdapterName(adapterIndex, (char *)&name);
297 		if (status != HBA_STATUS_OK) {
298 		    /* May have been DR'd */
299 		    continue;
300 		}
301 		handle = HBA_OpenAdapter(name);
302 		if (handle == 0) {
303 		    /* May have been DR'd */
304 		    continue;
305 		}
306 
307 		if (getAdapterAttrs(handle, name, &hbaAttrs)) {
308 		    /* Should never happen */
309 		    HBA_CloseAdapter(handle);
310 		    continue;
311 		}
312 
313 		/* Loop over all HBA Ports */
314 		for (portIndex = 0; portIndex < hbaAttrs.NumberOfPorts;
315 			portIndex++) {
316 		    if (getAdapterPortAttrs(handle, name, portIndex,
317 			    &portAttrs)) {
318 			continue;
319 		    }
320 
321 		    matched = 0;
322 		    if (is_wwn(argv[path_index])) {
323 			if (wwn == wwnConversion(
324 				portAttrs.NodeWWN.wwn) ||
325 				wwn == wwnConversion(
326 				portAttrs.PortWWN.wwn)) {
327 			    matched = 1;
328 			}
329 		    } else {
330 			slash_OSDeviceName = get_slash_devices_from_osDevName(
331 			    portAttrs.OSDeviceName, STANDARD_DEVNAME_HANDLING);
332 			if (!slash_OSDeviceName) {
333 			    continue;
334 			} else {
335 			    if (strncmp(physical, slash_OSDeviceName,
336 				    strlen(slash_OSDeviceName) -
337 				    strlen(strrchr(slash_OSDeviceName, ':')))
338 				== 0) {
339 				matched = 1;
340 			    }
341 			    free(slash_OSDeviceName);
342 			}
343 		    }
344 
345 		    if (!matched) {
346 			if (!fetch_mappings(handle, portAttrs.PortWWN, &map)) {
347 				/*
348 				 * matchr_mapping checks the arg
349 				 * so we pass argv here.
350 				 */
351 			    mapIndex = match_mappings(argv[path_index], map);
352 			    if (mapIndex >= 0) {
353 				matched = 1;
354 			    }
355 			} else {
356 			    continue;
357 			}
358 		    }
359 
360 		    if (matched) {
361 			if ((fd = open(portAttrs.OSDeviceName,
362 				O_RDONLY | O_EXCL)) == -1) {
363 			    print_errString(L_OPEN_PATH_FAIL,
364 				    portAttrs.OSDeviceName);
365 			    return (ret++);
366 			}
367 
368 			fcio.fcio_cmd = FCIO_RESET_LINK;
369 			fcio.fcio_xfer = FCIO_XFER_WRITE;
370 			/*
371 			 * Reset the local loop here (fcio_ibuf = 0).
372 			 * Reset a remote loop on the Fabric by
373 			 * passing its node wwn (fcio_len = sizeof(nwwn)
374 			 * and fcio_ibuf = (caddr_t)&nwwn) to the port driver.
375 			 */
376 			(void) memset(&wwn, 0, sizeof (wwn));
377 			fcio.fcio_ilen = sizeof (wwn);
378 			fcio.fcio_ibuf = (caddr_t)&wwn;
379 
380 			for (ntries = 0; ntries < RETRY_FCIO_IOCTL; ntries++) {
381 			    errno = 0;
382 			    if (ioctl(fd, FCIO_CMD, &fcio) != 0) {
383 				/*
384 				 * When port is offlined, qlc
385 				 * returns the FC_OFFLINE error and errno
386 				 * is set to EIO.
387 				 * We do want to ignore this error,
388 				 * especially when an enclosure is
389 				 * removed from the loop.
390 				 */
391 				if (fcio.fcio_errno == FC_OFFLINE)
392 				    break;
393 				if ((errno == EAGAIN) &&
394 				    (ntries+1 < RETRY_FCIO_IOCTL)) {
395 				    /* wait WAIT_FCIO_IOCTL */
396 				    (void) usleep(WAIT_FCIO_IOCTL);
397 				    continue;
398 				}
399 				I_DPRINTF("FCIO ioctl failed.\n"
400 				    "Error: %s. fc_error = %d (0x%x)\n",
401 				strerror(errno), fcio.fcio_errno,
402 				    fcio.fcio_errno);
403 				close(fd);
404 				print_errString(L_FCIO_FORCE_LIP_FAIL,
405 				    portAttrs.OSDeviceName);
406 				return (ret++);
407 			    } else {
408 				break; /* ioctl succeeds. */
409 			    }
410 			}
411 			close(fd);
412 			if (ntries == RETRY_FCIO_IOCTL) {
413 			    print_errString(L_FCIO_FORCE_LIP_FAIL,
414 			    portAttrs.OSDeviceName);
415 			    return (ret++);
416 			}
417 		    }
418 		    if (matched)
419 			break; /* for HBA port for loop */
420 		}
421 		if (matched) /* HBA adapter for loop */
422 		    break;
423 	    }
424 
425 	    if (!matched) {
426 		print_errString(L_INVALID_PATH, argv[path_index]);
427 		ret++;
428 	    }
429 	}
430 	HBA_FreeLibrary();
431 	return (ret);
432 }
433 
434 /*ARGSUSED*/
435 void adm_bypass_enable(char **argv, int bypass_flag) {
436 	terminate();
437 }
438 
439 /*ARGSUSED*/
440 int adm_port_offline_online(char **a, int b) {
441 	terminate();
442 	return (1);
443 }
444 
445 /*ARGSUSED*/
446 void display_link_status(char **a) {
447 	terminate();
448 }
449 
450 /*ARGSUSED*/
451 void dump_map(char **argv) {
452 	terminate();
453 }
454 
455 /*ARGSUSED*/
456 int adm_display_port(int a) {
457 	terminate();
458 	return (1);
459 }
460 
461 /*ARGSUSED*/
462 int adm_port_loopback(char *a, int b) {
463 	terminate();
464 	return (1);
465 }
466 
467 /*ARGSUSED*/
468 int hotplug_e(int todo, char **argv, int verbose_flag, int force_flag) {
469 	terminate();
470 	return (1);
471 }
472 
473 /*ARGSUSED*/
474 int
475 setboot(unsigned int yes, unsigned int verbose, char *fname)
476 {
477 	terminate();
478 	return (1);
479 }
480 
481 /*ARGSUSED*/
482 int hotplug(int todo, char **argv, int verbose_flag, int force_flag) {
483 	terminate();
484 	return (1);
485 }
486 
487 /*ARGSUSED*/
488 int adm_check_file(char **argv, int flag) {
489 	terminate();
490 	return (1);
491 }
492 
493 /*ARGSUSED*/
494 int sysdump(int verbose) {
495 	terminate();
496 	return (1);
497 }
498 
499 /*ARGSUSED*/
500 int fcal_update(unsigned int verbose, char *file) {
501 	terminate();
502 	return (1);
503 }
504 
505 /*ARGSUSED*/
506 int q_qlgc_update(unsigned int verbose, char *file) {
507 	terminate();
508 	return (1);
509 }
510 
511 /*ARGSUSED*/
512 int emulex_update(char *file) {
513 	terminate();
514 	return (1);
515 }
516 
517 /*ARGSUSED*/
518 int emulex_fcode_reader(int fcode_fd, char *pattern, char *pattern_value,
519     uint32_t pattern_value_size) {
520 	terminate();
521 	return (1);
522 }
523 
524 /*ARGSUSED*/
525 void dump(char **argv) {
526 	terminate();
527 }
528 
529 /*ARGSUSED*/
530 int h_insertSena_fcdev() {
531 	terminate();
532 	return (1);
533 }
534