#if defined(EEI)
/****************************************************************************
 *									    *
 *			  COPYRIGHT (c) 1990 - 2004			    *
 *			   This Software Provided			    *
 *				     By					    *
 *			  Robin's Nest Software Inc.			    *
 *									    *
 * Permission to use, copy, modify, distribute and sell this software and   *
 * its documentation for any purpose and without fee is hereby granted,	    *
 * provided that the above copyright notice appear in all copies and that   *
 * both that copyright notice and this permission notice appear in the	    *
 * supporting documentation, and that the name of the author not be used    *
 * in advertising or publicity pertaining to distribution of the software   *
 * without specific, written prior permission.				    *
 *									    *
 * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 	    *
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN	    *
 * NO EVENT SHALL HE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL   *
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR    *
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS  *
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF   *
 * THIS SOFTWARE.							    *
 *									    *
 ****************************************************************************/
/*
 * Module:	dteei.c
 * Author:	Robin T. Miller
 * Date:	September 13, 1997
 *
 * Description:
 *	This file contains functions for support of DEC EEI interface.
 *
 * Modification History:
 *
 * November 17th, 2003 by Robin Miller.
 *	Breakup output to stdout or stderr, rather than writing
 * all output to stderr.  If output file is stdout ('-') or a log
 * file is specified, then all output reverts to stderr.
 *
 * April 21st, 2000 by Robin Miller.
 *	Converted tabs to spaces in all messages, so formatting is not
 * screwed up when messages are prefixed by a timestamp or process ID.
 *
 * April 10th, 2000 by Robin Miller.
 *	For Wave4, added logic to handle EEI_DEVPATH_FAILURE, so we try
 * to re-open the tape device to 1) find another path (multi-pathing) or
 * 2) force DRD failover (find another server for the tape).
 *
 * February 19th, 2000 by Robin Miller.
 *	While processing a reset condition, if another operation errors
 * with no EEI status (EEI_NO_STATUS), then retry that operation.  This
 * may be a driver related problem, but we wish to recover from this.
 * If not compiled for Tru64 clusters, retry target selection timeouts.
 *
 * February 14th, 2000 by Robin Miller.
 *	Merge Mike Gilmore's changes:
 *	- change the data format from DEVIOCGET to DEVGETINFO.
 *
 * March 25, 1999 by Robin Miller.
 *	Fix problem with my fileno going negative (bad check).
 *
 * February 25, 1999 by Robin Miller.
 *	Add support for multiple reset conditions.
 *
 * December 21, 1998 by Robin Miller.
 *	Add HandleTapeResets() to reposition the tape after resets.
 *
 * March 11, 1998 by George Bittner.
 *	Remove unnecessary include files for building in steelos.
 *
 */

#include "dt.h"

#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <sys/ioctl_compat.h>
#include <sys/mtio.h>
#include <io/common/iotypes.h>
#include <io/common/devio.h>
#include <io/common/devgetinfo.h>
#include <io/cam/cam.h>
#include <io/cam/scsi_all.h>
#include <io/cam/scsi_status.h>
#if !defined(STEELOS)
#  include <io/common/kds.h>
#  include <io/cam/camdb.h>
#  include <io/cam/cam_tape.h>
#endif /* !defined(STEELOS) */

/*
 * These three defines are, unfortunately, not defined in the CAM code
 * because they are always used only as bit fields in the entire sense
 * data structure.  All we have available is the sense key itself.
 */
#define	ILI		0x20
#define	EOM		0x40
#define	FILE_MARK	0x80

#define DNL		0			/* Disable newline.	*/
#define PNL		1			/* Print newline.	*/

/*
 * Declare CAM Debugging Definitions:
 */
#define CDBG_BRIEF	0		/* Brief message text. */
#define CDBG_FULL	1		/* Full message text. */

/*
 * Additional Sense Code Table Entry Format:
 */
struct sense_entry {
	u_char	sense_code;		/* Additional sense code.	*/
	u_char	sense_qualifier;	/* Sense code qualifier.	*/
	char	*sense_message;		/* Error message text.		*/
};

static char *not_valid_str	= "<Not Valid>";

long	mt_blkno;			/* Starting tape block number.	*/
long	mt_fileno;			/* Starting tape file number.	*/

/*
 * Forward References:
 */
bool is_ResetCondition(struct dinfo *dip, DEV_EEI_STATUS *eei);
bool is_StatusRetryable(struct dinfo *dip, DEV_EEI_STATUS *eei);
void print_eei(DEV_EEI_STATUS *eei);
void print_devio(int fd);
void print_erreg(short erreg);
void print_stat(long stat);
void print_category(long stat, device_info_t *devinfop);

void PrintNumeric(char *field_str, u_long numeric_value, int nl_flag);
void PrintDecimal(char *field_str, u_long numeric_value, int nl_flag);
void PrintHex(char *field_str, u_long numeric_value, int nl_flag);
void PrintAscii(char *field_str, char *ascii_str, int nl_flag);
void PrintFields(u_char *bptr, int length);

char *cdbg_SenseKeyTable[];
char *cdbg_CamStatus(u_char cam_status, int report_format);
char *cdbg_ScsiStatus(u_char scsi_status, int report_format);
char *cdbg_SenseMessage(struct all_req_sns_data *sdp);
char *cdbg_EEIStatus(u_int eei_status, int report_format);

/*
 * HandleTapeResets() - Handle Tape Reset Conditions.
 *
 * Description:
 * 	This function is called to do reset processing for tape devices.
 * The idea is to reposition the tape to the file/record position prior
 * to the reset, then retry the operation.
 *
 * Inputs:	dip = The device information pointer.
 *
 * Return Value:
 *		TRUE/FALSE = Retry Operation/Error the Request.
 *
 */
bool
HandleTapeResets(struct dinfo *dip)
{
	int status;
	int fd = dip->di_fd;
	struct mtget mtget, *mt;
	int saved_errno;
	u_long fileno, files, records;

	if (dip->di_proc_eei) {
	    mt = &mtget;
	    memset(mt, '\0', sizeof(*mt));
	} else {
	    mt = dip->di_mt;
	}
	saved_errno = errno;
	status = get_eei_status(fd, mt);
	if (status != ESUCCESS) {
	    errno = saved_errno;
	    return (FALSE);
	}

	if (dip->di_mode == READ_MODE) {
	    files = dip->di_files_read;
	    records = dip->di_records_read;
	} else {
	    files = dip->di_files_written;
	    records = dip->di_records_written;
	}
	if (dip->di_proc_eei) {
	    if (debug_flag) print_mtstatus(fd, mt, FALSE);
	    /*
	     * See if we should retry this EEI status.
	     */
	    if ( is_StatusRetryable(dip, &mt->eei) ) {
		if (dip->di_eei_retries-- == 0) {
		    dip->di_eei_retries = EEI_RETRIES;
		    return (FALSE);		/* Exhausted retries. */
		}
		if (verbose_flag) {
		    Printf("Retry %d after %s status...\n",
			    (EEI_RETRIES - dip->di_eei_retries),
			    cdbg_EEIStatus(mt->eei.status, CDBG_BRIEF));
		}
		(void)sleep(dip->di_eei_sleep);
		return (TRUE);		/* Retry please! */
	    } else if ( is_ResetCondition(dip, &mt->eei) ) {
		return (FALSE);		/* Don't retry. */
	    } else {
		if (!debug_flag) print_mtstatus(fd, mt, TRUE);
		return (FALSE);		/* Don't retry. */
	    }
	}

	if ( is_StatusRetryable(dip, &mt->eei) ) {
	    if (verbose_flag) {
		Printf("Retrying after %s status...\n",
				cdbg_EEIStatus(mt->eei.status, CDBG_BRIEF));
	    }
	    (void)sleep(dip->di_eei_sleep);
	    return (TRUE);
	} else if ( !is_ResetCondition(dip, &mt->eei) ) {
	    print_mtstatus(fd, mt, TRUE);
	    return (FALSE);
	}

	dip->di_proc_eei = TRUE;		/* For recursion. */
	dip->di_eei_retries = EEI_RETRIES;

	if (verbose_flag) {
	    Printf("Processing reset condition (%s) - file %lu, record %lu\n",
				cdbg_EEIStatus(mt->eei.status, CDBG_BRIEF),
					mt->mt_fileno, mt->mt_blkno);
	}

	if (debug_flag) print_mtstatus(fd, mt, FALSE);

	/*
	 * When writing tape files, the last file mark gets written
	 * when closing the tape, so adjust file count appropriately.
	 */
	fileno = files;
	if ( (dip->di_mode == WRITE_MODE) &&
	     (files == file_limit) ) {
	    if (fileno) fileno--;
	}

	/*
	 * Sanity check the block and file counts.
	 */
	if (mt->mt_fileno != (fileno + mt_fileno)) {
	    /* NFG if the no-rewind device is used! */
	    Fprintf(
	"File count sanity check failed, mt_fileno = %ld, my count = %ld\n",
			mt->mt_fileno, (fileno + mt_fileno));
#if 0
	    return (FALSE);
#endif
	    /* Adjust and continue below... */
	    mt->mt_fileno = (fileno + mt_fileno);
	}

	/*
	 * ??? mt_blkno doesn't always match my counts ???
	 */
	if ( mt->mt_blkno != (records + mt_blkno) ) {
	    Fprintf(
	"Record count sanity check failed, mt_blkno = %ld, my count = %ld\n",
		mt->mt_blkno, (records + mt_blkno));
#if 0
	    return (FALSE);
#endif
	    /* Adjust and continue below... */
	    mt->mt_blkno = (records + mt_blkno);
	}

reposition:
	dip->di_reset_condition = FALSE;

#if defined(STEELOS)
    if (dip->di_devpath_failure) {
	dip->di_devpath_failure = FALSE;
	/* We terminate if we can't re-open the device. */
	(void) (*dip->di_funcs->tf_reopen_file)(dip, dip->di_oflags);
    } else {
	/*
	 * Rewind and reposition the tape.
	 */
	status = DoRewindTape(dip);
	if (status) {
	    if (dip->di_reset_condition) goto reposition;
	    dip->di_proc_eei = FALSE;
	    return (FALSE);
	}

	/*
	 * Bring the tape online, driver calls ctape_online(), to force
	 * auto-density selection to be done.  Otherwise, we may proceed
	 * with the wrong tape density.
	 */
	status = DoTapeOnline(dip);
	if (status) {
	    if (dip->di_reset_condition) goto reposition;
	    dip->di_proc_eei = FALSE;
	    return (FALSE);
	}
    }
#else /* !defined(STEELOS) */
	/*
	 * NOTE:  Re-open the tape (assumes we're using rewind device),
	 * and reposition the tape.  The re-open of the tape is necessary
	 * to clear state flags (CTAPE_UNIT_ATTEN_STATE & CTAPE_RESET_STATE)
	 * in the CAM tape driver.  If this is NOT done, the close function
	 * won't write file marks. [ Fixed in Steel, not earlier releases! ]
	 */
	(void) (*dip->di_funcs->tf_reopen_file)(dip, dip->di_oflags);
	/*
	 * NOTE: reopen of the tape also brings the tape online.
	 */
#endif /* !defined(STEELOS) */

	/*
	 * Finally, reposition to the correct file and block numbers.
	 */
	if (mt->mt_fileno) {
	    long fileno = mt->mt_fileno;
	    if (verbose_flag) {
		Printf("Positioning to file %lu...\n", fileno);
	    }
	    status = DoForwardSpaceFile(dip, fileno);
	    if (status) {
		if (dip->di_reset_condition) goto reposition;
		dip->di_proc_eei = FALSE;
		return (FALSE);
	    }
	}

	if (mt->mt_blkno) {
	    long record = MIN(mt->mt_blkno, records);
	    if (record) {
		if (verbose_flag) {
		    Printf("Positioning to record %lu...\n", record);
		}
		status = DoForwardSpaceRecord(dip, record);
		if (status) {
		    if (dip->di_reset_condition) goto reposition;
		    dip->di_proc_eei = FALSE;
		    return (FALSE);
		}
	    }
	}
	dip->di_proc_eei = FALSE;
	/*
	 * Don't need to clear EEI status here, since this function is
	 * called recursively when tape movement IOCTL errors occur.
	 */
	return (TRUE);
}

