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