view usr/src/cmd/mdb/common/modules/qlc/qlc.c @ 10736:d831c82c5d2c

6866510 Mismatched Metis FC-Qlogic Fcode level reported by 'fcinfo' and '.properties' 6867260 ssd_io_time to setting does not take effect in qlc driver while shorter than 25 6875471 fix failed for 6856545: ssertion failed: !MUTEX_HELD(&ha->mutex), file: ... 6876303 qlc driver fails to suspend during suspend/resume DR operation on an M5000 6883190 Failed SunVTS diagnostic 'HBA component stress' test. 6885119 qlc driver fails to initialize CNA cards on the M5000, but initializes OK on other platforms
author Daniel Beauregard <Daniel.Beauregard@Sun.COM>
date Wed, 07 Oct 2009 16:02:38 -0700
parents 567690184bfa
children ba3f66213a3a
line wrap: on
line source

/*
 * 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 QLogic Corporation */

/*
 * ISP2xxx Solaris Fibre Channel Adapter (FCA) qlc mdb source file.
 *
 * ***********************************************************************
 * *									**
 * *				NOTICE					**
 * *		COPYRIGHT (C) 1996-2009 QLOGIC CORPORATION		**
 * *			ALL RIGHTS RESERVED				**
 * *									**
 * ***********************************************************************
 *
 */

#pragma ident	"Copyright 2009 QLogic Corporation; ql_mdb.c"

#include <sys/mdb_modapi.h>
#include <ql_apps.h>
#include <ql_api.h>
#include <ql_init.h>
#include <ql_debug.h>

/*
 * local prototypes
 */
static int32_t ql_doprint(uintptr_t, int8_t *);
static void ql_dump_flags(uint64_t, int8_t **);
static int qlclinks_dcmd(uintptr_t, uint_t, int, const mdb_arg_t *);
static int qlcstate_dcmd(uintptr_t, uint_t, int, const mdb_arg_t *);
static int qlc_osc_dcmd(uintptr_t, uint_t, int, const mdb_arg_t *);
static int qlc_wdog_dcmd(uintptr_t, uint_t, int, const mdb_arg_t *);
static int qlc_getdump_dcmd(uintptr_t, uint_t, int, const mdb_arg_t *);
static int qlc_gettrace_dcmd(uintptr_t, uint_t, int, const mdb_arg_t *);
#if 0
static int qlc_triggerdump_dcmd(uintptr_t, uint_t, int, const mdb_arg_t *);
#endif
static int qlcver_dcmd(uintptr_t, uint_t, int, const mdb_arg_t *);
static int qlstates_walk_init(mdb_walk_state_t *);
static int qlstates_walk_step(mdb_walk_state_t *);
static void qlstates_walk_fini(mdb_walk_state_t *);
static int qlsrb_walk_init(mdb_walk_state_t *);
static int qlsrb_walk_step(mdb_walk_state_t *);
static void qlsrb_walk_fini(mdb_walk_state_t *);
static int get_next_link(ql_link_t *);
static int get_first_link(ql_head_t *, ql_link_t *);

static int ql_24xx_dump_dcmd(ql_adapter_state_t *, uint_t, int,
    const mdb_arg_t *);
static int ql_23xx_dump_dcmd(ql_adapter_state_t *, uint_t, int,
    const mdb_arg_t *);
static int ql_25xx_dump_dcmd(ql_adapter_state_t *, uint_t, int,
    const mdb_arg_t *);
static int ql_81xx_dump_dcmd(ql_adapter_state_t *, uint_t, int,
    const mdb_arg_t *);
static void ql_elog_common(ql_adapter_state_t *, boolean_t);

/*
 * local adapter state flags strings
 */
int8_t *adapter_state_flags[] = {
	"FCA_BOUND",
	"QL_OPENED",
	"ONLINE",
	"INTERRUPTS_ENABLED",
	"ABORT_CMDS_LOOP_DOWN_TMO",
	"POINT_TO_POINT",
	"IP_ENABLED",
	"IP_INITIALIZED",
	"MENLO_LOGIN_OPERATIONAL",
	"ADAPTER_SUSPENDED",
	"ADAPTER_TIMER_BUSY",
	"PARITY_ERROR",
	"FLASH_ERRLOG_MARKER",
	"VP_ENABLED",
	"FDISC_ENABLED",
	"FUNCTION_1",
	"MPI_RESET_NEEDED",
	NULL
};

int8_t *adapter_config_flags[] = {
	"ENABLE_HARD_ADDRESS",
	"ENABLE_64BIT_ADDRESSING",
	"ENABLE_LIP_RESET",
	"ENABLE_FULL_LIP_LOGIN",
	"ENABLE_TARGET_RESET",
	"ENABLE_LINK_DOWN_REPORTING",
	"DISABLE_EXTENDED_LOGGING_TRACE",
	"ENABLE_FCP_2_SUPPORT",
	"MULTI_CHIP_ADAPTER",
	"SBUS_CARD",
	"CTRL_2300",
	"CTRL_6322",
	"CTRL_2200",
	"CTRL_2422",
	"CTRL_25XX",
	"ENABLE_EXTENDED_LOGGING",
	"DISABLE_RISC_CODE_LOAD",
	"SET_CACHE_LINE_SIZE_1",
	"CTRL_MENLO",
	"EXT_FW_INTERFACE",
	"LOAD_FLASH_FW",
	"DUMP_MAILBOX_TIMEOUT",
	"DUMP_ISP_SYSTEM_ERROR",
	"DUMP_DRIVER_COMMAND_TIMEOUT",
	"DUMP_LOOP_OFFLINE_TIMEOUT",
	"ENABLE_FWEXTTRACE",
	"ENABLE_FWFCETRACE",
	"FW_MISMATCH",
	"CTRL_81XX",
	NULL
};

/*
 * local task daemon flags strings
 */
int8_t *task_daemon_flags[] = {
	"TASK_DAEMON_STOP_FLG",
	"TASK_DAEMON_SLEEPING_FLG",
	"TASK_DAEMON_ALIVE_FLG",
	"TASK_DAEMON_IDLE_CHK_FLG",
	"SUSPENDED_WAKEUP_FLG",
	"FC_STATE_CHANGE",
	"NEED_UNSOLICITED_BUFFERS",
	"RESET_MARKER_NEEDED",
	"RESET_ACTIVE",
	"ISP_ABORT_NEEDED",
	"ABORT_ISP_ACTIVE",
	"LOOP_RESYNC_NEEDED",
	"LOOP_RESYNC_ACTIVE",
	"LOOP_DOWN",
	"DRIVER_STALL",
	"COMMAND_WAIT_NEEDED",
	"COMMAND_WAIT_ACTIVE",
	"STATE_ONLINE",
	"ABORT_QUEUES_NEEDED",
	"TASK_DAEMON_STALLED_FLG",
	"TASK_THREAD_CALLED",
	"FIRMWARE_UP",
	"LIP_RESET_PENDING",
	"FIRMWARE_LOADED",
	"RSCN_UPDATE_NEEDED",
	"HANDLE_PORT_BYPASS_CHANGE",
	"PORT_RETRY_NEEDED",
	"TASK_DAEMON_POWERING_DOWN",
	"TD_IIDMA_NEEDED",
	"SEND_PLOGI",
	"IDC_ACK_NEEDED",
	NULL
};

/*
 * local interrupt aif flags
 */
int8_t *aif_flags[] = {
	"IFLG_INTR_LEGACY",
	"IFLG_INTR_FIXED",
	"IFLG_INTR_MSI",
	"IFLG_INTR_MSIX",
	NULL
};

int8_t *qlsrb_flags[] = {
	"SRB_ISP_STARTED",
	"SRB_ISP_COMPLETED",
	"SRB_RETRY",
	"SRB_POLL",
	"SRB_WATCHDOG_ENABLED",
	"SRB_ABORT",
	"SRB_UB_IN_FCA",
	"SRB_UB_IN_ISP",
	"SRB_UB_CALLBACK",
	"SRB_UB_RSCN",
	"SRB_UB_FCP",
	"SRB_FCP_CMD_PKT",
	"SRB_FCP_DATA_PKT",
	"SRB_FCP_RSP_PKT",
	"SRB_IP_PKT",
	"SRB_GENERIC_SERVICES_PKT",
	"SRB_COMMAND_TIMEOUT",
	"SRB_ABORTING",
	"SRB_IN_DEVICE_QUEUE",
	"SRB_IN_TOKEN_ARRAY",
	"SRB_UB_FREE_REQUESTED",
	"SRB_UB_ACQUIRED",
	"SRB_MS_PKT",
	NULL
};

int8_t *qllun_flags[] = {
	"LQF_UNTAGGED_PENDING",
	NULL
};

int8_t *qltgt_flags[] = {
	"TQF_TAPE_DEVICE",
	"TQF_QUEUE_SUSPENDED",
	"TQF_FABRIC_DEVICE",
	"TQF_INITIATOR_DEVICE",
	"TQF_RSCN_RCVD",
	"TQF_NEED_AUTHENTICATION",
	"TQF_PLOGI_PROGRS",
	"TQF_IIDMA_NEEDED",
	NULL
};

int8_t *qldump_flags[] = {
	"QL_DUMPING",
	"QL_DUMP_VALID",
	"QL_DUMP_UPLOADED",
	NULL
};

/*
 * qlclinks_dcmd
 *	mdb dcmd which prints out the ql_hba pointers
 *
 * Input:
 *	addr  = User supplied address -- error if supplied.
 *	flags = mdb flags.
 *	argc  = Number of user supplied args -- error if non-zero.
 *	argv  = Arg array.
 *
 * Returns:
 *	DCMD_ERR, DCMD_USAGE, or DCMD_OK
 *
 * Context:
 *	User context.
 *
 */
/*ARGSUSED*/
static int
qlclinks_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
	ql_head_t		ql_hba;
	ql_adapter_state_t	*qlstate;
	uintptr_t		hbaptr = NULL;

	if ((flags & DCMD_ADDRSPEC) || argc != 0) {
		return (DCMD_USAGE);
	}

	if (mdb_readvar(&ql_hba, "ql_hba") == -1) {
		mdb_warn("failed to read ql_hba structure");
		return (DCMD_ERR);
	}

	if (&ql_hba == NULL) {
		mdb_warn("failed to read ql_hba structure -- is qlc loaded?");
		return (DCMD_ERR);
	}

	mdb_printf("\nqlc adapter state linkages (f=0x%llx, l=0x%llx)\n\n",
	    ql_hba.first, ql_hba.last);

	if ((qlstate = (ql_adapter_state_t *)mdb_alloc(
	    sizeof (ql_adapter_state_t), UM_SLEEP)) == NULL) {
		mdb_warn("Unable to allocate memory for ql_adapter_state\n");
		return (DCMD_OK);
	}

	(void) mdb_inc_indent((ulong_t)4);
	mdb_printf("%<u>%-?s\t%-45s%</u>\n\n", "baseaddr", "instance");

	hbaptr = (uintptr_t)ql_hba.first;
	while (hbaptr != NULL) {

		if (mdb_vread(qlstate, sizeof (ql_adapter_state_t),
		    hbaptr) == -1) {
			mdb_free(qlstate, sizeof (ql_adapter_state_t));
			mdb_warn("failed to read ql_adapter_state at %p",
			    hbaptr);
			return (DCMD_OK);
		}

		mdb_printf("%<b>0x%016p%t%d%</b>\n",
		    qlstate->hba.base_address, qlstate->instance);

		/*
		 * If vp exists, loop through those
		 */

		if ((qlstate->flags & VP_ENABLED) &&
		    (qlstate->vp_next != NULL)) {

			ql_adapter_state_t	*vqlstate;
			uintptr_t		vhbaptr = NULL;

			vhbaptr = (uintptr_t)qlstate->vp_next;

			if ((vqlstate = (ql_adapter_state_t *)mdb_alloc(
			    sizeof (ql_adapter_state_t), UM_SLEEP)) == NULL) {
				mdb_warn("Unable to allocate memory for "
				    "ql_adapter_state vp\n");
				mdb_free(qlstate, sizeof (ql_adapter_state_t));
				return (DCMD_OK);
			}

			(void) mdb_inc_indent((ulong_t)30);

			mdb_printf("%<u>vp baseaddr\t\tvp index%</u>\n");

			while (vhbaptr != NULL) {

				if (mdb_vread(vqlstate,
				    sizeof (ql_adapter_state_t), vhbaptr) ==
				    -1) {
					mdb_free(vqlstate,
					    sizeof (ql_adapter_state_t));
					mdb_free(qlstate,
					    sizeof (ql_adapter_state_t));
					mdb_warn("failed to read vp "
					    "ql_adapter_state at %p", vhbaptr);
					return (DCMD_OK);
				}

				mdb_printf("%<b>0x%016p%t%d%</b>\n",
				    vqlstate->hba.base_address,
				    vqlstate->vp_index);

				vhbaptr = (uintptr_t)vqlstate->vp_next;
			}

			mdb_free(vqlstate, sizeof (ql_adapter_state_t));

			(void) mdb_dec_indent((ulong_t)30);

			mdb_printf("\n");
		}

		hbaptr = (uintptr_t)qlstate->hba.next;
	}

	(void) mdb_dec_indent((ulong_t)4);

	mdb_free(qlstate, sizeof (ql_adapter_state_t));

	return (DCMD_OK);
}

