freebsd-skq/sys/dev/aacraid/aacraid_debug.c
pfg 1537078d8f sys/dev: further adoption of SPDX licensing ID tags.
Mainly focus on files that use BSD 2-Clause license, however the tool I
was using misidentified many licenses so this was mostly a manual - error
prone - task.

The Software Package Data Exchange (SPDX) group provides a specification
to make it easier for automated tools to detect and summarize well known
opensource licenses. We are gradually adopting the specification, noting
that the tags are considered only advisory and do not, in any way,
superceed or replace the license texts.
2017-11-27 14:52:40 +00:00

717 lines
21 KiB
C

/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2006-2010 Adaptec, Inc.
* Copyright (c) 2010-2012 PMC-Sierra, Inc.
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* Debugging support.
*/
#include "opt_aacraid.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/conf.h>
#include <sys/bus.h>
#include <machine/resource.h>
#include <machine/bus.h>
#include <dev/aacraid/aacraid_reg.h>
#include <sys/aac_ioctl.h>
#include <dev/aacraid/aacraid_var.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/conf.h>
#include <sys/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>
#include <machine/bus.h>
#include <machine/stdarg.h>
#include <dev/aacraid/aacraid_debug.h>
#ifdef AACRAID_DEBUG
/*
* Dump the command queue indices
*/
void
aacraid_print_queues(struct aac_softc *sc)
{
device_printf(sc->aac_dev, "AACQ_FREE %d/%d\n",
sc->aac_qstat[AACQ_FREE].q_length, sc->aac_qstat[AACQ_FREE].q_max);
device_printf(sc->aac_dev, "AACQ_READY %d/%d\n",
sc->aac_qstat[AACQ_READY].q_length,
sc->aac_qstat[AACQ_READY].q_max);
device_printf(sc->aac_dev, "AACQ_BUSY %d/%d\n",
sc->aac_qstat[AACQ_BUSY].q_length, sc->aac_qstat[AACQ_BUSY].q_max);
}
/*
* Print a FIB
*/
void
aacraid_print_fib(struct aac_softc *sc, struct aac_fib *fib, const char *caller)
{
if (fib == NULL) {
device_printf(sc->aac_dev,
"aac_print_fib called with NULL fib\n");
return;
}
device_printf(sc->aac_dev, "%s: FIB @ %p\n", caller, fib);
device_printf(sc->aac_dev, " XferState %b\n", fib->Header.XferState,
"\20"
"\1HOSTOWNED"
"\2ADAPTEROWNED"
"\3INITIALISED"
"\4EMPTY"
"\5FROMPOOL"
"\6FROMHOST"
"\7FROMADAP"
"\10REXPECTED"
"\11RNOTEXPECTED"
"\12DONEADAP"
"\13DONEHOST"
"\14HIGH"
"\15NORM"
"\16ASYNC"
"\17PAGEFILEIO"
"\20SHUTDOWN"
"\21LAZYWRITE"
"\22ADAPMICROFIB"
"\23BIOSFIB"
"\24FAST_RESPONSE"
"\25APIFIB\n");
device_printf(sc->aac_dev, " Command %d\n", fib->Header.Command);
device_printf(sc->aac_dev, " StructType %d\n",
fib->Header.StructType);
device_printf(sc->aac_dev, " Size %d\n", fib->Header.Size);
device_printf(sc->aac_dev, " SenderSize %d\n",
fib->Header.SenderSize);
device_printf(sc->aac_dev, " SenderAddress 0x%x\n",
fib->Header.SenderFibAddress);
device_printf(sc->aac_dev, " RcvrAddress 0x%x\n",
fib->Header.u.ReceiverFibAddress);
device_printf(sc->aac_dev, " Handle 0x%x\n",
fib->Header.Handle);
switch(fib->Header.Command) {
case ContainerCommand:
{
struct aac_blockread *br;
struct aac_blockwrite *bw;
struct aac_sg_table *sg;
int i;
br = (struct aac_blockread*)fib->data;
bw = (struct aac_blockwrite*)fib->data;
sg = NULL;
if (br->Command == VM_CtBlockRead) {
device_printf(sc->aac_dev,
" BlockRead: container %d 0x%x/%d\n",
br->ContainerId, br->BlockNumber,
br->ByteCount);
sg = &br->SgMap;
}
if (bw->Command == VM_CtBlockWrite) {
device_printf(sc->aac_dev,
" BlockWrite: container %d 0x%x/%d "
"(%s)\n", bw->ContainerId,
bw->BlockNumber, bw->ByteCount,
bw->Stable == CSTABLE ? "stable" :
"unstable");
sg = &bw->SgMap;
}
if (sg != NULL) {
device_printf(sc->aac_dev,
" %d s/g entries\n", sg->SgCount);
for (i = 0; i < sg->SgCount; i++)
device_printf(sc->aac_dev, " 0x%08x/%d\n",
sg->SgEntry[i].SgAddress,
sg->SgEntry[i].SgByteCount);
}
break;
}
default:
device_printf(sc->aac_dev, " %16D\n", fib->data, " ");
device_printf(sc->aac_dev, " %16D\n", fib->data + 16, " ");
break;
}
}
/*
* Describe an AIF we have received.
*/
void
aacraid_print_aif(struct aac_softc *sc, struct aac_aif_command *aif)
{
switch(aif->command) {
case AifCmdEventNotify:
device_printf(sc->aac_dev, "EventNotify(%d)\n", aif->seqNumber);
switch(aif->data.EN.type) {
case AifEnGeneric: /* Generic notification */
device_printf(sc->aac_dev, "(Generic) %.*s\n",
(int)sizeof(aif->data.EN.data.EG),
aif->data.EN.data.EG.text);
break;
case AifEnTaskComplete: /* Task has completed */
device_printf(sc->aac_dev, "(TaskComplete)\n");
break;
case AifEnConfigChange: /* Adapter configuration change
* occurred */
device_printf(sc->aac_dev, "(ConfigChange)\n");
break;
case AifEnContainerChange: /* Adapter specific container
* configuration change */
device_printf(sc->aac_dev, "(ContainerChange) "
"container %d,%d\n",
aif->data.EN.data.ECC.container[0],
aif->data.EN.data.ECC.container[1]);
break;
case AifEnDeviceFailure: /* SCSI device failed */
device_printf(sc->aac_dev, "(DeviceFailure) "
"handle %d\n",
aif->data.EN.data.EDF.deviceHandle);
break;
case AifEnMirrorFailover: /* Mirror failover started */
device_printf(sc->aac_dev, "(MirrorFailover) "
"container %d failed, "
"migrating from slice %d to %d\n",
aif->data.EN.data.EMF.container,
aif->data.EN.data.EMF.failedSlice,
aif->data.EN.data.EMF.creatingSlice);
break;
case AifEnContainerEvent: /* Significant container
* event */
device_printf(sc->aac_dev, "(ContainerEvent) "
"container %d event "
"%d\n", aif->data.EN.data.ECE.container,
aif->data.EN.data.ECE.eventType);
break;
case AifEnFileSystemChange: /* File system changed */
device_printf(sc->aac_dev, "(FileSystemChange)\n");
break;
case AifEnConfigPause: /* Container pause event */
device_printf(sc->aac_dev, "(ConfigPause)\n");
break;
case AifEnConfigResume: /* Container resume event */
device_printf(sc->aac_dev, "(ConfigResume)\n");
break;
case AifEnFailoverChange: /* Failover space assignment
* changed */
device_printf(sc->aac_dev, "(FailoverChange)\n");
break;
case AifEnRAID5RebuildDone: /* RAID5 rebuild finished */
device_printf(sc->aac_dev, "(RAID5RebuildDone)\n");
break;
case AifEnEnclosureManagement: /* Enclosure management event */
device_printf(sc->aac_dev, "(EnclosureManagement) "
"EMPID %d unit %d "
"event %d\n", aif->data.EN.data.EEE.empID,
aif->data.EN.data.EEE.unitID,
aif->data.EN.data.EEE.eventType);
break;
case AifEnBatteryEvent: /* Significant NV battery
* event */
device_printf(sc->aac_dev, "(BatteryEvent) %d "
"(state was %d, is %d\n",
aif->data.EN.data.EBE.transition_type,
aif->data.EN.data.EBE.current_state,
aif->data.EN.data.EBE.prior_state);
break;
case AifEnAddContainer: /* A new container was
* created. */
device_printf(sc->aac_dev, "(AddContainer)\n");
break;
case AifEnDeleteContainer: /* A container was deleted. */
device_printf(sc->aac_dev, "(DeleteContainer)\n");
break;
case AifEnBatteryNeedsRecond: /* The battery needs
* reconditioning */
device_printf(sc->aac_dev, "(BatteryNeedsRecond)\n");
break;
case AifEnClusterEvent: /* Some cluster event */
device_printf(sc->aac_dev, "(ClusterEvent) event %d\n",
aif->data.EN.data.ECLE.eventType);
break;
case AifEnDiskSetEvent: /* A disk set event occurred. */
device_printf(sc->aac_dev, "(DiskSetEvent) event %d "
"diskset %jd creator %jd\n",
aif->data.EN.data.EDS.eventType,
(intmax_t)aif->data.EN.data.EDS.DsNum,
(intmax_t)aif->data.EN.data.EDS.CreatorId);
break;
case AifDenMorphComplete: /* A morph operation
* completed */
device_printf(sc->aac_dev, "(MorphComplete)\n");
break;
case AifDenVolumeExtendComplete: /* A volume expand operation
* completed */
device_printf(sc->aac_dev, "(VolumeExtendComplete)\n");
break;
default:
device_printf(sc->aac_dev, "(%d)\n", aif->data.EN.type);
break;
}
break;
case AifCmdJobProgress:
{
char *status;
switch(aif->data.PR[0].status) {
case AifJobStsSuccess:
status = "success"; break;
case AifJobStsFinished:
status = "finished"; break;
case AifJobStsAborted:
status = "aborted"; break;
case AifJobStsFailed:
status = "failed"; break;
case AifJobStsSuspended:
status = "suspended"; break;
case AifJobStsRunning:
status = "running"; break;
default:
status = "unknown status"; break;
}
device_printf(sc->aac_dev, "JobProgress (%d) - %s (%d, %d)\n",
aif->seqNumber, status,
aif->data.PR[0].currentTick,
aif->data.PR[0].finalTick);
switch(aif->data.PR[0].jd.type) {
case AifJobScsiZero: /* SCSI dev clear operation */
device_printf(sc->aac_dev, "(ScsiZero) handle %d\n",
aif->data.PR[0].jd.client.scsi_dh);
break;
case AifJobScsiVerify: /* SCSI device Verify operation
* NO REPAIR */
device_printf(sc->aac_dev, "(ScsiVerify) handle %d\n",
aif->data.PR[0].jd.client.scsi_dh);
break;
case AifJobScsiExercise: /* SCSI device Exercise
* operation */
device_printf(sc->aac_dev, "(ScsiExercise) handle %d\n",
aif->data.PR[0].jd.client.scsi_dh);
break;
case AifJobScsiVerifyRepair: /* SCSI device Verify operation
* WITH repair */
device_printf(sc->aac_dev,
"(ScsiVerifyRepair) handle %d\n",
aif->data.PR[0].jd.client.scsi_dh);
break;
case AifJobCtrZero: /* Container clear operation */
device_printf(sc->aac_dev,
"(ContainerZero) container %d\n",
aif->data.PR[0].jd.client.container.src);
break;
case AifJobCtrCopy: /* Container copy operation */
device_printf(sc->aac_dev,
"(ContainerCopy) container %d to %d\n",
aif->data.PR[0].jd.client.container.src,
aif->data.PR[0].jd.client.container.dst);
break;
case AifJobCtrCreateMirror: /* Container Create Mirror
* operation */
device_printf(sc->aac_dev,
"(ContainerCreateMirror) container %d\n",
aif->data.PR[0].jd.client.container.src);
/* XXX two containers? */
break;
case AifJobCtrMergeMirror: /* Container Merge Mirror
* operation */
device_printf(sc->aac_dev,
"(ContainerMergeMirror) container %d\n",
aif->data.PR[0].jd.client.container.src);
/* XXX two containers? */
break;
case AifJobCtrScrubMirror: /* Container Scrub Mirror
* operation */
device_printf(sc->aac_dev,
"(ContainerScrubMirror) container %d\n",
aif->data.PR[0].jd.client.container.src);
break;
case AifJobCtrRebuildRaid5: /* Container Rebuild Raid5
* operation */
device_printf(sc->aac_dev,
"(ContainerRebuildRaid5) container %d\n",
aif->data.PR[0].jd.client.container.src);
break;
case AifJobCtrScrubRaid5: /* Container Scrub Raid5
* operation */
device_printf(sc->aac_dev,
"(ContainerScrubRaid5) container %d\n",
aif->data.PR[0].jd.client.container.src);
break;
case AifJobCtrMorph: /* Container morph operation */
device_printf(sc->aac_dev,
"(ContainerMorph) container %d\n",
aif->data.PR[0].jd.client.container.src);
/* XXX two containers? */
break;
case AifJobCtrPartCopy: /* Container Partition copy
* operation */
device_printf(sc->aac_dev,
"(ContainerPartCopy) container %d to "
"%d\n",
aif->data.PR[0].jd.client.container.src,
aif->data.PR[0].jd.client.container.dst);
break;
case AifJobCtrRebuildMirror: /* Container Rebuild Mirror
* operation */
device_printf(sc->aac_dev,
"(ContainerRebuildMirror) container "
"%d\n",
aif->data.PR[0].jd.client.container.src);
break;
case AifJobCtrCrazyCache: /* crazy cache */
device_printf(sc->aac_dev,
"(ContainerCrazyCache) container %d\n",
aif->data.PR[0].jd.client.container.src);
/* XXX two containers? */
break;
case AifJobFsCreate: /* File System Create
* operation */
device_printf(sc->aac_dev, "(FsCreate)\n");
break;
case AifJobFsVerify: /* File System Verify
* operation */
device_printf(sc->aac_dev, "(FsVerivy)\n");
break;
case AifJobFsExtend: /* File System Extend
* operation */
device_printf(sc->aac_dev, "(FsExtend)\n");
break;
case AifJobApiFormatNTFS: /* Format a drive to NTFS */
device_printf(sc->aac_dev, "(FormatNTFS)\n");
break;
case AifJobApiFormatFAT: /* Format a drive to FAT */
device_printf(sc->aac_dev, "(FormatFAT)\n");
break;
case AifJobApiUpdateSnapshot: /* update the read/write half
* of a snapshot */
device_printf(sc->aac_dev, "(UpdateSnapshot)\n");
break;
case AifJobApiFormatFAT32: /* Format a drive to FAT32 */
device_printf(sc->aac_dev, "(FormatFAT32)\n");
break;
case AifJobCtlContinuousCtrVerify: /* Adapter operation */
device_printf(sc->aac_dev, "(ContinuousCtrVerify)\n");
break;
default:
device_printf(sc->aac_dev, "(%d)\n",
aif->data.PR[0].jd.type);
break;
}
break;
}
case AifCmdAPIReport:
device_printf(sc->aac_dev, "APIReport (%d)\n", aif->seqNumber);
break;
case AifCmdDriverNotify:
device_printf(sc->aac_dev, "DriverNotify (%d)\n",
aif->seqNumber);
break;
default:
device_printf(sc->aac_dev, "AIF %d (%d)\n", aif->command,
aif->seqNumber);
break;
}
}
#endif /* AACRAID_DEBUG */
/*
* Debug flags to be put into the HBA flags field when initialized
*/
const unsigned long aacraid_debug_flags = /* Variable to setup with above flags. */
/* HBA_FLAGS_DBG_KERNEL_PRINT_B | */
HBA_FLAGS_DBG_FW_PRINT_B |
/* HBA_FLAGS_DBG_FUNCTION_ENTRY_B | */
HBA_FLAGS_DBG_FUNCTION_EXIT_B |
HBA_FLAGS_DBG_ERROR_B |
HBA_FLAGS_DBG_INIT_B |
/* HBA_FLAGS_DBG_OS_COMMANDS_B | */
/* HBA_FLAGS_DBG_SCAN_B | */
/* HBA_FLAGS_DBG_COALESCE_B | */
/* HBA_FLAGS_DBG_IOCTL_COMMANDS_B | */
/* HBA_FLAGS_DBG_SYNC_COMMANDS_B | */
HBA_FLAGS_DBG_COMM_B |
/* HBA_FLAGS_DBG_AIF_B | */
/* HBA_FLAGS_DBG_CSMI_COMMANDS_B | */
HBA_FLAGS_DBG_DEBUG_B |
/* HBA_FLAGS_DBG_FLAGS_MASK | */
0;
int aacraid_get_fw_debug_buffer(struct aac_softc *sc)
{
u_int32_t MonDriverBufferPhysAddrLow = 0;
u_int32_t MonDriverBufferPhysAddrHigh = 0;
u_int32_t MonDriverBufferSize = 0;
u_int32_t MonDriverHeaderSize = 0;
/*
* Get the firmware print buffer parameters from the firmware
* If the command was successful map in the address.
*/
if (!aacraid_sync_command(sc, AAC_MONKER_GETDRVPROP, 0, 0, 0, 0, NULL, NULL)) {
MonDriverBufferPhysAddrLow = AAC_GET_MAILBOX(sc, 1);
MonDriverBufferPhysAddrHigh = AAC_GET_MAILBOX(sc, 2);
MonDriverBufferSize = AAC_GET_MAILBOX(sc, 3);
MonDriverHeaderSize = AAC_GET_MAILBOX(sc, 4);
if (MonDriverBufferSize) {
unsigned long Offset = MonDriverBufferPhysAddrLow
- rman_get_start(sc->aac_regs_res1);
/*
* See if the address is already mapped in and if so set it up
* from the base address
*/
if ((MonDriverBufferPhysAddrHigh == 0) &&
(Offset + MonDriverBufferSize <
rman_get_size(sc->aac_regs_res1))) {
sc->DebugOffset = Offset;
sc->DebugHeaderSize = MonDriverHeaderSize;
sc->FwDebugBufferSize = MonDriverBufferSize;
sc->FwDebugFlags = 0;
sc->DebugFlags = aacraid_debug_flags;
return 1;
}
}
}
/*
* The GET_DRIVER_BUFFER_PROPERTIES command failed
*/
return 0;
}
#define PRINT_TIMEOUT 250000 /* 1/4 second */
void aacraid_fw_printf(struct aac_softc *sc, unsigned long PrintFlags, const char * fmt, ...)
{
va_list args;
u_int32_t Count, i;
char PrintBuffer_P[PRINT_BUFFER_SIZE];
unsigned long PrintType;
PrintType = PrintFlags &
~(HBA_FLAGS_DBG_KERNEL_PRINT_B|HBA_FLAGS_DBG_FW_PRINT_B);
if (((PrintType!=0) && (sc!=NULL) && ((sc->DebugFlags & PrintType)==0))
|| ((sc!=NULL) && (sc->DebugFlags
& (HBA_FLAGS_DBG_KERNEL_PRINT_B|HBA_FLAGS_DBG_FW_PRINT_B)) == 0))
return;
/*
* Set up parameters and call sprintf function to format the data
*/
va_start(args, fmt);
vsprintf(PrintBuffer_P, fmt, args);
va_end(args);
/*
* Make sure the HBA structure has been passed in for this section
*/
if ((sc != NULL) && (sc->FwDebugBufferSize)) {
/*
* If we are set up for a Firmware print
*/
if ((sc->DebugFlags & HBA_FLAGS_DBG_FW_PRINT_B)
&& ((PrintFlags
& (HBA_FLAGS_DBG_KERNEL_PRINT_B|HBA_FLAGS_DBG_FW_PRINT_B))
!= HBA_FLAGS_DBG_KERNEL_PRINT_B)) {
/*
* Make sure the string size is within boundaries
*/
Count = strlen(PrintBuffer_P);
if (Count > sc->FwDebugBufferSize)
Count = (u_int16_t)sc->FwDebugBufferSize;
/*
* Wait for no more than PRINT_TIMEOUT for the previous
* message length to clear (the handshake).
*/
for (i = 0; i < PRINT_TIMEOUT; ++i) {
if (!AAC_MEM1_GETREG4(sc,
sc->DebugOffset + FW_DEBUG_STR_LENGTH_OFFSET)) {
break;
}
DELAY(1);
}
/*
* If the Length is clear, copy over the message, the
* flags, and the length. Make sure the length is the
* last because that is the signal for the Firmware to
* pick it up.
*/
if (!AAC_MEM1_GETREG4(sc,
sc->DebugOffset + FW_DEBUG_STR_LENGTH_OFFSET)) {
for (i = 0; i < Count; ++i) {
AAC_MEM1_SETREG1(sc, sc->DebugOffset + sc->DebugHeaderSize + i,
PrintBuffer_P[i]);
}
AAC_MEM1_SETREG4(sc, sc->DebugOffset + FW_DEBUG_FLAGS_OFFSET,
sc->FwDebugFlags);
AAC_MEM1_SETREG4(sc, sc->DebugOffset + FW_DEBUG_STR_LENGTH_OFFSET,
Count);
} else
sc->DebugFlags &= ~HBA_FLAGS_DBG_FW_PRINT_B;
}
/*
* If the Kernel Debug Print flag is set, send it off to the
* Kernel debugger
*/
if ((sc->DebugFlags & HBA_FLAGS_DBG_KERNEL_PRINT_B)
&& ((PrintFlags
& (HBA_FLAGS_DBG_KERNEL_PRINT_B|HBA_FLAGS_DBG_FW_PRINT_B))
!= HBA_FLAGS_DBG_FW_PRINT_B)) {
if (sc->FwDebugFlags & FW_DEBUG_FLAGS_NO_HEADERS_B)
printf ("%s\n", PrintBuffer_P);
else
device_printf (sc->aac_dev, "%s\n", PrintBuffer_P);
}
} else {
/*
* No HBA structure passed in so it has to be for the Kernel Debugger
*/
if ((sc != NULL) && (sc->FwDebugFlags & FW_DEBUG_FLAGS_NO_HEADERS_B))
printf ("%s\n", PrintBuffer_P);
else if (sc != NULL)
device_printf (sc->aac_dev, "%s\n", PrintBuffer_P);
else
printf("%s\n", PrintBuffer_P);
}
}
void aacraid_fw_print_mem(struct aac_softc *sc, unsigned long PrintFlags, u_int8_t *Addr, int Count)
{
int Offset, i;
u_int32_t DebugFlags = 0;
char Buffer[100];
char *LineBuffer_P;
/*
* If we have an HBA structure, save off the flags and set the no
* headers flag so we don't have garbage between our lines of data
*/
if (sc != NULL) {
DebugFlags = sc->FwDebugFlags;
sc->FwDebugFlags |= FW_DEBUG_FLAGS_NO_HEADERS_B;
}
Offset = 0;
/*
* Loop through all the data
*/
while (Offset < Count) {
/*
* We will format each line into a buffer and then print out
* the entire line so set the pointer to the beginning of the
* buffer
*/
LineBuffer_P = Buffer;
/*
* Set up the address in HEX
*/
sprintf(LineBuffer_P, "\n%04x ", Offset);
LineBuffer_P += 6;
/*
* Set up 16 bytes in HEX format
*/
for (i = 0; i < 16; ++i) {
/*
* If we are past the count of data bytes to output,
* pad with blanks
*/
if ((Offset + i) >= Count)
sprintf (LineBuffer_P, " ");
else
sprintf (LineBuffer_P, "%02x ", Addr[Offset+i]);
LineBuffer_P += 3;
/*
* At the mid point we will put in a divider
*/
if (i == 7) {
sprintf (LineBuffer_P, "- ");
LineBuffer_P += 2;
}
}
/*
* Now do the same 16 bytes at the end of the line in ASCII
* format
*/
sprintf (LineBuffer_P, " ");
LineBuffer_P += 2;
for (i = 0; i < 16; ++i) {
/*
* If all data processed, OUT-O-HERE
*/
if ((Offset + i) >= Count)
break;
/*
* If this is a printable ASCII character, convert it
*/
if ((Addr[Offset+i] > 0x1F) && (Addr[Offset+i] < 0x7F))
sprintf (LineBuffer_P, "%c", Addr[Offset+i]);
else
sprintf (LineBuffer_P, ".");
++LineBuffer_P;
}
/*
* The line is now formatted, so print it out
*/
aacraid_fw_printf(sc, PrintFlags, "%s", Buffer);
/*
* Bump the offset by 16 for the next line
*/
Offset += 16;
}
/*
* Restore the saved off flags
*/
if (sc != NULL)
sc->FwDebugFlags = DebugFlags;
}