bool
is_ResetCondition(
	struct dinfo	*dip,
	DEV_EEI_STATUS	*eei )
{
    /*
     * For Reference:
     *
     *    EEI_DEVPATH_RESET == ( CAM_SCSI_BUS_RESET || ASCQ_PON_RESET
     *						    || ASCQ_POWER_ON
     *						    || ASCQ_BUS_RESET
     *						    || ASCQ_BDR_RESET
     *						    || ASCQ_FIRMWARE_REBOOT )
     *
     *    EEI_CNTBUSY_FAILURE == CAM_BUSY
     *
     * A status of CAM_BUSY indicates the SIM/HBA is in recovery,
     * and usually that recovery is the result of reset handling.
     * So in the case of tapes, we reposition on CAM_BUSY too.
     *
     * NOTE: CAM_BDR_SENT belongs with EEI_DEVPATH_RESET :-)
     */
    if ( (eei->status == EEI_DEVPATH_RESET)		||
	 (eei->status == EEI_CNTBUSY_FAILURE)		||
	 (eei->status == EEI_TAPE_POS_LOST)		||
	 (eei->arch.cam.cam_status == CAM_BDR_SENT)	) {
	dip->di_reset_condition = TRUE;
	(void) sleep (EEI_RESET);
	return (TRUE);
    } else if (eei->status == EEI_DEVSTATE_FAILURE) {
	struct all_req_sns_data *sdp;
	sdp = (struct all_req_sns_data *)&eei->arch.cam.scsi_sense;
	if ( (eei->flags & EEI_SCSI_SENSE_VALID) &&
	     (sdp->sns_key == ALL_UNIT_ATTEN) ) {
	    dip->di_reset_condition = TRUE;
	    return (TRUE);	/* Result of reset or power on. */
	}
    }
#if defined(STEELOS) && defined(MUNSA)
    /*
     * On Wave4, a we must catch path failures and attempt to re-open
     * the tape, so we:
     *
     *    1) the tape driver looks for another path (multi-pathing)
     *    2) DRD will find a new server for this tape device.
     *
     * Again, for reference, here's the EEI_DEVPATH_FAILURE mapping:
     *
     *    EEI_DEVPATH_FAILURE == ( CAM_PATH_INVALID	||
     *				   CAM_DEV_NOT_THERE	||
     *				   CAM_SEL_TIMEOUT	||
     *				   CAM_NO_HBA		||
     *				   CAM_LUN_INVALID	||
     *				   CAM_TID_INVALID	)
     *
     */
    if (eei->status == EEI_DEVPATH_FAILURE) {
	dip->di_devpath_failure = TRUE;
	dip->di_reset_condition = TRUE;
	return (TRUE);		/* Re-open to find next path. */
    }
#endif /* defined(STEELOS) && defined(MUNSA) */

    return (FALSE);
}

bool
is_StatusRetryable(
	struct dinfo	*dip,
	DEV_EEI_STATUS	*eei )
{
    /*
     * Personally, I'm starting to think using EEI status mappings
     * is problematic, since its' groupings are subjective, and the
     * actual underlying status codes are hidden, so confusing :-)
     *
     * For Reference:
     *
     *     EEI_DEVBUSY_FAILURE == SCSI_STAT_BUSY
     *
     *     EEI_ABORTIO_FAILURE == ( CAM_REQ_ABORTED || CAM_CMD_TIMEOUT )
     */
    if ( (eei->status == EEI_DEVBUSY_FAILURE) ||
	 (eei->status == EEI_ABORTIO_FAILURE) ) {
	return (TRUE);			/* Retry please! */
    } else if ( (eei->status == EEI_NO_STATUS) && dip->di_proc_eei) {
	/*
	 * Occasionally, while processing a reset condition on V4.0F, the
	 * first mtop (rewind) is error'ed out with no EEI status.  This is
	 * probably broken in the tape driver, but like any good application
	 * we must try our best to workaround these anomalies :-)
	 */
	return (TRUE);			/* Retry please! */
    }

    switch (eei->arch.cam.cam_status) {
	/*
	 * Most of these CAM status' are mapped to EEI_DEVBIO_FAILURE,
	 * but this grouping also contains status codes which should
	 * NOT be retried. (IMHO)
	 *
	 * At this time, EEI_DEVBIO_FAILURE also includes CAM_BDR_SENT
	 * which is used for Reset detection above :-)
	 */
	case CAM_SCSI_BUSY:		/* SCSI bus busy.		*/
	case CAM_CMD_TIMEOUT:		/* Command timeout.		*/
	case CAM_MSG_REJECT_REC:	/* Message reject received.	*/
	case CAM_UNCOR_PARITY:		/* Uncorrectable parity error.	*/
	case CAM_DATA_RUN_ERR:		/* Data overrun/underrun error.	*/
	case CAM_SEQUENCE_FAIL:		/* Target bus phase sequence.	*/
	case CAM_UNEXP_BUSFREE:		/* Unexpected BUS free.		*/
	/*
	 * This status is NOT retried for cluster systems, since this
	 * is the primary status code used to initiate service failover.
	 * [ Changed my mind... we should NOT normally get this error. ]
	 */
#if 0 /* !defined(MUNSA) */
	case CAM_SEL_TIMEOUT:		/* Target selection timeout.	*/
#endif /* !defined(MUNSA) */
	    return (TRUE);		/* Retry these please! */

	default:
	    return (FALSE);		/* Don't retry. */
    }
}

/*
 * Check for retryable EEI status on non-open tape device.
 */
bool
check_eei_status(struct dinfo *dip, bool retry)
{
	struct mtget mt;
	char *file = dip->di_dname;
	int oflags = (dip->di_oflags | O_NONBLOCK);
	int fd, status;
	int saved_errno = errno;

	if (debug_flag) {
	    Printf (
		"Attempting to open %s file '%s', open flags = %#o...\n",
			(dip->di_ftype == INPUT_FILE) ? "input" : "output",
								file, oflags);
	}

	if ( (fd = open (file, oflags)) == FAILURE) {
	    report_error ("check_eei_status open", FALSE);
	    errno = saved_errno;
	    return (FALSE);
	}

	status = get_eei_status(fd, &mt);
	if (status != ESUCCESS) {
	    (void) close (fd);
	    errno = saved_errno;
	    return (FALSE);
	}

	if (debug_flag) print_mtstatus(fd, &mt, FALSE);

	(void) close (fd);
	errno = saved_errno;

	if (!retry) return (FALSE);

	if ( is_ResetCondition(dip, &mt.eei) ||
	     is_StatusRetryable(dip, &mt.eei) ) {
	    return (TRUE);
	} else {
	    return (FALSE);
	}
}

/*
 * Clear Tape EEI Status - Necessary since EEI is persistent.
 */
void
clear_eei_status(int fd, bool startup)
{
	struct mtget mt;
	int status;

	if (debug_flag) Printf("Clearing EEI data...\n");

	if ( get_eei_status(fd, &mt) != ESUCCESS) return;

	if (debug_flag) print_mtstatus(fd, &mt, FALSE);

	if (startup) {
	    /*
	     * blkno/fileno == -1 when invalid!
	     */
	    if ( (mt_blkno = mt.mt_blkno) < 0L) {
		mt_blkno = 0L;
	    }
	    if ( (mt_fileno = mt.mt_fileno) < 0L) {
		mt_fileno = 0L;
	    }
	}
	return;
}

int
get_eei_status(int fd, struct mtget *mt)
{
	int status;

	if ( (status = ioctl(fd, MTIOCGET, (char *)mt)) < 0) {
	    report_error ("MTIOCGET failed", FALSE);
	}
	return (status);
}

/*
 * Print out tape status based on deviocget and mtiocget.
 */
void
print_mtstatus(int fd, struct mtget *mt, bool print_all)
{
	/*
	 * When processing EEI Reset requests, we do not display
	 * the DEVIOCGET or DEVGETINFO, since these IOCTL's issue
	 * SCSI commands which can interfere with our recovery.
	 * [ Driver does Mode Sense to determine current density ]
	 */
	if ( print_all ) {
	    print_devio(fd);
	}
	print_mtio(fd, mt);
}

/*
 * Display the contents of the mtget struct.
 * Args: fd a file descriptor of the already opened tape device.
 */
void
print_mtio(int fd, struct mtget *mt)
{
	Fprint("\n");
	Fprint("MTIOCGET ELEMENT        CONTENTS\n");
	Fprint("----------------        --------\n");
	Fprint("mt_type                 ");
	switch(mt->mt_type) {
	case MT_ISTS:
		Fprint("MT_ISTS\n");
		break;
	case MT_ISHT:
		Fprint("MT_ISHT\n");
		break;
	case MT_ISTM:
		Fprint("MT_ISTM\n");
		break;
	case MT_ISMT:
		Fprint("MT_ISMT\n");
		break;
	case MT_ISUT:
		Fprint("MT_ISUT\n");
		break;
	case MT_ISTMSCP:
		Fprint("MT_ISTMSCP\n");
		break;
	case MT_ISST:
		Fprint("MT_ISST\n");
		break;
	case MT_ISSCSI:
		Fprint("MT_ISSCSI\n");
		break;
	default:
		Fprint("Unknown mt_type = 0x%x\n", mt->mt_type);
	}

	if ( mt->mt_type != MT_ISSCSI ) {
		Fprint("mt_dsreg                0x%X\n", mt->mt_dsreg);
		Fprint("mt_erreg                0x%X\n\n", mt->mt_erreg);
		Fprint("mt_resid                %d\n", mt->mt_resid);
		return;
	}

	/*
	 * The rest deals with functionality built into the SCSI tape
	 * driver which does not exist in TMSCP.
	 */

	Fprint("mt_dsreg                0x%X\n", mt->mt_dsreg);
	if (mt->mt_dsreg)
		print_stat(mt->mt_dsreg);
	Fprint("mt_erreg                0x%X ", mt->mt_erreg);
	print_erreg(mt->mt_erreg);
	Fprint("mt_resid                %d\n", mt->mt_resid);
	Fprint("mt_fileno               %ld %s\n",
		mt->mt_fileno, (mt->mt_fileno < 0L) ? "(invalid)" : "");
	Fprint("mt_blkno                %ld %s\n",
		mt->mt_blkno, (mt->mt_blkno < 0L) ? "(invalid)" : "");

	/*
	 * Display the Extended Error Information (EEI) Status.
	 */
	print_eei(&mt->eei);
	Fprint("\n");
	return;
}

#if defined(ZULUOS)

void print_status( v1_device_info_t *p_info );

/*
 * Display the contents of the device_info struct.
 * Args: fd a file descriptor of the already opened tape device.
 */
void
print_devio(int fd)
{
	int			status;
	device_info_t		devinfo;
	v1_device_info_t	*p_info;

	/*
	 *  Attempt to use preferred DEVGETINFO, if it fails: use DEVIOCGET
	 */
	status = ioctl( fd, DEVGETINFO, &devinfo );
	if ( status || ( devinfo.version != VERSION_1 ) ) {
	    struct devget devget;

	    status = ioctl( fd, DEVIOCGET, (void *)&devget );
	    if( status ) {
		report_error ("DEVIOCGET failed", FALSE);
		return;
	    }
	    devio_2_devgetinfo( &devget, &devinfo );
	}
	/*
	 *  At this point we have a valid devinfo struct
	 */
	p_info = &devinfo.v1;

	/*
	 * We keep the "status" information EXACTLY the same as before
	 * as there are most likely are user entities outthere that parse
	 * the "status" output. We'll follow the normal output with the
	 * additional devgetinfo information, if applicable.
	 */
	Fprint( "\n" );
	Fprint( "DEVIOGET ELEMENT       CONTENTS\n" );
	Fprint( "----------------       --------\n" );
	Fprint( "category               " );
	switch( p_info->category ) {

	    case  DEV_TAPE :
		Fprint( "DEV_TAPE\n" );
		break;
	    case  DEV_DISK :
		Fprint( "DEV_DISK\n" );
		break;
	    case  DEV_TERMINAL :
		Fprint( "DEV_TERMINAL\n" );
		break;
	    case  DEV_PRINTER :
		Fprint( "DEV_PRINTER\n" );
		break;
	    case  DEV_SPECIAL :
		Fprint( "DEV_SPECIAL\n" );
		break;
	    default :
		Fprint( "UNDEFINED VALUE (0x%x)\n", p_info->category );
		break;
	}
	Fprint( "bus                    " );
	switch( p_info->bus ) {

	    case  DEV_UB :
		Fprint( "DEV_UB\n" );
		break;
	    case  DEV_QB :
		Fprint( "DEV_QB\n" );
		break;
	    case  DEV_MB :
		Fprint( "DEV_MB\n" );
		break;
	    case  DEV_BI :
		Fprint( "DEV_BI\n" );
		break;
	    case  DEV_CI :
		Fprint( "DEV_CI\n" );
		break;
	    case  DEV_NB :
		Fprint( "DEV_NB\n" );
		break;
	    case  DEV_MSI :
		Fprint( "DEV_MSI\n" );
		break;
	    case  DEV_SCSI :
		Fprint( "DEV_SCSI\n" );
		break;
	    case  DEV_UNKBUS :
		Fprint( "DEV_UNKBUS\n" );
		break;
	    default :
		Fprint( "UNDEFINED VALUE (0x%x)\n", p_info->bus );
		break;
	}
	Fprint( "interface              %s\n", p_info->interface );
	Fprint( "device                 %s\n", p_info->device );
	Fprint( "adpt_num               %d\n", p_info->businfo.adpt_num );
	Fprint( "nexus_num              %d\n", p_info->businfo.nexus_num );
	Fprint( "bus_num                %d\n", p_info->businfo.bus_num );
	Fprint( "ctlr_num               %d\n", p_info->businfo.ctlr_num );
	Fprint( "slave_num              %d\n", p_info->businfo.slave_num );
	Fprint( "dev_name               %s\n", p_info->dev_name );
	Fprint( "unit_num               %d\n", p_info->businfo.unit_num );
	Fprint( "soft_count             %u\n", p_info->soft_count );
	Fprint( "hard_count             %u\n", p_info->hard_count );
	/*
	 *  New info status fields:
	 */
	print_status( p_info );
	return;
}