/*
 * qlcver_dcmd
 *	mdb dcmd which prints out the qlc driver version the mdb
 *	module was compiled with, and the verison of qlc which is
 *	currently loaded on the machine.
 *
 * Input:
 *	addr  = User supplied address -- error if supplied.
 *	flags = mdb flags.
 *	argc  = Number of user supplied args -- error if non-zero.
 *	argv  = Arg array.
 *
 * Returns:
 *	DCMD_USAGE, or DCMD_OK
 *
 * Context:
 *	User context.
 *
 */
/*ARGSUSED*/
static int
qlcver_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
	int8_t		qlcversion[100];
	struct fw_table	fw_table[10], *fwt = NULL;
	uint8_t		*fwverptr = NULL;
	ql_head_t	ql_hba;
	uint32_t	found = 0;

	if ((flags & DCMD_ADDRSPEC) || argc != 0) {
		return (DCMD_USAGE);
	}

	if (mdb_readvar(&qlcversion, "qlc_driver_version") == -1) {
		mdb_warn("unable to read qlc driver version\n");
	} else {
		mdb_printf("\n%s version currently loaded is: %s\n",
		    QL_NAME, qlcversion);
	}

	mdb_printf("qlc mdb library compiled with %s version: %s\n",
	    QL_NAME, QL_VERSION);

	if ((fwverptr = (uint8_t *)(mdb_alloc(50, UM_SLEEP))) == NULL) {
		mdb_warn("unable to alloc fwverptr\n");
		return (DCMD_OK);
	}

	if (mdb_readvar(&fw_table, "fw_table") == -1) {
		mdb_warn("unable to read firmware table\n");
	} else {
		ql_adapter_state_t	*qlstate;
		uintptr_t		hbaptr = NULL;

		if (mdb_readvar(&ql_hba, "ql_hba") == -1) {
			mdb_warn("failed to read ql_hba structure");
			return (DCMD_ERR);
		}

		if ((qlstate = (ql_adapter_state_t *)mdb_alloc(
		    sizeof (ql_adapter_state_t), UM_SLEEP)) == NULL) {
			mdb_warn("Unable to allocate memory for "
			    "ql_adapter_state\n");
			return (DCMD_OK);
		}

		mdb_printf("\n%-8s%-11s%s\n", "f/w", "compiled", "loaded");
		mdb_printf("%<u>%-8s%-11s%-13s%s%</u>\n\n", "class", "version",
		    "version", "instance list");

		for (fwt = &fw_table[0]; fwt->fw_class; fwt++) {

			if (mdb_vread(fwverptr, sizeof (void *),
			    (uintptr_t)fwt->fw_version) == -1) {
				mdb_warn("unable to read fwverptr\n");
				mdb_free(fwverptr, sizeof (void *));
				mdb_free(qlstate, sizeof (ql_adapter_state_t));
				return (DCMD_OK);
			}

			mdb_printf("%x\t%-11s", fwt->fw_class, fwverptr);

			if (&ql_hba == NULL) {
				mdb_warn("failed to read ql_hba structure");
				hbaptr = NULL;
			} else {
				hbaptr = (uintptr_t)ql_hba.first;
			}

			found = 0;
			while (hbaptr != NULL) {

				if (mdb_vread(qlstate,
				    sizeof (ql_adapter_state_t), hbaptr) ==
				    -1) {
					mdb_warn("failed to read "
					    "ql_adapter_state at %p", hbaptr);
					break;
				}

				if (qlstate->fw_class == fwt->fw_class) {
					if (found == 0) {
						mdb_printf("%x.%02x.%02x\t",
						    qlstate->fw_major_version,
						    qlstate->fw_minor_version,
						    qlstate->
						    fw_subminor_version);
						mdb_printf("%d",
						    qlstate->instance);
					} else {
						mdb_printf(", %d",
						    qlstate->instance);
					}
					found = 1;
				}

				hbaptr = (uintptr_t)qlstate->hba.next;
			}

			if (found == 1) {
				mdb_printf("\n");
			} else {
				mdb_printf("not loaded\n");
			}
		}

		mdb_free(qlstate, sizeof (ql_adapter_state_t));
		mdb_free(fwverptr, sizeof (void *));
	}

	return (DCMD_OK);
}

/*
 * qlc_el_dcmd
 *	mdb dcmd which turns the extended logging bit on or off
 *	for the specificed qlc instance(s).
 *
 * Input:
 *	addr  = User supplied address -- error if supplied.
 *	flags = mdb flags.
 *	argc  = Number of user supplied args -- error if non-zero.
 *	argv  = Arg array.
 *
 * Returns:
 *	DCMD_USAGE, or DCMD_OK
 *
 * Context:
 *	User context.
 *
 */
/*ARGSUSED*/
static int
qlc_el_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
	int8_t			qlcversion[100];
	boolean_t		elswitch;
	uint32_t		argcnt;
	int			mdbs;
	uint32_t		instance;
	uint32_t		qlsize = sizeof (ql_adapter_state_t);
	ql_adapter_state_t	*qlstate;
	uintptr_t		hbaptr = NULL;
	ql_head_t		ql_hba;

	if ((mdbs = mdb_get_state()) == MDB_STATE_DEAD) {
		mdb_warn("Cannot change core file data (state=%xh)\n", mdbs);
		return (DCMD_OK);
	}

	if ((flags & DCMD_ADDRSPEC) || argc < 2) {
		return (DCMD_USAGE);
	}

	/*
	 * Check and make sure the driver version and the mdb versions
	 * match so all the structures and flags line up
	 */

	if (mdb_readvar(&qlcversion, "qlc_driver_version") == -1) {
		mdb_warn("unable to read qlc driver version\n");
		return (DCMD_OK);
	}

	if ((strcmp(QL_VERSION, (const char *)&qlcversion)) != 0) {
		mdb_warn("Error: qlc driver/qlc mdb version mismatch\n");
		mdb_printf("\tqlc mdb library compiled version is: %s\n",
		    QL_VERSION);
		mdb_printf("\tqlc driver version is: %s\n", qlcversion);

		return (DCMD_OK);
	}

	if ((strcasecmp(argv[0].a_un.a_str, "on")) == 0) {
		elswitch = TRUE;
	} else if ((strcasecmp(argv[0].a_un.a_str, "off")) == 0) {
		elswitch = FALSE;
	} else {
		return (DCMD_USAGE);
	}

	if (mdb_readvar(&ql_hba, "ql_hba") == -1) {
		mdb_warn("failed to read ql_hba structure");
		return (DCMD_ERR);
	}

	if (&ql_hba == NULL) {
		mdb_warn("failed to read ql_hba structure - is qlc loaded?");
		return (DCMD_ERR);
	}

	if ((qlstate = (ql_adapter_state_t *)mdb_alloc(qlsize,
	    UM_SLEEP)) == NULL) {
		mdb_warn("Unable to allocate memory for "
		    "ql_adapter_state\n");
		return (DCMD_OK);
	}

	if ((strcasecmp(argv[1].a_un.a_str, "all")) == 0) {

		if (argc != 2) {
			mdb_free(qlstate, qlsize);
			return (DCMD_USAGE);
		}

		hbaptr = (uintptr_t)ql_hba.first;

		while (hbaptr != NULL) {

			if (mdb_vread(qlstate, qlsize, hbaptr) == -1) {
				mdb_free(qlstate, qlsize);
				mdb_warn("failed to read ql_adapter_state "
				    "at %p", hbaptr);
				return (DCMD_OK);
			}

			ql_elog_common(qlstate, elswitch);

			hbaptr = (uintptr_t)qlstate->hba.next;
		}
	} else {
		for (argcnt = 1; argcnt < argc; argcnt++) {

			instance = (uint32_t)mdb_strtoull(
			    argv[argcnt].a_un.a_str);

			/* find the correct instance to change */
			hbaptr = (uintptr_t)ql_hba.first;
			while (hbaptr != NULL) {

				if (mdb_vread(qlstate, qlsize, hbaptr) == -1) {
					mdb_free(qlstate, qlsize);
					mdb_warn("failed to read "
					    "ql_adapter_state at %p", hbaptr);
					return (DCMD_OK);
				}

				if (qlstate->instance == instance) {
					break;
				}

				hbaptr = (uintptr_t)qlstate->hba.next;
			}

			if (hbaptr == NULL) {
				mdb_printf("instance %d is not loaded",
				    instance);
				continue;
			}

			ql_elog_common(qlstate, elswitch);
		}
	}

	mdb_free(qlstate, qlsize);

	return (DCMD_OK);
}

/*
 * qlc_elog_common
 *	mdb helper function which set/resets the extended logging bit
 *
 * Input:
 *	qlstate  = adapter state structure
 *	elswitch = boolean which specifies to reset (0) or set (1) the
 *		   extended logging bit.
 *
 * Returns:
 *
 * Context:
 *	User context.
 *
 */
static void
ql_elog_common(ql_adapter_state_t *qlstate, boolean_t elswitch)
{
	uintptr_t	hbaptr = (uintptr_t)qlstate->hba.base_address;
	size_t		qlsize = sizeof (ql_adapter_state_t);

	if (elswitch) {
		if ((qlstate->cfg_flags & CFG_ENABLE_EXTENDED_LOGGING) == 0) {

			qlstate->cfg_flags |= CFG_ENABLE_EXTENDED_LOGGING;

			if ((mdb_vwrite((const void *)qlstate, qlsize,
			    hbaptr)) != (ssize_t)qlsize) {
				mdb_warn("instance %d - unable to update",
				    qlstate->instance);
			} else {
				mdb_printf("instance %d extended logging is "
				    "now on\n", qlstate->instance);
			}
		} else {
			mdb_printf("instance %d extended logging is "
			    "already on\n", qlstate->instance);
		}
	} else {
		if ((qlstate->cfg_flags & CFG_ENABLE_EXTENDED_LOGGING) != 0) {

			qlstate->cfg_flags &= ~CFG_ENABLE_EXTENDED_LOGGING;

			if ((mdb_vwrite((const void *)qlstate, qlsize,
			    hbaptr)) != (ssize_t)qlsize) {
				mdb_warn("instance %d - unable to update",
				    qlstate->instance);
			} else {
				mdb_printf("instance %d extended logging is "
				    "now off\n", qlstate->instance);
			}
		} else {
			mdb_printf("instance %d extended logging is "
			    "already off\n", qlstate->instance);
		}
	}
}

/*
 * qlc_ocs_dcmd
 *	mdb dcmd which prints out the outstanding command array using
 *	caller supplied address (which sb the ha structure).
 *
 * Input:
 *	addr  = User supplied ha address.
 *	flags = mdb flags.
 *	argc  = Number of user supplied args.
 *	argv  = Arg array.
 *
 * Returns:
 *	DCMD_USAGE, or DCMD_OK
 *
 * Context:
 *	User context.
 *
 *
 */
static int
/*ARGSUSED*/
qlc_osc_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
	ql_adapter_state_t	*qlstate;
	uintptr_t		qlosc, ptr1;
	uint32_t		indx, found = 0;
	ql_srb_t		*qlsrb;

	if (!(flags & DCMD_ADDRSPEC)) {
		return (DCMD_USAGE);
	}

	if ((qlstate = (ql_adapter_state_t *)
	    mdb_alloc(sizeof (ql_adapter_state_t), UM_SLEEP)) == NULL) {
		mdb_warn("Unable to allocate memory for ql_adapter_state\n");
		return (DCMD_OK);
	}
	if (mdb_vread(qlstate, sizeof (ql_adapter_state_t), addr) == -1) {
		mdb_free(qlstate, sizeof (ql_adapter_state_t));
		mdb_warn("failed to read ql_adapter_state at %p", addr);
		return (DCMD_OK);
	}

	qlosc = (uintptr_t)qlstate->outstanding_cmds;
	mdb_printf("qlc instance: %d, base addr = %llx, osc base = %p\n",
	    qlstate->instance, qlstate->hba.base_address, qlosc);

	if ((qlsrb = (ql_srb_t *)mdb_alloc(sizeof (ql_srb_t), UM_SLEEP)) ==
	    NULL) {
		mdb_free(qlstate, sizeof (ql_adapter_state_t));
		mdb_warn("failed to allocate space for srb_t\n");
		return (DCMD_OK);
	}
	for (indx = 0; indx < MAX_OUTSTANDING_COMMANDS; indx++, qlosc += 8) {
		if (mdb_vread(&ptr1, 8, qlosc) == -1) {
			mdb_warn("failed to read ptr1, indx=%d", indx);
			break;
		}
		if (ptr1 == 0) {
			continue;
		}

		mdb_printf("osc ptr = %p, indx = %xh\n", ptr1, indx);

		if (mdb_vread(qlsrb, sizeof (ql_srb_t), ptr1) == -1) {
			mdb_warn("failed to read ql_srb_t at %p", ptr1);
			break;
		}
		(void) ql_doprint(ptr1, "struct ql_srb");
		found++;
	}

	mdb_free(qlsrb, sizeof (ql_srb_t));
	mdb_free(qlstate, sizeof (ql_adapter_state_t));

	mdb_printf("number of outstanding command srb's is: %d\n", found);

	return (DCMD_OK);
}

