/* * Copyright (c) 2011-2015, Emulex * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ /** * @file ECD library test progrem * * This is a user space test program that uses the elxcdul library to retrieve coreDump * information from Emulex HBA's that support the capability. * * In this example, the helper functions run on top of Emulex OCS driver, using an * ioctl() interface. */ #include #include #include #include #include #include #include #include #include #include #include #include #define DEFAULT_OFNAME "out.core" #define DEVNAME_TEMPLATE "/dev/ocs_%d" /** * @brief user provided context passed to the helper functions */ typedef struct { int fd; } ecdtest_context_t; /**************************************************************************************************** * OCS IOCTL declarations * * Warning: these ioctl() structures need to be in sync with OCS driver declarations */ typedef struct { uint16_t pci_vendor; uint16_t pci_device; char businfo[16]; uint32_t sli_intf; char desc[64]; char fw_rev[32]; uint8_t wwnn[8]; uint8_t wwpn[8]; char serialnum[32]; } ocs_ioctl_driver_info_t; typedef enum { OCS_ECD_HELPER_CFG_READ8, OCS_ECD_HELPER_CFG_READ16, OCS_ECD_HELPER_CFG_READ32, OCS_ECD_HELPER_CFG_WRITE8, OCS_ECD_HELPER_CFG_WRITE16, OCS_ECD_HELPER_CFG_WRITE32, OCS_ECD_HELPER_BAR_READ8, OCS_ECD_HELPER_BAR_READ16, OCS_ECD_HELPER_BAR_READ32, OCS_ECD_HELPER_BAR_WRITE8, OCS_ECD_HELPER_BAR_WRITE16, OCS_ECD_HELPER_BAR_WRITE32, } ocs_ecd_helper_cmd_t; typedef struct { ocs_ecd_helper_cmd_t cmd; uint32_t bar; uint32_t offset; uint32_t data; int status; } ocs_ioctl_ecd_helper_t; #define OCS_IOCTL_CMD_BASE 'o' #define OCS_IOCTL_CMD_DRIVER_INFO _IOWR(OCS_IOCTL_CMD_BASE, 4, ocs_ioctl_driver_info_t) #define OCS_IOCTL_CMD_ECD_HELPER _IOWR(OCS_IOCTL_CMD_BASE, 5, ocs_ioctl_ecd_helper_t) #if !defined(ARRAY_SIZE) #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) #endif static int enable_helper_trace = 0; #define helper_trace(fmt, ...) \ do { \ if (enable_helper_trace) \ printf(fmt, ##__VA_ARGS__); \ } while(0) static void usage(void); int main(int argc, char *argv[]) { int i; int rc; ecdtest_context_t ctx; uint8_t *buffer; uint32_t bufferLength; char *test_template_ecdargs[] = {"dead", "testtemplate"}; char *be3_template_ecdargs[] = {"dead", "be3template"}; char **ecdargs = be3_template_ecdargs; uint32_t ecdargs_count = ARRAY_SIZE(be3_template_ecdargs); struct utsname utsname; ecd_fwState_t fwState = 0; ecd_get_params_t params; char *ofname = DEFAULT_OFNAME; int devNum = 0; char devname[FILENAME_MAX]; ocs_ioctl_driver_info_t info; int major; int minor; int release; for (i = 1; i < argc; i ++) if (*argv[i] == '-') switch (*(argv[i]+1)) { case 'o': if (++i < argc) ofname = argv[i]; break; case 'd': if (++i < argc) devNum = atoi(argv[i]); break; case 't': enable_helper_trace = 1; break; case '-': if (strcmp(argv[i], "--test") == 0) { ecdargs = test_template_ecdargs; ecdargs_count = ARRAY_SIZE(test_template_ecdargs); } else if (strcmp(argv[i], "--be3") == 0) { ecdargs = be3_template_ecdargs; ecdargs_count = ARRAY_SIZE(be3_template_ecdargs); } else usage(); // no return break; default: usage(); // no return } /* Initialize user context */ memset(&ctx, 0, sizeof(ctx)); snprintf(devname, sizeof(devname), DEVNAME_TEMPLATE, devNum); ctx.fd = open(devname, O_RDWR); if (ctx.fd < 0) { printf("Error: can't open %s\n", devname); return -1; } /* Allocate a buffer */ bufferLength = 32*1024*1024; buffer = malloc(bufferLength); if (buffer == NULL) { printf("Error: buffer malloc %d failed\n", bufferLength); return -1; } fwState = ECD_FW_STATE_UE; /* Build parameters */ memset(¶ms, 0, sizeof(params)); params.instance = devNum; /* Using uname() system call fetch required parameter information */ rc = uname(&utsname); if (rc != 0) { strncpy(params.system_name, "unknown", sizeof(params.system_name)); strncpy(params.os_name, "unknown", sizeof(params.os_name)); } else { strncpy(params.os_name, utsname.release, sizeof(params.os_name)); strncpy(params.system_name, utsname.nodename, sizeof(params.system_name)); } params.ioctl_high_version = 1; params.ioctl_low_version = 0; /* Parse out the linux version, pass in 2.6.32 as 26.32 */ sscanf(utsname.release, "%d.%d.%d", &major, &minor, &release); params.os_major = major*10 + minor; params.os_minor = release; /* We need to get the SLI_INTF register value for this device using a driver ioctl */ rc = ioctl(ctx.fd, OCS_IOCTL_CMD_DRIVER_INFO, &info); if (rc) { printf("Error: OCS_IOCTL_CMD_DRIVER_INFO failed: %d\n", rc); return -1; } else params.sli_intf = info.sli_intf; /* Get the core dump data */ rc = ecd_GetCoreDumpData(&ctx, fwState, ¶ms, buffer, bufferLength, ecdargs_count, ecdargs); /* A return value >= 0 means that there is data in the buffer */ if ((rc > 0) && (ofname != NULL)) { FILE *out; uint32_t len = rc; out = fopen(ofname, "wb"); if (out == NULL) printf("Error: can't create %s\n", ofname); else { rc = fwrite(buffer, 1, len, out); if (rc != len) printf("Error: fwrite failed: %d\n", rc); fclose(out); } } free(buffer); return 0; } static void usage(void) { printf("Usage: ecdtest options\n"); printf(" -o output-file # default out.core\n"); printf(" -d device-instance # default 0\n"); printf(" -t # enable helper funtion trace\n"); printf(" --test # use test template\n"); printf(" --be3 # use BE3 template (default)\n"); exit(0); } /**************************************************************************************************** * Helper functions * * These helper functions implement an interface to the Emulex OCS driver using the ioctl() interface. * * The customer implementation would replace these with functions that interface to their particular * driver. */ void ecd_log(char *fmt, ...) { va_list ap; va_start(ap, fmt); vprintf(fmt, ap); } void os_assert(char *message, uint32_t Line, char *File) { ecd_log("%s(%d) %s\n", File, Line, message); exit(0); } void os_stall(void *ctx, uint32_t usecTime) { usleep(usecTime); } void os_cfg_read8 (void *ctx, uint32_t offset, uint32_t *pdata) { int32_t rc; ecdtest_context_t *ecd = ctx; ocs_ioctl_ecd_helper_t cmd; helper_trace("%-16s: offset x%x\n", __func__, offset); memset(&cmd, 0, sizeof(cmd)); cmd.cmd = OCS_ECD_HELPER_CFG_READ8; cmd.offset = offset; rc = ioctl(ecd->fd, OCS_IOCTL_CMD_ECD_HELPER, &cmd); if (rc == 0) *pdata = cmd.data; } void os_cfg_read16(void *ctx, uint32_t offset, uint32_t *pdata) { int32_t rc; ecdtest_context_t *ecd = ctx; ocs_ioctl_ecd_helper_t cmd; helper_trace("%-16s: offset x%x\n", __func__, offset); memset(&cmd, 0, sizeof(cmd)); cmd.cmd = OCS_ECD_HELPER_CFG_READ16; cmd.offset = offset; rc = ioctl(ecd->fd, OCS_IOCTL_CMD_ECD_HELPER, &cmd); if (rc == 0) *pdata = cmd.data; } void os_cfg_read32(void *ctx, uint32_t offset, uint32_t *pdata) { int32_t rc; ecdtest_context_t *ecd = ctx; ocs_ioctl_ecd_helper_t cmd; helper_trace("%-16s: offset x%x\n", __func__, offset); memset(&cmd, 0, sizeof(cmd)); cmd.cmd = OCS_ECD_HELPER_CFG_READ32; cmd.offset = offset; rc = ioctl(ecd->fd, OCS_IOCTL_CMD_ECD_HELPER, &cmd); if (rc == 0) *pdata = cmd.data; } void os_cfg_write8 (void *ctx, uint32_t offset, uint32_t data) { ecdtest_context_t *ecd = ctx; ocs_ioctl_ecd_helper_t cmd; helper_trace("%-16s: offset x%x\n", __func__, offset); memset(&cmd, 0, sizeof(cmd)); cmd.cmd = OCS_ECD_HELPER_CFG_WRITE8; cmd.offset = offset; cmd.data = data; ioctl(ecd->fd, OCS_IOCTL_CMD_ECD_HELPER, &cmd); } void os_cfg_write16(void *ctx, uint32_t offset, uint32_t data) { ecdtest_context_t *ecd = ctx; ocs_ioctl_ecd_helper_t cmd; helper_trace("%-16s: offset x%x\n", __func__, offset); memset(&cmd, 0, sizeof(cmd)); cmd.cmd = OCS_ECD_HELPER_CFG_WRITE16; cmd.offset = offset; cmd.data = data; ioctl(ecd->fd, OCS_IOCTL_CMD_ECD_HELPER, &cmd); } void os_cfg_write32(void *ctx, uint32_t offset, uint32_t data) { ecdtest_context_t *ecd = ctx; ocs_ioctl_ecd_helper_t cmd; helper_trace("%-16s: offset x%x\n", __func__, offset); memset(&cmd, 0, sizeof(cmd)); cmd.cmd = OCS_ECD_HELPER_CFG_WRITE16; cmd.offset = offset; cmd.data = data; ioctl(ecd->fd, OCS_IOCTL_CMD_ECD_HELPER, &cmd); } void os_bar_read8 (void *ctx, uint32_t bar, uint32_t offset, uint32_t *pdata) { int32_t rc; ecdtest_context_t *ecd = ctx; ocs_ioctl_ecd_helper_t cmd; helper_trace("%-16s: bar %d offset x%x\n", __func__, bar, offset); memset(&cmd, 0, sizeof(cmd)); cmd.cmd = OCS_ECD_HELPER_BAR_READ8; cmd.bar = bar; cmd.offset = offset; rc = ioctl(ecd->fd, OCS_IOCTL_CMD_ECD_HELPER, &cmd); if (rc == 0) *pdata = cmd.data; } void os_bar_read16(void *ctx, uint32_t bar, uint32_t offset, uint32_t *pdata) { int32_t rc; ecdtest_context_t *ecd = ctx; ocs_ioctl_ecd_helper_t cmd; helper_trace("%-16s: bar %d offset x%x\n", __func__, bar, offset); memset(&cmd, 0, sizeof(cmd)); cmd.cmd = OCS_ECD_HELPER_BAR_READ16; cmd.bar = bar; cmd.offset = offset; rc = ioctl(ecd->fd, OCS_IOCTL_CMD_ECD_HELPER, &cmd); if (rc == 0) *pdata = cmd.data; } void os_bar_read32(void *ctx, uint32_t bar, uint32_t offset, uint32_t *pdata) { int32_t rc; ecdtest_context_t *ecd = ctx; ocs_ioctl_ecd_helper_t cmd; helper_trace("%-16s: bar %d offset x%x\n", __func__, bar, offset); memset(&cmd, 0, sizeof(cmd)); cmd.cmd = OCS_ECD_HELPER_BAR_READ32; cmd.bar = bar; cmd.offset = offset; rc = ioctl(ecd->fd, OCS_IOCTL_CMD_ECD_HELPER, &cmd); if (rc == 0) *pdata = cmd.data; } void os_bar_write8 (void *ctx, uint32_t bar, uint32_t offset, uint32_t data) { ecdtest_context_t *ecd = ctx; ocs_ioctl_ecd_helper_t cmd; helper_trace("%-16s: bar %d offset x%x\n", __func__, bar, offset); memset(&cmd, 0, sizeof(cmd)); cmd.cmd = OCS_ECD_HELPER_BAR_WRITE8; cmd.bar = bar; cmd.offset = offset; cmd.data = data; ioctl(ecd->fd, OCS_IOCTL_CMD_ECD_HELPER, &cmd); } void os_bar_write16(void *ctx, uint32_t bar, uint32_t offset, uint32_t data) { ecdtest_context_t *ecd = ctx; ocs_ioctl_ecd_helper_t cmd; helper_trace("%-16s: bar %d offset x%x\n", __func__, bar, offset); memset(&cmd, 0, sizeof(cmd)); cmd.cmd = OCS_ECD_HELPER_BAR_WRITE16; cmd.bar = bar; cmd.offset = offset; cmd.data = data; ioctl(ecd->fd, OCS_IOCTL_CMD_ECD_HELPER, &cmd); } void os_bar_write32(void *ctx, uint32_t bar, uint32_t offset, uint32_t data) { ecdtest_context_t *ecd = ctx; ocs_ioctl_ecd_helper_t cmd; helper_trace("%-16s: bar %d offset x%x\n", __func__, bar, offset); memset(&cmd, 0, sizeof(cmd)); cmd.cmd = OCS_ECD_HELPER_BAR_WRITE32; cmd.bar = bar; cmd.offset = offset; cmd.data = data; ioctl(ecd->fd, OCS_IOCTL_CMD_ECD_HELPER, &cmd); } void *os_malloc(void *ctx, uint32_t size) { return malloc(size); } void os_free(void *ctx, void *ptr) { return free(ptr); }