/*
 *  Dissect the status field of the device_info struct
 */
void
print_status( v1_device_info_t *p_info )
{
    v1_disk_dev_info_t	*p_disk;
    v1_tape_dev_info_t	*p_tape;

    switch( p_info->category ) {

      case  DEV_DISK :
        p_disk = &p_info->devinfo.disk;
        if( !p_disk->status ) {
            break;
	}
	Fprint( "\n" );
        Fprint( "DEVGETINFO ELEMENT      CONTENTS\n" );
        Fprint( "------------------      --------\n" );
        Fprint( "status                  0x%x\n", p_disk->status );
        if( p_disk->status ) {
            Fprint( "                        " );
            if( p_disk->status & DKDEV_OFFLINE )
                Fprint( "OFFLINE " );
            if( p_disk->status & DKDEV_WRTPROT )
                Fprint( "WRTPROT " );
            if( p_disk->status & DKDEV_RDONLY )
                Fprint( "RDONLY " );
            if( p_disk->status & DKDEV_REMOVABLE )
                Fprint( "REMOVABLE " );
            if( p_disk->status & DKDEV_REMOVABLE )
                Fprint( "REMOVABLE " );
	}
        Fprint( "part_num                %d\n", p_disk->part_num );
        Fprint( "media_changes           %d\n", p_disk->media_changes );
        Fprint( "class                   %s\n", p_disk->class==DKDEV_CLS_FLPY_GENERIC ? "GENERIC"
                                              : p_disk->class==DKDEV_CLS_FLPY_3_DD2S ? "3_DD2S"
                                              : p_disk->class==DKDEV_CLS_FLPY_3_HD2S ? "3_HD2S"
                                              : p_disk->class==DKDEV_CLS_FLPY_3_ED2S ? "3_ED2S"
                                              : p_disk->class==DKDEV_CLS_FLPY_5_LD2S ? "5_LD2S"
                                              : p_disk->class==DKDEV_CLS_FLPY_5_DD1S ? "5_DD1S"
                                              : p_disk->class==DKDEV_CLS_FLPY_5_DD2S ? "5_DD2S"
                                              : p_disk->class==DKDEV_CLS_FLPY_5_HD2S ? "5_HD2S"
                                              : "<unrecognized>" );
        break;

      case  DEV_TAPE :
        p_tape = &p_info->devinfo.tape;
        if ( !p_tape->unit_status && !p_tape->media_status ) {
            break;
	}
        Fprint( "\n" );
        Fprint( "DEVGETINFO ELEMENT      CONTENTS\n");
        Fprint( "------------------      --------\n");
        Fprint( "media_status            0x%x\n", p_tape->media_status );
        if( p_tape->media_status ) {
            Fprint( "                        " );
            if( p_tape->media_status & TPDEV_BOM )
                Fprint( "BOM " );
            if( p_tape->media_status & TPDEV_EOM )
                Fprint( "EOM " );
            if( p_tape->media_status & TPDEV_WRTPROT )
                Fprint( "WrtProt " );
            if( p_tape->media_status & TPDEV_BLANK )
                Fprint( "Blank " );
            if( p_tape->media_status & TPDEV_WRITTEN )
                Fprint( "Written " );
            if( p_tape->media_status & TPDEV_SOFTERR )
                Fprint( "SoftERR " );
            if( p_tape->media_status & TPDEV_HARDERR )
                Fprint( "HardERR " );
            if( p_tape->media_status & TPDEV_DONE )
                Fprint( "Done " );
            if( p_tape->media_status & TPDEV_RETRY )
                Fprint( "Retry " );
            if( p_tape->media_status & TPDEV_ERASED )
                Fprint( "Erased " );
            if( p_tape->media_status & TPDEV_TPMARK )
                Fprint( "TPmark " );
            if( p_tape->media_status & TPDEV_SHRTREC )
                Fprint( "ShortRec " );
            if( p_tape->media_status & TPDEV_RDOPP )
                Fprint( "RD_Opposite " );
            if( p_tape->media_status & TPDEV_RWDING )
                Fprint( "Rewinding " );
            if( p_tape->media_status & TPDEV_POS_VALID )
                Fprint( "POS_VALID " );
            Fprint( "\n" );
	}
        Fprint( "unit_status             0x%x\n", p_tape->unit_status );
        if( p_tape->unit_status ) {
            Fprint( "                        " );
            if( p_tape->unit_status & TPDEV_READY )
                Fprint( "Ready " );
              else
                Fprint( "Offline " );
            if( p_tape->unit_status & TPDEV_NO_EOM )
                Fprint( "No_EOM_Warn " );
            if( p_tape->unit_status & TPDEV_HAS_LOADER )
                Fprint( "Loader " );
            if( p_tape->unit_status & TPDEV_1FM_ONCLOSE )
                Fprint( "1_FM_Close " );
              else
                Fprint( "2_FM_Close " );
            if( p_tape->unit_status & TPDEV_REW_ONCLOSE )
                Fprint( "Rewind " );
              else
                Fprint( "NO_Rewind " );
            if( p_tape->unit_status & TPDEV_COMPACTING )
                Fprint( "Compacting " );
            if( p_tape->unit_status & TPDEV_COMPRESSING )
                Fprint( "Compacting " );
            if( p_tape->unit_status & TPDEV_BUFFERED )
                Fprint( "Buffered " );
            Fprint( "\n" );
	}
        Fprint( "record_size             %ld\n", p_tape->recordsz );
        Fprint( "density (current)       %ld BPI\n", p_tape->density_bpi );
        Fprint( "density (on write)      %ld BPI\n", p_tape->density_bpi_wrt );
        if( p_tape->media_status & TPDEV_POS_VALID ) {
            Fprint( "Filemark Cnt            %ld\n", p_tape->fm_cnt );
            Fprint( "Record Cnt              %ld\n", p_tape->position );
	} else {
            Fprint( "Filemark Cnt            <Not Valid>\n" );
            Fprint( "Record Cnt              <Not Valid>\n" );
	}
        Fprint( "Class                   %d - ", ((int )p_tape->class ) & 0xFF );
        switch( p_tape->class ) {
          case  TPDEV_CLS_DLT :
            Fprint( "DLT (tk )\n" );
            break;
          case  TPDEV_CLS_RDAT :
            Fprint( "RDAT\n" );
            break;
          case  TPDEV_CLS_9TRK :
            Fprint( "9TRK\n" );
            break;
          case  TPDEV_CLS_QIC :
            Fprint( "QIC\n" );
            break;
          case  TPDEV_CLS_8MM :
            Fprint( "8MM\n" );
            break;
          case  TPDEV_CLS_3480 :
            Fprint( "3480\n" );
            break;
          case  TPDEV_CLS_UNKNOWN :
            Fprint( "<unspecified>\n" );
            break;
          default :
            Fprint( "<unrecognized>\n" );
            break;
	}
        break;
    }
    return;
}

#else /* !defined(ZULUOS) */

/*
 * Display the contents of the deviocget struct.
 * Args: fd a file descriptor of the already opened tape device.
 */
void
print_devio(int fd)
{
	struct devget	devinf;
	device_info_t	*devinfop;

	/*
	 * First, attempt to use the DEVGETINFO ioctl (preferred),
	 * if that fails, try the backward-compatibility ioctl
	 * DEVIOCGET.
	 */

	/* malloc this as this is a large structure */
	devinfop = (device_info_t *)malloc(sizeof(device_info_t));

	if (!(devinfop) || 
		(ioctl(fd, DEVGETINFO, (char *)devinfop) < 0) ||
		(devinfop->version != VERSION_1) || /* what a joke! */
		(devgetinfo_2_devio(devinfop, &devinf) != ESUCCESS)) {

		/* DEVGETINFO failure */
		if (devinfop)
			free(devinfop);
		devinfop = (device_info_t *)NULL;

		if (ioctl(fd, DEVIOCGET, (char *)&devinf) < 0) {
			report_error ("DEVIOCGET failed", FALSE);
			return;
		}
	}
	/*
	 * at this point we have a valid devinf struct and possibly
	 * a valid device_info struct.
	 */

	/*
	 * We keep the "status" information EXACTLY the same as before
	 * as there are most likely are user entities outthere that parse
	 * the "status" output. We'll follow the normal output with the
	 * additional devgetinfo information, if applicable.
	 */

	Fprint("\n");
	Fprint("DEVIOGET ELEMENT        CONTENTS\n");
	Fprint("----------------        --------\n");
	Fprint("category                ");
	switch(devinf.category) {
	    case DEV_TAPE:
		Fprint("DEV_TAPE\n");
		break;
	    case DEV_DISK:
		Fprint("DEV_DISK\n");
		break;
	    case DEV_TERMINAL:
		Fprint("DEV_TERMINAL\n");
		break;
	    case DEV_PRINTER:
		Fprint("DEV_PRINTER\n");
		break;
	    case DEV_SPECIAL:
		Fprint("DEV_SPECIAL\n");
		break;
	    default:
		Fprint("UNDEFINED VALUE (0x%x)\n", devinf.category);
		break;
	}
	Fprint("bus                     ");
	switch(devinf.bus) {
	    case DEV_UB:
		Fprint("DEV_UB\n");
		break;
	    case DEV_QB:
		Fprint("DEV_QB\n");
		break;
	    case DEV_MB:
		Fprint("DEV_MB\n");
		break;
	    case DEV_BI:
		Fprint("DEV_BI\n");
		break;
	    case DEV_CI:
		Fprint("DEV_CI\n");
		break;
	    case DEV_NB:
		Fprint("DEV_NB\n");
		break;
	    case DEV_MSI:
		Fprint("DEV_MSI\n");
		break;
	    case DEV_SCSI:
		Fprint("DEV_SCSI\n");
		break;
	    case DEV_UNKBUS:
		Fprint("DEV_UNKBUS\n");
		break;
	    default:
		Fprint("UNDEFINED VALUE (0x%x)\n", devinf.bus);
		break;
	}
	Fprint("interface               %s\n", devinf.interface);
	Fprint("device                  %s\n", devinf.device);
	Fprint("adpt_num                %d\n", devinf.adpt_num);
	Fprint("nexus_num               %d\n", devinf.nexus_num);
	Fprint("bus_num                 %d\n", devinf.bus_num);
	Fprint("ctlr_num                %d\n", devinf.ctlr_num);
	Fprint("slave_num               %d\n", devinf.slave_num);
	Fprint("dev_name                %s\n", devinf.dev_name);
	Fprint("unit_num                %d\n", devinf.unit_num);
	Fprint("soft_count              %u\n", devinf.soft_count);
	Fprint("hard_count              %u\n", devinf.hard_count);
	Fprint("stat                    0x%X\n", devinf.stat);
	if (devinf.stat) print_stat(devinf.stat);
	Fprint("category_stat           0x%X\n", devinf.category_stat);
	if (devinf.category_stat) print_category(devinf.category_stat,devinfop);

	/* now print any additional DEVGETINFO data */
	if (devinfop) {
		v1_tape_dev_info_t *tapep;

		tapep = (v1_tape_dev_info_t *)&devinfop->v1.devinfo;

		Fprint("\n");
		Fprint("DEVGETINFO ELEMENT      CONTENTS\n");
		Fprint("------------------      --------\n");
		Fprint("media_status            0x%x\n", tapep->media_status);
		if (tapep->media_status) {
		    Fprint("                        ");
		    if (tapep->media_status & TPDEV_BOM)
			Fprint("BOM ");
		    if (tapep->media_status & TPDEV_EOM)
			Fprint("EOM ");
		    if (tapep->media_status & TPDEV_WRTPROT)
			Fprint("WrtProt ");
		    if (tapep->media_status & TPDEV_BLANK)
			Fprint("Blank ");
		    if (tapep->media_status & TPDEV_WRITTEN)
			Fprint("Written ");
		    if (tapep->media_status & TPDEV_SOFTERR)
			Fprint("SoftERR ");
		    if (tapep->media_status & TPDEV_HARDERR)
			Fprint("HardERR ");
		    if (tapep->media_status & TPDEV_DONE)
			Fprint("Done ");
		    if (tapep->media_status & TPDEV_RETRY)
			Fprint("Retry ");
		    if (tapep->media_status & TPDEV_ERASED)
			Fprint("Erased ");
		    if (tapep->media_status & TPDEV_TPMARK)
			Fprint("TPmark ");
		    if (tapep->media_status & TPDEV_SHRTREC)
			Fprint("ShortRec ");
		    if (tapep->media_status & TPDEV_RDOPP)
			Fprint("RD_Opposite ");
		    if (tapep->media_status & TPDEV_RWDING)
			Fprint("Rewinding ");
		    if (tapep->media_status & TPDEV_POS_VALID)
			Fprint("POS_VALID ");
		    Fprint("\n");
		}
		Fprint("unit_status             0x%x\n", tapep->unit_status);
		if (tapep->unit_status) {
		    Fprint("                        ");
		    if (tapep->unit_status & TPDEV_READY)
			Fprint("Ready ");
		    else
			Fprint("Offline ");
		    if (tapep->unit_status & TPDEV_NO_EOM)
			Fprint("No_EOM_Warn ");
		    if (tapep->unit_status & TPDEV_HAS_LOADER)
			Fprint("Loader ");
		    if (tapep->unit_status & TPDEV_1FM_ONCLOSE)
			Fprint("1_FM_Close ");
		    else
			Fprint("2_FM_Close ");
		    if (tapep->unit_status & TPDEV_REW_ONCLOSE)
			Fprint("Rewind ");
		    else
			Fprint("NO_Rewind ");
		    if (tapep->unit_status & TPDEV_COMPACTING)
			Fprint("Compacting ");
		    if (tapep->unit_status & TPDEV_COMPRESSING)
			Fprint("Compacting ");
		    if (tapep->unit_status & TPDEV_BUFFERED)
			Fprint("Buffered ");
		    Fprint("\n");
		}
		Fprint("record_size             %ld\n", tapep->recordsz);
		Fprint("density (current)       %ld BPI\n", tapep->density_bpi);
		Fprint("density (on write)      %ld BPI\n", tapep->density_bpi_wrt);
		if (tapep->media_status & TPDEV_POS_VALID) {
			Fprint("Filemark Cnt            %ld\n", tapep->fm_cnt);
			Fprint("Record Cnt              %ld\n", tapep->position);
		} else {
			Fprint("Filemark Cnt            %s\n", not_valid_str);
			Fprint("Record Cnt              %s\n", not_valid_str);
		}
		Fprint("Class                   %d - ", ((int)tapep->class) & 0xFF);
		switch (tapep->class) {
		case TPDEV_CLS_DLT:
			Fprint("DLT (tk)\n");
			break;
		case TPDEV_CLS_RDAT:
			Fprint("RDAT\n");
			break;
		case TPDEV_CLS_9TRK:
			Fprint("9TRK\n");
			break;
		case TPDEV_CLS_QIC:
			Fprint("QIC\n");
			break;
		case TPDEV_CLS_8MM:
			Fprint("8MM\n");
			break;
		case TPDEV_CLS_3480:
			Fprint("3480\n");
			break;
		case TPDEV_CLS_UNKNOWN:
			Fprint("<unspecified>\n");
			break;
		default:
			Fprint("<unrecognized>\n");
			break;
		}
		free(devinfop);
	}
	return;
}