/*
 * qlc_wdog_dcmd
 *	mdb dcmd which prints out the commands which are linked
 *	on the watchdog linked list. Caller supplied address (which
 *	sb the ha structure).
 *
 * Input:
 *	addr  = User supplied ha address.
 *	flags = mdb flags.
 *	argc  = Number of user supplied args.
 *	argv  = Arg array.
 *
 * Returns:
 *	DCMD_USAGE, or DCMD_OK
 *
 * Context:
 *	User context.
 *
 *
 */
static int
/*ARGSUSED*/
qlc_wdog_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
	ql_adapter_state_t	*qlstate;
	uint16_t		index, count;
	ql_head_t		*dev;
	ql_srb_t		*srb;
	ql_tgt_t		*tq;
	ql_lun_t		*lq;
	ql_link_t		*tqlink, *srblink, *lqlink;
	int			nextlink;

	if (!(flags & DCMD_ADDRSPEC)) {
		mdb_warn("Address required\n", addr);
		return (DCMD_USAGE);
	}

	if ((qlstate = (ql_adapter_state_t *)
	    mdb_alloc(sizeof (ql_adapter_state_t), UM_SLEEP)) == NULL) {
		mdb_warn("Unable to allocate memory for ql_adapter_state\n");
		return (DCMD_OK);
	}

	if (mdb_vread(qlstate, sizeof (ql_adapter_state_t), addr) == -1) {
		mdb_free(qlstate, sizeof (ql_adapter_state_t));
		mdb_warn("failed to read ql_adapter_state at %p", addr);
		return (DCMD_OK);
	}

	/*
	 * Read in the device array
	 */
	dev = (ql_head_t *)
	    mdb_alloc(sizeof (ql_head_t) * DEVICE_HEAD_LIST_SIZE, UM_SLEEP);

	if (mdb_vread(dev, sizeof (ql_head_t) * DEVICE_HEAD_LIST_SIZE,
	    (uintptr_t)qlstate->dev) == -1) {
		mdb_warn("failed to read ql_head_t (dev) at %p", qlstate->dev);
		mdb_free(qlstate, sizeof (ql_adapter_state_t));
		mdb_free(dev, sizeof (ql_head_t) * DEVICE_HEAD_LIST_SIZE);
		return (DCMD_OK);
	}

	tqlink = (ql_link_t *)mdb_alloc(sizeof (ql_link_t), UM_SLEEP);
	tq = (ql_tgt_t *)mdb_alloc(sizeof (ql_tgt_t), UM_SLEEP);
	lqlink = (ql_link_t *)mdb_alloc(sizeof (ql_link_t), UM_SLEEP);
	lq = (ql_lun_t *)mdb_alloc(sizeof (ql_lun_t), UM_SLEEP);
	srblink = (ql_link_t *)mdb_alloc(sizeof (ql_link_t), UM_SLEEP);
	srb = (ql_srb_t *)mdb_alloc(sizeof (ql_srb_t), UM_SLEEP);

	/*
	 * Validate the devices watchdog queue
	 */
	for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) {

		/* Skip empty ones */
		if (dev[index].first == NULL) {
			continue;
		}

		mdb_printf("dev array index = %x\n", index);

		/* Loop through targets on device linked list */
		/* get the first link */

		nextlink = get_first_link(&dev[index], tqlink);

		/*
		 * traverse the targets linked list at this device array index.
		 */
		while (nextlink == DCMD_OK) {
			/* Get the target */
			if (mdb_vread(tq, sizeof (ql_tgt_t),
			    (uintptr_t)(tqlink->base_address)) == -1) {
				mdb_warn("failed to read ql_tgt at %p",
				    tqlink->base_address);
				break;
			}
			mdb_printf("tgt q base = %llx, ",
			    tqlink->base_address);

			mdb_printf("flags: (%xh)", tq->flags);

			if (tq->flags) {
				ql_dump_flags((uint64_t)tq->flags, qltgt_flags);
			}

			mdb_printf("tgt: %02x%02x%02x%02x%02x%02x%02x%02x ",
			    tq->node_name[0], tq->node_name[1],
			    tq->node_name[2], tq->node_name[3],
			    tq->node_name[4], tq->node_name[5],
			    tq->node_name[6], tq->node_name[7]);

			/*
			 * Loop through commands on this targets watchdog queue.
			 */

			/* Get the first link on the targets cmd wdg q. */
			if (tq->wdg.first == NULL) {
				mdb_printf(" watchdog list empty ");
				break;
			} else {
				if (mdb_vread(srblink, sizeof (ql_link_t),
				    (uintptr_t)tq->wdg.first) == -1) {
					mdb_warn("failed to read ql_link_t"
					    " at %p", tq->wdg.first);
					break;
				}
				/* There is aleast one. */
				count = 1;
				/*
				 * Count the remaining items in the
				 * cmd watchdog list.
				 */
				while (srblink->next != NULL) {
					/* Read in the next ql_link_t header */
					if (mdb_vread(srblink,
					    sizeof (ql_link_t),
					    (uintptr_t)srblink->next) == -1) {
						mdb_warn("failed to read"
						    " ql_link_t next at %p",
						    srblink->next);
						break;
					}
					count = (uint16_t)(count + 1);
				}
				mdb_printf(" watchdog list: %d entries\n",
				    count);
				/* get the first one again */
				if (mdb_vread(srblink, sizeof (ql_link_t),
				    (uintptr_t)tq->wdg.first) == -1) {
					mdb_warn("failed to read ql_link_t"
					    " at %p", tq->wdg.first);
					break;
				}
			}
			/*
			 * Traverse the targets cmd watchdog linked list
			 * verifying srb's from the list are on a lun cmd list.
			 */
			while (nextlink == DCMD_OK) {
				int	found = 0;
				/* get the srb */
				if (mdb_vread(srb, sizeof (ql_srb_t),
				    (uintptr_t)srblink->base_address) == -1) {
					mdb_warn("failed to read ql_srb_t"
					" at %p", srblink->base_address);
					break;
				}
				mdb_printf("ql_srb %llx ",
				    srblink->base_address);

				/*
				 * Get the lun q the srb is on
				 */
				if (mdb_vread(lq, sizeof (ql_lun_t),
				    (uintptr_t)srb->lun_queue) == -1) {
					mdb_warn("failed to read ql_srb_t"
					    " at %p", srb->lun_queue);
					break;
				}
				nextlink = get_first_link(&lq->cmd, lqlink);
				/*
				 * traverse the lun cmd linked list looking
				 * for the srb from the targets watchdog list
				 */
				while (nextlink == DCMD_OK) {
					if (srblink->base_address ==
					    lqlink->base_address) {
						mdb_printf("on lun %d cmd q\n",
						    lq->lun_no);
						found = 1;
						break;
					}
					/* get next item on lun cmd list */
					nextlink = get_next_link(lqlink);
				}
				if (!found) {
					mdb_printf("not found on lun cmd q\n");
				}
				/* get next item in the watchdog list */
				nextlink = get_next_link(srblink);
			} /* End targets command watchdog list */
			/* get next item in this target list */
			nextlink = get_next_link(tqlink);
		} /* End traverse the device targets linked list */
		mdb_printf("\n");
	} /* End device array */

	mdb_free(tq, sizeof (ql_tgt_t));
	mdb_free(lq, sizeof (ql_lun_t));
	mdb_free(srb, sizeof (ql_srb_t));
	mdb_free(tqlink, sizeof (ql_link_t));
	mdb_free(srblink, sizeof (ql_link_t));
	mdb_free(lqlink, sizeof (ql_link_t));
	mdb_free(qlstate, sizeof (ql_adapter_state_t));
	mdb_free(dev, sizeof (ql_head_t)*DEVICE_HEAD_LIST_SIZE);

	return (DCMD_OK);
}

/*
 * get_first_link
 *	Gets the first ql_link_t header on ql_head.
 *
 * Input:
 *	ql_head  = pointer to a ql_head_t structure.
 *	ql_link  = pointer to a ql_link_t structure.
 *
 * Returns:
 *	DCMD_ABORT, or DCMD_OK
 *
 * Context:
 *	User context.
 *
 */
static int
get_first_link(ql_head_t *qlhead, ql_link_t *qllink)
{
	int	rval = DCMD_ABORT;

	if (qlhead != NULL) {
		if (qlhead->first != NULL) {
			/* Read in the first ql_link_t header */
			if (mdb_vread(qllink, sizeof (ql_link_t),
			    (uintptr_t)(qlhead->first)) == -1) {
				mdb_warn("failed to read ql_link_t "
				    "next at %p", qlhead->first);
			} else {
				rval = DCMD_OK;
			}
		}
	}
	return (rval);
}

/*
 * get_next_link
 *	Gets the next ql_link_t structure.
 *
 * Input:
 *	ql_link  = pointer to a ql_link_t structure.
 *
 * Returns:
 *	DCMD_ABORT, or DCMD_OK
 *
 * Context:
 *	User context.
 *
 */
static int
get_next_link(ql_link_t *qllink)
{
	int	rval = DCMD_ABORT;

	if (qllink != NULL) {
		if (qllink->next != NULL) {
			/* Read in the next ql_link_t header */
			if (mdb_vread(qllink, sizeof (ql_link_t),
			    (uintptr_t)(qllink->next)) == -1) {
				mdb_warn("failed to read ql_link_t "
				    "next at %p", qllink->next);
			} else {
				rval = DCMD_OK;
			}
		}
	}
	return (rval);
}

/*
 * qlcstate_dcmd
 *	mdb dcmd which prints out the ql_state info using
 *	caller supplied address.
 *
 * Input:
 *	addr  = User supplied address.
 *	flags = mdb flags.
 *	argc  = Number of user supplied args.
 *	argv  = Arg array.
 *
 * Returns:
 *	DCMD_USAGE, or DCMD_OK
 *
 * Context:
 *	User context.
 *
 */
static int
qlcstate_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
	ql_adapter_state_t	*qlstate;
	int			verbose = 0;

	if (!(flags & DCMD_ADDRSPEC)) {
		return (DCMD_USAGE);
	}

	if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &verbose) !=
	    argc) {
		return (DCMD_USAGE);
	}

	if ((qlstate = (ql_adapter_state_t *)
	    mdb_alloc(sizeof (ql_adapter_state_t), UM_SLEEP)) == NULL) {
		mdb_warn("failed to allocate memory for ql_adapter_state\n");
		return (DCMD_OK);
	}
	if (mdb_vread(qlstate, sizeof (ql_adapter_state_t), addr) == -1) {
		mdb_free(qlstate, sizeof (ql_adapter_state_t));
		mdb_warn("failed to read ql_adapter_state at %p", addr);
		return (DCMD_OK);
	}

	mdb_printf("qlc instance: %d, base addr = %llx\n", qlstate->instance,
	    addr);

	mdb_printf("\nadapter state flags:\n");
	ql_dump_flags((uint64_t)qlstate->flags, adapter_state_flags);
	mdb_printf("\nadapter cfg flags:\n");
	ql_dump_flags((uint64_t)qlstate->cfg_flags, adapter_config_flags);
	mdb_printf("\ntask daemon state flags:\n");
	ql_dump_flags((uint64_t)qlstate->task_daemon_flags,
	    task_daemon_flags);

	if (verbose) {
		(void) ql_doprint(addr, "struct ql_adapter_state");
	}

	mdb_free(qlstate, sizeof (ql_adapter_state_t));

	return (DCMD_OK);
}

/*
 * qlcstates_walk_init
 *	mdb walker init which prints out all qlc states info.
 *
 * Input:
 *	wsp - Pointer to walker state struct
 *
 * Returns:
 *	WALK_ERR, or WALK_NEXT
 *
 * Context:
 *	User context.
 *
 */
static int
qlstates_walk_init(mdb_walk_state_t *wsp)
{
	ql_head_t	ql_hba;

	if (wsp->walk_addr == NULL) {
		if ((mdb_readvar(&ql_hba, "ql_hba") == -1) ||
		    (&ql_hba == NULL)) {
			mdb_warn("failed to read ql_hba structure");
			return (WALK_ERR);
		}

		wsp->walk_addr = (uintptr_t)ql_hba.first;
		wsp->walk_data = mdb_alloc(sizeof (ql_adapter_state_t),
		    UM_SLEEP);
		return (WALK_NEXT);
	} else {
		return (ql_doprint(wsp->walk_addr, "struct ql_adapter_state"));
	}
}

/*
 * qlstates_walk_step
 *	mdb walker step which prints out all qlc states info.
 *
 * Input:
 *	wsp - Pointer to walker state struct
 *
 * Returns:
 *	WALK_DONE, or WALK_NEXT
 *
 * Context:
 *	User context.
 *
 */
