1
2/*-
3 * Copyright (c) 2006-2010 Adaptec, Inc.
4 * Copyright (c) 2010-2012 PMC-Sierra, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD$");
32
33/*
34 * Debugging support.
35 */
36#include "opt_aacraid.h"
37
38#include <sys/param.h>
39#include <sys/systm.h>
40#include <sys/kernel.h>
41#include <sys/conf.h>
42
43#include <sys/bus.h>
44
45#include <machine/resource.h>
46#include <machine/bus.h>
47
48#include <dev/aacraid/aacraid_reg.h>
49#include <sys/aac_ioctl.h>
50#include <dev/aacraid/aacraid_var.h>
51#include <sys/param.h>
52#include <sys/systm.h>
53#include <sys/kernel.h>
54#include <sys/conf.h>
55
56#include <sys/bus.h>
57#include <sys/rman.h>
58
59#include <machine/resource.h>
60#include <machine/bus.h>
61#include <machine/stdarg.h>
62
63#include <dev/aacraid/aacraid_debug.h>
64
65#ifdef AACRAID_DEBUG
66/*
67 * Dump the command queue indices
68 */
69void
70aacraid_print_queues(struct aac_softc *sc)
71{
72	device_printf(sc->aac_dev, "AACQ_FREE      %d/%d\n",
73	    sc->aac_qstat[AACQ_FREE].q_length, sc->aac_qstat[AACQ_FREE].q_max);
74	device_printf(sc->aac_dev, "AACQ_READY     %d/%d\n",
75	    sc->aac_qstat[AACQ_READY].q_length,
76	    sc->aac_qstat[AACQ_READY].q_max);
77	device_printf(sc->aac_dev, "AACQ_BUSY      %d/%d\n",
78	    sc->aac_qstat[AACQ_BUSY].q_length, sc->aac_qstat[AACQ_BUSY].q_max);
79}
80
81/*
82 * Print a FIB
83 */
84void
85aacraid_print_fib(struct aac_softc *sc, struct aac_fib *fib, const char *caller)
86{
87	if (fib == NULL) {
88		device_printf(sc->aac_dev,
89			      "aac_print_fib called with NULL fib\n");
90		return;
91	}
92	device_printf(sc->aac_dev, "%s: FIB @ %p\n", caller, fib);
93	device_printf(sc->aac_dev, "  XferState %b\n", fib->Header.XferState,
94		      "\20"
95		      "\1HOSTOWNED"
96		      "\2ADAPTEROWNED"
97		      "\3INITIALISED"
98		      "\4EMPTY"
99		      "\5FROMPOOL"
100		      "\6FROMHOST"
101		      "\7FROMADAP"
102		      "\10REXPECTED"
103		      "\11RNOTEXPECTED"
104		      "\12DONEADAP"
105		      "\13DONEHOST"
106		      "\14HIGH"
107		      "\15NORM"
108		      "\16ASYNC"
109		      "\17PAGEFILEIO"
110		      "\20SHUTDOWN"
111		      "\21LAZYWRITE"
112		      "\22ADAPMICROFIB"
113		      "\23BIOSFIB"
114		      "\24FAST_RESPONSE"
115		      "\25APIFIB\n");
116	device_printf(sc->aac_dev, "  Command       %d\n", fib->Header.Command);
117	device_printf(sc->aac_dev, "  StructType    %d\n",
118		      fib->Header.StructType);
119	device_printf(sc->aac_dev, "  Size          %d\n", fib->Header.Size);
120	device_printf(sc->aac_dev, "  SenderSize    %d\n",
121		      fib->Header.SenderSize);
122	device_printf(sc->aac_dev, "  SenderAddress 0x%x\n",
123		      fib->Header.SenderFibAddress);
124	device_printf(sc->aac_dev, "  RcvrAddress   0x%x\n",
125		      fib->Header.u.ReceiverFibAddress);
126	device_printf(sc->aac_dev, "  Handle    0x%x\n",
127		      fib->Header.Handle);
128	switch(fib->Header.Command) {
129	case ContainerCommand:
130	{
131		struct aac_blockread *br;
132		struct aac_blockwrite *bw;
133		struct aac_sg_table *sg;
134		int i;
135
136		br = (struct aac_blockread*)fib->data;
137		bw = (struct aac_blockwrite*)fib->data;
138		sg = NULL;
139
140		if (br->Command == VM_CtBlockRead) {
141			device_printf(sc->aac_dev,
142				      "  BlockRead: container %d  0x%x/%d\n",
143				      br->ContainerId, br->BlockNumber,
144				      br->ByteCount);
145			sg = &br->SgMap;
146		}
147		if (bw->Command == VM_CtBlockWrite) {
148			device_printf(sc->aac_dev,
149				      "  BlockWrite: container %d  0x%x/%d "
150				      "(%s)\n", bw->ContainerId,
151				      bw->BlockNumber, bw->ByteCount,
152				      bw->Stable == CSTABLE ? "stable" :
153				      "unstable");
154			sg = &bw->SgMap;
155		}
156		if (sg != NULL) {
157			device_printf(sc->aac_dev,
158				      "  %d s/g entries\n", sg->SgCount);
159			for (i = 0; i < sg->SgCount; i++)
160				device_printf(sc->aac_dev, "  0x%08x/%d\n",
161					      sg->SgEntry[i].SgAddress,
162					      sg->SgEntry[i].SgByteCount);
163		}
164		break;
165	}
166	default:
167		device_printf(sc->aac_dev, "   %16D\n", fib->data, " ");
168		device_printf(sc->aac_dev, "   %16D\n", fib->data + 16, " ");
169		break;
170	}
171}
172
173/*
174 * Describe an AIF we have received.
175 */
176void
177aacraid_print_aif(struct aac_softc *sc, struct aac_aif_command *aif)
178{
179	switch(aif->command) {
180	case AifCmdEventNotify:
181		device_printf(sc->aac_dev, "EventNotify(%d)\n", aif->seqNumber);
182		switch(aif->data.EN.type) {
183		case AifEnGeneric:		/* Generic notification */
184			device_printf(sc->aac_dev, "(Generic) %.*s\n",
185				  (int)sizeof(aif->data.EN.data.EG),
186				  aif->data.EN.data.EG.text);
187			break;
188		case AifEnTaskComplete:		/* Task has completed */
189			device_printf(sc->aac_dev, "(TaskComplete)\n");
190			break;
191		case AifEnConfigChange:		/* Adapter configuration change
192						 * occurred */
193			device_printf(sc->aac_dev, "(ConfigChange)\n");
194			break;
195		case AifEnContainerChange:	/* Adapter specific container
196						 * configuration change */
197			device_printf(sc->aac_dev, "(ContainerChange) "
198				      "container %d,%d\n",
199				      aif->data.EN.data.ECC.container[0],
200				      aif->data.EN.data.ECC.container[1]);
201			break;
202		case AifEnDeviceFailure:	/* SCSI device failed */
203			device_printf(sc->aac_dev, "(DeviceFailure) "
204				      "handle %d\n",
205				      aif->data.EN.data.EDF.deviceHandle);
206			break;
207		case AifEnMirrorFailover:	/* Mirror failover started */
208			device_printf(sc->aac_dev, "(MirrorFailover) "
209				      "container %d failed, "
210				      "migrating from slice %d to %d\n",
211				      aif->data.EN.data.EMF.container,
212				      aif->data.EN.data.EMF.failedSlice,
213				      aif->data.EN.data.EMF.creatingSlice);
214			break;
215		case AifEnContainerEvent:	/* Significant container
216						 * event */
217			device_printf(sc->aac_dev, "(ContainerEvent) "
218				      "container %d event "
219				      "%d\n", aif->data.EN.data.ECE.container,
220				      aif->data.EN.data.ECE.eventType);
221			break;
222		case AifEnFileSystemChange:	/* File system changed */
223			device_printf(sc->aac_dev, "(FileSystemChange)\n");
224			break;
225		case AifEnConfigPause:		/* Container pause event */
226			device_printf(sc->aac_dev, "(ConfigPause)\n");
227			break;
228		case AifEnConfigResume:		/* Container resume event */
229			device_printf(sc->aac_dev, "(ConfigResume)\n");
230			break;
231		case AifEnFailoverChange:	/* Failover space assignment
232						 * changed */
233			device_printf(sc->aac_dev, "(FailoverChange)\n");
234			break;
235		case AifEnRAID5RebuildDone:	/* RAID5 rebuild finished */
236			device_printf(sc->aac_dev, "(RAID5RebuildDone)\n");
237			break;
238		case AifEnEnclosureManagement:	/* Enclosure management event */
239			device_printf(sc->aac_dev, "(EnclosureManagement) "
240				      "EMPID %d unit %d "
241				      "event %d\n", aif->data.EN.data.EEE.empID,
242				      aif->data.EN.data.EEE.unitID,
243				      aif->data.EN.data.EEE.eventType);
244			break;
245		case AifEnBatteryEvent:		/* Significant NV battery
246						 * event */
247			device_printf(sc->aac_dev, "(BatteryEvent) %d "
248				      "(state was %d, is %d\n",
249				      aif->data.EN.data.EBE.transition_type,
250				      aif->data.EN.data.EBE.current_state,
251				      aif->data.EN.data.EBE.prior_state);
252			break;
253		case AifEnAddContainer:		/* A new container was
254						 * created. */
255			device_printf(sc->aac_dev, "(AddContainer)\n");
256			break;
257		case AifEnDeleteContainer:	/* A container was deleted. */
258			device_printf(sc->aac_dev, "(DeleteContainer)\n");
259			break;
260		case AifEnBatteryNeedsRecond:	/* The battery needs
261						 * reconditioning */
262			device_printf(sc->aac_dev, "(BatteryNeedsRecond)\n");
263			break;
264		case AifEnClusterEvent:		/* Some cluster event */
265			device_printf(sc->aac_dev, "(ClusterEvent) event %d\n",
266				      aif->data.EN.data.ECLE.eventType);
267			break;
268		case AifEnDiskSetEvent:		/* A disk set event occured. */
269			device_printf(sc->aac_dev, "(DiskSetEvent) event %d "
270				      "diskset %jd creator %jd\n",
271				      aif->data.EN.data.EDS.eventType,
272				      (intmax_t)aif->data.EN.data.EDS.DsNum,
273				      (intmax_t)aif->data.EN.data.EDS.CreatorId);
274			break;
275		case AifDenMorphComplete: 	/* A morph operation
276						 * completed */
277			device_printf(sc->aac_dev, "(MorphComplete)\n");
278			break;
279		case AifDenVolumeExtendComplete: /* A volume expand operation
280						  * completed */
281			device_printf(sc->aac_dev, "(VolumeExtendComplete)\n");
282			break;
283		default:
284			device_printf(sc->aac_dev, "(%d)\n", aif->data.EN.type);
285			break;
286		}
287		break;
288	case AifCmdJobProgress:
289	{
290		char	*status;
291		switch(aif->data.PR[0].status) {
292		case AifJobStsSuccess:
293			status = "success"; break;
294		case AifJobStsFinished:
295			status = "finished"; break;
296		case AifJobStsAborted:
297			status = "aborted"; break;
298		case AifJobStsFailed:
299			status = "failed"; break;
300		case AifJobStsSuspended:
301			status = "suspended"; break;
302		case AifJobStsRunning:
303			status = "running"; break;
304		default:
305			status = "unknown status"; break;
306		}
307
308		device_printf(sc->aac_dev, "JobProgress (%d) - %s (%d, %d)\n",
309			      aif->seqNumber, status,
310			      aif->data.PR[0].currentTick,
311			      aif->data.PR[0].finalTick);
312		switch(aif->data.PR[0].jd.type) {
313		case AifJobScsiZero:		/* SCSI dev clear operation */
314			device_printf(sc->aac_dev, "(ScsiZero) handle %d\n",
315				      aif->data.PR[0].jd.client.scsi_dh);
316			break;
317		case AifJobScsiVerify:		/* SCSI device Verify operation
318						 * NO REPAIR */
319			device_printf(sc->aac_dev, "(ScsiVerify) handle %d\n",
320				      aif->data.PR[0].jd.client.scsi_dh);
321			break;
322		case AifJobScsiExercise:	/* SCSI device Exercise
323						 * operation */
324			device_printf(sc->aac_dev, "(ScsiExercise) handle %d\n",
325				      aif->data.PR[0].jd.client.scsi_dh);
326			break;
327		case AifJobScsiVerifyRepair:	/* SCSI device Verify operation
328						 * WITH repair */
329			device_printf(sc->aac_dev,
330				      "(ScsiVerifyRepair) handle %d\n",
331				      aif->data.PR[0].jd.client.scsi_dh);
332			break;
333		case AifJobCtrZero:		/* Container clear operation */
334			device_printf(sc->aac_dev,
335				      "(ContainerZero) container %d\n",
336				      aif->data.PR[0].jd.client.container.src);
337			break;
338		case AifJobCtrCopy:		/* Container copy operation */
339			device_printf(sc->aac_dev,
340				      "(ContainerCopy) container %d to %d\n",
341				      aif->data.PR[0].jd.client.container.src,
342				      aif->data.PR[0].jd.client.container.dst);
343			break;
344		case AifJobCtrCreateMirror:	/* Container Create Mirror
345						 * operation */
346			device_printf(sc->aac_dev,
347				      "(ContainerCreateMirror) container %d\n",
348				      aif->data.PR[0].jd.client.container.src);
349				      /* XXX two containers? */
350			break;
351		case AifJobCtrMergeMirror:	/* Container Merge Mirror
352						 * operation */
353			device_printf(sc->aac_dev,
354				      "(ContainerMergeMirror) container %d\n",
355				      aif->data.PR[0].jd.client.container.src);
356				      /* XXX two containers? */
357			break;
358		case AifJobCtrScrubMirror:	/* Container Scrub Mirror
359						 * operation */
360			device_printf(sc->aac_dev,
361				      "(ContainerScrubMirror) container %d\n",
362				      aif->data.PR[0].jd.client.container.src);
363			break;
364		case AifJobCtrRebuildRaid5:	/* Container Rebuild Raid5
365						 * operation */
366			device_printf(sc->aac_dev,
367				      "(ContainerRebuildRaid5) container %d\n",
368				      aif->data.PR[0].jd.client.container.src);
369			break;
370		case AifJobCtrScrubRaid5:	/* Container Scrub Raid5
371						 * operation */
372			device_printf(sc->aac_dev,
373				      "(ContainerScrubRaid5) container %d\n",
374				      aif->data.PR[0].jd.client.container.src);
375			break;
376		case AifJobCtrMorph:		/* Container morph operation */
377			device_printf(sc->aac_dev,
378				      "(ContainerMorph) container %d\n",
379				      aif->data.PR[0].jd.client.container.src);
380				      /* XXX two containers? */
381			break;
382		case AifJobCtrPartCopy:		/* Container Partition copy
383						 * operation */
384			device_printf(sc->aac_dev,
385				      "(ContainerPartCopy) container %d to "
386				      "%d\n",
387				      aif->data.PR[0].jd.client.container.src,
388				      aif->data.PR[0].jd.client.container.dst);
389			break;
390		case AifJobCtrRebuildMirror:	/* Container Rebuild Mirror
391						 * operation */
392			device_printf(sc->aac_dev,
393				      "(ContainerRebuildMirror) container "
394				      "%d\n",
395				      aif->data.PR[0].jd.client.container.src);
396			break;
397		case AifJobCtrCrazyCache:	/* crazy cache */
398			device_printf(sc->aac_dev,
399				      "(ContainerCrazyCache) container %d\n",
400				      aif->data.PR[0].jd.client.container.src);
401				      /* XXX two containers? */
402			break;
403		case AifJobFsCreate:		/* File System Create
404						 * operation */
405			device_printf(sc->aac_dev, "(FsCreate)\n");
406			break;
407		case AifJobFsVerify:		/* File System Verify
408						 * operation */
409			device_printf(sc->aac_dev, "(FsVerivy)\n");
410			break;
411		case AifJobFsExtend:		/* File System Extend
412						 * operation */
413			device_printf(sc->aac_dev, "(FsExtend)\n");
414			break;
415		case AifJobApiFormatNTFS:	/* Format a drive to NTFS */
416			device_printf(sc->aac_dev, "(FormatNTFS)\n");
417			break;
418		case AifJobApiFormatFAT:	/* Format a drive to FAT */
419			device_printf(sc->aac_dev, "(FormatFAT)\n");
420			break;
421		case AifJobApiUpdateSnapshot:	/* update the read/write half
422						 * of a snapshot */
423			device_printf(sc->aac_dev, "(UpdateSnapshot)\n");
424			break;
425		case AifJobApiFormatFAT32:	/* Format a drive to FAT32 */
426			device_printf(sc->aac_dev, "(FormatFAT32)\n");
427			break;
428		case AifJobCtlContinuousCtrVerify: /* Adapter operation */
429			device_printf(sc->aac_dev, "(ContinuousCtrVerify)\n");
430			break;
431		default:
432			device_printf(sc->aac_dev, "(%d)\n",
433				      aif->data.PR[0].jd.type);
434			break;
435		}
436		break;
437	}
438	case AifCmdAPIReport:
439		device_printf(sc->aac_dev, "APIReport (%d)\n", aif->seqNumber);
440		break;
441	case AifCmdDriverNotify:
442		device_printf(sc->aac_dev, "DriverNotify (%d)\n",
443			      aif->seqNumber);
444		break;
445	default:
446		device_printf(sc->aac_dev, "AIF %d (%d)\n", aif->command,
447			      aif->seqNumber);
448		break;
449	}
450}
451#endif /* AACRAID_DEBUG */
452
453/*
454 * Debug flags to be put into the HBA flags field when initialized
455 */
456const unsigned long aacraid_debug_flags = /* Variable to setup with above flags. */
457/*			HBA_FLAGS_DBG_KERNEL_PRINT_B |		*/
458			HBA_FLAGS_DBG_FW_PRINT_B |
459/*			HBA_FLAGS_DBG_FUNCTION_ENTRY_B |	*/
460			HBA_FLAGS_DBG_FUNCTION_EXIT_B |
461			HBA_FLAGS_DBG_ERROR_B |
462			HBA_FLAGS_DBG_INIT_B |
463/*			HBA_FLAGS_DBG_OS_COMMANDS_B |		*/
464/*			HBA_FLAGS_DBG_SCAN_B |			*/
465/*			HBA_FLAGS_DBG_COALESCE_B |		*/
466/*			HBA_FLAGS_DBG_IOCTL_COMMANDS_B |	*/
467/*			HBA_FLAGS_DBG_SYNC_COMMANDS_B |		*/
468			HBA_FLAGS_DBG_COMM_B |
469/*			HBA_FLAGS_DBG_AIF_B |			*/
470/*			HBA_FLAGS_DBG_CSMI_COMMANDS_B | 	*/
471			HBA_FLAGS_DBG_DEBUG_B |
472/*			HBA_FLAGS_DBG_FLAGS_MASK | 		*/
4730;
474
475int aacraid_get_fw_debug_buffer(struct aac_softc *sc)
476{
477	u_int32_t MonDriverBufferPhysAddrLow = 0;
478	u_int32_t MonDriverBufferPhysAddrHigh = 0;
479	u_int32_t MonDriverBufferSize = 0;
480	u_int32_t MonDriverHeaderSize = 0;
481
482	/*
483	 * Get the firmware print buffer parameters from the firmware
484	 * If the command was successful map in the address.
485	 */
486	if (!aacraid_sync_command(sc, AAC_MONKER_GETDRVPROP, 0, 0, 0, 0, NULL, NULL)) {
487		MonDriverBufferPhysAddrLow = AAC_GET_MAILBOX(sc, 1);
488		MonDriverBufferPhysAddrHigh = AAC_GET_MAILBOX(sc, 2);
489		MonDriverBufferSize = AAC_GET_MAILBOX(sc, 3);
490		MonDriverHeaderSize = AAC_GET_MAILBOX(sc, 4);
491		if (MonDriverBufferSize) {
492			unsigned long Offset = MonDriverBufferPhysAddrLow
493				- rman_get_start(sc->aac_regs_res1);
494
495			/*
496			 * See if the address is already mapped in and if so set it up
497			 * from the base address
498			 */
499			if ((MonDriverBufferPhysAddrHigh == 0) &&
500				(Offset + MonDriverBufferSize <
501				rman_get_size(sc->aac_regs_res1))) {
502				sc->DebugOffset = Offset;
503				sc->DebugHeaderSize = MonDriverHeaderSize;
504				sc->FwDebugBufferSize = MonDriverBufferSize;
505				sc->FwDebugFlags = 0;
506				sc->DebugFlags = aacraid_debug_flags;
507				return 1;
508			}
509		}
510	}
511
512	/*
513	 * The GET_DRIVER_BUFFER_PROPERTIES command failed
514	 */
515	return 0;
516}
517
518#define PRINT_TIMEOUT 250000 /* 1/4 second */
519
520void aacraid_fw_printf(struct aac_softc *sc, unsigned long PrintFlags, const char * fmt, ...)
521{
522	va_list args;
523	u_int32_t Count, i;
524	char PrintBuffer_P[PRINT_BUFFER_SIZE];
525	unsigned long PrintType;
526
527	PrintType = PrintFlags &
528		~(HBA_FLAGS_DBG_KERNEL_PRINT_B|HBA_FLAGS_DBG_FW_PRINT_B);
529	if (((PrintType!=0) && (sc!=NULL) && ((sc->DebugFlags & PrintType)==0))
530		|| ((sc!=NULL) && (sc->DebugFlags
531		& (HBA_FLAGS_DBG_KERNEL_PRINT_B|HBA_FLAGS_DBG_FW_PRINT_B)) == 0))
532		return;
533
534	/*
535	 * Set up parameters and call sprintf function to format the data
536	 */
537	va_start(args, fmt);
538	vsprintf(PrintBuffer_P, fmt, args);
539	va_end(args);
540
541	/*
542	 * Make sure the HBA structure has been passed in for this section
543	 */
544	if ((sc != NULL) && (sc->FwDebugBufferSize)) {
545		/*
546		 * If we are set up for a Firmware print
547		 */
548		if ((sc->DebugFlags & HBA_FLAGS_DBG_FW_PRINT_B)
549			&& ((PrintFlags
550			& (HBA_FLAGS_DBG_KERNEL_PRINT_B|HBA_FLAGS_DBG_FW_PRINT_B))
551			!= HBA_FLAGS_DBG_KERNEL_PRINT_B)) {
552			/*
553			 * Make sure the string size is within boundaries
554			 */
555			Count = strlen(PrintBuffer_P);
556			if (Count > sc->FwDebugBufferSize)
557				Count = (u_int16_t)sc->FwDebugBufferSize;
558
559			/*
560			 * Wait for no more than PRINT_TIMEOUT for the previous
561			 * message length to clear (the handshake).
562			 */
563			for (i = 0; i < PRINT_TIMEOUT; ++i) {
564				if (!AAC_MEM1_GETREG4(sc,
565					sc->DebugOffset + FW_DEBUG_STR_LENGTH_OFFSET)) {
566					break;
567				}
568				DELAY(1);
569            }
570
571			/*
572			 * If the Length is clear, copy over the message, the
573			 * flags, and the length. Make sure the length is the
574			 * last because that is the signal for the Firmware to
575			 * pick it up.
576			 */
577			if (!AAC_MEM1_GETREG4(sc,
578				sc->DebugOffset + FW_DEBUG_STR_LENGTH_OFFSET)) {
579				for (i = 0; i < Count; ++i) {
580					AAC_MEM1_SETREG1(sc, sc->DebugOffset + sc->DebugHeaderSize + i,
581								PrintBuffer_P[i]);
582				}
583				AAC_MEM1_SETREG4(sc, sc->DebugOffset + FW_DEBUG_FLAGS_OFFSET,
584							sc->FwDebugFlags);
585				AAC_MEM1_SETREG4(sc, sc->DebugOffset + FW_DEBUG_STR_LENGTH_OFFSET,
586                            Count);
587			} else
588				sc->DebugFlags &= ~HBA_FLAGS_DBG_FW_PRINT_B;
589		}
590
591		/*
592		 * If the Kernel Debug Print flag is set, send it off to the
593		 * Kernel debugger
594		 */
595		if ((sc->DebugFlags & HBA_FLAGS_DBG_KERNEL_PRINT_B)
596			&& ((PrintFlags
597			& (HBA_FLAGS_DBG_KERNEL_PRINT_B|HBA_FLAGS_DBG_FW_PRINT_B))
598			!= HBA_FLAGS_DBG_FW_PRINT_B)) {
599			if (sc->FwDebugFlags & FW_DEBUG_FLAGS_NO_HEADERS_B)
600				printf ("%s\n", PrintBuffer_P);
601			else
602				device_printf (sc->aac_dev, "%s\n", PrintBuffer_P);
603		}
604
605	} else {
606		/*
607		 * No HBA structure passed in so it has to be for the Kernel Debugger
608		 */
609		if ((sc != NULL) && (sc->FwDebugFlags & FW_DEBUG_FLAGS_NO_HEADERS_B))
610			printf ("%s\n", PrintBuffer_P);
611		else if (sc != NULL)
612			device_printf (sc->aac_dev, "%s\n", PrintBuffer_P);
613		else
614			printf("%s\n", PrintBuffer_P);
615	}
616}
617
618void aacraid_fw_print_mem(struct aac_softc *sc, unsigned long PrintFlags, u_int8_t *Addr, int Count)
619{
620	int Offset, i;
621	u_int32_t DebugFlags = 0;
622	char Buffer[100];
623	char *LineBuffer_P;
624
625	/*
626	 * If we have an HBA structure, save off the flags and set the no
627	 * headers flag so we don't have garbage between our lines of data
628	 */
629	if (sc != NULL) {
630		DebugFlags = sc->FwDebugFlags;
631		sc->FwDebugFlags |= FW_DEBUG_FLAGS_NO_HEADERS_B;
632	}
633
634	Offset = 0;
635
636	/*
637	 * Loop through all the data
638	 */
639	while (Offset < Count) {
640		/*
641		 * We will format each line into a buffer and then print out
642		 * the entire line so set the pointer to the beginning of the
643		 * buffer
644		 */
645		LineBuffer_P = Buffer;
646
647		/*
648		 * Set up the address in HEX
649		 */
650		sprintf(LineBuffer_P, "\n%04x  ", Offset);
651		LineBuffer_P += 6;
652
653		/*
654		 * Set up 16 bytes in HEX format
655		 */
656		for (i = 0; i < 16; ++i) {
657			/*
658			 * If we are past the count of data bytes to output,
659			 * pad with blanks
660			 */
661			if ((Offset + i) >= Count)
662				sprintf (LineBuffer_P, "   ");
663			else
664			  	sprintf (LineBuffer_P, "%02x ", Addr[Offset+i]);
665			LineBuffer_P += 3;
666
667			/*
668			 * At the mid point we will put in a divider
669			 */
670			if (i == 7) {
671				sprintf (LineBuffer_P, "- ");
672				LineBuffer_P += 2;
673			}
674		}
675		/*
676		 * Now do the same 16 bytes at the end of the line in ASCII
677		 * format
678		 */
679		sprintf (LineBuffer_P, "  ");
680		LineBuffer_P += 2;
681		for (i = 0; i < 16; ++i) {
682			/*
683			 * If all data processed, OUT-O-HERE
684			 */
685			if ((Offset + i) >= Count)
686				break;
687
688			/*
689			 * If this is a printable ASCII character, convert it
690			 */
691			if ((Addr[Offset+i] > 0x1F) && (Addr[Offset+i] < 0x7F))
692				sprintf (LineBuffer_P, "%c", Addr[Offset+i]);
693			else
694				sprintf (LineBuffer_P, ".");
695			++LineBuffer_P;
696		}
697		/*
698		 * The line is now formatted, so print it out
699		 */
700		aacraid_fw_printf(sc, PrintFlags, "%s", Buffer);
701
702		/*
703		 * Bump the offset by 16 for the next line
704		 */
705		Offset += 16;
706
707	}
708
709	/*
710	 * Restore the saved off flags
711	 */
712	if (sc != NULL)
713		sc->FwDebugFlags = DebugFlags;
714}
715
716