#endif /* defined(ZULUOS) */

/*
 * Decode and display the EEI status:
 */
void
print_eei(DEV_EEI_STATUS *eei)
{
	if (eei->version == 0) {
	    PrintAscii ("EEI Information", not_valid_str, PNL);
	    return;
	}
	Fprint("\nCAM Extended Error Information:\n\n");
	PrintHex ("EEI Version", eei->version, PNL);
	PrintAscii ("EEI Status", "", DNL);
	print_eei_status (eei->status);

	PrintHex ("EEI Valid Flags", eei->flags, DNL);
	Fprint (" - ");
	if (eei->flags & EEI_CAM_STATUS_VALID)
		Fprint ("CAM_STATUS ");
	if (eei->flags & EEI_SCSI_STATUS_VALID)
		Fprint ("SCSI_STATUS ");
	if (eei->flags & EEI_SCSI_SENSE_VALID)
		Fprint ("SCSI_SENSE ");
	if (eei->flags & EEI_CAM_DATA_VALID)
		Fprint ("CAM_DATA");
	Fprint("\n");

	PrintAscii ("CAM Status", "", DNL);
	if (eei->flags & EEI_CAM_STATUS_VALID) {
	    print_cam_status (eei->arch.cam.cam_status);
	} else {
	    Fprint ("%s\n", not_valid_str);
	}

	PrintAscii ("SCSI Status", "", DNL);
	if (eei->flags & EEI_SCSI_STATUS_VALID) {
	    print_scsi_status(eei->arch.cam.scsi_status);
	} else {
	    Fprint ("%s\n", not_valid_str);
	}

	if (eei->flags & EEI_SCSI_SENSE_VALID) {
	    print_sense_data (eei->arch.cam.scsi_sense);
	} else {
	    PrintAscii ("SCSI Sense Data", not_valid_str, PNL);
	}
}

/*
 * Dissect the mt_erreg field of the mtget structure
 */
void
print_erreg(short erreg)
{
	Fprint ("(%s)\n", cdbg_SenseKeyTable[erreg&0xF]);
	if (erreg & 0xE0) {	/* check these three flags */
		Fprint("\t\t\t");
		if (erreg & FILE_MARK)
			Fprint("FILE_MARK ");
		if (erreg & EOM)
			Fprint("EOM ");
		if (erreg & ILI)
			Fprint("ILI ");
		Fprint("\n");
	}
}

/*
 * Display the EEI status code:
 */
void
print_eei_status(u_int eei_status)
{
	Fprint ("%s (%#x) - %s\n",
		cdbg_EEIStatus(eei_status, CDBG_BRIEF),
		eei_status, cdbg_EEIStatus(eei_status, CDBG_FULL));
}

/*
 * Dissect the cam_status field of the mtget structure
 */
void
print_cam_status(u_int cam_status)
{
	Fprint ("%s (%#x) - %s\n",
		cdbg_CamStatus(cam_status, CDBG_BRIEF),
		cam_status, cdbg_CamStatus(cam_status, CDBG_FULL));
}

/*
 * Dissect the scsi_status field of the mtget structure
 */
void
print_scsi_status(u_char scsi_status)
{
	Fprint ("%s (%#x) - %s\n",
		cdbg_ScsiStatus(scsi_status, CDBG_BRIEF),
		scsi_status, cdbg_ScsiStatus(scsi_status, CDBG_FULL));
}

/*
 * Print the SCSI sense data.
 */
void
print_sense_data(u_char *scsi_sense_ptr)
{
	struct all_req_sns_data *sdp = (struct all_req_sns_data *) scsi_sense_ptr;
	int sense_length = (int) sdp->addition_len + 8;
	u_short ascq;
	u_int info;

	Fprint ("\nSCSI Request Sense Information:\n\n");
	PrintHex ("Error Code", sdp->error_code, DNL);
	if (sdp->error_code == ALL_IMED_ERR_CODE) {
	    Fprint (" (Current Error)\n");
	} else if (sdp->error_code == ALL_DEFER_ERR_CODE) {
	    Fprint (" (Deferred Error)\n");
	} else if (sdp->error_code == ALL_VENDOR_SPECIFIC) {
	    Fprint (" (Vendor Specific)\n");
	} else {
	    Fprint ("\n");
	}
	PrintHex ("Valid Bit", sdp->valid, DNL);
	Fprint ("%s\n", (sdp->valid) ? " (Information field is valid)" : "");
	PrintHex ("Segment Number", sdp->segment, PNL);
	PrintHex ("Sense Key", sdp->sns_key, DNL);
	Fprint (" (%s)\n", cdbg_SenseKeyTable[sdp->sns_key]);
	PrintHex ("Illegal Length", sdp->ili, PNL);
	PrintHex ("End Of Media", sdp->eom, PNL);
	PrintHex ("File Mark", sdp->filemark, PNL);
	info = (u_int)( ((u_int)sdp->info_byte3 << 24) +
			((u_int)sdp->info_byte2 << 16) +
			((u_int)sdp->info_byte1 << 8) +
			 (sdp->info_byte0) );
	PrintHex ("Information Field", info, (info) ? DNL : PNL);
	if (info) Fprint (" (%d)\n", info);
	PrintHex ("Additional Sense Length", sdp->addition_len, PNL);

	if ( (sense_length -= 8) > 0) {
	    info = (u_int)( ((u_int)sdp->cmd_specific3 << 24) +
			    ((u_int)sdp->cmd_specific2 << 16) +
			    ((u_int)sdp->cmd_specific1 << 8) +
			     (sdp->cmd_specific0) );
	    PrintHex ("Command Specific Information", info, (info) ? DNL : PNL);
	    if (info) Fprint (" (%d)\n", info);
	    sense_length -= 4;
	}

	if (sense_length > 0) {
	    char *ascq_msg = cdbg_SenseMessage (sdp);
	    ASCQ_TO_USHORT (sdp, ascq);
	    PrintAscii ("Additional Sense Code/Qualifier", "", DNL);
	    Fprint ("(%#x, %#x) = %s\n", sdp->asc, sdp->asq,
					(ascq_msg) ? ascq_msg : "Unknown");
	    sense_length -= 2;
	}

	if (sense_length-- > 0) {
	    PrintHex ("Field Replaceable Unit Code", sdp->fru, PNL);
	}

	/*
	 * Sense specific sense data.
	 */
	if (sense_length > 0) {
	    struct all_sks_ill_req *sksi;
	    sksi = &sdp->sense_specific.sks_ill_req;
	    if (sksi->sksv && (sdp->sns_key == ALL_ILLEGAL_REQ) ) {
		u_short field_ptr = ((sksi->field_ptr1 << 8) + sksi->field_ptr0);
		PrintHex ("Bit Pointer to Field in Error", sksi->bit_pointer,
					(sksi->bit_pointer) ? DNL : PNL);
		if (sksi->bpv) {
		    Fprint (" (valid, bit %u)\n", (sksi->bit_pointer + 1));
		}
		PrintHex ("Error Field Command/Data (C/D)", sksi->c_or_d, DNL);
		Fprint (" (%s)\n", (sksi->c_or_d) ? "Illegal parameter in CDB bytes"
						  : "Illegal parameter in Data Sent");
		PrintHex ("Byte Pointer to Field in Error", field_ptr,
						(field_ptr) ? DNL : PNL);
		if (field_ptr) {
		    Fprint (" (byte %u)\n", (field_ptr + 1)); /* zero-based */
		}
		sense_length -= sizeof(*sksi);
	    } else if (sksi->sksv && ( (sdp->sns_key == ALL_RECOVER_ERR) ||
				       (sdp->sns_key == ALL_HARDWARE_ERR) ||
				       (sdp->sns_key == ALL_MEDIUM_ERR) ) ) {
		struct all_sks_retry_cnt *sksr;
		sksr = &sdp->sense_specific.sks_retry_cnt;
		PrintHex ("Actual Retry Count",
			    ((sksr->retry_cnt1 << 8) + sksr->retry_cnt0), PNL);
		sense_length -= sizeof(*sksr);
	    } else if (sksi->sksv && (sdp->sns_key == ALL_NOT_READY) &&
				     (ascq == ASCQ_LUN_NRDY_FMT) ) {
		u_short progress;
		struct all_sks_prog_cnt *sksp;
		sksp = &sdp->sense_specific.sks_prog_cnt;
		progress = ((sksp->progress1 << 8) + sksp->progress0);
		PrintDecimal ("Format Progress Indication", progress, DNL);
		/*Fprint (" (%d%% complete)\n", FormatProgress(progress));*/
		sense_length -= sizeof(*sksp);
	    } else {
		PrintAscii ("Sense Specific Bytes", "", DNL);
		PrintFields ((u_char *) &sdp->sense_specific,
					sizeof(sdp->sense_specific));
		sense_length -= sizeof(sdp->sense_specific);
	    }
	}
	/*
	 * Additional sense bytes (if any);
	 */
	if (sense_length > 0) {
	    PrintAscii ("Additional Sense Bytes", "", DNL);
	    PrintFields ((u_char *)sdp->additional_sense.other_sns,
							sense_length);
	}
}