static int
qlstates_walk_step(mdb_walk_state_t *wsp)
{
	ql_adapter_state_t	*qlstate;

	if (wsp->walk_addr == NULL) {
		return (WALK_DONE);
	}

	if (mdb_vread(wsp->walk_data, sizeof (ql_adapter_state_t),
	    wsp->walk_addr) == -1) {
		mdb_warn("failed to read ql_adapter_state at %p",
		    wsp->walk_addr);
		return (WALK_DONE);
	}

	qlstate = (ql_adapter_state_t *)(wsp->walk_data);
	mdb_printf("qlc instance: %d, base addr = %llx\n",
	    qlstate->instance, wsp->walk_addr);

	mdb_printf("\nadapter state flags:\n");
	ql_dump_flags((uint64_t)qlstate->flags, adapter_state_flags);
	mdb_printf("\nadapter cfg flags:\n");
	ql_dump_flags((uint64_t)qlstate->cfg_flags, adapter_config_flags);
	mdb_printf("\ntask daemon state flags:\n");
	ql_dump_flags((uint64_t)qlstate->task_daemon_flags,
	    task_daemon_flags);

	mdb_printf("\nadapter state:\n");
	(void) ql_doprint(wsp->walk_addr, "struct ql_adapter_state");

	mdb_printf("\n");

	wsp->walk_addr = (uintptr_t)
	    (((ql_adapter_state_t *)wsp->walk_data)->hba.next);

	return (WALK_NEXT);
}

/*
 * qlstates_walk_fini
 *	mdb walker fini which wraps up the walker
 *
 * Input:
 *	wsp - Pointer to walker state struct
 *
 * Returns:
 *
 * Context:
 *	User context.
 *
 */
static void
qlstates_walk_fini(mdb_walk_state_t *wsp)
{
	mdb_free(wsp->walk_data, sizeof (ql_adapter_state_t));
}

/*
 * qlsrb_walk_init
 *	mdb walker init which prints out linked srb's
 *
 * Input:
 *	wsp - Pointer to walker ql_srb struct
 *
 * Returns:
 *	WALK_ERR, or WALK_NEXT
 *
 * Context:
 *	User context.
 *
 */
static int
qlsrb_walk_init(mdb_walk_state_t *wsp)
{
	if (wsp->walk_addr == NULL) {
		mdb_warn("failed to read ql_srb addr at %p",
		    wsp->walk_addr);
		return (WALK_ERR);
	}

	wsp->walk_data = mdb_alloc(sizeof (ql_srb_t), UM_SLEEP);

	return (WALK_NEXT);
}

/*
 * qlcsrb_walk_step
 *	mdb walker step which prints out linked ql_srb structures
 *
 * Input:
 *	wsp - Pointer to walker srb struct
 *
 * Returns:
 *	WALK_DONE, or WALK_NEXT
 *
 * Context:
 *	User context.
 *
 */
static int
qlsrb_walk_step(mdb_walk_state_t *wsp)
{
	ql_srb_t	*qlsrb;

	if (wsp->walk_addr == NULL)
		return (WALK_DONE);

	if (mdb_vread(wsp->walk_data, sizeof (ql_srb_t),
	    wsp->walk_addr) == -1) {
		mdb_warn("failed to read ql_srb at %p", wsp->walk_addr);
		return (WALK_DONE);
	}

	qlsrb = (ql_srb_t *)(wsp->walk_data);
	mdb_printf("ql_srb base addr = %llx\n", wsp->walk_addr);

	mdb_printf("\nql_srb flags:\n");
	ql_dump_flags((uint64_t)qlsrb->flags, qlsrb_flags);

	mdb_printf("\nql_srb:\n");
	(void) ql_doprint(wsp->walk_addr, "struct ql_srb");

	mdb_printf("\n");

	wsp->walk_addr = (uintptr_t)
	    (((ql_srb_t *)wsp->walk_data)->cmd.next);

	return (WALK_NEXT);
}

/*
 * qlsrb_walk_fini
 *	mdb walker fini which wraps up the walker
 *
 * Input:
 *	wsp - Pointer to walker state struct
 *
 * Returns:
 *
 * Context:
 *	User context.
 *
 */
static void
qlsrb_walk_fini(mdb_walk_state_t *wsp)
{
	mdb_free(wsp->walk_data, sizeof (ql_srb_t));
}

/*
 * qllunq_dcmd
 *	mdb walker which prints out lun q's
 *
 * Input:
 *	wsp - Pointer to walker ql_lun struct
 *
 * Returns:
 *	WALK_ERR, or WALK_NEXT
 *
 * Context:
 *	User context.
 *
 */
static int
qllunq_walk_init(mdb_walk_state_t *wsp)
{
	if (wsp->walk_addr == NULL) {
		mdb_warn("failed to read ql_lun addr at %p",
		    wsp->walk_addr);
		return (WALK_ERR);
	}

	wsp->walk_data = mdb_alloc(sizeof (ql_lun_t), UM_SLEEP);

	return (WALK_NEXT);
}

/*
 * qlclunq_walk_step
 *	mdb walker step which prints out linked ql_lun structures
 *
 * Input:
 *	wsp - Pointer to walker srb struct
 *
 * Returns:
 *	WALK_DONE, or WALK_NEXT
 *
 * Context:
 *	User context.
 *
 */
static int
qllunq_walk_step(mdb_walk_state_t *wsp)
{
	ql_lun_t	*qllun;
	ql_link_t	ql_link;
	ql_link_t	*qllink;

	if (wsp->walk_addr == NULL)
		return (WALK_DONE);

	if (mdb_vread(wsp->walk_data, sizeof (ql_lun_t),
	    wsp->walk_addr) == -1) {
		mdb_warn("failed to read ql_lun at %p", wsp->walk_addr);
		return (WALK_DONE);
	}

	qllun = (ql_lun_t *)(wsp->walk_data);
	mdb_printf("ql_lun base addr = %llx\n", wsp->walk_addr);

	mdb_printf("\nql_lun flags:\n");
	ql_dump_flags((uint64_t)qllun->flags, qllun_flags);

	mdb_printf("\nql_lun:\n");
	(void) ql_doprint(wsp->walk_addr, "struct ql_lun");

	mdb_printf("\n");

	qllink = (ql_link_t *)
	    (((ql_lun_t *)wsp->walk_data)->link.next);

	if (qllink == NULL) {
		return (WALK_DONE);
	} else {
		/*
		 * Read in the next link_t header
		 */
		if (mdb_vread(&ql_link, sizeof (ql_link_t),
		    (uintptr_t)qllink) == -1) {
			mdb_warn("failed to read ql_link_t "
			    "next at %p", qllink->next);
			return (WALK_DONE);
		}
		qllink = &ql_link;
	}

	wsp->walk_addr = (uintptr_t)qllink->base_address;

	return (WALK_NEXT);
}

/*
 * qllunq_walk_fini
 *	mdb walker fini which wraps up the walker
 *
 * Input:
 *	wsp - Pointer to walker state struct
 *
 * Returns:
 *
 * Context:
 *	User context.
 *
 */
static void
qllunq_walk_fini(mdb_walk_state_t *wsp)
{
	mdb_free(wsp->walk_data, sizeof (ql_lun_t));
}

/*
 * qltgtq_dcmd
 *	mdb dcmd which prints out an hs's tq struct info.
 *
 * Input:
 *	addr  = User supplied address. (NB: nust be an ha)
 *	flags = mdb flags.
 *	argc  = Number of user supplied args.
 *	argv  = Arg array.
 *
 * Returns:
 *	DCMD_USAGE, or DCMD_OK
 *
 * Context:
 *	User context.
 *
 */
/*ARGSUSED*/
static int
qltgtq_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
	ql_adapter_state_t	*ha;
	ql_link_t		*link;
	ql_tgt_t		*tq;
	uint32_t		index;
	ql_head_t		*dev;

	if ((!(flags & DCMD_ADDRSPEC)) || addr == NULL) {
		mdb_warn("ql_hba structure addr is required");
		return (DCMD_USAGE);
	}

	/*
	 * Get the adapter state struct which was passed
	 */

	ha = (ql_adapter_state_t *)mdb_alloc(sizeof (ql_adapter_state_t),
	    UM_SLEEP);

	if (mdb_vread(ha, sizeof (ql_adapter_state_t), addr) == -1) {
		mdb_warn("failed to read ql_adapter_state at %p", addr);
		mdb_free(ha, sizeof (ql_adapter_state_t));
		return (DCMD_OK);
	}

	if (ha->dev == NULL) {
		mdb_warn("dev ptr is NULL for ha: %p", addr);
		mdb_free(ha, sizeof (ql_adapter_state_t));
		return (DCMD_OK);
	}

	/*
	 * Read in the device array
	 */
	dev = (ql_head_t *)
	    mdb_alloc(sizeof (ql_head_t) * DEVICE_HEAD_LIST_SIZE, UM_SLEEP);

	if (mdb_vread(dev, sizeof (ql_head_t) * DEVICE_HEAD_LIST_SIZE,
	    (uintptr_t)ha->dev) == -1) {
		mdb_warn("failed to read ql_head_t (dev) at %p", ha->dev);
		mdb_free(ha, sizeof (ql_adapter_state_t));
		mdb_free(dev, sizeof (ql_head_t) * DEVICE_HEAD_LIST_SIZE);
	}

	tq = (ql_tgt_t *)mdb_alloc(sizeof (ql_tgt_t), UM_SLEEP);
	link = (ql_link_t *)mdb_alloc(sizeof (ql_link_t), UM_SLEEP);

	for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) {

		if (dev[index].first == NULL) {
			continue;
		}

		if (mdb_vread(link, sizeof (ql_link_t),
		    (uintptr_t)dev[index].first) == -1) {
			mdb_warn("failed to read ql_link_t at %p",
			    dev[index].first);
			break;
		}

		while (link != NULL) {
			if (mdb_vread(tq, sizeof (ql_tgt_t),
			    (uintptr_t)(link->base_address)) == -1) {
				mdb_warn("failed to read ql_tgt at %p",
				    link->base_address);
				break;
			}

			mdb_printf("tgt queue base addr = %llx\n",
			    link->base_address);

			mdb_printf("\ntgt queue flags: (%xh)\n", tq->flags);
			ql_dump_flags((uint64_t)tq->flags, qltgt_flags);

			mdb_printf("\ntgt queue:\n");

			(void) ql_doprint((uintptr_t)link->base_address,
			    "struct ql_target");

			mdb_printf("\n");

			if (get_next_link(link) != DCMD_OK) {
				break;
			}
		}
	}

	mdb_free(ha, sizeof (ql_adapter_state_t));
	mdb_free(tq, sizeof (ql_tgt_t));
	mdb_free(link, sizeof (ql_link_t));
	mdb_free(dev, sizeof (ql_head_t)*DEVICE_HEAD_LIST_SIZE);

	return (DCMD_OK);
}

/*
 * ql_triggerdump_dcmd
 *	Triggers the driver to take a firmware dump
 *
 * Input:
 *	addr  = User supplied address (optional)
 *	flags = mdb flags.
 *	argc  = Number of user supplied args.
 *	argv  = Arg array (instance #, optional).
 *
 * Returns:
 *	DCMD_OK or DCMD_ERR
 *
 * Context:
 *	User context.
 *
 */

#if 0

/*ARGSUSED*/
static int
qlc_triggerdump_dcmd(uintptr_t addr, uint_t flags, int argc,
    const mdb_arg_t *argv)
{
	ql_adapter_state_t	*qlstate;
	uintptr_t		hbaptr = NULL;
	ql_head_t		ql_hba;
	uint32_t		qlsize = sizeof (ql_adapter_state_t);
	int			mdbs;

	if ((mdbs = mdb_get_state()) == MDB_STATE_DEAD) {
		mdb_warn("Cannot change core file data (state=%xh)\n", mdbs);
		return (DCMD_OK);
	}

	if ((qlstate = (ql_adapter_state_t *)mdb_alloc(qlsize,
	    UM_SLEEP)) == NULL) {
		mdb_warn("Unable to allocate memory for ql_adapter_state\n");
		return (DCMD_OK);
	}

	if (addr == NULL) {
		char		*tptr;
		uint32_t	instance;

		if (argc == 0) {
			mdb_warn("must specify either the ha addr or "
			    "the instance number\n");
			mdb_free(qlstate, qlsize);
			return (DCMD_OK);
		}

		/*
		 * find the specified instance in the ha list
		 */

		instance = (uint32_t)strtol(argv[1].a_un.a_str, &tptr, 16);
		if (tptr == argv[1].a_un.a_str) {
			mdb_printf("instance # is illegal: '%s'\n",
			    argv[1].a_un.a_str);
			mdb_free(qlstate, qlsize);
			return (DCMD_OK);
		}

		if (mdb_readvar(&ql_hba, "ql_hba") == -1) {
			mdb_warn("failed to read ql_hba structure");
			mdb_free(qlstate, qlsize);
			return (DCMD_ERR);
		}

		if (&ql_hba == NULL) {
			mdb_warn("failed to read ql_hba structure - "
			    "is qlc loaded?");
			mdb_free(qlstate, qlsize);
			return (DCMD_ERR);
		}

		hbaptr = (uintptr_t)ql_hba.first;
		while (hbaptr != NULL) {

			if (mdb_vread(qlstate, qlsize, hbaptr) == -1) {
				mdb_free(qlstate, qlsize);
				mdb_warn("failed to read "
				    "ql_adapter_state at %p", hbaptr);
				return (DCMD_OK);
			}

			if (qlstate->instance == instance) {
				break;
			}

			hbaptr = (uintptr_t)qlstate->hba.next;
		}
	} else {

		/*
		 * verify the addr specified
		 */

		if (mdb_readvar(&ql_hba, "ql_hba") == -1) {
			mdb_warn("failed to read ql_hba structure");
			mdb_free(qlstate, qlsize);
			return (DCMD_ERR);
		}

		if (&ql_hba == NULL) {
			mdb_warn("failed to read ql_hba structure - "
			    "is qlc loaded?");
			mdb_free(qlstate, qlsize);
			return (DCMD_ERR);
		}

		hbaptr = (uintptr_t)ql_hba.first;
		while (hbaptr != NULL) {

			if (mdb_vread(qlstate, qlsize, hbaptr) == -1) {
				mdb_free(qlstate, qlsize);
				mdb_warn("failed to read "
				    "ql_adapter_state at %p", hbaptr);
				return (DCMD_OK);
			}

			if (hbaptr == addr) {
				break;
			}

			hbaptr = (uintptr_t)qlstate->hba.next;
		}
	}

	if (hbaptr == NULL) {
		mdb_free(qlstate, qlsize);
		if (argc == 0) {
			mdb_warn("addr specified is not in the hba list\n");
		} else {
			mdb_warn("instance specified does not exist\n");
		}
		return (DCMD_OK);
	}

	if (((qlstate->ql_dump_state & QL_DUMP_VALID) != 0) ||
	    (qlstate->ql_dump_ptr != NULL)) {
		mdb_warn("instance %d already has a valid dump\n",
		    qlstate->instance);
		mdb_free(qlstate, qlsize);
		return (DCMD_OK);
	}
}
#endif

