diff options
Diffstat (limited to 'usr/src/cmd/luxadm/x86_adm.c')
| -rw-r--r-- | usr/src/cmd/luxadm/x86_adm.c | 533 |
1 files changed, 533 insertions, 0 deletions
diff --git a/usr/src/cmd/luxadm/x86_adm.c b/usr/src/cmd/luxadm/x86_adm.c new file mode 100644 index 0000000000..a53b2b92fe --- /dev/null +++ b/usr/src/cmd/luxadm/x86_adm.c @@ -0,0 +1,533 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <hbaapi.h> +#include <errno.h> +#include <fcntl.h> +#include <string.h> +#include <sys/fibre-channel/fcio.h> +#include <sys/fibre-channel/impl/fc_error.h> +#include <sys/scsi/adapters/scsi_vhci.h> +#include "common.h" +#include "errorcodes.h" +#include <locale.h> + +/* The i18n catalog */ +nl_catd l_catd; + +void +i18n_catopen() { + static int fileopen = 0; + + if (setlocale(LC_ALL, "") == NULL) { + (void) fprintf(stderr, + "Cannot operate in the locale requested. " + "Continuing in the default C locale\n"); + } + if (!fileopen) { + l_catd = catopen("a5k_g_fc_i18n_cat", NL_CAT_LOCALE); + if (l_catd == (nl_catd)-1) { + return; + } + fileopen = 1; + } + return; + +} + +/* + * Given an error number, this functions + * calls the get_errString() to print a + * corresponding error message to the stderr. + * get_errString() always returns an error + * message, even in case of undefined error number. + * So, there is no need to check for a NULL pointer + * while printing the error message to the stdout. + * + * RETURNS: N/A + * + */ +void +print_errString(int errnum, char *devpath) +{ + +char *errStr; + + errStr = get_errString(errnum); + + if (devpath == NULL) { + (void) fprintf(stderr, + "%s \n\n", errStr); + } else { + (void) fprintf(stderr, + "%s - %s.\n\n", errStr, devpath); + } + + /* free the allocated memory for error string */ + if (errStr != NULL) + (void) free(errStr); +} + +static void terminate() { + fprintf(stdout, MSGSTR(2506, "Unsupported")); + fprintf(stdout, "\n"); + exit(1); +} + +/*ARGSUSED*/ +int adm_display_config(char **a) { + terminate(); + return (1); +} + +/*ARGSUSED*/ +void adm_download(char **a, char *b) { + terminate(); +} + +/*ARGSUSED*/ +void up_encl_name(char **a, int b) { + terminate(); +} + +void adm_failover(char **argv) { + int path_index = 0, err = 0, fd; + char path_class[MAXNAMELEN]; + char client_path[MAXPATHLEN]; + char *path_phys = NULL, *trailingMinor; + sv_switch_to_cntlr_iocdata_t iocsc; + + (void) memset(path_class, 0, sizeof (path_class)); + (void) strcpy(path_class, argv[path_index++]); + if ((strcmp(path_class, "primary") != 0) && + (strcmp(path_class, "secondary") != 0)) { + (void) fprintf(stderr, + MSGSTR(2300, "Incorrect pathclass\n")); + exit(-1); + } + + if ((fd = open("/devices/scsi_vhci:devctl", O_RDWR)) < 0) { + print_errString(L_OPEN_PATH_FAIL, "/devices/scsi_vhci:devctl"); + exit(-1); + } + + iocsc.client = client_path; + iocsc.class = path_class; + + while (argv[path_index] != NULL) { + path_phys = + get_slash_devices_from_osDevName(argv[path_index++], + STANDARD_DEVNAME_HANDLING); + if ((path_phys == NULL) || + (strstr(path_phys, "/devices/scsi_vhci") == NULL)) { + (void) fprintf(stderr, + MSGSTR(2301, "Incorrect pathname\n")); + close(fd); + exit(-1); + } + + strcpy(iocsc.client, path_phys + strlen("/devices")); + + /* Now chop off the trailing ":xxx" portion if present */ + if ((trailingMinor = strrchr(iocsc.client, ':')) != NULL) { + trailingMinor[0] = '\0'; + } + + if (ioctl(fd, SCSI_VHCI_SWITCH_TO_CNTLR, &iocsc) != 0) { + switch (errno) { + case EALREADY: + err = L_SCSI_VHCI_ALREADY_ACTIVE; + break; + case ENXIO: + err = L_INVALID_PATH; + break; + case EIO: + err = L_SCSI_VHCI_NO_STANDBY; + break; + case ENOTSUP: + err = L_SCSI_VHCI_FAILOVER_NOTSUP; + break; + case EBUSY: + err = L_SCSI_VHCI_FAILOVER_BUSY; + break; + case EFAULT: + default: + err = L_SCSI_VHCI_ERROR; + } + } + + if (err != 0) { + close(fd); + print_errString(err, path_phys); + exit(-1); + } + } + + close(fd); +} + +/*ARGSUSED*/ +int adm_inquiry(char **a) { + terminate(); + return (1); +} + +/*ARGSUSED*/ +void pho_probe() { + terminate(); +} + +/*ARGSUSED*/ +void non_encl_probe() { + terminate(); +} + +/*ARGSUSED*/ +void adm_led(char **a, int b) { + terminate(); +} + +/*ARGSUSED*/ +void up_password(char **a) { + terminate(); +} + +/*ARGSUSED*/ +int adm_reserve(char *path) { + terminate(); + return (1); +} + +/*ARGSUSED*/ +int adm_release(char *path) { + terminate(); + return (1); +} + +/*ARGSUSED*/ +int adm_start(char **a) { + terminate(); + return (1); +} + +/*ARGSUSED*/ +int adm_stop(char **a) { + terminate(); + return (1); +} + +/*ARGSUSED*/ +int adm_power_off(char **a, int b) { + terminate(); + return (1); +} + +int +adm_forcelip(char **argv) +{ + int path_index = 0, fd; + uint64_t wwn; + fcio_t fcio; + HBA_HANDLE handle; + HBA_ADAPTERATTRIBUTES hbaAttrs; + HBA_PORTATTRIBUTES portAttrs; + HBA_FCPTARGETMAPPINGV2 *map; + HBA_STATUS status; + int count, adapterIndex, portIndex, mapIndex; + char name[256]; + int matched, ret = 0, wwnCompare = 0, ntries; + char *physical = NULL, *slash_OSDeviceName = NULL; + + if ((status = loadLibrary())) { + /* loadLibrary print out error msg */ + return (ret++); + } + for (path_index = 0; argv[path_index] != NULL; path_index++) { + + if (is_wwn(argv[path_index])) { + (void) sscanf(argv[path_index], "%016llx", &wwn); + wwnCompare = 1; + } else if (!is_path(argv[path_index])) { + print_errString(L_INVALID_PATH, argv[path_index]); + ret++; + continue; + } + if (!wwnCompare) { + /* Convert the paths to phsyical paths */ + physical = get_slash_devices_from_osDevName(argv[path_index], + STANDARD_DEVNAME_HANDLING); + if (!physical) { + print_errString(L_INVALID_PATH, argv[path_index]); + ret++; + continue; + } + } + + count = getNumberOfAdapters(); + + matched = 0; + for (adapterIndex = 0; adapterIndex < count; adapterIndex ++) { + status = HBA_GetAdapterName(adapterIndex, (char *)&name); + if (status != HBA_STATUS_OK) { + /* May have been DR'd */ + continue; + } + handle = HBA_OpenAdapter(name); + if (handle == 0) { + /* May have been DR'd */ + continue; + } + + if (getAdapterAttrs(handle, name, &hbaAttrs)) { + /* Should never happen */ + HBA_CloseAdapter(handle); + continue; + } + + /* Loop over all HBA Ports */ + for (portIndex = 0; portIndex < hbaAttrs.NumberOfPorts; + portIndex++) { + if (getAdapterPortAttrs(handle, name, portIndex, + &portAttrs)) { + continue; + } + + matched = 0; + if (is_wwn(argv[path_index])) { + if (wwn == wwnConversion( + portAttrs.NodeWWN.wwn) || + wwn == wwnConversion( + portAttrs.PortWWN.wwn)) { + matched = 1; + } + } else { + slash_OSDeviceName = get_slash_devices_from_osDevName( + portAttrs.OSDeviceName, STANDARD_DEVNAME_HANDLING); + if (!slash_OSDeviceName) { + continue; + } else { + if (strncmp(physical, slash_OSDeviceName, + strlen(slash_OSDeviceName) - + strlen(strrchr(slash_OSDeviceName, ':'))) + == 0) { + matched = 1; + } + free(slash_OSDeviceName); + } + } + + if (!matched) { + if (!fetch_mappings(handle, portAttrs.PortWWN, &map)) { + /* + * matchr_mapping checks the arg + * so we pass argv here. + */ + mapIndex = match_mappings(argv[path_index], map); + if (mapIndex >= 0) { + matched = 1; + } + } else { + continue; + } + } + + if (matched) { + if ((fd = open(portAttrs.OSDeviceName, + O_RDONLY | O_EXCL)) == -1) { + print_errString(L_OPEN_PATH_FAIL, + portAttrs.OSDeviceName); + return (ret++); + } + + fcio.fcio_cmd = FCIO_RESET_LINK; + fcio.fcio_xfer = FCIO_XFER_WRITE; + /* + * Reset the local loop here (fcio_ibuf = 0). + * Reset a remote loop on the Fabric by + * passing its node wwn (fcio_len = sizeof(nwwn) + * and fcio_ibuf = (caddr_t)&nwwn) to the port driver. + */ + (void) memset(&wwn, 0, sizeof (wwn)); + fcio.fcio_ilen = sizeof (wwn); + fcio.fcio_ibuf = (caddr_t)&wwn; + + for (ntries = 0; ntries < RETRY_FCIO_IOCTL; ntries++) { + errno = 0; + if (ioctl(fd, FCIO_CMD, &fcio) != 0) { + /* + * When port is offlined, qlc + * returns the FC_OFFLINE error and errno + * is set to EIO. + * We do want to ignore this error, + * especially when an enclosure is + * removed from the loop. + */ + if (fcio.fcio_errno == FC_OFFLINE) + break; + if ((errno == EAGAIN) && + (ntries+1 < RETRY_FCIO_IOCTL)) { + /* wait WAIT_FCIO_IOCTL */ + (void) usleep(WAIT_FCIO_IOCTL); + continue; + } + I_DPRINTF("FCIO ioctl failed.\n" + "Error: %s. fc_error = %d (0x%x)\n", + strerror(errno), fcio.fcio_errno, + fcio.fcio_errno); + close(fd); + print_errString(L_FCIO_FORCE_LIP_FAIL, + portAttrs.OSDeviceName); + return (ret++); + } else { + break; /* ioctl succeeds. */ + } + } + close(fd); + if (ntries == RETRY_FCIO_IOCTL) { + print_errString(L_FCIO_FORCE_LIP_FAIL, + portAttrs.OSDeviceName); + return (ret++); + } + } + if (matched) + break; /* for HBA port for loop */ + } + if (matched) /* HBA adapter for loop */ + break; + } + + if (!matched) { + print_errString(L_INVALID_PATH, argv[path_index]); + ret++; + } + } + HBA_FreeLibrary(); + return (ret); +} + +/*ARGSUSED*/ +void adm_bypass_enable(char **argv, int bypass_flag) { + terminate(); +} + +/*ARGSUSED*/ +int adm_port_offline_online(char **a, int b) { + terminate(); + return (1); +} + +/*ARGSUSED*/ +void display_link_status(char **a) { + terminate(); +} + +/*ARGSUSED*/ +void dump_map(char **argv) { + terminate(); +} + +/*ARGSUSED*/ +int adm_display_port(int a) { + terminate(); + return (1); +} + +/*ARGSUSED*/ +int adm_port_loopback(char *a, int b) { + terminate(); + return (1); +} + +/*ARGSUSED*/ +int hotplug_e(int todo, char **argv, int verbose_flag, int force_flag) { + terminate(); + return (1); +} + +/*ARGSUSED*/ +int +setboot(unsigned int yes, unsigned int verbose, char *fname) +{ + terminate(); + return (1); +} + +/*ARGSUSED*/ +int hotplug(int todo, char **argv, int verbose_flag, int force_flag) { + terminate(); + return (1); +} + +/*ARGSUSED*/ +int adm_check_file(char **argv, int flag) { + terminate(); + return (1); +} + +/*ARGSUSED*/ +int sysdump(int verbose) { + terminate(); + return (1); +} + +/*ARGSUSED*/ +int fcal_update(unsigned int verbose, char *file) { + terminate(); + return (1); +} + +/*ARGSUSED*/ +int q_qlgc_update(unsigned int verbose, char *file) { + terminate(); + return (1); +} + +/*ARGSUSED*/ +int emulex_update(char *file) { + terminate(); + return (1); +} + +/*ARGSUSED*/ +int emulex_fcode_reader(int fcode_fd, char *pattern, char *pattern_value, + uint32_t pattern_value_size) { + terminate(); + return (1); +} + +/*ARGSUSED*/ +void dump(char **argv) { + terminate(); +} + +/*ARGSUSED*/ +int h_insertSena_fcdev() { + terminate(); + return (1); +} |