/*
 * Dissect the stat field of a devio structure
 *  or the mt_dsreg field of the mtget structure
 */
void
print_stat(long stat)
{
	Fprint("                        ");
	if (stat & DEV_BOM)
		Fprint("DEV_BOM ");
	if (stat & DEV_EOM)
		Fprint("DEV_EOM ");
	if (stat & DEV_OFFLINE)
		Fprint("DEV_OFFLINE ");
	if (stat & DEV_WRTLCK)
		Fprint("DEV_WRTLCK ");
	if (stat & DEV_BLANK)
		Fprint("DEV_BLANK ");
	if (stat & DEV_WRITTEN)
		Fprint("DEV_WRITTEN ");
	if (stat & DEV_CSE)
		Fprint("DEV_CSE ");
	if (stat & DEV_SOFTERR)
		Fprint("DEV_SOFTERR ");
	if (stat & DEV_HARDERR)
		Fprint("DEV_HARDERR ");
	if (stat & DEV_DONE)
		Fprint("DEV_DONE ");
	if (stat & DEV_RETRY)
		Fprint("DEV_RETRY ");
	if (stat & DEV_ERASED)
		Fprint("DEV_ERASED ");
#if defined(STEELOS)
	if (stat & DEV_TAPE_MARK)
		Fprint("TPMARK ");
	if (stat & DEV_SHORT_REC)
		Fprint("SHRTREC ");
	if (stat & DEV_TPMRK_PEND)
		Fprint("TPMARK_PENDING ");
	if (stat & DEV_REWINDING)
		Fprint("REWINDING ");
	if (stat & DEV_READ_OPP)
		Fprint("READING_OPPOSITE ");
#else /* !defined(STEELOS) */
	if (stat & CTAPE_TPMARK)
		Fprint("TPMARK ");
	if (stat & CTAPE_SHRTREC)
		Fprint("SHRTREC ");
	if (stat & CTAPE_TPMARK_PENDING)
		Fprint("TPMARK_PENDING ");
	if (stat & CTAPE_REWINDING)
		Fprint("REWINDING ");
#endif /* defined(STEELOS) */
	Fprint("\n");
}

/*
 * Dissect the category_stat field of a devio structure
 *
 * With the advent of the DEVGETINFO ioctl, we may get densities that are
 * unknown with the DEV_xxxBPI bitmasks. Thus, rather than simply
 * stating "unspecified density", if the devinfop exists and has a
 * non-zero density, we'll dummy up a DEV_xxxBPI name.
 */
void
print_category(long stat, device_info_t *devinfop)
{
	Fprint("                        ");
	if (stat & DEV_TPMARK)
		Fprint("DEV_TPMARK ");
	if (stat & DEV_SHRTREC)
		Fprint("DEV_SHRTREC ");
	if (stat & DEV_RDOPP)
		Fprint("DEV_RDOPP ");
	if (stat & DEV_RWDING)
		Fprint("DEV_RWDING ");
	if (stat & DEV_LOADER)
		Fprint("DEV_LOADER ");

	if (stat & DEV_800BPI) {
		Fprint("DEV_800BPI");
	} else if (stat & DEV_1600BPI) {
		Fprint("DEV_1600BPI");
	} else if (stat & DEV_6250BPI) {
		Fprint("DEV_6250BPI");
	} else if (stat & DEV_6666BPI) {
		Fprint("DEV_6666BPI");
	} else if (stat & DEV_10240BPI) {
		Fprint("DEV_10240BPI");
	} else if (stat & DEV_38000BPI) {
		Fprint("DEV_38000BPI");
#ifdef DEV_38000_CP
	} else if (stat & DEV_38000_CP) {
		Fprint("DEV_38000_CP");
	} else if (stat & DEV_76000BPI) {
		Fprint("DEV_76000BPI");
	} else if (stat & DEV_76000_CP) {
		Fprint("DEV_76000_CP");
#endif /* DEV_38000_CP */
	} else if (stat & DEV_8000_BPI) {
		Fprint("DEV_8000_BPI");
	} else if (stat & DEV_10000_BPI) {
		Fprint("DEV_10000_BPI");
	} else if (stat & DEV_16000_BPI) {
		Fprint("DEV_16000_BPI");
	} else if (stat & DEV_54000_BPI) {
		Fprint("DEV_54000_BPI");
	} else if (stat & DEV_61000_BPI) {
		Fprint ("DEV_61000_BPI");
	} else if (stat & DEV_45434_BPI) {
		Fprint ("DEV_45434_BPI");
	} else if (stat & DEV_42500_BPI) {
		Fprint ("DEV_42500_BPI");
	} else if (stat & DEV_62500_BPI) {
		Fprint ("DEV_62500_BPI");
	} else if (stat & DEV_40640_BPI) {
		Fprint ("DEV_40640_BPI");
	} else if (stat & DEV_36000_BPI) {
		Fprint ("DEV_36000_BPI");
	} else if (stat & DEV_81630_BPI) {
		Fprint ("DEV_81630_BPI");
	} else {
		if (devinfop && devinfop->v1.devinfo.tape.density_bpi) {
			Fprint("DEV_%ld_%s",
				devinfop->v1.devinfo.tape.density_bpi,
				((devinfop->v1.devinfo.tape.unit_status &
					TPDEV_COMPACTING) ? "CP" : "BPI"));
		} else
			Fprint("<unspecified density>");
	}
	Fprint("\n");
}

/*
 * Strings used by Common Printing Functions.
 */
#define ASCII_FIELD	"%34.34s: %s"
#define EMPTY_FIELD	"%36.36s%s"
#define NUMERIC_FIELD	"%34.34s: %lu"
#define HEX_FIELD	"%34.34s: %#lx"
#define FIELD_WIDTH	36		/* The field width (see above).	*/
#define DEFAULT_WIDTH	80		/* Default tty display width.	*/

int OutputRadix = DEC_RADIX;		/* Default to decimal output.	*/

void
PrintNumeric (char *field_str, u_long numeric_value, int nl_flag)
{
	char *Fprint_str;

	if (OutputRadix == HEX_RADIX) {
		Fprint_str = HEX_FIELD;
	} else {
		Fprint_str = NUMERIC_FIELD;
	}
	Fprint (Fprint_str, field_str, numeric_value);
	if (nl_flag) Fprint ("\n");
}

void
PrintDecimal (char *field_str, u_long numeric_value, int nl_flag)
{
	char *Fprint_str = NUMERIC_FIELD;

	Fprint (Fprint_str, field_str, numeric_value);
	if (nl_flag) Fprint ("\n");
}

void
PrintHex (char *field_str, u_long numeric_value, int nl_flag)
{
	char *Fprint_str = HEX_FIELD;

	Fprint (Fprint_str, field_str, numeric_value);
	if (nl_flag) Fprint ("\n");
}

void
PrintAscii (char *field_str, char *ascii_str, int nl_flag)
{
	int length = strlen(field_str);
	char *Fprint_str = ((length) ? ASCII_FIELD : EMPTY_FIELD);

	Fprint (Fprint_str, field_str, ascii_str);
	if (nl_flag) Fprint ("\n");
}

void
PrintFields (u_char *bptr, int length)
{
	int field_entrys = ((DEFAULT_WIDTH - FIELD_WIDTH) / 3) - 1;
	int count = 0;

	while (count < length) {
	    if ((++count % field_entrys) == 0) {
		Fprint("%02x\n", *bptr++);
		if (count < length) PrintAscii("", "", DNL);
	    } else {
		Fprint ("%02x ", *bptr++);
	    }
	}
	if (count % field_entrys) Fprint("\n");
}

/*
 * CAM Status Code Table.
 */
struct CAM_StatusTable {
	u_char	cam_status;
	caddr_t	status_msg_brief;
	caddr_t	status_msg_full;
} cam_StatusTable[] = {
    {	CAM_REQ_INPROG,		"CAM_REQ_INPROG",
				"CCB request is in progress"		},
    {	CAM_REQ_CMP ,		"CAM_REQ_CMP",
				"CCB request completed w/out error"	},
    {	CAM_REQ_ABORTED,	"CAM_REQ_ABORTED",
				"CCB request aborted by the host"	},
    {	CAM_UA_ABORT,		"CAM_UA_ABORT",
				"Unable to Abort CCB request"		},
    {	CAM_REQ_CMP_ERR,	"CAM_REQ_CMP_ERR",
				"CCB request completed with an error"	},
    {	CAM_BUSY,		"CAM_BUSY",
				"CAM subsystem is busy"			},
    {	CAM_REQ_INVALID,	"CAM_REQ_INVALID",
				"CCB request is invalid"		},
    {	CAM_PATH_INVALID,	"CAM_PATH_INVALID",
				"ID supplied is invalid"		},
    {	CAM_DEV_NOT_THERE,	"CAM_DEV_NOT_THERE",
				"device not installed/there"		},
    {	CAM_UA_TERMIO,		"CAM_UA_TERMIO",
				"Unable to Terminate I/O CCB request"	},
    {	CAM_SEL_TIMEOUT,	"CAM_SEL_TIMEOUT",
				"Target selection timeout"		},
    {	CAM_CMD_TIMEOUT,	"CAM_CMD_TIMEOUT",
				"Command timed out",			},
    {	CAM_MSG_REJECT_REC,	"CAM_MSG_REJECT_REC",
				"reject received"			},
    {	CAM_SCSI_BUS_RESET,	"CAM_SCSI_BUS_RESET",
				"bus reset sent/received"		},
    {	CAM_UNCOR_PARITY,	"CAM_UNCOR_PARITY",
				"parity error occurred"			},
    {	CAM_AUTOSENSE_FAIL,	"CAM_AUTOSENSE_FAIL",
				"Request sense cmd fail"		},
    {	CAM_NO_HBA,		"CAM_NO_HBA",
				"No HBA detected Error"			},
    {	CAM_DATA_RUN_ERR,	"CAM_DATA_RUN_ERR",
				"overrun/underrun error"		},
    {	CAM_UNEXP_BUSFREE,	"CAM_UNEXP_BUSFREE",
				"Unexpected bus free"			},
    {	CAM_SEQUENCE_FAIL,	"CAM_SEQUENCE_FAIL",
				"bus phase sequence failure"		},
    {	CAM_CCB_LEN_ERR,	"CAM_CCB_LEN_ERR",
				"CCB length supplied is inadequate"	},
    {	CAM_PROVIDE_FAIL,	"CAM_PROVIDE_FAIL",
				"to provide requ. capability"		},
    {	CAM_BDR_SENT,		"CAM_BDR_SENT",
				"A SCSI BDR msg was sent to target"	},
    {	CAM_REQ_TERMIO,		"CAM_REQ_TERMIO",
				"CCB request terminated by the host"	},
    {	CAM_HBA_ERR,		"CAM_HBA_ERR",
				"Unrecoverable host bus adaptor error"	},
    {	CAM_BUS_RESET_DENIED,	"CAM_BUS_RESET_DENIED",
				"bus reset denied"			},
    {	CAM_MUNSA_REJECT,	"CAM_MUNSA_REJECT",
				"rejecting device"			},
    {	CAM_IDE,		"CAM_IDE",
				"Initiator Detected Error Received"	},
    {	CAM_RESRC_UNAVAIL,	"CAM_RESRC_UNAVAIL",
				"Resource unavailable"			},
    {	CAM_UNACKED_EVENT,	"CAM_UNACKED_EVENT",
				"Unacknowledged event by host"		},
    {	CAM_MESSAGE_RECV,	"CAM_MESSAGE_RECV",
				"Msg received in Host Target Mode"	},
    {	CAM_INVALID_CDB,	"CAM_INVALID_CDB",
				"Invalid CDB recvd in HT Mode"		},
    {	CAM_LUN_INVALID,	"CAM_LUN_INVALID",
				"LUN supplied is invalid"		},
    {	CAM_TID_INVALID,	"CAM_TID_INVALID",
				"Target ID supplied is invalid"		},
    {	CAM_FUNC_NOTAVAIL,	"CAM_FUNC_NOTAVAIL",
				"Requested function is not available"	},
    {	CAM_NO_NEXUS,		"CAM_NO_NEXUS",
				"Nexus is not established"		},
    {	CAM_IID_INVALID,	"CAM_IID_INVALID",
				"The initiator ID is invalid"		},
    {	CAM_CDB_RECVD,		"CAM_CDB_RECVD",
				"The SCSI CDB has been received"	},
    {	CAM_LUN_ALLREADY_ENAB,	"CAM_LUN_ALLREADY_ENAB",
				"LUN is already enabled"		},
    {	CAM_SCSI_BUSY,		"CAM_SCSI_BUSY",
				"SCSI bus busy"				}
};
static int cam_StatusEntrys =
		sizeof(cam_StatusTable) / sizeof(cam_StatusTable[0]);