/*
 * ql_getdump_dcmd
 *	prints out the firmware dump buffer
 *
 * Input:
 *	addr  = User supplied address. (NB: must be an ha)
 *	flags = mdb flags.
 *	argc  = Number of user supplied args.
 *	argv  = Arg array.
 *
 * Returns:
 *	DCMD_OK or DCMD_ERR
 *
 * Context:
 *	User context.
 *
 */
static int
qlc_getdump_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
	ql_adapter_state_t	*ha;
	ql_head_t		ql_hba;
	uintptr_t		hbaptr = NULL;
	int			verbose = 0;

	if ((!(flags & DCMD_ADDRSPEC)) || addr == NULL) {
		mdb_warn("ql_adapter_state structure addr is required");
		return (DCMD_USAGE);
	}

	if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &verbose) !=
	    argc) {
		return (DCMD_USAGE);
	}

	/*
	 * Get the adapter state struct which was passed
	 */
	if ((ha = (ql_adapter_state_t *)mdb_alloc(sizeof (ql_adapter_state_t),
	    UM_SLEEP)) == NULL) {
		mdb_warn("failed to allocate memory for ql_adapter_state\n");
		return (DCMD_OK);
	}

	/*
	 * show user which instances have valid f/w dumps available if
	 * user has specified verbose option
	 */
	if (mdb_readvar(&ql_hba, "ql_hba") == -1) {
		mdb_warn("failed to read ql_hba structure");
	} else if (&ql_hba == NULL) {
		mdb_warn("failed to read ql_hba structure -- is qlc loaded?");
	} else if (verbose) {
		hbaptr = (uintptr_t)ql_hba.first;
		while (hbaptr != NULL) {

			if (mdb_vread(ha, sizeof (ql_adapter_state_t),
			    hbaptr) == -1) {
				mdb_free(ha, sizeof (ql_adapter_state_t));
				mdb_warn("failed read ql_adapter_state at %p",
				    hbaptr);
				return (DCMD_OK);
			}

			mdb_printf("instance %d:\n", ha->instance);
			(void) mdb_inc_indent((ulong_t)4);

			if (ha->ql_dump_state == 0) {
				mdb_printf("no dump flags\n");
			} else {
				ql_dump_flags((uint64_t)ha->ql_dump_state,
				    qldump_flags);
			}

			if (ha->ql_dump_ptr == NULL) {
				mdb_printf("no dump address\n");
			} else {
				mdb_printf("dump address is: %p\n",
				    ha->ql_dump_ptr);
			}

			(void) mdb_dec_indent((ulong_t)4);

			hbaptr = (uintptr_t)ha->hba.next;
		}
		mdb_printf("\n");
	}

	if (mdb_vread(ha, sizeof (ql_adapter_state_t), addr) == -1) {
		mdb_warn("failed to read ql_adapter_state at %p", addr);
		mdb_free(ha, sizeof (ql_adapter_state_t));
		return (DCMD_OK);
	}

	/*
	 * If its not a valid dump or there's not a f/w dump binary (???)
	 * then bail out
	 */
	if (((ha->ql_dump_state & QL_DUMP_VALID) == 0) ||
	    (ha->ql_dump_ptr == NULL)) {
		mdb_warn("dump does not exist for instance %d (%x, %p)\n",
		    ha->instance, ha->ql_dump_state, ha->ql_dump_ptr);
		mdb_free(ha, sizeof (ql_adapter_state_t));
		return (DCMD_OK);
	}

	if (CFG_IST(ha, CFG_CTRL_2422)) {
		(void) ql_24xx_dump_dcmd(ha, flags, argc, argv);
	} else if (CFG_IST(ha, CFG_CTRL_25XX))  {
		(void) ql_25xx_dump_dcmd(ha, flags, argc, argv);
	} else if (CFG_IST(ha, CFG_CTRL_81XX))  {
		(void) ql_81xx_dump_dcmd(ha, flags, argc, argv);
	} else {
		(void) ql_23xx_dump_dcmd(ha, flags, argc, argv);
	}

	mdb_free(ha, sizeof (ql_adapter_state_t));

	return (DCMD_OK);
}

/*
 * ql_23xx_dump_dcmd
 *	prints out a firmware dump buffer
 *
 * Input:
 *	addr  = User supplied address. (NB: nust be an ha)
 *	flags = mdb flags.
 *	argc  = Number of user supplied args.
 *	argv  = Arg array.
 *
 * Returns:
 *	DCMD_OK or DCMD_ERR
 *
 * Context:
 *	User context.
 *
 */
/*ARGSUSED*/
static int
ql_23xx_dump_dcmd(ql_adapter_state_t *ha, uint_t flags, int argc,
    const mdb_arg_t *argv)
{
	ql_fw_dump_t	*fw;
	uint32_t	cnt = 0;
	int		mbox_cnt;

	fw = (ql_fw_dump_t *)mdb_alloc(ha->ql_dump_size, UM_SLEEP);

	if (mdb_vread(fw, ha->ql_dump_size,
	    (uintptr_t)ha->ql_dump_ptr) == -1) {
		mdb_warn("failed to read ql_dump_ptr (no f/w dump active?)");
		mdb_free(fw, ha->ql_dump_size);
		return (DCMD_OK);
	}

	if (ha->cfg_flags & CFG_CTRL_2300) {
		mdb_printf("\nISP 2300IP ");
	} else if (ha->cfg_flags & CFG_CTRL_6322) {
		mdb_printf("\nISP 6322FLX ");
	} else {
		mdb_printf("\nISP 2200IP ");
	}

	mdb_printf("Firmware Version %d.%d.%d\n",
	    ha->fw_major_version, ha->fw_minor_version,
	    ha->fw_subminor_version);

	mdb_printf("\nPBIU Registers:");
	for (cnt = 0; cnt < sizeof (fw->pbiu_reg) / 2; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%04x  ", fw->pbiu_reg[cnt]);
	}

	if (ha->cfg_flags & (CFG_CTRL_2300 | CFG_CTRL_6322)) {
		mdb_printf("\n\nReqQ-RspQ-Risc2Host Status registers:");
		for (cnt = 0; cnt < sizeof (fw->risc_host_reg) / 2; cnt++) {
			if (cnt % 8 == 0) {
				mdb_printf("\n");
			}
			mdb_printf("%04x  ", fw->risc_host_reg[cnt]);
		}
	}

	mdb_printf("\n\nMailbox Registers:");
	mbox_cnt = (ha->cfg_flags & (CFG_CTRL_2300 | CFG_CTRL_6322)) ? 16 : 8;
	for (cnt = 0; cnt < mbox_cnt; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%04x  ", fw->mailbox_reg[cnt]);
	}

	if (ha->cfg_flags & (CFG_CTRL_2300 | CFG_CTRL_6322)) {
		mdb_printf("\n\nAuto Request Response DMA Registers:");
		for (cnt = 0; cnt < sizeof (fw->resp_dma_reg) / 2; cnt++) {
			if (cnt % 8 == 0) {
				mdb_printf("\n");
			}
			mdb_printf("%04x  ", fw->resp_dma_reg[cnt]);
		}
	}

	mdb_printf("\n\nDMA Registers:");
	for (cnt = 0; cnt < sizeof (fw->dma_reg) / 2; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%04x  ", fw->dma_reg[cnt]);
	}

	mdb_printf("\n\nRISC Hardware Registers:");
	for (cnt = 0; cnt < sizeof (fw->risc_hdw_reg) / 2; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%04x  ", fw->risc_hdw_reg[cnt]);
	}

	mdb_printf("\n\nRISC GP0 Registers:");
	for (cnt = 0; cnt < sizeof (fw->risc_gp0_reg) / 2; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%04x  ", fw->risc_gp0_reg[cnt]);
	}

	mdb_printf("\n\nRISC GP1 Registers:");
	for (cnt = 0; cnt < sizeof (fw->risc_gp1_reg) / 2; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%04x  ", fw->risc_gp1_reg[cnt]);
	}

	mdb_printf("\n\nRISC GP2 Registers:");
	for (cnt = 0; cnt < sizeof (fw->risc_gp2_reg) / 2; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%04x  ", fw->risc_gp2_reg[cnt]);
	}

	mdb_printf("\n\nRISC GP3 Registers:");
	for (cnt = 0; cnt < sizeof (fw->risc_gp3_reg) / 2; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%04x  ", fw->risc_gp3_reg[cnt]);
	}

	mdb_printf("\n\nRISC GP4 Registers:");
	for (cnt = 0; cnt < sizeof (fw->risc_gp4_reg) / 2; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%04x  ", fw->risc_gp4_reg[cnt]);
	}

	mdb_printf("\n\nRISC GP5 Registers:");
	for (cnt = 0; cnt < sizeof (fw->risc_gp5_reg) / 2; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%04x  ", fw->risc_gp5_reg[cnt]);
	}

	mdb_printf("\n\nRISC GP6 Registers:");
	for (cnt = 0; cnt < sizeof (fw->risc_gp6_reg) / 2; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%04x  ", fw->risc_gp6_reg[cnt]);
	}

	mdb_printf("\n\nRISC GP7 Registers:");
	for (cnt = 0; cnt < sizeof (fw->risc_gp7_reg) / 2; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%04x  ", fw->risc_gp7_reg[cnt]);
	}

	mdb_printf("\n\nFrame Buffer Hardware Registers:");
	for (cnt = 0; cnt < sizeof (fw->frame_buf_hdw_reg) / 2; cnt++) {
		if ((cnt == 16) &&
		    ((ha->cfg_flags & (CFG_CTRL_2300 | CFG_CTRL_6322)) == 0)) {
			break;
		}
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%04x  ", fw->frame_buf_hdw_reg[cnt]);
	}

	mdb_printf("\n\nFPM B0 Registers:");
	for (cnt = 0; cnt < sizeof (fw->fpm_b0_reg) / 2; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%04x  ", fw->fpm_b0_reg[cnt]);
	}

	mdb_printf("\n\nFPM B1 Registers:");
	for (cnt = 0; cnt < sizeof (fw->fpm_b1_reg) / 2; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%04x  ", fw->fpm_b1_reg[cnt]);
	}

	if (ha->cfg_flags & (CFG_CTRL_2300 | CFG_CTRL_6322)) {
		mdb_printf("\n\nCode RAM Dump:");
		for (cnt = 0; cnt < sizeof (fw->risc_ram) / 2; cnt++) {
			if (cnt % 8 == 0) {
				mdb_printf("\n%05x: ", cnt + 0x0800);
			}
			mdb_printf("%04x  ", fw->risc_ram[cnt]);
		}

		mdb_printf("\n\nStack RAM Dump:");
		for (cnt = 0; cnt < sizeof (fw->stack_ram) / 2; cnt++) {
			if (cnt % 8 == 0) {
				mdb_printf("\n%05x: ", cnt + 0x010000);
			}
			mdb_printf("%04x  ", fw->stack_ram[cnt]);
		}

		mdb_printf("\n\nData RAM Dump:");
		for (cnt = 0; cnt < sizeof (fw->data_ram) / 2; cnt++) {
			if (cnt % 8 == 0) {
				mdb_printf("\n%05x: ", cnt + 0x010800);
			}
			mdb_printf("%04x  ", fw->data_ram[cnt]);
		}

		mdb_printf("\n\n[<==END] ISP Debug Dump.\n");

		mdb_printf("\n\nRequest Queue");

		for (cnt = 0; cnt < REQUEST_QUEUE_SIZE / 4; cnt++) {
			if (cnt % 8 == 0) {
				mdb_printf("\n%08x: ", cnt);
			}
			mdb_printf("%08x ", fw->req_q[cnt]);
		}

		mdb_printf("\n\nResponse Queue");

		for (cnt = 0; cnt < RESPONSE_QUEUE_SIZE / 4; cnt++) {
			if (cnt % 8 == 0) {
				mdb_printf("\n%08x: ", cnt);
			}
			mdb_printf("%08x ", fw->rsp_q[cnt]);
		}

		mdb_printf("\n");

	} else {
		mdb_printf("\n\nRISC SRAM:");
		for (cnt = 0; cnt < 0xf000; cnt++) {
			if (cnt % 8 == 0) {
				mdb_printf("\n%04x: ", cnt + 0x1000);
			}
			mdb_printf("%04x  ", fw->risc_ram[cnt]);
		}
	}

	mdb_free(fw, ha->ql_dump_size);

	return (DCMD_OK);
}

