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