char *
cdbg_CamStatus (u_char cam_status, int report_format)
{
	struct CAM_StatusTable *cst = cam_StatusTable;
	I32 entrys;

	for (entrys = 0; entrys < cam_StatusEntrys; cst++, entrys++) {
	    if (cst->cam_status == (cam_status&CAM_STATUS_MASK)) {
		if (report_format == CDBG_BRIEF) {
		    return (cst->status_msg_brief);
		} else {
		    return (cst->status_msg_full);
		}
	    }
	}
	return ((report_format) ? "Unknown CAM Status" : "Unknown");
}

/*
 * CAM Status Code Table.
 */
struct SCSI_StatusTable {
	u_char	scsi_status;
	caddr_t	status_msg_brief;
	caddr_t	status_msg_full;
} scsi_StatusTable[] = {
    {	SCSI_STAT_GOOD,			"SCSI_STAT_GOOD",
	/* 0x00 */ "Command successfully completed"		},
    {	SCSI_STAT_CHECK_CONDITION,	"SCSI_STAT_CHECK_CONDITION",
	/* 0x02 */ "Error, exception, or abnormal condition"	},
    {	SCSI_STAT_CONDITION_MET,	"SCSI_STAT_CONDITION_MET",
	/* 0x04 */ "Requested operation satisifed"		},
    {	SCSI_STAT_BUSY,			"SCSI_STAT_BUSY",
	/* 0x08 */ "Target is BUSY"				},
    {	SCSI_STAT_INTERMEDIATE,		"SCSI_STAT_INTERMEDIATE",
	/* 0x10 */ "Linked commands successfully completed"	},
    {	SCSI_STAT_INTER_COND_MET,	"SCSI_STAT_INTER_COND_MET",
	/* 0x14 */ "Intermediate-Condition met"			},
    {	SCSI_STAT_RESERVATION_CONFLICT,	"SCSI_STAT_RESERVATION_CONFLICT",
	/* 0x18 */ "Target reservation conflict"		},
    {	SCSI_STAT_COMMAND_TERMINATED,	"SCSI_STAT_COMMAND_TERMINATED",
	/* 0x22 */ "Command terminated by Terminate I/O Message"},
    {	SCSI_STAT_QUEUE_FULL,		"SCSI_STAT_QUEUE_FULL",
	/* 0x28 */ "Command tag queue is full"			}
};
static int scsi_StatusEntrys =
		sizeof(scsi_StatusTable) / sizeof(scsi_StatusTable[0]);

char *
cdbg_ScsiStatus (u_char scsi_status, int report_format)
{
	struct SCSI_StatusTable *cst = scsi_StatusTable;
	I32 entrys;

	for (entrys = 0; entrys < scsi_StatusEntrys; cst++, entrys++) {
	    if (cst->scsi_status == scsi_status) {
		if (report_format == CDBG_BRIEF) {
		    return (cst->status_msg_brief);
		} else {
		    return (cst->status_msg_full);
		}
	    }
	}
	return ((report_format) ? "Unknown SCSI Status" : "Unknown");
}

/*
 * Sense Key Error Table.
 */
char *cdbg_SenseKeyTable[] = {
	"NO SENSE - No error or no sense information",		/* 0x00 */
	"RECOVERED ERROR - Recovery action performed",		/* 0x01 */
	"NOT READY - Logical unit is NOT ready",		/* 0x02 */
	"MEDIUM ERROR - Nonrecoverable medium error",		/* 0x03 */
	"HARDWARE ERROR - Nonrecoverable hardware error",	/* 0x04 */
	"ILLEGAL REQUEST - Illegal request or CDB parameter",	/* 0x05 */
	"UNIT ATTENTION - Medium changed or target reset",	/* 0x06 */
	"DATA PROTECT - Data protected from this operation",	/* 0x07 */
	"BLANK CHECK - No-data condition occured",		/* 0x08 */
	"Vendor Specific",					/* 0x09 */
	"COPY ABORTED - Copy command was aborted",		/* 0x0a */
	"ABORTED COMMAND - Target aborted command",		/* 0x0b */
	"EQUAL - Search satisfied with equal comparison",	/* 0x0c */
	"VOLUME OVERFLOW - Physical end of media detected",	/* 0x0d */
	"MISCOMPARE - Source and medium data differ",		/* 0x0e */
	"RESERVED",						/* 0x0f */
};

/*
 * Sense Code/Qualifier Table:
 */