/*
 * ql_24xx_dump_dcmd
 *	prints out a firmware dump buffer
 *
 * Input:
 *	addr  = User supplied address. (NB: nust be an ha)
 *	flags = mdb flags.
 *	argc  = Number of user supplied args.
 *	argv  = Arg array.
 *
 * Returns:
 *	DCMD_OK or DCMD_ERR
 *
 * Context:
 *	User context.
 *
 */
/*ARGSUSED*/
static int
ql_24xx_dump_dcmd(ql_adapter_state_t *ha, uint_t flags, int argc,
    const mdb_arg_t *argv)
{
	ql_24xx_fw_dump_t	*fw;
	uint32_t		cnt = 0;

	fw = (ql_24xx_fw_dump_t *)mdb_alloc(ha->ql_dump_size, UM_SLEEP);

	if (mdb_vread(fw, ha->ql_dump_size,
	    (uintptr_t)ha->ql_dump_ptr) == -1) {
		mdb_warn("failed to read ql_dump_ptr (no f/w dump active?)");
		mdb_free(fw, ha->ql_dump_size);
		return (DCMD_OK);
	}

	mdb_printf("ISP FW Version %d.%02d.%02d Attributes %X\n",
	    ha->fw_major_version, ha->fw_minor_version,
	    ha->fw_subminor_version, ha->fw_attributes);

	mdb_printf("\nHCCR Register\n%08x\n", fw->hccr);

	mdb_printf("\nHost Interface Registers");
	for (cnt = 0; cnt < sizeof (fw->host_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->host_reg[cnt]);
	}

	mdb_printf("\n\nMailbox Registers");
	for (cnt = 0; cnt < sizeof (fw->mailbox_reg) / 2; cnt++) {
		if (cnt % 16 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%04x ", fw->mailbox_reg[cnt]);
	}

	mdb_printf("\n\nXSEQ GP Registers");
	for (cnt = 0; cnt < sizeof (fw->xseq_gp_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->xseq_gp_reg[cnt]);
	}

	mdb_printf("\n\nXSEQ-0 Registers");
	for (cnt = 0; cnt < sizeof (fw->xseq_0_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->xseq_0_reg[cnt]);
	}

	mdb_printf("\n\nXSEQ-1 Registers");
	for (cnt = 0; cnt < sizeof (fw->xseq_1_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->xseq_1_reg[cnt]);
	}

	mdb_printf("\n\nRSEQ GP Registers");
	for (cnt = 0; cnt < sizeof (fw->rseq_gp_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->rseq_gp_reg[cnt]);
	}

	mdb_printf("\n\nRSEQ-0 Registers");
	for (cnt = 0; cnt < sizeof (fw->rseq_0_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->rseq_0_reg[cnt]);
	}

	mdb_printf("\n\nRSEQ-1 Registers");
	for (cnt = 0; cnt < sizeof (fw->rseq_1_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->rseq_1_reg[cnt]);
	}

	mdb_printf("\n\nRSEQ-2 Registers");
	for (cnt = 0; cnt < sizeof (fw->rseq_2_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->rseq_2_reg[cnt]);
	}

	mdb_printf("\n\nCommand DMA Registers");
	for (cnt = 0; cnt < sizeof (fw->cmd_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->cmd_dma_reg[cnt]);
	}

	mdb_printf("\n\nRequest0 Queue DMA Channel Registers");
	for (cnt = 0; cnt < sizeof (fw->req0_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->req0_dma_reg[cnt]);
	}

	mdb_printf("\n\nResponse0 Queue DMA Channel Registers");
	for (cnt = 0; cnt < sizeof (fw->resp0_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->resp0_dma_reg[cnt]);
	}

	mdb_printf("\n\nRequest1 Queue DMA Channel Registers");
	for (cnt = 0; cnt < sizeof (fw->req1_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->req1_dma_reg[cnt]);
	}

	mdb_printf("\n\nXMT0 Data DMA Registers");
	for (cnt = 0; cnt < sizeof (fw->xmt0_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->xmt0_dma_reg[cnt]);
	}

	mdb_printf("\n\nXMT1 Data DMA Registers");
	for (cnt = 0; cnt < sizeof (fw->xmt1_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->xmt1_dma_reg[cnt]);
	}

	mdb_printf("\n\nXMT2 Data DMA Registers");
	for (cnt = 0; cnt < sizeof (fw->xmt2_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->xmt2_dma_reg[cnt]);
	}

	mdb_printf("\n\nXMT3 Data DMA Registers");
	for (cnt = 0; cnt < sizeof (fw->xmt3_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->xmt3_dma_reg[cnt]);
	}

	mdb_printf("\n\nXMT4 Data DMA Registers");
	for (cnt = 0; cnt < sizeof (fw->xmt4_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->xmt4_dma_reg[cnt]);
	}

	mdb_printf("\n\nXMT Data DMA Common Registers");
	for (cnt = 0; cnt < sizeof (fw->xmt_data_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->xmt_data_dma_reg[cnt]);
	}

	mdb_printf("\n\nRCV Thread 0 Data DMA Registers");
	for (cnt = 0; cnt < sizeof (fw->rcvt0_data_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->rcvt0_data_dma_reg[cnt]);
	}

	mdb_printf("\n\nRCV Thread 1 Data DMA Registers");
	for (cnt = 0; cnt < sizeof (fw->rcvt1_data_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->rcvt1_data_dma_reg[cnt]);
	}

	mdb_printf("\n\nRISC GP Registers");
	for (cnt = 0; cnt < sizeof (fw->risc_gp_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->risc_gp_reg[cnt]);
	}

	mdb_printf("\n\nShadow Registers");
	for (cnt = 0; cnt < sizeof (fw->shadow_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->shadow_reg[cnt]);
	}

	mdb_printf("\n\nLMC Registers");
	for (cnt = 0; cnt < sizeof (fw->lmc_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->lmc_reg[cnt]);
	}

	mdb_printf("\n\nFPM Hardware Registers");
	for (cnt = 0; cnt < sizeof (fw->fpm_hdw_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->fpm_hdw_reg[cnt]);
	}

	mdb_printf("\n\nFB Hardware Registers");
	for (cnt = 0; cnt < sizeof (fw->fb_hdw_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->fb_hdw_reg[cnt]);
	}

	mdb_printf("\n\nCode RAM");
	for (cnt = 0; cnt < sizeof (fw->code_ram) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n%08x: ", cnt + 0x20000);
		}
		mdb_printf("%08x ", fw->code_ram[cnt]);
	}

	mdb_printf("\n\nExternal Memory");
	for (cnt = 0; cnt < ha->fw_ext_memory_size / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n%08x: ", cnt + 0x100000);
		}
		mdb_printf("%08x ", fw->ext_mem[cnt]);
	}

	mdb_printf("\n[<==END] ISP Debug Dump");

	mdb_printf("\n\nRequest Queue");

	for (cnt = 0; cnt < REQUEST_QUEUE_SIZE / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n%08x: ", cnt);
		}
		mdb_printf("%08x ", fw->req_q[cnt]);
	}

	mdb_printf("\n\nResponse Queue");

	for (cnt = 0; cnt < RESPONSE_QUEUE_SIZE / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n%08x: ", cnt);
		}
		mdb_printf("%08x ", fw->rsp_q[cnt]);
	}

	if ((ha->cfg_flags & CFG_ENABLE_FWEXTTRACE) &&
	    (ha->fwexttracebuf.bp != NULL)) {
		uint32_t cnt_b = 0;
		uint32_t *w32 = ha->fwexttracebuf.bp;

		mdb_printf("\n\nExtended Trace Buffer Memory");
		/* show data address as a byte address, data as long words */
		for (cnt = 0; cnt < FWEXTSIZE / 4; cnt++) {
			cnt_b = cnt * 4;
			if (cnt_b % 32 == 0) {
				mdb_printf("\n%08x: ", w32 + cnt_b);
			}
			mdb_printf("%08x ", fw->ext_trace_buf[cnt]);
		}
	}

	if ((ha->cfg_flags & CFG_ENABLE_FWFCETRACE) &&
	    (ha->fwfcetracebuf.bp != NULL)) {
		uint32_t cnt_b = 0;
		uint32_t *w32 = ha->fwfcetracebuf.bp;

		mdb_printf("\n\nFC Event Trace Buffer Memory");
		/* show data address as a byte address, data as long words */
		for (cnt = 0; cnt < FWFCESIZE / 4; cnt++) {
			cnt_b = cnt * 4;
			if (cnt_b % 32 == 0) {
				mdb_printf("\n%08x: ", w32 + cnt_b);
			}
			mdb_printf("%08x ", fw->fce_trace_buf[cnt]);
		}
	}
	mdb_free(fw, ha->ql_dump_size);

	return (DCMD_OK);
}

/*
 * ql_25xx_dump_dcmd
 *	prints out a firmware dump buffer
 *
 * Input:
 *	addr  = User supplied address. (NB: nust be an ha)
 *	flags = mdb flags.
 *	argc  = Number of user supplied args.
 *	argv  = Arg array.
 *
 * Returns:
 *	DCMD_OK or DCMD_ERR
 *
 * Context:
 *	User context.
 *
 */
