emlxs.c revision 825277341c15b6b0d2c4b8b622ae7b1d2bdc0390
/*
* 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 2009 Emulex. All rights reserved.
* Use is subject to license terms.
*/
#define DUMP_SUPPORT
#include <emlxs_mdb.h>
#include <emlxs_msg.h>
#include <emlxs_dump.h>
#include <emlxs_device.h>
/*
* MDB module linkage information:
*/
static const mdb_dcmd_t dcmds[] =
{
{ "emlxs_msgbuf", "<instance>", "dumps the emlxs driver internal " \
"message buffer", emlxs_msgbuf, emlxs_msgbuf_help},
{ "emlxs_dump", "<type> <instance>", "dumps the emlxs driver " \
"firmware core", emlxs_dump, emlxs_dump_help},
{ NULL }
};
static const mdb_modinfo_t modinfo =
{
MDB_API_VERSION,
dcmds,
NULL
};
const mdb_modinfo_t *
_mdb_init(void)
{
return (&modinfo);
}
/*
* emlxs_msgbuf library
*/
void
emlxs_msgbuf_help()
{
mdb_printf("Usage: ::%s_msgbuf <instance(hex)>\n\n", DRIVER_NAME);
mdb_printf(" <instance> This is the %s driver instance " \
"number in hex.\n", DRIVER_NAME);
mdb_printf(" (e.g. 0, 1,..., e, f, etc.)\n");
} /* emlxs_msgbuf_help() */
/*ARGSUSED*/
int emlxs_msgbuf(uintptr_t base_addr, uint_t flags, int argc,
const mdb_arg_t *argv)
{
uintptr_t addr;
emlxs_device_t device;
uint32_t brd_no;
emlxs_msg_log_t log;
uint32_t count;
uint32_t first;
uint32_t last;
uint32_t idx;
uint32_t i;
char *level;
emlxs_msg_t msg;
char merge[1024];
emlxs_msg_entry_t entry;
char buffer[256];
char buffer2[256];
int32_t instance[MAX_FC_BRDS];
char driver[32];
int32_t instance_count;
uint32_t ddiinst;
if (argc != 1) {
mdb_printf("Usage: ::%s_msgbuf <instance(hex)>\n",
DRIVER_NAME);
mdb_printf("mdb: try \"::help %s_msgbuf\" for more information",
DRIVER_NAME);
return (DCMD_ERR);
}
/* Get the device address */
mdb_snprintf(buffer, sizeof (buffer), "%s_device", DRIVER_NAME);
if (mdb_readvar(&device, buffer) == -1) {
mdb_snprintf(buffer2, sizeof (buffer2),
"%s not found.\n", buffer);
mdb_warn(buffer2);
mdb_snprintf(buffer2, sizeof (buffer2),
"Is the %s driver loaded ?\n", DRIVER_NAME);
mdb_warn(buffer2);
return (DCMD_ERR);
}
/* Get the device instance table */
mdb_snprintf(buffer, sizeof (buffer), "%s_instance", DRIVER_NAME);
if (mdb_readvar(&instance, buffer) == -1) {
mdb_snprintf(buffer2, sizeof (buffer2), "%s not found.\n",
buffer);
mdb_warn(buffer2);
mdb_snprintf(buffer2, sizeof (buffer2),
"Is the %s driver loaded ?\n", DRIVER_NAME);
mdb_warn(buffer2);
return (DCMD_ERR);
}
/* Get the device instance count */
mdb_snprintf(buffer, sizeof (buffer), "%s_instance_count", DRIVER_NAME);
if (mdb_readvar(&instance_count, buffer) == -1) {
mdb_snprintf(buffer2, sizeof (buffer2), "%s not found.\n",
buffer);
mdb_warn(buffer2);
mdb_snprintf(buffer2, sizeof (buffer2),
"Is the %s driver loaded ?\n", DRIVER_NAME);
mdb_warn(buffer2);
return (DCMD_ERR);
}
ddiinst = (uint32_t)mdb_strtoull(argv[0].a_un.a_str);
for (brd_no = 0; brd_no < instance_count; brd_no++) {
if (instance[brd_no] == ddiinst) {
break;
}
}
if (brd_no == instance_count) {
mdb_warn("Device instance not found. ddinst=%d\n", ddiinst);
return (DCMD_ERR);
}
/* Check if buffer is null */
addr = (uintptr_t)device.log[brd_no];
if (addr == 0) {
mdb_warn("Device instance not found. ddinst=%d\n", ddiinst);
return (0);
}
if (mdb_vread(&log, sizeof (emlxs_msg_log_t), addr) !=
sizeof (emlxs_msg_log_t)) {
mdb_warn("\nUnable to read %d bytes @ %llx.\n",
sizeof (emlxs_msg_log_t), addr);
return (0);
}
/* Check if buffer is empty */
if (log.count == 0) {
mdb_warn("Log buffer empty.\n");
return (0);
}
/* Get last entry id saved */
last = log.count - 1;
/* Check if buffer has already been filled once */
if (log.count >= log.size) {
first = log.count - log.size;
idx = log.next;
} else {
/* Buffer not yet filled */
first = 0;
idx = 0;
}
/* Get the total number of messages available for return */
count = last - first + 1;
mdb_printf("\n");
/* Print the messages */
for (i = 0; i < count; i++) {
if (mdb_vread(&entry, sizeof (emlxs_msg_entry_t),
(uintptr_t)&log.entry[idx]) != sizeof (emlxs_msg_entry_t)) {
mdb_warn("Cannot read log entry. index=%d count=%d\n",
idx, count);
return (DCMD_ERR);
}
if (mdb_vread(&msg, sizeof (emlxs_msg_t),
(uintptr_t)entry.msg) != sizeof (emlxs_msg_t)) {
mdb_warn("Cannot read msg. index=%d count=%d\n",
idx, count);
return (DCMD_ERR);
}
switch (msg.level) {
case EMLXS_DEBUG:
level = " DEBUG";
break;
case EMLXS_NOTICE:
level = " NOTICE";
break;
case EMLXS_WARNING:
level = "WARNING";
break;
case EMLXS_ERROR:
level = " ERROR";
break;
case EMLXS_PANIC:
level = " PANIC";
break;
default:
level = "UNKNOWN";
break;
}
if (entry.vpi == 0) {
mdb_snprintf(driver, sizeof (driver), "%s%d",
DRIVER_NAME, entry.instance);
} else {
mdb_snprintf(driver, sizeof (driver), "%s%d.%d",
DRIVER_NAME, entry.instance, entry.vpi);
}
/* Generate the message string */
if (msg.buffer[0] != 0) {
if (entry.buffer[0] != 0) {
mdb_snprintf(merge, sizeof (merge),
"[%Y:%03d:%03d:%03d] "
"%6d:[%1X.%04X]%s:%7s:%4d: %s\n(%s)\n",
entry.id_time.tv_sec,
(int)entry.id_time.tv_nsec/1000000,
(int)(entry.id_time.tv_nsec/1000)%1000,
(int)entry.id_time.tv_nsec%1000,
entry.id, entry.fileno,
entry.line, driver, level, msg.id,
msg.buffer, entry.buffer);
} else {
mdb_snprintf(merge, sizeof (merge),
"[%Y:%03d:%03d:%03d] "
"%6d:[%1X.%04X]%s:%7s:%4d: %s\n",
entry.id_time.tv_sec,
(int)entry.id_time.tv_nsec/1000000,
(int)(entry.id_time.tv_nsec/1000)%1000,
(int)entry.id_time.tv_nsec%1000,
entry.id, entry.fileno,
entry.line, driver, level, msg.id,
msg.buffer);
}
} else {
if (entry.buffer[0] != 0) {
mdb_snprintf(merge, sizeof (merge),
"[%Y:%03d:%03d:%03d] "
"%6d:[%1X.%04X]%s:%7s:%4d:\n(%s)\n",
entry.id_time.tv_sec,
(int)entry.id_time.tv_nsec/1000000,
(int)(entry.id_time.tv_nsec/1000)%1000,
(int)entry.id_time.tv_nsec%1000,
entry.id, entry.fileno,
entry.line, driver, level, msg.id,
entry.buffer);
} else {
mdb_snprintf(merge, sizeof (merge),
"[%Y:%03d:%03d:%03d] "
"%6d:[%1X.%04X]%s:%7s:%4d: %s\n",
entry.id_time.tv_sec,
(int)entry.id_time.tv_nsec/1000000,
(int)(entry.id_time.tv_nsec/1000)%1000,
(int)entry.id_time.tv_nsec%1000,
entry.id, entry.fileno,
entry.line, driver, level, msg.id,
msg.buffer);
}
}
mdb_printf("%s", merge);
/* Increment index */
if (++idx >= log.size) {
idx = 0;
}
}
mdb_printf("\n");
return (0);
} /* emlxs_msgbuf() */
void
emlxs_dump_help()
{
mdb_printf("Usage: ::%s_dump all <instance(hex)>\n", DRIVER_NAME);
mdb_printf(" ::%s_dump txt <instance(hex)>\n", DRIVER_NAME);
mdb_printf(" ::%s_dump dmp <instance(hex)>\n", DRIVER_NAME);
mdb_printf(" ::%s_dump cee <instance(hex)>\n", DRIVER_NAME);
mdb_printf("\n");
mdb_printf(" txt Display firmware text summary " \
"file.\n");
mdb_printf(" dmp Display firmware dmp binary file.\n");
mdb_printf(" cee Display firmware cee binary file. " \
"(FCOE adapters only)\n");
mdb_printf(" all Display all firmware core files.\n");
mdb_printf(" <instance> This is the %s driver instance " \
"number in hex.\n", DRIVER_NAME);
mdb_printf(" (e.g. 0, 1,..., e, f, etc.)\n");
} /* emlxs_dump_help() */
/*ARGSUSED*/
int
emlxs_dump(uintptr_t base_addr, uint_t flags, int argc,
const mdb_arg_t *argv)
{
uintptr_t addr;
emlxs_device_t device;
uint32_t brd_no;
uint32_t i;
char buffer[256];
char buffer2[256];
int32_t instance[MAX_FC_BRDS];
int32_t instance_count;
uint32_t ddiinst;
uint8_t *bptr;
char *cptr;
emlxs_file_t dump_txtfile;
emlxs_file_t dump_dmpfile;
emlxs_file_t dump_ceefile;
uint32_t size;
uint32_t file;
if (argc != 2) {
goto usage;
}
if ((strcmp(argv[0].a_un.a_str, "all") == 0) ||
(strcmp(argv[0].a_un.a_str, "ALL") == 0) ||
(strcmp(argv[0].a_un.a_str, "All") == 0)) {
file = 0;
} else if ((strcmp(argv[0].a_un.a_str, "txt") == 0) ||
(strcmp(argv[0].a_un.a_str, "TXT") == 0) ||
(strcmp(argv[0].a_un.a_str, "Txt") == 0)) {
file = 1;
} else if ((strcmp(argv[0].a_un.a_str, "dmp") == 0) ||
(strcmp(argv[0].a_un.a_str, "DMP") == 0) ||
(strcmp(argv[0].a_un.a_str, "Dmp") == 0)) {
file = 2;
} else if ((strcmp(argv[0].a_un.a_str, "cee") == 0) ||
(strcmp(argv[0].a_un.a_str, "CEE") == 0) ||
(strcmp(argv[0].a_un.a_str, "Cee") == 0)) {
file = 3;
} else {
goto usage;
}
/* Get the device address */
mdb_snprintf(buffer, sizeof (buffer), "%s_device", DRIVER_NAME);
if (mdb_readvar(&device, buffer) == -1) {
mdb_snprintf(buffer2, sizeof (buffer2),
"%s not found.\n", buffer);
mdb_warn(buffer2);
mdb_snprintf(buffer2, sizeof (buffer2),
"Is the %s driver loaded ?\n", DRIVER_NAME);
mdb_warn(buffer2);
return (DCMD_ERR);
}
/* Get the device instance table */
mdb_snprintf(buffer, sizeof (buffer), "%s_instance", DRIVER_NAME);
if (mdb_readvar(&instance, buffer) == -1) {
mdb_snprintf(buffer2, sizeof (buffer2), "%s not found.\n",
buffer);
mdb_warn(buffer2);
mdb_snprintf(buffer2, sizeof (buffer2),
"Is the %s driver loaded ?\n", DRIVER_NAME);
mdb_warn(buffer2);
return (DCMD_ERR);
}
/* Get the device instance count */
mdb_snprintf(buffer, sizeof (buffer), "%s_instance_count", DRIVER_NAME);
if (mdb_readvar(&instance_count, buffer) == -1) {
mdb_snprintf(buffer2, sizeof (buffer2), "%s not found.\n",
buffer);
mdb_warn(buffer2);
mdb_snprintf(buffer2, sizeof (buffer2),
"Is the %s driver loaded ?\n", DRIVER_NAME);
mdb_warn(buffer2);
return (DCMD_ERR);
}
ddiinst = (uint32_t)mdb_strtoull(argv[1].a_un.a_str);
for (brd_no = 0; brd_no < instance_count; brd_no++) {
if (instance[brd_no] == ddiinst) {
break;
}
}
if (brd_no == instance_count) {
mdb_warn("Device instance not found. ddinst=%d\n", ddiinst);
return (DCMD_ERR);
}
if (file == 0 || file == 1) {
addr = (uintptr_t)device.dump_txtfile[brd_no];
if (addr == 0) {
mdb_warn("TXT file: Device instance not found. " \
"ddinst=%d\n", ddiinst);
goto dmp_file;
}
if (mdb_vread(&dump_txtfile, sizeof (dump_txtfile), addr)
!= sizeof (dump_txtfile)) {
mdb_warn("TXT file: Unable to read %d bytes @ %llx.\n",
sizeof (dump_txtfile), addr);
goto dmp_file;
}
size = (uintptr_t)dump_txtfile.ptr -
(uintptr_t)dump_txtfile.buffer;
if (size == 0) {
mdb_printf("TXT file: Not available.\n");
goto dmp_file;
}
bptr = (uint8_t *)mdb_zalloc(size, UM_SLEEP|UM_GC);
if (bptr == 0) {
mdb_warn("TXT file: Unable to allocate file buffer. " \
"ddinst=%d size=%d\n", ddiinst, size);
goto dmp_file;
}
if (mdb_vread(bptr, size, (uintptr_t)dump_txtfile.buffer)
!= size) {
mdb_warn("TXT file: Unable to read %d bytes @ %llx.\n",
size, dump_txtfile.buffer);
goto dmp_file;
}
mdb_printf("<TXT File Start>\n");
mdb_printf("\n");
mdb_printf("%s", bptr);
mdb_printf("\n");
mdb_printf("<TXT File End>\n");
}
dmp_file:
if (file == 0 || file == 2) {
addr = (uintptr_t)device.dump_dmpfile[brd_no];
if (addr == 0) {
mdb_warn("DMP file: Device instance not found. " \
"ddinst=%d\n", ddiinst);
goto cee_file;
}
if (mdb_vread(&dump_dmpfile, sizeof (dump_dmpfile), addr)
!= sizeof (dump_dmpfile)) {
mdb_warn("DMP file: Unable to read %d bytes @ %llx.\n",
sizeof (dump_dmpfile), addr);
goto cee_file;
}
size = (uintptr_t)dump_dmpfile.ptr -
(uintptr_t)dump_dmpfile.buffer;
if (size == 0) {
mdb_printf("DMP file: Not available.\n");
goto cee_file;
}
bptr = (uint8_t *)mdb_zalloc(size, UM_SLEEP|UM_GC);
if (bptr == 0) {
mdb_warn("DMP file: Unable to allocate file buffer. " \
"ddinst=%d size=%d\n", ddiinst, size);
goto cee_file;
}
if (mdb_vread(bptr, size, (uintptr_t)dump_dmpfile.buffer)
!= size) {
mdb_warn("DMP file: Unable to read %d bytes @ %llx.\n",
size, dump_dmpfile.buffer);
goto cee_file;
}
mdb_printf("<DMP File Start>\n");
mdb_printf("\n");
bzero(buffer2, sizeof (buffer2));
cptr = buffer2;
for (i = 0; i < size; i++) {
if (i && !(i % 16)) {
mdb_printf(" %s\n", buffer2);
bzero(buffer2, sizeof (buffer2));
cptr = buffer2;
}
if (!(i % 16)) {
mdb_printf("%08X: ", i);
}
if (!(i % 4)) {
mdb_printf(" ");
}
if ((*bptr >= 32) && (*bptr <= 126)) {
*cptr++ = *bptr;
} else {
*cptr++ = '.';
}
mdb_printf("%02X ", *bptr++);
}
size = 16 - (i % 16);
for (i = 0; size < 16 && i < size; i++) {
if (!(i % 4)) {
mdb_printf(" ");
}
mdb_printf(" ");
}
mdb_printf(" %s\n", buffer2);
mdb_printf("\n");
mdb_printf("<DMP File End>\n");
}
cee_file:
if (file == 0 || file == 3) {
addr = (uintptr_t)device.dump_ceefile[brd_no];
if (addr == 0) {
mdb_warn("CEE file: Device instance not found. " \
"ddinst=%d\n", ddiinst);
goto done;
}
if (mdb_vread(&dump_ceefile, sizeof (dump_ceefile), addr)
!= sizeof (dump_ceefile)) {
mdb_warn("CEE file: Unable to read %d bytes @ %llx.\n",
sizeof (dump_ceefile), addr);
goto done;
}
size = (uintptr_t)dump_ceefile.ptr -
(uintptr_t)dump_ceefile.buffer;
if (size == 0) {
mdb_printf("CEE file: Not available.\n");
goto done;
}
bptr = (uint8_t *)mdb_zalloc(size, UM_SLEEP|UM_GC);
if (bptr == 0) {
mdb_warn("CEE file: Unable to allocate file buffer. " \
"ddinst=%d size=%d\n", ddiinst, size);
goto done;
}
if (mdb_vread(bptr, size, (uintptr_t)dump_ceefile.buffer)
!= size) {
mdb_warn("CEE file: Unable to read %d bytes @ %llx.\n",
size, dump_ceefile.buffer);
goto done;
}
mdb_printf("<CEE File Start>\n");
mdb_printf("\n");
bzero(buffer2, sizeof (buffer2));
cptr = buffer2;
for (i = 0; i < size; i++) {
if (i && !(i % 16)) {
mdb_printf(" %s\n", buffer2);
bzero(buffer2, sizeof (buffer2));
cptr = buffer2;
}
if (!(i % 16)) {
mdb_printf("%08X: ", i);
}
if (!(i % 4)) {
mdb_printf(" ");
}
if ((*bptr >= 32) && (*bptr <= 126)) {
*cptr++ = *bptr;
} else {
*cptr++ = '.';
}
mdb_printf("%02X ", *bptr++);
}
size = 16 - (i % 16);
for (i = 0; size < 16 && i < size; i++) {
if (!(i % 4)) {
mdb_printf(" ");
}
mdb_printf(" ");
}
mdb_printf(" %s\n", buffer2);
mdb_printf("\n");
mdb_printf("<CEE File End>\n");
}
done:
mdb_printf("\n");
return (0);
usage:
mdb_printf("Usage: ::%s_dump <file> <instance (hex)>\n",
DRIVER_NAME);
mdb_printf("mdb: try \"::help %s_dump\" for more information",
DRIVER_NAME);
return (DCMD_ERR);
} /* emlxs_dump() */