/*
* This file is part of the zfcp device driver for
* FCP adapters for IBM System z9 and zSeries.
*
* (C) Copyright IBM Corp. 2002, 2006
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <asm/debug.h>
#include <linux/ctype.h>
#include "zfcp_ext.h"
static u32 dbfsize = 4;
module_param(dbfsize, uint, 0400);
MODULE_PARM_DESC(dbfsize,
"number of pages for each debug feature area (default 4)");
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_OTHER
static int
zfcp_dbf_stck(char *out_buf, const char *label, unsigned long long stck)
{
unsigned long long sec;
struct timespec xtime;
int len = 0;
stck -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
sec = stck >> 12;
do_div(sec, 1000000);
xtime.tv_sec = sec;
stck -= (sec * 1000000) << 12;
xtime.tv_nsec = ((stck * 1000) >> 12);
len += sprintf(out_buf + len, "%-24s%011lu:%06lu\n",
label, xtime.tv_sec, xtime.tv_nsec);
return len;
}
static int zfcp_dbf_tag(char *out_buf, const char *label, const char *tag)
{
int len = 0, i;
len += sprintf(out_buf + len, "%-24s", label);
for (i = 0; i < ZFCP_DBF_TAG_SIZE; i++)
len += sprintf(out_buf + len, "%c", tag[i]);
len += sprintf(out_buf + len, "\n");
return len;
}
static int
zfcp_dbf_view(char *out_buf, const char *label, const char *format, ...)
{
va_list arg;
int len = 0;
len += sprintf(out_buf + len, "%-24s", label);
va_start(arg, format);
len += vsprintf(out_buf + len, format, arg);
va_end(arg);
len += sprintf(out_buf + len, "\n");
return len;
}
static int
zfcp_dbf_view_dump(char *out_buf, const char *label,
char *buffer, int buflen, int offset, int total_size)
{
int len = 0;
if (offset == 0)
len += sprintf(out_buf + len, "%-24s ", label);
while (buflen--) {
if (offset > 0) {
if ((offset % 32) == 0)
len += sprintf(out_buf + len, "\n%-24c ", ' ');
else if ((offset % 4) == 0)
len += sprintf(out_buf + len, " ");
}
len += sprintf(out_buf + len, "%02x", *buffer++);
if (++offset == total_size) {
len += sprintf(out_buf + len, "\n");
break;
}
}
if (total_size == 0)
len += sprintf(out_buf + len, "\n");
return len;
}
static int
zfcp_dbf_view_header(debug_info_t * id, struct debug_view *view, int area,
debug_entry_t * entry, char *out_buf)
{
struct zfcp_dbf_dump *dump = (struct zfcp_dbf_dump *)DEBUG_DATA(entry);
int len = 0;
if (strncmp(dump->tag, "dump", ZFCP_DBF_TAG_SIZE) != 0) {
len += zfcp_dbf_stck(out_buf + len, "timestamp",
entry->id.stck);
len += zfcp_dbf_view(out_buf + len, "cpu", "%02i",
entry->id.fields.cpuid);
} else {
len += zfcp_dbf_view_dump(