/*ARGSUSED*/
static int
ql_25xx_dump_dcmd(ql_adapter_state_t *ha, uint_t flags, int argc,
    const mdb_arg_t *argv)
{
	ql_25xx_fw_dump_t	*fw;
	uint32_t		cnt = 0;

	fw = (ql_25xx_fw_dump_t *)mdb_alloc(ha->ql_dump_size, UM_SLEEP);

	if (mdb_vread(fw, ha->ql_dump_size,
	    (uintptr_t)ha->ql_dump_ptr) == -1) {
		mdb_warn("failed to read ql_dump_ptr (no f/w dump active?)");
		mdb_free(fw, ha->ql_dump_size);
		return (DCMD_OK);
	}

	mdb_printf("\nISP FW Version %d.%02d.%02d Attributes %X\n",
	    ha->fw_major_version, ha->fw_minor_version,
	    ha->fw_subminor_version, ha->fw_attributes);

	mdb_printf("\nR2H Register\n%08x\n", fw->r2h_status);

	mdb_printf("\n\nHostRisc Registers");
	for (cnt = 0; cnt < sizeof (fw->hostrisc_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->hostrisc_reg[cnt]);
	}

	mdb_printf("\n\nPCIe Registers");
	for (cnt = 0; cnt < sizeof (fw->pcie_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->pcie_reg[cnt]);
	}

	mdb_printf("\n\nHost Interface Registers");
	for (cnt = 0; cnt < sizeof (fw->host_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->host_reg[cnt]);
	}

	mdb_printf("\n\nShadow Registers");
	for (cnt = 0; cnt < sizeof (fw->shadow_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}

		mdb_printf("%08x ", fw->shadow_reg[cnt]);
	}

	mdb_printf("\n\nMailbox Registers");
	for (cnt = 0; cnt < sizeof (fw->mailbox_reg) / 2; cnt++) {
		if (cnt % 16 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%04x ", fw->mailbox_reg[cnt]);
	}

	mdb_printf("\n\nXSEQ GP Registers");
	for (cnt = 0; cnt < sizeof (fw->xseq_gp_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->xseq_gp_reg[cnt]);
	}

	mdb_printf("\n\nXSEQ-0 Registers");
	for (cnt = 0; cnt < sizeof (fw->xseq_0_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->xseq_0_reg[cnt]);
	}

	mdb_printf("\n\nXSEQ-1 Registers");
	for (cnt = 0; cnt < sizeof (fw->xseq_1_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->xseq_1_reg[cnt]);
	}

	mdb_printf("\n\nRSEQ GP Registers");
	for (cnt = 0; cnt < sizeof (fw->rseq_gp_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->rseq_gp_reg[cnt]);
	}

	mdb_printf("\n\nRSEQ-0 Registers");
	for (cnt = 0; cnt < sizeof (fw->rseq_0_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->rseq_0_reg[cnt]);
	}

	mdb_printf("\n\nRSEQ-1 Registers");
	for (cnt = 0; cnt < sizeof (fw->rseq_1_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->rseq_1_reg[cnt]);
	}

	mdb_printf("\n\nRSEQ-2 Registers");
	for (cnt = 0; cnt < sizeof (fw->rseq_2_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->rseq_2_reg[cnt]);
	}

	mdb_printf("\n\nASEQ GP Registers");
	for (cnt = 0; cnt < sizeof (fw->aseq_gp_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->aseq_gp_reg[cnt]);
	}

	mdb_printf("\n\nASEQ-0 GP Registers");
	for (cnt = 0; cnt < sizeof (fw->aseq_0_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}

		mdb_printf("%08x ", fw->aseq_0_reg[cnt]);
	}

	mdb_printf("\n\nASEQ-1 GP Registers");
	for (cnt = 0; cnt < sizeof (fw->aseq_1_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}

		mdb_printf("%08x ", fw->aseq_1_reg[cnt]);
	}

	mdb_printf("\n\nASEQ-2 GP Registers");
	for (cnt = 0; cnt < sizeof (fw->aseq_2_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->aseq_2_reg[cnt]);
	}

	mdb_printf("\n\nCommand DMA Registers");
	for (cnt = 0; cnt < sizeof (fw->cmd_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->cmd_dma_reg[cnt]);
	}

	mdb_printf("\n\nRequest0 Queue DMA Channel Registers");
	for (cnt = 0; cnt < sizeof (fw->req0_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->req0_dma_reg[cnt]);
	}

	mdb_printf("\n\nResponse0 Queue DMA Channel Registers");
	for (cnt = 0; cnt < sizeof (fw->resp0_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->resp0_dma_reg[cnt]);
	}

	mdb_printf("\n\nRequest1 Queue DMA Channel Registers");
	for (cnt = 0; cnt < sizeof (fw->req1_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->req1_dma_reg[cnt]);
	}

	mdb_printf("\n\nXMT0 Data DMA Registers");
	for (cnt = 0; cnt < sizeof (fw->xmt0_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->xmt0_dma_reg[cnt]);
	}

	mdb_printf("\n\nXMT1 Data DMA Registers");
	for (cnt = 0; cnt < sizeof (fw->xmt1_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->xmt1_dma_reg[cnt]);
	}

	mdb_printf("\n\nXMT2 Data DMA Registers");
	for (cnt = 0; cnt < sizeof (fw->xmt2_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->xmt2_dma_reg[cnt]);
	}

	mdb_printf("\n\nXMT3 Data DMA Registers");
	for (cnt = 0; cnt < sizeof (fw->xmt3_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->xmt3_dma_reg[cnt]);
	}

	mdb_printf("\n\nXMT4 Data DMA Registers");
	for (cnt = 0; cnt < sizeof (fw->xmt4_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->xmt4_dma_reg[cnt]);
	}

	mdb_printf("\n\nXMT Data DMA Common Registers");
	for (cnt = 0; cnt < sizeof (fw->xmt_data_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->xmt_data_dma_reg[cnt]);
	}

	mdb_printf("\n\nRCV Thread 0 Data DMA Registers");
	for (cnt = 0; cnt < sizeof (fw->rcvt0_data_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->rcvt0_data_dma_reg[cnt]);
	}

	mdb_printf("\n\nRCV Thread 1 Data DMA Registers");
	for (cnt = 0; cnt < sizeof (fw->rcvt1_data_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->rcvt1_data_dma_reg[cnt]);
	}

	mdb_printf("\n\nRISC GP Registers");
	for (cnt = 0; cnt < sizeof (fw->risc_gp_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->risc_gp_reg[cnt]);
	}

	mdb_printf("\n\nRISC IO Register\n%08x", fw->risc_io);

	mdb_printf("\n\nLMC Registers");
	for (cnt = 0; cnt < sizeof (fw->lmc_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->lmc_reg[cnt]);
	}

	mdb_printf("\n\nFPM Hardware Registers");
	for (cnt = 0; cnt < sizeof (fw->fpm_hdw_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->fpm_hdw_reg[cnt]);
	}

	mdb_printf("\n\nFB Hardware Registers");
	for (cnt = 0; cnt < sizeof (fw->fb_hdw_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->fb_hdw_reg[cnt]);
	}

	mdb_printf("\n\nCode RAM");
	for (cnt = 0; cnt < sizeof (fw->code_ram) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n%08x: ", cnt + 0x20000);
		}
		mdb_printf("%08x ", fw->code_ram[cnt]);
	}

	mdb_printf("\n\nExternal Memory");
	for (cnt = 0; cnt < ha->fw_ext_memory_size / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n%08x: ", cnt + 0x100000);
		}
		mdb_printf("%08x ", fw->ext_mem[cnt]);
	}

	mdb_printf("\n[<==END] ISP Debug Dump");

	mdb_printf("\n\nRequest Queue");

	for (cnt = 0; cnt < REQUEST_QUEUE_SIZE / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n%08x: ", cnt);
		}
		mdb_printf("%08x ", fw->req_q[cnt]);
	}

	mdb_printf("\n\nResponse Queue");

	for (cnt = 0; cnt < RESPONSE_QUEUE_SIZE / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n%08x: ", cnt);
		}
		mdb_printf("%08x ", fw->rsp_q[cnt]);
	}

	if ((ha->cfg_flags & CFG_ENABLE_FWEXTTRACE) &&
	    (ha->fwexttracebuf.bp != NULL)) {
		uint32_t cnt_b = 0;
		uint32_t *w32 = ha->fwexttracebuf.bp;

		mdb_printf("\n\nExtended Trace Buffer Memory");
		/* show data address as a byte address, data as long words */
		for (cnt = 0; cnt < FWEXTSIZE / 4; cnt++) {
			cnt_b = cnt * 4;
			if (cnt_b % 32 == 0) {
				mdb_printf("\n%08x: ", w32 + cnt_b);
			}
			mdb_printf("%08x ", fw->ext_trace_buf[cnt]);
		}
	}

	if ((ha->cfg_flags & CFG_ENABLE_FWFCETRACE) &&
	    (ha->fwfcetracebuf.bp != NULL)) {
		uint32_t cnt_b = 0;
		uint32_t *w32 = ha->fwfcetracebuf.bp;

		mdb_printf("\n\nFC Event Trace Buffer Memory");
		/* show data address as a byte address, data as long words */
		for (cnt = 0; cnt < FWFCESIZE / 4; cnt++) {
			cnt_b = cnt * 4;
			if (cnt_b % 32 == 0) {
				mdb_printf("\n%08x: ", w32 + cnt_b);
			}
			mdb_printf("%08x ", fw->fce_trace_buf[cnt]);
		}
	}

	mdb_free(fw, ha->ql_dump_size);

	mdb_printf("\n\nreturn exit\n");

	return (DCMD_OK);
}

/*
 * ql_81xx_dump_dcmd
 *	prints out a firmware dump buffer
 *
 * Input:
 *	addr  = User supplied address. (NB: nust be an ha)
 *	flags = mdb flags.
 *	argc  = Number of user supplied args.
 *	argv  = Arg array.
 *
 * Returns:
 *	DCMD_OK or DCMD_ERR
 *
 * Context:
 *	User context.
 *
 */
/*ARGSUSED*/
static int
ql_81xx_dump_dcmd(ql_adapter_state_t *ha, uint_t flags, int argc,
    const mdb_arg_t *argv)
{
	ql_81xx_fw_dump_t	*fw;
	uint32_t		cnt = 0;

	fw = (ql_81xx_fw_dump_t *)mdb_alloc(ha->ql_dump_size, UM_SLEEP);

	if (mdb_vread(fw, ha->ql_dump_size,
	    (uintptr_t)ha->ql_dump_ptr) == -1) {
		mdb_warn("failed to read ql_dump_ptr (no f/w dump active?)");
		mdb_free(fw, ha->ql_dump_size);
		return (DCMD_OK);
	}

	mdb_printf("\nISP FW Version %d.%02d.%02d Attributes %X\n",
	    ha->fw_major_version, ha->fw_minor_version,
	    ha->fw_subminor_version, ha->fw_attributes);

	mdb_printf("\nR2H Register\n%08x\n", fw->r2h_status);

	mdb_printf("\n\nHostRisc Registers");
	for (cnt = 0; cnt < sizeof (fw->hostrisc_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->hostrisc_reg[cnt]);
	}

	mdb_printf("\n\nPCIe Registers");
	for (cnt = 0; cnt < sizeof (fw->pcie_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->pcie_reg[cnt]);
	}

	mdb_printf("\n\nHost Interface Registers");
	for (cnt = 0; cnt < sizeof (fw->host_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->host_reg[cnt]);
	}

	mdb_printf("\n\nShadow Registers");
	for (cnt = 0; cnt < sizeof (fw->shadow_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}

		mdb_printf("%08x ", fw->shadow_reg[cnt]);
	}

	mdb_printf("\n\nMailbox Registers");
	for (cnt = 0; cnt < sizeof (fw->mailbox_reg) / 2; cnt++) {
		if (cnt % 16 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%04x ", fw->mailbox_reg[cnt]);
	}

	mdb_printf("\n\nXSEQ GP Registers");
	for (cnt = 0; cnt < sizeof (fw->xseq_gp_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->xseq_gp_reg[cnt]);
	}

	mdb_printf("\n\nXSEQ-0 Registers");
	for (cnt = 0; cnt < sizeof (fw->xseq_0_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->xseq_0_reg[cnt]);
	}

	mdb_printf("\n\nXSEQ-1 Registers");
	for (cnt = 0; cnt < sizeof (fw->xseq_1_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->xseq_1_reg[cnt]);
	}

	mdb_printf("\n\nRSEQ GP Registers");
	for (cnt = 0; cnt < sizeof (fw->rseq_gp_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->rseq_gp_reg[cnt]);
	}

	mdb_printf("\n\nRSEQ-0 Registers");
	for (cnt = 0; cnt < sizeof (fw->rseq_0_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->rseq_0_reg[cnt]);
	}

	mdb_printf("\n\nRSEQ-1 Registers");
	for (cnt = 0; cnt < sizeof (fw->rseq_1_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->rseq_1_reg[cnt]);
	}

	mdb_printf("\n\nRSEQ-2 Registers");
	for (cnt = 0; cnt < sizeof (fw->rseq_2_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->rseq_2_reg[cnt]);
	}

	mdb_printf("\n\nASEQ GP Registers");
	for (cnt = 0; cnt < sizeof (fw->aseq_gp_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->aseq_gp_reg[cnt]);
	}

	mdb_printf("\n\nASEQ-0 GP Registers");
	for (cnt = 0; cnt < sizeof (fw->aseq_0_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}

		mdb_printf("%08x ", fw->aseq_0_reg[cnt]);
	}

	mdb_printf("\n\nASEQ-1 GP Registers");
	for (cnt = 0; cnt < sizeof (fw->aseq_1_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}

		mdb_printf("%08x ", fw->aseq_1_reg[cnt]);
	}

	mdb_printf("\n\nASEQ-2 GP Registers");
	for (cnt = 0; cnt < sizeof (fw->aseq_2_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->aseq_2_reg[cnt]);
	}

	mdb_printf("\n\nCommand DMA Registers");
	for (cnt = 0; cnt < sizeof (fw->cmd_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->cmd_dma_reg[cnt]);
	}

	mdb_printf("\n\nRequest0 Queue DMA Channel Registers");
	for (cnt = 0; cnt < sizeof (fw->req0_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->req0_dma_reg[cnt]);
	}

	mdb_printf("\n\nResponse0 Queue DMA Channel Registers");
	for (cnt = 0; cnt < sizeof (fw->resp0_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->resp0_dma_reg[cnt]);
	}

	mdb_printf("\n\nRequest1 Queue DMA Channel Registers");
	for (cnt = 0; cnt < sizeof (fw->req1_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->req1_dma_reg[cnt]);
	}

	mdb_printf("\n\nXMT0 Data DMA Registers");
	for (cnt = 0; cnt < sizeof (fw->xmt0_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->xmt0_dma_reg[cnt]);
	}

	mdb_printf("\n\nXMT1 Data DMA Registers");
	for (cnt = 0; cnt < sizeof (fw->xmt1_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->xmt1_dma_reg[cnt]);
	}

	mdb_printf("\n\nXMT2 Data DMA Registers");
	for (cnt = 0; cnt < sizeof (fw->xmt2_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->xmt2_dma_reg[cnt]);
	}

	mdb_printf("\n\nXMT3 Data DMA Registers");
	for (cnt = 0; cnt < sizeof (fw->xmt3_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->xmt3_dma_reg[cnt]);
	}

	mdb_printf("\n\nXMT4 Data DMA Registers");
	for (cnt = 0; cnt < sizeof (fw->xmt4_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->xmt4_dma_reg[cnt]);
	}

	mdb_printf("\n\nXMT Data DMA Common Registers");
	for (cnt = 0; cnt < sizeof (fw->xmt_data_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->xmt_data_dma_reg[cnt]);
	}

	mdb_printf("\n\nRCV Thread 0 Data DMA Registers");
	for (cnt = 0; cnt < sizeof (fw->rcvt0_data_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->rcvt0_data_dma_reg[cnt]);
	}

	mdb_printf("\n\nRCV Thread 1 Data DMA Registers");
	for (cnt = 0; cnt < sizeof (fw->rcvt1_data_dma_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->rcvt1_data_dma_reg[cnt]);
	}

	mdb_printf("\n\nRISC GP Registers");
	for (cnt = 0; cnt < sizeof (fw->risc_gp_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->risc_gp_reg[cnt]);
	}

	mdb_printf("\n\nRISC IO Register\n%08x", fw->risc_io);

	mdb_printf("\n\nLMC Registers");
	for (cnt = 0; cnt < sizeof (fw->lmc_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->lmc_reg[cnt]);
	}

	mdb_printf("\n\nFPM Hardware Registers");
	for (cnt = 0; cnt < sizeof (fw->fpm_hdw_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->fpm_hdw_reg[cnt]);
	}

	mdb_printf("\n\nFB Hardware Registers");
	for (cnt = 0; cnt < sizeof (fw->fb_hdw_reg) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n");
		}
		mdb_printf("%08x ", fw->fb_hdw_reg[cnt]);
	}

	mdb_printf("\n\nCode RAM");
	for (cnt = 0; cnt < sizeof (fw->code_ram) / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n%08x: ", cnt + 0x20000);
		}
		mdb_printf("%08x ", fw->code_ram[cnt]);
	}

	mdb_printf("\n\nExternal Memory");
	for (cnt = 0; cnt < ha->fw_ext_memory_size / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n%08x: ", cnt + 0x100000);
		}
		mdb_printf("%08x ", fw->ext_mem[cnt]);
	}

	mdb_printf("\n[<==END] ISP Debug Dump");

	mdb_printf("\n\nRequest Queue");

	for (cnt = 0; cnt < REQUEST_QUEUE_SIZE / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n%08x: ", cnt);
		}
		mdb_printf("%08x ", fw->req_q[cnt]);
	}

	mdb_printf("\n\nResponse Queue");

	for (cnt = 0; cnt < RESPONSE_QUEUE_SIZE / 4; cnt++) {
		if (cnt % 8 == 0) {
			mdb_printf("\n%08x: ", cnt);
		}
		mdb_printf("%08x ", fw->rsp_q[cnt]);
	}

	if ((ha->cfg_flags & CFG_ENABLE_FWEXTTRACE) &&
	    (ha->fwexttracebuf.bp != NULL)) {
		uint32_t cnt_b = 0;
		uint32_t *w32 = ha->fwexttracebuf.bp;

		mdb_printf("\n\nExtended Trace Buffer Memory");
		/* show data address as a byte address, data as long words */
		for (cnt = 0; cnt < FWEXTSIZE / 4; cnt++) {
			cnt_b = cnt * 4;
			if (cnt_b % 32 == 0) {
				mdb_printf("\n%08x: ", w32 + cnt_b);
			}
			mdb_printf("%08x ", fw->ext_trace_buf[cnt]);
		}
	}

	if ((ha->cfg_flags & CFG_ENABLE_FWFCETRACE) &&
	    (ha->fwfcetracebuf.bp != NULL)) {
		uint32_t cnt_b = 0;
		uint32_t *w32 = ha->fwfcetracebuf.bp;

		mdb_printf("\n\nFC Event Trace Buffer Memory");
		/* show data address as a byte address, data as long words */
		for (cnt = 0; cnt < FWFCESIZE / 4; cnt++) {
			cnt_b = cnt * 4;
			if (cnt_b % 32 == 0) {
				mdb_printf("\n%08x: ", w32 + cnt_b);
			}
			mdb_printf("%08x ", fw->fce_trace_buf[cnt]);
		}
	}

	mdb_free(fw, ha->ql_dump_size);

	mdb_printf("\n\nreturn exit\n");

	return (DCMD_OK);
}