struct sense_entry SenseCodeTable[] = {
/*
                     Table 7-41: ASC and ASCQ Assignments
--------------------------------------------------------------------------

                 ASC AND ASCQ ASSIGNMENTS

      D          = Direct Access Device
       T         = Sequential Access Device
        L        = Printer Device
         P       = Processor Device
          W      = Write Once Read Multiple Device
           R     = Read Only (CD-ROM) Device
            S    = Scanner Device
             O   = Optical Memory Device
              M  = Media Changer Device
               C = Communication Device
     BYTE
   12    13     DTLPWRSOMC    DESCRIPTION
   --    --                   -------------------------------------------- */
{ 0x13, 0x00, /*D   W  O  */ "Address mark not found for data field" },
{ 0x12, 0x00, /*D   W  O  */ "Address mark not found for ID field" },
{ 0x00, 0x11, /*     R    */ "Audio play operation in progress" },
{ 0x00, 0x12, /*     R    */ "Audio play operation paused" },
{ 0x00, 0x14, /*     R    */ "Audio play operation stopped due to error" },
{ 0x00, 0x13, /*     R    */ "Audio play operation successfully completed" },
{ 0x00, 0x04, /* T    S   */ "Beginning-of-partition/medium detected" },
{ 0x14, 0x04, /* T        */ "Block sequence error" },
{ 0x30, 0x02, /*DT  WR O  */ "Cannot read medium - incompatible format" },
{ 0x30, 0x01, /*DT  WR O  */ "Cannot read medium - unknown format" },
{ 0x52, 0x00, /* T        */ "Cartridge fault" },
{ 0x3F, 0x02, /*DTLPWRSOMC*/ "Changed operating definition" },
{ 0x11, 0x06, /*    WR O  */ "Circ unrecovered error" },
{ 0x30, 0x03, /*DT        */ "Cleaning cartridge installed" },
{ 0x4A, 0x00, /*DTLPWRSOMC*/ "Command phase error" },
{ 0x2C, 0x00, /*DTLPWRSOMC*/ "Command sequence error" },
{ 0x2F, 0x00, /*DTLPWRSOMC*/ "Commands cleared by another initiator" },
{ 0x2B, 0x00, /*DTLPWRSO C*/ "Copy cannot execute since host cannot disconnect" },
{ 0x41, 0x00, /*D         */ "Data path failure (should use 40 nn)" },
{ 0x4B, 0x00, /*DTLPWRSOMC*/ "Data phase error" },
{ 0x11, 0x07, /*    W  O  */ "Data resychronization error" },
{ 0x16, 0x00, /*D   W  O  */ "Data synchronization mark error" },
{ 0x19, 0x00, /*D      O  */ "Defect list error" },
{ 0x19, 0x03, /*D      O  */ "Defect list error in grown list" },
{ 0x19, 0x02, /*D      O  */ "Defect list error in primary list" },
{ 0x19, 0x01, /*D      O  */ "Defect list not available" },
{ 0x1C, 0x00, /*D      O  */ "Defect list not found" },
{ 0x32, 0x01, /*D   W  O  */ "Defect list update failure" },
#if 0
{ 0x40, 0xNN, /*DTLPWRSOMC*/ "Diagnostic failure on component nn (80h-ffh)" },
#endif
{ 0x40, 0x00, /*DTLPWRSOMC*/ "Diagnostic failure on component 0 (80h-ffh)" },
{ 0x63, 0x00, /*     R    */ "End of user area encountered on this track" },
{ 0x00, 0x05, /* T    S   */ "End-of-data detected" },
{ 0x14, 0x03, /* T        */ "End-of-data not found" },
{ 0x00, 0x02, /* T    S   */ "End-of-partition/medium detected" },
{ 0x51, 0x00, /* T     O  */ "Erase failure" },
{ 0x0A, 0x00, /*DTLPWRSOMC*/ "Error log overflow" },
{ 0x11, 0x02, /*DT  W SO  */ "Error too long to correct" },
{ 0x03, 0x02, /* T        */ "Excessive write errors" },
{ 0x3B, 0x07, /*  L       */ "Failed to sense bottom-of-form" },
{ 0x3B, 0x06, /*  L       */ "Failed to sense top-of-form" },
{ 0x00, 0x01, /* T        */ "Filemark detected" },
{ 0x14, 0x02, /* T        */ "Filemark or setmark not found" },
{ 0x09, 0x02, /*    WR O  */ "Focus servo failure" },
{ 0x31, 0x01, /*D L    O  */ "Format command failed" },
{ 0x58, 0x00, /*       O  */ "Generation does not exist" },
{ 0x1C, 0x02, /*D      O  */ "Grown defect list not found" },
{ 0x00, 0x06, /*DTLPWRSOMC*/ "I/O process terminated" },
{ 0x10, 0x00, /*D   W  O  */ "Id CRC or ECC error" },
{ 0x22, 0x00, /*D         */ "Illegal function (should use 20 00, 24 00, or 26 00)" },
{ 0x64, 0x00, /*     R    */ "Illegal mode for this track" },
{ 0x28, 0x01, /*        M */ "Import or export element accessed" },
{ 0x30, 0x00, /*DT  WR OM */ "Incompatible medium installed" },
{ 0x11, 0x08, /* T        */ "Incomplete block read" },
{ 0x48, 0x00, /*DTLPWRSOMC*/ "Initiator detected error message received" },
{ 0x3F, 0x03, /*DTLPWRSOMC*/ "Inquiry data has changed" },
{ 0x44, 0x00, /*DTLPWRSOMC*/ "Internal target failure" },
{ 0x3D, 0x00, /*DTLPWRSOMC*/ "Invalid bits in identify message" },
{ 0x2C, 0x02, /*      S   */ "Invalid combination of windows specified" },
{ 0x20, 0x00, /*DTLPWRSOMC*/ "Invalid command operation code" },
{ 0x21, 0x01, /*        M */ "Invalid element address" },
{ 0x24, 0x00, /*DTLPWRSOMC*/ "Invalid field in CDB" },
{ 0x26, 0x00, /*DTLPWRSOMC*/ "Invalid field in parameter list" },
{ 0x49, 0x00, /*DTLPWRSOMC*/ "Invalid message error" },
{ 0x11, 0x05, /*    WR O  */ "L-ec uncorrectable error" },
{ 0x60, 0x00, /*      S   */ "Lamp failure" },
{ 0x5B, 0x02, /*DTLPWRSOM */ "Log counter at maximum" },
{ 0x5B, 0x00, /*DTLPWRSOM */ "Log exception" },
{ 0x5B, 0x03, /*DTLPWRSOM */ "Log list codes exhausted" },
{ 0x2A, 0x02, /*DTL WRSOMC*/ "Log parameters changed" },
{ 0x21, 0x00, /*DT  WR OM */ "Logical block address out of range" },
{ 0x08, 0x00, /*DTL WRSOMC*/ "Logical unit communication failure" },
{ 0x08, 0x02, /*DTL WRSOMC*/ "Logical unit communication parity error" },
{ 0x08, 0x01, /*DTL WRSOMC*/ "Logical unit communication time-out" },
{ 0x05, 0x00, /*DTL WRSOMC*/ "Logical unit does not respond to selection" },
{ 0x4C, 0x00, /*DTLPWRSOMC*/ "Logical unit failed self-configuration" },
{ 0x3E, 0x00, /*DTLPWRSOMC*/ "Logical unit has not self-configured yet" },
{ 0x04, 0x01, /*DTLPWRSOMC*/ "Logical unit is in process of becoming ready" },
{ 0x04, 0x00, /*DTLPWRSOMC*/ "Logical unit not ready, cause not reportable" },
{ 0x04, 0x04, /*DTL    O  */ "Logical unit not ready, format in progress" },
{ 0x04, 0x02, /*DTLPWRSOMC*/ "Logical unit not ready, initializing command required" },
{ 0x04, 0x03, /*DTLPWRSOMC*/ "Logical unit not ready, manual intervention required" },
{ 0x25, 0x00, /*DTLPWRSOMC*/ "Logical unit not supported" },
{ 0x15, 0x01, /*DTL WRSOM */ "Mechanical positioning error" },
{ 0x53, 0x00, /*DTL WRSOM */ "Media load or eject failed" },
{ 0x3B, 0x0D, /*        M */ "Medium destination element full" },
{ 0x31, 0x00, /*DT  W  O  */ "Medium format corrupted" },
{ 0x3A, 0x00, /*DTL WRSOM */ "Medium not present" },
{ 0x53, 0x02, /*DT  WR OM */ "Medium removal prevented" },
{ 0x3B, 0x0E, /*        M */ "Medium source element empty" },
{ 0x43, 0x00, /*DTLPWRSOMC*/ "Message error" },
{ 0x3F, 0x01, /*DTLPWRSOMC*/ "Microcode has been changed" },
{ 0x1D, 0x00, /*D   W  O  */ "Miscompare during verify operation" },
{ 0x11, 0x0A, /*DT     O  */ "Miscorrected error" },
{ 0x2A, 0x01, /*DTL WRSOMC*/ "Mode parameters changed" },
{ 0x07, 0x00, /*DTL WRSOM */ "Multiple peripheral devices selected" },
{ 0x11, 0x03, /*DT  W SO  */ "Multiple read errors" },
{ 0x00, 0x00, /*DTLPWRSOMC*/ "No additional sense information" },
{ 0x00, 0x15, /*     R    */ "No current audio status to return" },
{ 0x32, 0x00, /*D   W  O  */ "No defect spare location available" },
{ 0x11, 0x09, /* T        */ "No gap found" },
{ 0x01, 0x00, /*D   W  O  */ "No index/sector signal" },
{ 0x06, 0x00, /*D   WR OM */ "No reference position found" },
{ 0x02, 0x00, /*D   WR OM */ "No seek complete" },
{ 0x03, 0x01, /* T        */ "No write current" },
{ 0x28, 0x00, /*DTLPWRSOMC*/ "Not ready to ready transition (medium may have changed)" },
{ 0x5A, 0x01, /*DT  WR OM */ "Operator medium removal request" },
{ 0x5A, 0x00, /*DTLPWRSOM */ "Operator request or state change input (unspecified)" },
{ 0x5A, 0x03, /*DT  W  O  */ "Operator selected write permit" },
{ 0x5A, 0x02, /*DT  W  O  */ "Operator selected write protect" },
{ 0x61, 0x02, /*      S   */ "Out of focus" },
{ 0x4E, 0x00, /*DTLPWRSOMC*/ "Overlapped commands attempted" },
{ 0x2D, 0x00, /* T        */ "Overwrite error on update in place" },
{ 0x3B, 0x05, /*  L       */ "Paper jam" },
{ 0x1A, 0x00, /*DTLPWRSOMC*/ "Parameter list length error" },
{ 0x26, 0x01, /*DTLPWRSOMC*/ "Parameter not supported" },
{ 0x26, 0x02, /*DTLPWRSOMC*/ "Parameter value invalid" },
{ 0x2A, 0x00, /*DTL WRSOMC*/ "Parameters changed" },
{ 0x03, 0x00, /*DTL W SO  */ "Peripheral device write fault" },
{ 0x50, 0x02, /* T        */ "Position error related to timing" },
{ 0x3B, 0x0C, /*      S   */ "Position past beginning of medium" },
{ 0x3B, 0x0B, /*      S   */ "Position past end of medium" },
{ 0x15, 0x02, /*DT  WR O  */ "Positioning error detected by read of medium" },
{ 0x29, 0x00, /*DTLPWRSOMC*/ "Power on, reset, or bus device reset occurred" },
{ 0x42, 0x00, /*D         */ "Power-on or self-test failure (should use 40 nn)" },
{ 0x1C, 0x01, /*D      O  */ "Primary defect list not found" },
{ 0x40, 0x00, /*D         */ "Ram failure (should use 40 nn)" },
{ 0x15, 0x00, /*DTL WRSOM */ "Random positioning error" },
{ 0x3B, 0x0A, /*      S   */ "Read past beginning of medium" },
{ 0x3B, 0x09, /*      S   */ "Read past end of medium" },
{ 0x11, 0x01, /*DT  W SO  */ "Read retries exhausted" },
{ 0x14, 0x01, /*DT  WR O  */ "Record not found" },
{ 0x14, 0x00, /*DTL WRSO  */ "Recorded entity not found" },
{ 0x18, 0x02, /*D   WR O  */ "Recovered data - data auto-reallocated" },
{ 0x18, 0x05, /*D   WR O  */ "Recovered data - recommend reassignment" },
{ 0x17, 0x05, /*D   WR O  */ "Recovered data using previous sector ID" },
{ 0x18, 0x03, /*     R    */ "Recovered data with CIRC" },
{ 0x18, 0x01, /*D   WR O  */ "Recovered data with error correction and retries applied" },
{ 0x18, 0x00, /*DT  WR O  */ "Recovered data with error correction applied" },
{ 0x18, 0x04, /*     R    */ "Recovered data with LEC" },
{ 0x17, 0x03, /*DT  WR O  */ "Recovered data with negative head offset" },
{ 0x17, 0x00, /*DT  WRSO  */ "Recovered data with no error correction applied" },
{ 0x17, 0x02, /*DT  WR O  */ "Recovered data with positive head offset" },
{ 0x17, 0x01, /*DT  WRSO  */ "Recovered data with retries" },
{ 0x17, 0x04, /*    WR O  */ "Recovered data with retries and/or CIRC applied" },
{ 0x17, 0x06, /*D   W  O  */ "Recovered data without ECC - data auto-reallocated" },
{ 0x17, 0x07, /*D   W  O  */ "Recovered data without ECC - recommend reassignment" },
{ 0x1E, 0x00, /*D   W  O  */ "Recovered ID with ECC correction" },
{ 0x3B, 0x08, /* T        */ "Reposition error" },
{ 0x36, 0x00, /*  L       */ "Ribbon, ink, or toner failure" },
{ 0x37, 0x00, /*DTL WRSOMC*/ "Rounded parameter" },
{ 0x5C, 0x00, /*D      O  */ "Rpl status change" },
{ 0x39, 0x00, /*DTL WRSOMC*/ "Saving parameters not supported" },
{ 0x62, 0x00, /*      S   */ "Scan head positioning error" },
{ 0x47, 0x00, /*DTLPWRSOMC*/ "Scsi parity error" },
{ 0x54, 0x00, /*   P      */ "Scsi to host system interface failure" },
{ 0x45, 0x00, /*DTLPWRSOMC*/ "Select or reselect failure" },
{ 0x3B, 0x00, /* TL       */ "Sequential positioning error" },
{ 0x00, 0x03, /* T        */ "Setmark detected" },
{ 0x3B, 0x04, /*  L       */ "Slew failure" },
{ 0x09, 0x03, /*    WR O  */ "Spindle servo failure" },
{ 0x5C, 0x02, /*D      O  */ "Spindles not synchronized" },
{ 0x5C, 0x01, /*D      O  */ "Spindles synchronized" },
{ 0x1B, 0x00, /*DTLPWRSOMC*/ "Synchronous data transfer error" },
{ 0x55, 0x00, /*   P      */ "System resource failure" },
{ 0x33, 0x00, /* T        */ "Tape length error" },
{ 0x3B, 0x03, /*  L       */ "Tape or electronic vertical forms unit not ready" },
{ 0x3B, 0x01, /* T        */ "Tape position error at beginning-of-medium" },
{ 0x3B, 0x02, /* T        */ "Tape position error at end-of-medium" },
{ 0x3F, 0x00, /*DTLPWRSOMC*/ "Target operating conditions have changed" },
{ 0x5B, 0x01, /*DTLPWRSOM */ "Threshold condition met" },
{ 0x26, 0x03, /*DTLPWRSOMC*/ "Threshold parameters not supported" },
{ 0x2C, 0x01, /*      S   */ "Too many windows specified" },
{ 0x09, 0x00, /*DT  WR O  */ "Track following error" },
{ 0x09, 0x01, /*    WR O  */ "Tracking servo failure" },
{ 0x61, 0x01, /*      S   */ "Unable to acquire video" },
{ 0x57, 0x00, /*     R    */ "Unable to recover table-of-contents" },
{ 0x53, 0x01, /* T        */ "Unload tape failure" },
{ 0x11, 0x00, /*DT  WRSO  */ "Unrecovered read error" },
{ 0x11, 0x04, /*D   W  O  */ "Unrecovered read error - auto reallocate failed" },
{ 0x11, 0x0B, /*D   W  O  */ "Unrecovered read error - recommend reassignment" },
{ 0x11, 0x0C, /*D   W  O  */ "Unrecovered read error - recommend rewrite the data" },
{ 0x46, 0x00, /*DTLPWRSOMC*/ "Unsuccessful soft reset" },
{ 0x59, 0x00, /*       O  */ "Updated block read" },
{ 0x61, 0x00, /*      S   */ "Video acquisition error" },
{ 0x50, 0x00, /* T        */ "Write append error" },
{ 0x50, 0x01, /* T        */ "Write append position error" },
{ 0x0C, 0x00, /* T    S   */ "Write error" },
{ 0x0C, 0x02, /*D   W  O  */ "Write error - auto reallocation failed" },
{ 0x0C, 0x01, /*D   W  O  */ "Write error recovered with auto reallocation" },
{ 0x27, 0x00, /*DT  W  O  */ "Write protected" },
/*=================================================================================+
 | SCSI-3 Additions:                                                               |
 |                                                                                 |
 |              D - DIRECT ACCESS DEVICE (SBC)                Device column key    |
 |              .T - SEQUENTIAL ACCESS DEVICE (SSC)              blank = reserved  |
 |              . L - PRINTER DEVICE (SSC)                    not blank = allowed  |
 |              .  P - PROCESSOR DEVICE (SPC)                                      |
 |              .  .W - WRITE ONCE READ MULTIPLE DEVICE (SBC)                      |
 |              .  . R - CD DEVICE (MMC)                                           |
 |              .  .  S - SCANNER DEVICE (SGC)                                     |
 |              .  .  .O - OPTICAL MEMORY DEVICE (SBC)                             |
 |              .  .  . M - MEDIA CHANGER DEVICE (SMC)                             |
 |              .  .  .  C - COMMUNICATION DEVICE (SSC)                            |
 |              .  .  .  .A - STORAGE ARRAY DEVICE (SCC)                           |
 |              .  .  .  . E - ENCLOSURE SERVICES DEVICE (SES)                     |
 |              .  .  .  .                                                         |
 | ASC ASCQ     DTLPWRSOMCAE    Description                                        |
 |---------+-----------------+-----------------------------------------------------|
 */
{ 0x00, 0x16, /*DTLPWRSOMCAE*/ "Operation in progress" },
{ 0x00, 0x17, /*DTL WRSOM AE*/ "Cleaning requested" },
{ 0x04, 0x05, /*          A */ "Logical unit not ready, rebuild in progress" },
{ 0x04, 0x06, /*          A */ "Logical unit not ready, recalculation in progress" },
{ 0x04, 0x07, /*DTLPWRSOMCAE*/ "Logical unit not ready, operation in progress" },
{ 0x04, 0x08, /*     R      */ "Logical unit not ready, long write in progress" },
{ 0x08, 0x03, /*DT  R OM    */ "Logical unit communication CRC error (ULTRA-DMA/32)" },
{ 0x09, 0x04, /*DT  WR O    */ "Head select fault" },
{ 0x0B, 0x00, /*DTLPWRSOMCAE*/ "Warning" },
{ 0x0B, 0x01, /*DTLPWRSOMCAE*/ "Warning - specified temperature exceeded" },
{ 0x0B, 0x02, /*DTLPWRSOMCAE*/ "Warning - enclosure degraded" },
{ 0x0C, 0x03, /*D   W  O    */ "Write error - recommend reassignment" },
{ 0x0C, 0x04, /*DT  W  O    */ "Compression check miscompare error" },
{ 0x0C, 0x05, /*DT  W  O    */ "Data expansion occurred during compression" },
{ 0x0C, 0x06, /*DT  W  O    */ "Block not compressible" },
{ 0x0C, 0x07, /*     R      */ "Write error - recovery needed" },
{ 0x0C, 0x08, /*     R      */ "Write error - recovery failed" },
{ 0x0C, 0x09, /*     R      */ "Write error - loss of streaming" },
{ 0x0C, 0x0A, /*     R      */ "Write error - padding blocks added" },
{ 0x11, 0x0D, /*DT  WR O    */ "De-compression CRC error" },
{ 0x11, 0x0E, /*DT  WR O    */ "Cannot decompress using declared algorithm" },
{ 0x11, 0x0F, /*     R      */ "Error reading UPC/EAN number" },
{ 0x11, 0x10, /*     R      */ "Error reading ISRC number" },
{ 0x11, 0x11, /*     R      */ "Read error - loss of streaming" },
{ 0x14, 0x05, /*DT  W  O    */ "Record not found - recommend reassignment" },
{ 0x14, 0x06, /*DT  W  O    */ "Record not found - data auto-reallocated" },
{ 0x16, 0x01, /*D   W  O    */ "Data sync error - data rewritten" },
{ 0x16, 0x02, /*D   W  O    */ "Data sync error - recommend rewrite" },
{ 0x16, 0x03, /*D   W  O    */ "Data sync error - data auto-reallocated" },
{ 0x16, 0x04, /*D   W  O    */ "Data sync error - recommend reassignment" },
{ 0x17, 0x08, /*D   W  O    */ "Recovered data without ECC - recommend rewrite" },
{ 0x17, 0x09, /*D   W  O    */ "Recovered data without ECC - data rewritten" },
{ 0x18, 0x06, /*D   WR O    */ "Recovered data - recommend rewrite" },
{ 0x18, 0x07, /*D   W  O    */ "Recovered data with ECC - data rewritten" },
{ 0x1F, 0x00, /*D      O    */ "Partial defect list transfer" },
{ 0x26, 0x04, /*DTLPWRSOMCAE*/ "Invalid release of active persistent reservation" },
{ 0x27, 0x01, /*DT  W  O    */ "Hardware write protected" },
{ 0x27, 0x02, /*DT  W  O    */ "Logical unit software write protected" },
{ 0x27, 0x03, /* T          */ "Associated write protect" },
{ 0x27, 0x04, /* T          */ "Persistent write protect" },
{ 0x27, 0x05, /* T          */ "Permanent write protect" },
{ 0x29, 0x01, /*DTLPWRSOMCAE*/ "Power on occurred" },
{ 0x29, 0x02, /*DTLPWRSOMCAE*/ "SCSI bus reset occurred" },
{ 0x29, 0x03, /*DTLPWRSOMCAE*/ "Bus device reset function occurred" },
{ 0x29, 0x04, /*DTLPWRSOMCAE*/ "Device internal reset" },
{ 0x2A, 0x03, /*DTLPWRSOMCAE*/ "Reservations preempted" },
{ 0x2C, 0x03, /*     R      */ "Current program area is not empty" },
{ 0x2C, 0x04, /*     R      */ "Current program area is empty" },
{ 0x30, 0x04, /*DT  WR O    */ "Cannot write medium - unknown format" },
{ 0x30, 0x05, /*DT  WR O    */ "Cannot write medium - incompatible format" },
{ 0x30, 0x06, /*DT  W  O    */ "Cannot format medium - incompatible medium" },
{ 0x30, 0x07, /*DTL WRSOM AE*/ "Cleaning failure" },
{ 0x30, 0x08, /*     R      */ "Cannot write - application code mismatch" },
{ 0x30, 0x09, /*     R      */ "Current session not fixated for append" },
{ 0x34, 0x00, /*DTLPWRSOMCAE*/ "Enclosure failure" },
{ 0x35, 0x00, /*DTLPWRSOMCAE*/ "Enclosure services failure" },
{ 0x35, 0x01, /*DTLPWRSOMCAE*/ "Unsupported enclosure function" },
{ 0x35, 0x02, /*DTLPWRSOMCAE*/ "Enclosure services unavailable" },
{ 0x35, 0x03, /*DTLPWRSOMCAE*/ "Enclosure services transfer failure" },
{ 0x35, 0x04, /*DTLPWRSOMCAE*/ "Enclosure services transfer refused" },
{ 0x3A, 0x01, /*DT  WR OM   */ "Medium not present - tray closed" },
{ 0x3A, 0x02, /*DT  WR OM   */ "Medium not present - tray open" },
{ 0x3B, 0x0F, /*     R      */ "End of medium reached" },
{ 0x3B, 0x11, /*DT  WR OM   */ "Medium magazine not accessible" },
{ 0x3B, 0x12, /*DT  WR OM   */ "Medium magazine removed" },
{ 0x3B, 0x13, /*DT  WR OM   */ "Medium magazine inserted" },
{ 0x3B, 0x14, /*DT  WR OM   */ "Medium magazine locked" },
{ 0x3B, 0x15, /*DT  WR OM   */ "Medium magazine unlocked" },
{ 0x3E, 0x01, /*          A */ "Logical unit failure" },
{ 0x3E, 0x02, /*          A */ "Timeout on logical unit" },
{ 0x55, 0x01, /*D      O    */ "System buffer full" },
{ 0x5D, 0x00, /*DTLPWRSOMCAE*/ "Failure prediction threshold exceeded" },
{ 0x5D, 0xFF, /*DTLPWRSOMCAE*/ "Failure prediction threshold exceeded (false)" },
{ 0x5E, 0x00, /*DTLPWRSO CA */ "Low power condition on" },
{ 0x5E, 0x01, /*DTLPWRSO CA */ "Idle condition activated by timer" },
{ 0x5E, 0x02, /*DTLPWRSO CA */ "Standby condition activated by timer" },
{ 0x5E, 0x03, /*DTLPWRSO CA */ "Idle condition activated by command" },
{ 0x5E, 0x04, /*DTLPWRSO CA */ "Standby condition activated by command" },
{ 0x63, 0x01, /*     R      */ "Packet does not fit in available space" },
{ 0x64, 0x01, /*     R      */ "Invalid packet size" },
{ 0x65, 0x00, /*DTLPWRSOMCAE*/ "Voltage fault" },
{ 0x66, 0x00, /*      S     */ "Automatic document feeder cover up" },
{ 0x66, 0x01, /*      S     */ "Automatic document feeder lift up" },
{ 0x66, 0x02, /*      S     */ "Document jam in automatic document feeder" },
{ 0x66, 0x03, /*      S     */ "Document miss feed automatic in document feeder" },
{ 0x67, 0x00, /*          A */ "Configuration failure" },
{ 0x67, 0x01, /*          A */ "Configuration of incapable logical units failed" },
{ 0x67, 0x02, /*          A */ "Add logical unit failed" },
{ 0x67, 0x03, /*          A */ "Modification of logical unit failed" },
{ 0x67, 0x04, /*          A */ "Exchange of logical unit failed" },
{ 0x67, 0x05, /*          A */ "Remove of logical unit failed" },
{ 0x67, 0x06, /*          A */ "Attachment of logical unit failed" },
{ 0x67, 0x07, /*          A */ "Creation of logical unit failed" },
{ 0x68, 0x00, /*          A */ "Logical unit not configured" },
{ 0x69, 0x00, /*          A */ "Data loss on logical unit" },
{ 0x69, 0x01, /*          A */ "Multiple logical unit failures" },
{ 0x69, 0x02, /*          A */ "Parity/data mismatch" },
{ 0x6A, 0x00, /*          A */ "Informational, refer to log" },
{ 0x6B, 0x00, /*          A */ "State change has occurred" },
{ 0x6B, 0x01, /*          A */ "Redundancy level got better" },
{ 0x6B, 0x02, /*          A */ "Redundancy level got worse" },
{ 0x6C, 0x00, /*          A */ "Rebuild failure occurred" },
{ 0x6D, 0x00, /*          A */ "Recalculate failure occurred" },
{ 0x6E, 0x00, /*          A */ "Command to logical unit failed" },
#if 0
{ 0x70, 0xNN, /* T          */ "Decompression exception short algorithm ID of NN" },
#endif
{ 0x71, 0x00, /* T          */ "Decompression exception long algorithm id" },
{ 0x72, 0x00, /*     R      */ "Session fixation error" },
{ 0x72, 0x01, /*     R      */ "Session fixation error writing lead-in" },
{ 0x72, 0x02, /*     R      */ "Session fixation error writing lead-out" },
{ 0x72, 0x03, /*     R      */ "Session fixation error - incomplete track in session" },
{ 0x72, 0x04, /*     R      */ "Empty or partially written reserved track" },
{ 0x73, 0x00, /*     R      */ "CD control error" },
{ 0x73, 0x01, /*     R      */ "Power calibration area almost full" },
{ 0x73, 0x02, /*     R      */ "Power calibration area is full" },
{ 0x73, 0x03, /*     R      */ "Power calibration area error" },
{ 0x73, 0x04, /*     R      */ "Program memory area update failure" },
{ 0x73, 0x05, /*     R      */ "program memory area is full" }
};
int SenseCodeEntrys = sizeof(SenseCodeTable) / sizeof(struct sense_entry);

