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 */
42nl_catd l_catd;
43
44void
45i18n_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 */
76void
77print_errString(int errnum, char *devpath)
78{
79
80char	*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
97static void terminate() {
98	fprintf(stdout, MSGSTR(2506, "Unsupported"));
99	fprintf(stdout, "\n");
100	exit(1);
101}
102
103/*ARGSUSED*/
104int adm_display_config(char **a) {
105	terminate();
106	return (1);
107}
108
109/*ARGSUSED*/
110void adm_download(char **a, char *b) {
111	terminate();
112}
113
114/*ARGSUSED*/
115void up_encl_name(char **a, int b) {
116	terminate();
117}
118
119void 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*/
196int adm_inquiry(char **a) {
197	terminate();
198	return (1);
199}
200
201/*ARGSUSED*/
202void pho_probe() {
203	terminate();
204}
205
206/*ARGSUSED*/
207void non_encl_probe() {
208	terminate();
209}
210
211/*ARGSUSED*/
212void adm_led(char **a, int b) {
213	terminate();
214}
215
216/*ARGSUSED*/
217void up_password(char **a) {
218	terminate();
219}
220
221/*ARGSUSED*/
222int adm_reserve(char *path) {
223	terminate();
224	return (1);
225}
226
227/*ARGSUSED*/
228int adm_release(char *path) {
229	terminate();
230	return (1);
231}
232
233/*ARGSUSED*/
234int adm_start(char **a) {
235	terminate();
236	return (1);
237}
238
239/*ARGSUSED*/
240int adm_stop(char **a) {
241	terminate();
242	return (1);
243}
244
245/*ARGSUSED*/
246int adm_power_off(char **a, int b) {
247	terminate();
248	return (1);
249}
250
251int
252adm_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*/
435void adm_bypass_enable(char **argv, int bypass_flag) {
436	terminate();
437}
438
439/*ARGSUSED*/
440int adm_port_offline_online(char **a, int b) {
441	terminate();
442	return (1);
443}
444
445/*ARGSUSED*/
446void display_link_status(char **a) {
447	terminate();
448}
449
450/*ARGSUSED*/
451void dump_map(char **argv) {
452	terminate();
453}
454
455/*ARGSUSED*/
456int adm_display_port(int a) {
457	terminate();
458	return (1);
459}
460
461/*ARGSUSED*/
462int adm_port_loopback(char *a, int b) {
463	terminate();
464	return (1);
465}
466
467/*ARGSUSED*/
468int hotplug_e(int todo, char **argv, int verbose_flag, int force_flag) {
469	terminate();
470	return (1);
471}
472
473/*ARGSUSED*/
474int
475setboot(unsigned int yes, unsigned int verbose, char *fname)
476{
477	terminate();
478	return (1);
479}
480
481/*ARGSUSED*/
482int hotplug(int todo, char **argv, int verbose_flag, int force_flag) {
483	terminate();
484	return (1);
485}
486
487/*ARGSUSED*/
488int adm_check_file(char **argv, int flag) {
489	terminate();
490	return (1);
491}
492
493/*ARGSUSED*/
494int sysdump(int verbose) {
495	terminate();
496	return (1);
497}
498
499/*ARGSUSED*/
500int fcal_update(unsigned int verbose, char *file) {
501	terminate();
502	return (1);
503}
504
505/*ARGSUSED*/
506int q_qlgc_update(unsigned int verbose, char *file) {
507	terminate();
508	return (1);
509}
510
511/*ARGSUSED*/
512int emulex_update(char *file) {
513	terminate();
514	return (1);
515}
516
517/*ARGSUSED*/
518int 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*/
525void dump(char **argv) {
526	terminate();
527}
528
529/*ARGSUSED*/
530int h_insertSena_fcdev() {
531	terminate();
532	return (1);
533}
534