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