/*
 * Function to Find Additional Sense Code/Qualifier Message.
 */
char *
cdbg_SenseMessage (struct all_req_sns_data *sdp)
{
      struct sense_entry *se;
      int entrys = 0;

      for (se = SenseCodeTable; entrys < SenseCodeEntrys; se++, entrys++) {
	if ( (se->sense_code == sdp->asc) &&
	     (se->sense_qualifier == sdp->asq) ) {
	    return (se->sense_message);
	}
      }
      return ((char *) 0);
}

/*
 * EEI Status Code Table.
 */
struct EEI_StatusTable {
	u_int	eei_status;
	caddr_t	status_msg_brief;
	caddr_t	status_msg_full;
} eei_StatusTable[] = {
    {	EEI_NO_STATUS,		"EEI_NO_STATUS",
				"No EEI status available"		},
    {	EEI_INVALID_PARAM,	"EEI_INVALID_PARAM",
				"Invalid software parameter provided"	},
    {	EEI_MALLOC_FAILURE,	"EEI_MALLOC_FAILURE",
				"Memory allocation failed"		},
    {	EEI_CNTBUSY_FAILURE,	"EEI_CNTBUSY_FAILURE",
				"HBA/Controller Busy (retriable)"	},
    {	EEI_GROSSSW_FAILURE,	"EEI_GROSSSW_FAILURE",
				"Gross internal software error"		},
    {	EEI_DEVBUSY_FAILURE,	"EEI_DEVBUSY_FAILURE",
				"Device is busy (retriable)"		},
    {	EEI_DEVBIO_FAILURE,	"EEI_DEVBIO_FAILURE",
				"Device/bus I/O error (retriable)"	},
    {	EEI_DEVSOFT_FAILURE,	"EEI_DEVSOFT_FAILURE",
				"Device medium error (soft error)"	},
    {	EEI_TAPE_POS_LOST,	"EEI_TAPE_POS_LOST",
				"Tape position lost"			},
    {	EEI_DEVREQ_FAILURE,	"EEI_DEVREQ_FAILURE",
				"Device request illegal/unsupported"	},
    {	EEI_DEVSTATE_FAILURE,	"EEI_DEVSTATE_FAILURE",
				"Device inoperable (needs initialize)"	},
    {	EEI_DEVHARD_FAILURE,	"EEI_DEVHARD_FAILURE",
				"Device hardware error (hard error)"	},
    {	EEI_ABORTIO_FAILURE,	"EEI_ABORTIO_FAILURE",
				"Abort/Timed out I/O occured"		},
    {	EEI_CNTRLR_FAILURE,	"EEI_CNTRLR_FAILURE",
				"HBA/Controller failure (retriable)"	},
    {	EEI_CXALLOC_FAILURE,	"EEI_CXALLOC_FAILURE",
				"Shared Device allocation failed"	},
    {	EEI_RESERVE_PENDING,	"EEI_RESERVE_PENDING",
				"Shared Device Re-reserve pending"	},
    {	EEI_DEVPATH_FAILURE,	"EEI_DEVPATH_FAILURE",
				"Device not there (powered off?)"	},
    {	EEI_DEVPATH_RESET,	"EEI_DEVPATH_RESET",
				"Device/bus reset occured"		},
    {	EEI_DEVPATH_CONFLICT,	"EEI_DEVPATH_CONFLICT",
				"Device access denied (path conflict)"	}
};
static int eei_StatusEntrys =
		sizeof(eei_StatusTable) / sizeof(eei_StatusTable[0]);

char *
cdbg_EEIStatus (u_int eei_status, int report_format)
{
	struct EEI_StatusTable *est = eei_StatusTable;
	int entrys;

	for (entrys = 0; entrys < eei_StatusEntrys; est++, entrys++) {
	    if (est->eei_status == eei_status) {
		if (report_format == CDBG_BRIEF) {
		    return (est->status_msg_brief);
		} else {
		    return (est->status_msg_full);
		}
	    }
	}
	return ((report_format) ? "Unknown Status" : "Unknown");
}
#endif /* defined(EEI) */


syntax highlighted by Code2HTML, v. 0.9.1