/*
 * ql_gettrace_dcmd
 *	prints out the Extended Logging trace buffer
 *
 * Input:
 *	addr  = User supplied address. (NB: must be an ha)
 *	flags = mdb flags.
 *	argc  = Number of user supplied args.
 *	argv  = Arg array.
 *
 * Returns:
 *	DCMD_OK or DCMD_ERR
 *
 * Context:
 *	User context.
 *
 */
static int
qlc_gettrace_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
	ql_adapter_state_t	*ha;
	int			verbose = 0;
	int			wrapped = 0;
	char			*trace_start;
	char			*trace_end;
	char			*dump_start = 0;
	char			*trace_next  = 0;
	char			*dump_current  = 0;
	el_trace_desc_t		*trace_desc;

	if ((!(flags & DCMD_ADDRSPEC)) || addr == NULL) {
		mdb_warn("ql_adapter_state structure addr is required");
		return (DCMD_USAGE);
	}

	if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &verbose) !=
	    argc) {
		return (DCMD_USAGE);
	}

	/*
	 * Get the adapter state struct which was passed
	 */
	if ((ha = (ql_adapter_state_t *)mdb_alloc(sizeof (ql_adapter_state_t),
	    UM_SLEEP)) == NULL) {
		mdb_warn("failed to allocate memory for ql_adapter_state\n");
		return (DCMD_OK);
	}

	if (mdb_vread(ha, sizeof (ql_adapter_state_t), addr) == -1) {
		mdb_warn("failed to read ql_adapter_state at %p", addr);
		mdb_free(ha, sizeof (ql_adapter_state_t));
		return (DCMD_OK);
	}

	/*
	 * If its not a valid trace descriptor then bail out
	 */
	if (ha->el_trace_desc == NULL) {
		mdb_warn("trace descriptor does not exist for instance %d\n",
		    ha->instance);
		mdb_free(ha, sizeof (ql_adapter_state_t));
		return (DCMD_OK);
	} else {
		trace_desc = (el_trace_desc_t *)
		    mdb_alloc(sizeof (el_trace_desc_t), UM_SLEEP);
		if (mdb_vread(trace_desc, sizeof (el_trace_desc_t),
		    (uintptr_t)ha->el_trace_desc) == -1) {
			mdb_warn("failed to read ql_adapter_state at %p",
			    addr);
			mdb_free(trace_desc, sizeof (el_trace_desc_t));
			mdb_free(ha, sizeof (ql_adapter_state_t));
			return (DCMD_OK);
		}
		if (trace_desc->trace_buffer == NULL) {
			mdb_warn("trace buffer does not exist for "
			    "instance %d\n", ha->instance);
			mdb_free(trace_desc, sizeof (el_trace_desc_t));
			mdb_free(ha, sizeof (ql_adapter_state_t));
			return (DCMD_OK);
		}
	}

	/* Get the trace buffer */

	trace_start = (char *)
	    mdb_zalloc(trace_desc->trace_buffer_size, UM_SLEEP);

	if (mdb_vread(trace_start, trace_desc->trace_buffer_size,
	    (uintptr_t)trace_desc->trace_buffer) == -1) {
		mdb_warn("failed to read trace buffer?)");
		mdb_free(trace_start, trace_desc->trace_buffer_size);
		mdb_free(ha, sizeof (ql_adapter_state_t));
		return (DCMD_OK);
	}

	/* set the end of the trace buffer. */
	trace_end = trace_start + trace_desc->trace_buffer_size;

	/* Find the start point of trace. */
	trace_next = trace_start + trace_desc->next;

	/*
	 * If the buffer has not wrapped next will point at a null so
	 * start is the begining of the buffer.  If next points at a char
	 * then we must traverse the buffer further until a null is detected.
	 * The location after the null will be the beginning of the oldest
	 * whole object in the buffer, which we use as the start.
	 */

	if ((trace_next + EL_BUFFER_RESERVE) >= trace_end) {
		dump_start = trace_start;
	} else if (*trace_next != NULL) {
		dump_start = trace_next + (strlen(trace_next) + 1);
	} else {
		dump_start = trace_start;
	}

	dump_current = dump_start;

	mdb_printf("\nExtended Logging trace buffer @%x, start @%x, "
	    "size=%d\n\n", trace_start, dump_current,
	    trace_desc->trace_buffer_size);

	/* Don't run off the end, no matter what. */
	while (((uintptr_t)dump_current - (uintptr_t)trace_start) <=
	    (uintptr_t)trace_desc->trace_buffer_size) {
		/* Show it... */
		mdb_printf("%s", dump_current);
		/* Calculate the next and make it the current */
		dump_current += (strlen(dump_current) + 1);
		/* check for wrap */
		if ((dump_current + EL_BUFFER_RESERVE) >= trace_end) {
			mdb_printf("Wraping %x\n", dump_current);
			dump_current = trace_start;
			wrapped = 1;
		} else if (wrapped) {
			/*   Don't go past next. */
			if ((trace_start + trace_desc->next) <= dump_current) {
				mdb_printf("Done %x", dump_current);
				break;
			}
		} else if (*dump_current == NULL) {
			mdb_printf("Done %x(null)", dump_current);
			break;
		}
	}

	mdb_free(ha, sizeof (ql_adapter_state_t));
	mdb_free(trace_start, trace_desc->trace_buffer_size);
	mdb_free(trace_desc, sizeof (el_trace_desc_t));

	return (DCMD_OK);
}
/*
 * ql_doprint
 *	ql generic function to call the print dcmd
 *
 * Input:
 *	addr - address to struct
 *	prtsting - address to string
 *
 * Returns:
 *	WALK_DONE
 *
 * Context:
 *	User context.
 *
 */
static int32_t
ql_doprint(uintptr_t addr, int8_t *prtstring)
{
	struct	mdb_arg		printarg;

	printarg.a_un.a_str = (int8_t *)(mdb_zalloc(strlen(prtstring),
	    UM_SLEEP));
	printarg.a_type = MDB_TYPE_STRING;
	(void) strcpy((int8_t *)(printarg.a_un.a_str), prtstring);

	if ((mdb_call_dcmd("print", addr, DCMD_ADDRSPEC, 1,
	    &printarg)) == -1) {
		mdb_warn("ql_doprint: failed print dcmd: %s"
		    "at addr: %llxh", prtstring, addr);
	}

	mdb_free((void *)(printarg.a_un.a_str), strlen(prtstring));
	return (WALK_DONE);
}

/*
 * ql_dump_flags
 *	mdb utility to print the flag string
 *
 * Input:
 *	flags - flags to print
 *	strings - text to print when flag is set
 *
 * Returns:
 *
 *
 * Context:
 *	User context.
 *
 */
static void
ql_dump_flags(uint64_t flags, int8_t **strings)
{
	int		i, linel, first = 1;
	uint64_t	mask = 1;

	linel = 8;
	mdb_printf("\t");
	for (i = 0; i < 64; i++) {
		if (strings[i] == NULL)
			break;
		if (flags & mask) {
			if (!first) {
				mdb_printf(" | ");
			} else {
				first = 0;
			}
			linel += (int32_t)strlen(strings[i]) + 3;
			if (linel > 80) {
				mdb_printf("\n\t");
				linel = (int32_t)strlen(strings[i]) + 1 + 8;
			}
			mdb_printf("%s", strings[i]);
		}
		mask <<= 1;
	}
	mdb_printf("\n");
}

/*
 * MDB module linkage information
 *
 *
 * dcmd structures for the _mdb_init function
 */
static const mdb_dcmd_t dcmds[] = {
	{ "qlclinks", NULL, "Prints qlc link information", qlclinks_dcmd },
	{ "qlcosc", NULL, "Prints outstanding cmd info", qlc_osc_dcmd },
	{ "qlcver", NULL, "Prints driver/mdb version", qlcver_dcmd },
	{ "qlc_elog", "[on|off] [<inst #>|all]", "Turns qlc extended logging "
	    "on / off", qlc_el_dcmd },
	{ "qlcstate", ":[-v]", "Prints qlc adapter state information",
	    qlcstate_dcmd },
	{ "qlctgtq", NULL, "Prints qlc target queues", qltgtq_dcmd },
	{ "qlcwdog", NULL, "Prints out watchdog linked list", qlc_wdog_dcmd},
	{ "qlcgetdump", ":[-v]", "Retrieves the ASCII f/w dump",
	    qlc_getdump_dcmd },
	{ "qlcgettrace", ":[-v]", "Retrieves the ASCII Extended Logging trace",
	    qlc_gettrace_dcmd },
	{ NULL }
};

/*
 * walker structures for the _mdb_init function
 */
static const mdb_walker_t walkers[] = {
	{ "qlcstates", "walk list of qlc ql_state_t structures",
	    qlstates_walk_init, qlstates_walk_step, qlstates_walk_fini },
	{ "qlcsrbs", "walk list of qlc ql_srb_t strctures",
	    qlsrb_walk_init, qlsrb_walk_step, qlsrb_walk_fini },
	{ "qlclunq", "walk list of qlc ql_lun_t strctures",
	    qllunq_walk_init, qllunq_walk_step, qllunq_walk_fini },
	{ NULL }
};

static const mdb_modinfo_t ql_mdb_modinfo = {
	MDB_API_VERSION, dcmds, walkers
};

/*
 * Registration function which lists the dcmds and walker structures
 */
const mdb_modinfo_t *
_mdb_init(void)
{
	return (&ql_mdb_modinfo);
}