summaryrefslogtreecommitdiff
path: root/libusal/scsitransp.c
diff options
context:
space:
mode:
Diffstat (limited to 'libusal/scsitransp.c')
-rw-r--r--libusal/scsitransp.c1345
1 files changed, 1345 insertions, 0 deletions
diff --git a/libusal/scsitransp.c b/libusal/scsitransp.c
new file mode 100644
index 0000000..b3cc502
--- /dev/null
+++ b/libusal/scsitransp.c
@@ -0,0 +1,1345 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)scsitransp.c 1.91 04/06/17 Copyright 1988,1995,2000-2004 J. Schilling */
+/*#ifndef lint*/
+static char sccsid[] =
+ "@(#)scsitransp.c 1.91 04/06/17 Copyright 1988,1995,2000-2004 J. Schilling";
+/*#endif*/
+/*
+ * SCSI user level command transport routines (generic part).
+ *
+ * Warning: you may change this source, but if you do that
+ * you need to change the _usal_version and _usal_auth* string below.
+ * You may not return "schily" for an SCG_AUTHOR request anymore.
+ * Choose your name instead of "schily" and make clear that the version
+ * string is related to a modified source.
+ *
+ * Copyright (c) 1988,1995,2000-2004 J. Schilling
+ */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <mconfig.h>
+#include <stdio.h>
+#include <standard.h>
+#include <stdxlib.h>
+#include <unixstd.h>
+#include <errno.h>
+#include <timedefs.h>
+#include <strdefs.h>
+#include <schily.h>
+
+#include <usal/usalcmd.h>
+#include <usal/scsireg.h>
+#include <usal/scsitransp.h>
+#include "usaltimes.h"
+
+#include <stdarg.h>
+
+
+/*
+ * Warning: you may change this source, but if you do that
+ * you need to change the _usal_version and _usal_auth* string below.
+ * You may not return "schily" for an SCG_AUTHOR request anymore.
+ * Choose your name instead of "schily" and make clear that the version
+ * string is related to a modified source.
+ */
+static char _usal_version[] = CDRKIT_VERSION; /* The global libusal version */
+static char _usal_auth_cdrkit[] = "Cdrkit"; /* The author for this module */
+
+#define DEFTIMEOUT 20 /* Default timeout for SCSI command transport */
+
+char *usal_version(SCSI *usalp, int what);
+int usal__open(SCSI *usalp, char *device);
+int usal__close(SCSI *usalp);
+BOOL usal_havebus(SCSI *usalp, int);
+int usal_initiator_id(SCSI *usalp);
+int usal_isatapi(SCSI *usalp);
+int usal_reset(SCSI *usalp, int what);
+void *usal_getbuf(SCSI *usalp, long);
+void usal_freebuf(SCSI *usalp);
+long usal_bufsize(SCSI *usalp, long);
+void usal_setnonstderrs(SCSI *usalp, const char **);
+BOOL usal_yes(char *);
+#ifdef nonono
+static void usal_sighandler(int);
+#endif
+int usal_cmd(SCSI *usalp);
+void usal_vhead(SCSI *usalp);
+int usal_svhead(SCSI *usalp, char *buf, int maxcnt);
+int usal_vtail(SCSI *usalp);
+int usal_svtail(SCSI *usalp, int *retp, char *buf, int maxcnt);
+void usal_vsetup(SCSI *usalp);
+int usal_getresid(SCSI *usalp);
+int usal_getdmacnt(SCSI *usalp);
+BOOL usal_cmd_err(SCSI *usalp);
+void usal_printerr(SCSI *usalp);
+void usal_fprinterr(SCSI *usalp, FILE *f);
+int usal_sprinterr(SCSI *usalp, char *buf, int maxcnt);
+int usal__sprinterr(SCSI *usalp, char *buf, int maxcnt);
+void usal_printcdb(SCSI *usalp);
+int usal_sprintcdb(SCSI *usalp, char *buf, int maxcnt);
+void usal_printwdata(SCSI *usalp);
+int usal_sprintwdata(SCSI *usalp, char *buf, int maxcnt);
+void usal_printrdata(SCSI *usalp);
+int usal_sprintrdata(SCSI *usalp, char *buf, int maxcnt);
+void usal_printresult(SCSI *usalp);
+int usal_sprintresult(SCSI *usalp, char *buf, int maxcnt);
+void usal_printstatus(SCSI *usalp);
+int usal_sprintstatus(SCSI *usalp, char *buf, int maxcnt);
+void usal_fprbytes(FILE *, char *, unsigned char *, int);
+void usal_fprascii(FILE *, char *, unsigned char *, int);
+void usal_prbytes(char *, unsigned char *, int);
+void usal_prascii(char *, unsigned char *, int);
+int usal_sprbytes(char *buf, int maxcnt, char *, unsigned char *, int);
+int usal_sprascii(char *buf, int maxcnt, char *, unsigned char *, int);
+void usal_fprsense(FILE *f, unsigned char *, int);
+int usal_sprsense(char *buf, int maxcnt, unsigned char *, int);
+void usal_prsense(unsigned char *, int);
+int usal_cmd_status(SCSI *usalp);
+int usal_sense_key(SCSI *usalp);
+int usal_sense_code(SCSI *usalp);
+int usal_sense_qual(SCSI *usalp);
+unsigned char *usal_sense_table(SCSI *usalp);
+void usal_fprintdev(FILE *, struct scsi_inquiry *);
+void usal_printdev(struct scsi_inquiry *);
+int usal_printf(SCSI *usalp, const char *form, ...);
+int usal_errflush(SCSI *usalp);
+int usal_errfflush(SCSI *usalp, FILE *f);
+
+/*
+ * Return version information for the SCSI transport code.
+ * This has been introduced to make it easier to trace down problems
+ * in applications.
+ *
+ * If usalp is NULL, return general library version information.
+ * If usalp is != NULL, return version information for the low level transport.
+ */
+char *
+usal_version(SCSI *usalp, int what)
+{
+ if (usalp == (SCSI *)0) {
+ switch (what) {
+
+ case SCG_VERSION:
+ return (_usal_version);
+ /*
+ * If you changed this source, you are not allowed to
+ * return "schily" for the SCG_AUTHOR request.
+ */
+ case SCG_AUTHOR:
+ return (_usal_auth_cdrkit);
+ case SCG_SCCS_ID:
+ return (sccsid);
+ default:
+ return ((char *)0);
+ }
+ }
+ return (SCGO_VERSION(usalp, what));
+}
+
+/*
+ * Call low level SCSI open routine from transport abstraction layer.
+ */
+int
+usal__open(SCSI *usalp, char *device)
+{
+ int ret;
+ usal_ops_t *ops;
+extern usal_ops_t usal_std_ops;
+
+ usalp->ops = &usal_std_ops;
+
+ if (device && strncmp(device, "REMOTE", 6) == 0) {
+ ops = usal_remote();
+ if (ops != NULL)
+ usalp->ops = ops;
+ }
+
+ ret = SCGO_OPEN(usalp, device);
+ if (ret < 0)
+ return (ret);
+
+ /*
+ * Now make usalp->fd valid if possible.
+ * Note that usal_scsibus(usalp)/usal_target(usalp)/usal_lun(usalp) may have
+ * changed in SCGO_OPEN().
+ */
+ usal_settarget(usalp, usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp));
+ return (ret);
+}
+
+/*
+ * Call low level SCSI close routine from transport abstraction layer.
+ */
+int
+usal__close(SCSI *usalp)
+{
+ return (SCGO_CLOSE(usalp));
+}
+
+/*
+ * Retrieve max DMA count for this target.
+ */
+long
+usal_bufsize(SCSI *usalp, long amt)
+{
+ long maxdma;
+
+ maxdma = SCGO_MAXDMA(usalp, amt);
+ if (amt <= 0 || amt > maxdma)
+ amt = maxdma;
+
+ usalp->maxdma = maxdma; /* Max possible */
+ usalp->maxbuf = amt; /* Current value */
+
+ return (amt);
+}
+
+/*
+ * Allocate a buffer that may be used for DMA.
+ */
+void *
+usal_getbuf(SCSI *usalp, long amt)
+{
+ void *buf;
+
+ if (amt <= 0 || amt > usal_bufsize(usalp, amt))
+ return ((void *)0);
+
+ buf = SCGO_GETBUF(usalp, amt);
+ usalp->bufptr = buf;
+ return (buf);
+}
+
+/*
+ * Free DMA buffer.
+ */
+void
+usal_freebuf(SCSI *usalp)
+{
+ SCGO_FREEBUF(usalp);
+ usalp->bufptr = NULL;
+}
+
+/*
+ * Check if 'busno' is a valid SCSI bus number.
+ */
+BOOL
+usal_havebus(SCSI *usalp, int busno)
+{
+ return (SCGO_HAVEBUS(usalp, busno));
+}
+
+/*
+ * Return SCSI initiator ID for current SCSI bus if available.
+ */
+int
+usal_initiator_id(SCSI *usalp)
+{
+ return (SCGO_INITIATOR_ID(usalp));
+}
+
+/*
+ * Return a hint whether current SCSI target refers to a ATAPI device.
+ */
+int
+usal_isatapi(SCSI *usalp)
+{
+ return (SCGO_ISATAPI(usalp));
+}
+
+/*
+ * Reset SCSI bus or target.
+ */
+int
+usal_reset(SCSI *usalp, int what)
+{
+ return (SCGO_RESET(usalp, what));
+}
+
+/*
+ * Set up nonstd error vector for curren target.
+ * To clear additional error table, call usal_setnonstderrs(usalp, NULL);
+ * Note: do not use this when scanning the SCSI bus.
+ */
+void
+usal_setnonstderrs(SCSI *usalp, const char **vec)
+{
+ usalp->nonstderrs = vec;
+}
+
+/*
+ * Simple Yes/No answer checker.
+ */
+BOOL
+usal_yes(char *msg)
+{
+ char okbuf[10];
+
+ printf("%s", msg);
+ flush();
+ if (rols_getline(okbuf, sizeof (okbuf)) == EOF)
+ exit(EX_BAD);
+ if (streql(okbuf, "y") || streql(okbuf, "yes") ||
+ streql(okbuf, "Y") || streql(okbuf, "YES"))
+ return (TRUE);
+ else
+ return (FALSE);
+}
+
+#ifdef nonono
+static void
+usal_sighandler(int sig)
+{
+ printf("\n");
+ if (scsi_running) {
+ printf("Running command: %s\n", scsi_command);
+ printf("Resetting SCSI - Bus.\n");
+ if (usal_reset(usalp) < 0)
+ errmsg("Cannot reset SCSI - Bus.\n");
+ }
+ if (usal_yes("EXIT ? "))
+ exit(sig);
+}
+#endif
+
+/*
+ * Send a SCSI command.
+ * Do error checking and reporting depending on the values of
+ * usalp->verbose, usalp->debug and usalp->silent.
+ */
+int
+usal_cmd(SCSI *usalp)
+{
+ int ret;
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ /*
+ * Reset old error messages in usalp->errstr
+ */
+ usalp->errptr = usalp->errbeg = usalp->errstr;
+
+ scmd->kdebug = usalp->kdebug;
+ if (scmd->timeout == 0 || scmd->timeout < usalp->deftimeout)
+ scmd->timeout = usalp->deftimeout;
+ if (usalp->disre_disable)
+ scmd->flags &= ~SCG_DISRE_ENA;
+ if (usalp->noparity)
+ scmd->flags |= SCG_NOPARITY;
+
+ scmd->u_sense.cmd_sense[0] = 0; /* Paranioa */
+ if (scmd->sense_len > SCG_MAX_SENSE)
+ scmd->sense_len = SCG_MAX_SENSE;
+ else if (scmd->sense_len < 0)
+ scmd->sense_len = 0;
+
+ if (usalp->verbose) {
+ usal_vhead(usalp);
+ usal_errflush(usalp);
+ }
+
+ if (usalp->running) {
+ if (usalp->curcmdname) {
+ fprintf(stderr, "Currently running '%s' command.\n",
+ usalp->curcmdname);
+ }
+ raisecond("SCSI ALREADY RUNNING !!", 0L);
+ }
+ usalp->cb_fun = NULL;
+ gettimeofday(usalp->cmdstart, (struct timezone *)0);
+ usalp->curcmdname = usalp->cmdname;
+ usalp->running = TRUE;
+ ret = SCGO_SEND(usalp);
+ usalp->running = FALSE;
+ __usal_times(usalp);
+ if (ret < 0) {
+ /*
+ * Old /dev/usal versions will not allow to access targets > 7.
+ * Include a workaround to make this non fatal.
+ */
+ if (usal_target(usalp) < 8 || geterrno() != EINVAL)
+ comerr("Cannot send SCSI cmd via ioctl\n");
+ if (scmd->ux_errno == 0)
+ scmd->ux_errno = geterrno();
+ if (scmd->error == SCG_NO_ERROR)
+ scmd->error = SCG_FATAL;
+ if (usalp->debug > 0) {
+ errmsg("ret < 0 errno: %d ux_errno: %d error: %d\n",
+ geterrno(), scmd->ux_errno, scmd->error);
+ }
+ }
+
+ ret = usal_vtail(usalp);
+ usal_errflush(usalp);
+ if (usalp->cb_fun != NULL)
+ (*usalp->cb_fun)(usalp->cb_arg);
+ return (ret);
+}
+
+/*
+ * Fill the head of verbose printing into the SCSI error buffer.
+ * Action depends on SCSI verbose status.
+ */
+void
+usal_vhead(SCSI *usalp)
+{
+ usalp->errptr += usal_svhead(usalp, usalp->errptr, usal_errrsize(usalp));
+}
+
+/*
+ * Fill the head of verbose printing into a buffer.
+ * Action depends on SCSI verbose status.
+ */
+int
+usal_svhead(SCSI *usalp, char *buf, int maxcnt)
+{
+ register char *p = buf;
+ register int amt;
+
+ if (usalp->verbose <= 0)
+ return (0);
+
+ amt = snprintf(p, maxcnt,
+ "\nExecuting '%s' command on Bus %d Target %d, Lun %d timeout %ds\n",
+ /* XXX Really this ??? */
+/* usalp->cmdname, usal_scsibus(usalp), usal_target(usalp), usalp->scmd->cdb.g0_cdb.lun,*/
+ usalp->cmdname, usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp),
+ usalp->scmd->timeout);
+ if (amt < 0)
+ return (amt);
+ p += amt;
+ maxcnt -= amt;
+
+ amt = usal_sprintcdb(usalp, p, maxcnt);
+ if (amt < 0)
+ return (amt);
+ p += amt;
+ maxcnt -= amt;
+
+ if (usalp->verbose > 1) {
+ amt = usal_sprintwdata(usalp, p, maxcnt);
+ if (amt < 0)
+ return (amt);
+ p += amt;
+ maxcnt -= amt;
+ }
+ return (p - buf);
+}
+
+/*
+ * Fill the tail of verbose printing into the SCSI error buffer.
+ * Action depends on SCSI verbose status.
+ */
+int
+usal_vtail(SCSI *usalp)
+{
+ int ret;
+
+ usalp->errptr += usal_svtail(usalp, &ret, usalp->errptr, usal_errrsize(usalp));
+ return (ret);
+}
+
+/*
+ * Fill the tail of verbose printing into a buffer.
+ * Action depends on SCSI verbose status.
+ */
+int
+usal_svtail(SCSI *usalp, int *retp, char *buf, int maxcnt)
+{
+ register char *p = buf;
+ register int amt;
+ int ret;
+
+ ret = usal_cmd_err(usalp) ? -1 : 0;
+ if (retp)
+ *retp = ret;
+ if (ret) {
+ if (usalp->silent <= 0 || usalp->verbose) {
+ amt = usal__sprinterr(usalp, p, maxcnt);
+ if (amt < 0)
+ return (amt);
+ p += amt;
+ maxcnt -= amt;
+ }
+ }
+ if ((usalp->silent <= 0 || usalp->verbose) && usalp->scmd->resid) {
+ if (usalp->scmd->resid < 0) {
+ /*
+ * An operating system that does DMA the right way
+ * will not allow DMA overruns - it will stop DMA
+ * before bad things happen.
+ * A DMA residual count < 0 (-1) is a hint for a DMA
+ * overrun but does not affect the transfer count.
+ */
+ amt = snprintf(p, maxcnt, "DMA overrun, ");
+ if (amt < 0)
+ return (amt);
+ p += amt;
+ maxcnt -= amt;
+ }
+ amt = snprintf(p, maxcnt, "resid: %d\n", usalp->scmd->resid);
+ if (amt < 0)
+ return (amt);
+ p += amt;
+ maxcnt -= amt;
+ }
+ if (usalp->verbose > 0 || (ret < 0 && usalp->silent <= 0)) {
+ amt = usal_sprintresult(usalp, p, maxcnt);
+ if (amt < 0)
+ return (amt);
+ p += amt;
+ maxcnt -= amt;
+ }
+ return (p - buf);
+}
+
+/*
+ * Set up SCSI error buffer with verbose print data.
+ * Action depends on SCSI verbose status.
+ */
+void
+usal_vsetup(SCSI *usalp)
+{
+ usal_vhead(usalp);
+ usal_vtail(usalp);
+}
+
+/*
+ * Return the residual DMA count for last command.
+ * If this count is < 0, then a DMA overrun occured.
+ */
+int
+usal_getresid(SCSI *usalp)
+{
+ return (usalp->scmd->resid);
+}
+
+/*
+ * Return the actual DMA count for last command.
+ */
+int
+usal_getdmacnt(SCSI *usalp)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ if (scmd->resid < 0)
+ return (scmd->size);
+
+ return (scmd->size - scmd->resid);
+}
+
+/*
+ * Test if last SCSI command got an error.
+ */
+BOOL
+usal_cmd_err(SCSI *usalp)
+{
+ register struct usal_cmd *cp = usalp->scmd;
+
+ if (cp->error != SCG_NO_ERROR ||
+ cp->ux_errno != 0 ||
+ *(Uchar *)&cp->scb != 0 ||
+ cp->u_sense.cmd_sense[0] != 0) /* Paranioa */
+ return (TRUE);
+ return (FALSE);
+}
+
+/*
+ * Used to print error messges if the command itself has been run silently.
+ *
+ * print the following SCSI codes:
+ *
+ * - command transport status
+ * - CDB
+ * - SCSI status byte
+ * - Sense Bytes
+ * - Decoded Sense data
+ * - DMA status
+ * - SCSI timing
+ *
+ * to SCSI errfile.
+ */
+void
+usal_printerr(SCSI *usalp)
+{
+ usal_fprinterr(usalp, (FILE *)usalp->errfile);
+}
+
+/*
+ * print the following SCSI codes:
+ *
+ * - command transport status
+ * - CDB
+ * - SCSI status byte
+ * - Sense Bytes
+ * - Decoded Sense data
+ * - DMA status
+ * - SCSI timing
+ *
+ * to a file.
+ */
+void
+usal_fprinterr(SCSI *usalp, FILE *f)
+{
+ char errbuf[SCSI_ERRSTR_SIZE];
+ int amt;
+
+ amt = usal_sprinterr(usalp, errbuf, sizeof (errbuf));
+ if (amt > 0) {
+ filewrite(f, errbuf, amt);
+ fflush(f);
+ }
+}
+
+/*
+ * print the following SCSI codes:
+ *
+ * - command transport status
+ * - CDB
+ * - SCSI status byte
+ * - Sense Bytes
+ * - Decoded Sense data
+ * - DMA status
+ * - SCSI timing
+ *
+ * into a buffer.
+ */
+int
+usal_sprinterr(SCSI *usalp, char *buf, int maxcnt)
+{
+ int amt;
+ int osilent = usalp->silent;
+ int overbose = usalp->verbose;
+
+ usalp->silent = 0;
+ usalp->verbose = 0;
+ amt = usal_svtail(usalp, NULL, buf, maxcnt);
+ usalp->silent = osilent;
+ usalp->verbose = overbose;
+ return (amt);
+}
+
+/*
+ * print the following SCSI codes:
+ *
+ * - command transport status
+ * - CDB
+ * - SCSI status byte
+ * - Sense Bytes
+ * - Decoded Sense data
+ *
+ * into a buffer.
+ */
+int
+usal__sprinterr(SCSI *usalp, char *buf, int maxcnt)
+{
+ register struct usal_cmd *cp = usalp->scmd;
+ register char *err;
+ char *cmdname = "SCSI command name not set by caller";
+ char errbuf[64];
+ register char *p = buf;
+ register int amt;
+
+ switch (cp->error) {
+
+ case SCG_NO_ERROR : err = "no error"; break;
+ case SCG_RETRYABLE: err = "retryable error"; break;
+ case SCG_FATAL : err = "fatal error"; break;
+ /*
+ * We need to cast timeval->* to long because
+ * of the broken sys/time.h in Linux.
+ */
+ case SCG_TIMEOUT : snprintf(errbuf, sizeof (errbuf),
+ "cmd timeout after %ld.%03ld (%d) s",
+ (long)usalp->cmdstop->tv_sec,
+ (long)usalp->cmdstop->tv_usec/1000,
+ cp->timeout);
+ err = errbuf;
+ break;
+ default: snprintf(errbuf, sizeof (errbuf),
+ "error: %d", cp->error);
+ err = errbuf;
+ }
+
+ if (usalp->cmdname != NULL && usalp->cmdname[0] != '\0')
+ cmdname = usalp->cmdname;
+ /*amt = serrmsgno(cp->ux_errno, p, maxcnt, "%s: scsi sendcmd: %s\n", cmdname, err);
+ if (amt < 0)
+ return (amt);
+ */
+ amt=snprintf(p, maxcnt, "Errno: %d (%s), %s scsi sendcmd: %s\n", cp->ux_errno, strerror(cp->ux_errno), cmdname, err);
+ if(amt>=maxcnt || amt<0)
+ return (amt);
+ p += amt;
+ maxcnt -= amt;
+
+ amt = usal_sprintcdb(usalp, p, maxcnt);
+ if (amt < 0)
+ return (amt);
+ p += amt;
+ maxcnt -= amt;
+
+ if (cp->error <= SCG_RETRYABLE) {
+ amt = usal_sprintstatus(usalp, p, maxcnt);
+ if (amt < 0)
+ return (amt);
+ p += amt;
+ maxcnt -= amt;
+ }
+
+ if (cp->scb.chk) {
+ amt = usal_sprsense(p, maxcnt, (Uchar *)&cp->sense, cp->sense_count);
+ if (amt < 0)
+ return (amt);
+ p += amt;
+ maxcnt -= amt;
+ amt = usal__errmsg(usalp, p, maxcnt, &cp->sense, &cp->scb, -1);
+ if (amt < 0)
+ return (amt);
+ p += amt;
+ maxcnt -= amt;
+ }
+ return (p - buf);
+}
+
+/*
+ * XXX Do we need this function?
+ *
+ * print the SCSI Command descriptor block to XXX stderr.
+ */
+void
+usal_printcdb(SCSI *usalp)
+{
+ usal_prbytes("CDB: ", usalp->scmd->cdb.cmd_cdb, usalp->scmd->cdb_len);
+}
+
+/*
+ * print the SCSI Command descriptor block into a buffer.
+ */
+int
+usal_sprintcdb(SCSI *usalp, char *buf, int maxcnt)
+{
+ int cnt;
+
+ cnt = usal_sprbytes(buf, maxcnt, "CDB: ", usalp->scmd->cdb.cmd_cdb, usalp->scmd->cdb_len);
+ if (cnt < 0)
+ cnt = 0;
+ return (cnt);
+}
+
+/*
+ * XXX Do we need this function?
+ * XXX usal_printrdata() is used.
+ * XXX We need to check if we should write to stderr or better to usal->errfile
+ *
+ * print the SCSI send data to stderr.
+ */
+void
+usal_printwdata(SCSI *usalp)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ if (scmd->size > 0 && (scmd->flags & SCG_RECV_DATA) == 0) {
+ fprintf(stderr, "Sending %d (0x%X) bytes of data.\n",
+ scmd->size, scmd->size);
+ usal_prbytes("Write Data: ",
+ (Uchar *)scmd->addr,
+ scmd->size > 100 ? 100 : scmd->size);
+ }
+}
+
+/*
+ * print the SCSI send data into a buffer.
+ */
+int
+usal_sprintwdata(SCSI *usalp, char *buf, int maxcnt)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+ register char *p = buf;
+ register int amt;
+
+ if (scmd->size > 0 && (scmd->flags & SCG_RECV_DATA) == 0) {
+ amt = snprintf(p, maxcnt,
+ "Sending %d (0x%X) bytes of data.\n",
+ scmd->size, scmd->size);
+ if (amt < 0)
+ return (amt);
+ p += amt;
+ maxcnt -= amt;
+ amt = usal_sprbytes(p, maxcnt, "Write Data: ",
+ (Uchar *)scmd->addr,
+ scmd->size > 100 ? 100 : scmd->size);
+ if (amt < 0)
+ return (amt);
+ p += amt;
+ }
+ return (p - buf);
+}
+
+/*
+ * XXX We need to check if we should write to stderr or better to usal->errfile
+ *
+ * print the SCSI received data to stderr.
+ */
+void
+usal_printrdata(SCSI *usalp)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+ register int trcnt = usal_getdmacnt(usalp);
+
+ if (scmd->size > 0 && (scmd->flags & SCG_RECV_DATA) != 0) {
+ fprintf(stderr, "Got %d (0x%X), expecting %d (0x%X) bytes of data.\n",
+ trcnt, trcnt,
+ scmd->size, scmd->size);
+ usal_prbytes("Received Data: ",
+ (Uchar *)scmd->addr,
+ trcnt > 100 ? 100 : trcnt);
+ }
+}
+
+/*
+ * print the SCSI received data into a buffer.
+ */
+int
+usal_sprintrdata(SCSI *usalp, char *buf, int maxcnt)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+ register char *p = buf;
+ register int amt;
+ register int trcnt = usal_getdmacnt(usalp);
+
+ if (scmd->size > 0 && (scmd->flags & SCG_RECV_DATA) != 0) {
+ amt = snprintf(p, maxcnt,
+ "Got %d (0x%X), expecting %d (0x%X) bytes of data.\n",
+ trcnt, trcnt,
+ scmd->size, scmd->size);
+ if (amt < 0)
+ return (amt);
+ p += amt;
+ maxcnt -= amt;
+ amt = usal_sprbytes(p, maxcnt,
+ "Received Data: ",
+ (Uchar *)scmd->addr,
+ trcnt > 100 ? 100 : trcnt);
+ if (amt < 0)
+ return (amt);
+ p += amt;
+ }
+ return (p - buf);
+}
+
+/*
+ * XXX We need to check if we should write to stderr or better to usal->errfile
+ *
+ * print the SCSI timings and (depending on verbose) received data to stderr.
+ */
+void
+usal_printresult(SCSI *usalp)
+{
+ fprintf(stderr, "cmd finished after %ld.%03lds timeout %ds\n",
+ (long)usalp->cmdstop->tv_sec,
+ (long)usalp->cmdstop->tv_usec/1000,
+ usalp->scmd->timeout);
+ if (usalp->verbose > 1)
+ usal_printrdata(usalp);
+ flush();
+}
+
+/*
+ * print the SCSI timings and (depending on verbose) received data into a buffer.
+ */
+int
+usal_sprintresult(SCSI *usalp, char *buf, int maxcnt)
+{
+ register char *p = buf;
+ register int amt;
+
+ amt = snprintf(p, maxcnt,
+ "cmd finished after %ld.%03lds timeout %ds\n",
+ (long)usalp->cmdstop->tv_sec,
+ (long)usalp->cmdstop->tv_usec/1000,
+ usalp->scmd->timeout);
+ if (amt < 0)
+ return (amt);
+ p += amt;
+ maxcnt -= amt;
+ if (usalp->verbose > 1) {
+ amt = usal_sprintrdata(usalp, p, maxcnt);
+ if (amt < 0)
+ return (amt);
+ p += amt;
+ }
+ return (p - buf);
+}
+
+/*
+ * XXX Do we need this function?
+ *
+ * print the SCSI status byte in human readable form to the SCSI error file.
+ */
+void
+usal_printstatus(SCSI *usalp)
+{
+ char errbuf[SCSI_ERRSTR_SIZE];
+ int amt;
+
+ amt = usal_sprintstatus(usalp, errbuf, sizeof (errbuf));
+ if (amt > 0) {
+ filewrite((FILE *)usalp->errfile, errbuf, amt);
+ fflush((FILE *)usalp->errfile);
+ }
+}
+
+/*
+ * print the SCSI status byte in human readable form into a buffer.
+ */
+int
+usal_sprintstatus(SCSI *usalp, char *buf, int maxcnt)
+{
+ register struct usal_cmd *cp = usalp->scmd;
+ char *err;
+ char *err2 = "";
+ register char *p = buf;
+ register int amt;
+
+ amt = snprintf(p, maxcnt, "status: 0x%x ", *(Uchar *)&cp->scb);
+ if (amt < 0)
+ return (amt);
+ p += amt;
+ maxcnt -= amt;
+#ifdef SCSI_EXTENDED_STATUS
+ if (cp->scb.ext_st1) {
+ amt = snprintf(p, maxcnt, "0x%x ", ((Uchar *)&cp->scb)[1]);
+ if (amt < 0)
+ return (amt);
+ p += amt;
+ maxcnt -= amt;
+ }
+ if (cp->scb.ext_st2) {
+ amt = snprintf(p, maxcnt, "0x%x ", ((Uchar *)&cp->scb)[2]);
+ if (amt < 0)
+ return (amt);
+ p += amt;
+ maxcnt -= amt;
+ }
+#endif
+ switch (*(Uchar *)&cp->scb & 036) {
+
+ case 0 : err = "GOOD STATUS"; break;
+ case 02 : err = "CHECK CONDITION"; break;
+ case 04 : err = "CONDITION MET/GOOD"; break;
+ case 010: err = "BUSY"; break;
+ case 020: err = "INTERMEDIATE GOOD STATUS"; break;
+ case 024: err = "INTERMEDIATE CONDITION MET/GOOD"; break;
+ case 030: err = "RESERVATION CONFLICT"; break;
+ default : err = "Reserved"; break;
+ }
+#ifdef SCSI_EXTENDED_STATUS
+ if (cp->scb.ext_st1 && cp->scb.ha_er)
+ err2 = " host adapter detected error";
+#endif
+ amt = snprintf(p, maxcnt, "(%s%s)\n", err, err2);
+ if (amt < 0)
+ return (amt);
+ p += amt;
+ return (p - buf);
+}
+
+/*
+ * print some bytes in hex to a file.
+ */
+void
+usal_fprbytes(FILE *f, char *s, register Uchar *cp, register int n)
+{
+ fprintf(f, "%s", s);
+ while (--n >= 0)
+ fprintf(f, " %02X", *cp++);
+ fprintf(f, "\n");
+}
+
+/*
+ * print some bytes in ascii to a file.
+ */
+void
+usal_fprascii(FILE *f, char *s, register Uchar *cp, register int n)
+{
+ register int c;
+
+ fprintf(f, "%s", s);
+ while (--n >= 0) {
+ c = *cp++;
+ if (c >= ' ' && c < 0177)
+ fprintf(f, "%c", c);
+ else
+ fprintf(f, ".");
+ }
+ fprintf(f, "\n");
+}
+
+/*
+ * XXX We need to check if we should write to stderr or better to usal->errfile
+ *
+ * print some bytes in hex to stderr.
+ */
+void
+usal_prbytes(char *s, register Uchar *cp, register int n)
+{
+ usal_fprbytes(stderr, s, cp, n);
+}
+
+/*
+ * XXX We need to check if we should write to stderr or better to usal->errfile
+ *
+ * print some bytes in ascii to stderr.
+ */
+void
+usal_prascii(char *s, register Uchar *cp, register int n)
+{
+ usal_fprascii(stderr, s, cp, n);
+}
+
+/*
+ * print some bytes in hex into a buffer.
+ */
+int
+usal_sprbytes(char *buf, int maxcnt, char *s, register Uchar *cp, register int n)
+{
+ register char *p = buf;
+ register int amt;
+
+ amt = snprintf(p, maxcnt, "%s", s);
+ if (amt < 0)
+ return (amt);
+ p += amt;
+ maxcnt -= amt;
+
+ while (--n >= 0) {
+ amt = snprintf(p, maxcnt, " %02X", *cp++);
+ if (amt < 0)
+ return (amt);
+ p += amt;
+ maxcnt -= amt;
+ }
+ amt = snprintf(p, maxcnt, "\n");
+ if (amt < 0)
+ return (amt);
+ p += amt;
+ return (p - buf);
+}
+
+/*
+ * print some bytes in ascii into a buffer.
+ */
+int
+usal_sprascii(char *buf, int maxcnt, char *s, register Uchar *cp, register int n)
+{
+ register char *p = buf;
+ register int amt;
+ register int c;
+
+ amt = snprintf(p, maxcnt, "%s", s);
+ if (amt < 0)
+ return (amt);
+ p += amt;
+ maxcnt -= amt;
+
+ while (--n >= 0) {
+ c = *cp++;
+ if (c >= ' ' && c < 0177)
+ amt = snprintf(p, maxcnt, "%c", c);
+ else
+ amt = snprintf(p, maxcnt, ".");
+ if (amt < 0)
+ return (amt);
+ p += amt;
+ maxcnt -= amt;
+ }
+ amt = snprintf(p, maxcnt, "\n");
+ if (amt < 0)
+ return (amt);
+ p += amt;
+ return (p - buf);
+}
+
+/*
+ * print the SCSI sense data for last command in hex to a file.
+ */
+void
+usal_fprsense(FILE *f, Uchar *cp, int n)
+{
+ usal_fprbytes(f, "Sense Bytes:", cp, n);
+}
+
+/*
+ * XXX We need to check if we should write to stderr or better to usal->errfile
+ *
+ * print the SCSI sense data for last command in hex to stderr.
+ */
+void
+usal_prsense(Uchar *cp, int n)
+{
+ usal_fprsense(stderr, cp, n);
+}
+
+/*
+ * print the SCSI sense data for last command in hex into a buffer.
+ */
+int
+usal_sprsense(char *buf, int maxcnt, Uchar *cp, int n)
+{
+ return (usal_sprbytes(buf, maxcnt, "Sense Bytes:", cp, n));
+}
+
+/*
+ * Return the SCSI status byte for last command.
+ */
+int
+usal_cmd_status(SCSI *usalp)
+{
+ struct usal_cmd *cp = usalp->scmd;
+ int cmdstatus = *(Uchar *)&cp->scb;
+
+ return (cmdstatus);
+}
+
+/*
+ * Return the SCSI sense key for last command.
+ */
+int
+usal_sense_key(SCSI *usalp)
+{
+ register struct usal_cmd *cp = usalp->scmd;
+ int key = -1;
+
+ if (!usal_cmd_err(usalp))
+ return (0);
+
+ if (cp->sense.code >= 0x70)
+ key = ((struct scsi_ext_sense *)&(cp->sense))->key;
+ return (key);
+}
+
+/*
+ * Return all the SCSI sense table last command.
+ */
+unsigned char *
+usal_sense_table(SCSI *usalp)
+{
+ register struct usal_cmd *cp = usalp->scmd;
+
+ if(!usal_cmd_err(usalp))
+ return (0);
+
+ /* if (cp->sense.code >= 0x70) */
+ return (unsigned char *) &(cp->sense);
+}
+
+
+/*
+ * Return the SCSI sense code for last command.
+ */
+int
+usal_sense_code(SCSI *usalp)
+{
+ register struct usal_cmd *cp = usalp->scmd;
+ int code = -1;
+
+ if (!usal_cmd_err(usalp))
+ return (0);
+
+ if (cp->sense.code >= 0x70)
+ code = ((struct scsi_ext_sense *)&(cp->sense))->sense_code;
+ else
+ code = cp->sense.code;
+ return (code);
+}
+
+/*
+ * Return the SCSI sense qualifier for last command.
+ */
+int
+usal_sense_qual(SCSI *usalp)
+{
+ register struct usal_cmd *cp = usalp->scmd;
+
+ if (!usal_cmd_err(usalp))
+ return (0);
+
+ if (cp->sense.code >= 0x70)
+ return (((struct scsi_ext_sense *)&(cp->sense))->qual_code);
+ else
+ return (0);
+}
+
+/*
+ * Print the device type from the SCSI inquiry buffer to file.
+ */
+void
+usal_fprintdev(FILE *f, struct scsi_inquiry *ip)
+{
+ if (ip->removable)
+ fprintf(f, "Removable ");
+ if (ip->data_format >= 2) {
+ switch (ip->qualifier) {
+
+ case INQ_DEV_PRESENT:
+ break;
+ case INQ_DEV_NOTPR:
+ fprintf(f, "not present ");
+ break;
+ case INQ_DEV_RES:
+ fprintf(f, "reserved ");
+ break;
+ case INQ_DEV_NOTSUP:
+ if (ip->type == INQ_NODEV) {
+ fprintf(f, "unsupported\n"); return;
+ }
+ fprintf(f, "unsupported ");
+ break;
+ default:
+ fprintf(f, "vendor specific %d ",
+ (int)ip->qualifier);
+ }
+ }
+ switch (ip->type) {
+
+ case INQ_DASD:
+ fprintf(f, "Disk"); break;
+ case INQ_SEQD:
+ fprintf(f, "Tape"); break;
+ case INQ_PRTD:
+ fprintf(f, "Printer"); break;
+ case INQ_PROCD:
+ fprintf(f, "Processor"); break;
+ case INQ_WORM:
+ fprintf(f, "WORM"); break;
+ case INQ_ROMD:
+ fprintf(f, "CD-ROM"); break;
+ case INQ_SCAN:
+ fprintf(f, "Scanner"); break;
+ case INQ_OMEM:
+ fprintf(f, "Optical Storage"); break;
+ case INQ_JUKE:
+ fprintf(f, "Juke Box"); break;
+ case INQ_COMM:
+ fprintf(f, "Communication"); break;
+ case INQ_IT8_1:
+ fprintf(f, "IT8 1"); break;
+ case INQ_IT8_2:
+ fprintf(f, "IT8 2"); break;
+ case INQ_STARR:
+ fprintf(f, "Storage array"); break;
+ case INQ_ENCL:
+ fprintf(f, "Enclosure services"); break;
+ case INQ_SDAD:
+ fprintf(f, "Simple direct access"); break;
+ case INQ_OCRW:
+ fprintf(f, "Optical card r/w"); break;
+ case INQ_BRIDGE:
+ fprintf(f, "Bridging expander"); break;
+ case INQ_OSD:
+ fprintf(f, "Object based storage"); break;
+ case INQ_ADC:
+ fprintf(f, "Automation/Drive Interface"); break;
+ case INQ_WELLKNOWN:
+ fprintf(f, "Well known lun"); break;
+
+ case INQ_NODEV:
+ if (ip->data_format >= 2) {
+ fprintf(f, "unknown/no device");
+ break;
+ } else if (ip->qualifier == INQ_DEV_NOTSUP) {
+ fprintf(f, "unit not present");
+ break;
+ }
+ default:
+ fprintf(f, "unknown device type 0x%x",
+ (int)ip->type);
+ }
+ fprintf(f, "\n");
+}
+
+/*
+ * Print the device type from the SCSI inquiry buffer to stdout.
+ */
+void
+usal_printdev(struct scsi_inquiry *ip)
+{
+ usal_fprintdev(stdout, ip);
+}
+
+/*
+ * print into the SCSI error buffer, adjust the next write pointer.
+ */
+/* VARARGS2 */
+int
+usal_printf(SCSI *usalp, const char *form, ...)
+{
+ int cnt;
+ va_list args;
+
+ va_start(args, form);
+ cnt = vsnprintf(usalp->errptr, usal_errrsize(usalp), form, args);
+ va_end(args);
+
+ if (cnt < 0) {
+ usalp->errptr[0] = '\0';
+ } else {
+ usalp->errptr += cnt;
+ }
+ return (cnt);
+}
+
+/*
+ * Flush the SCSI error buffer to SCSI errfile.
+ * Clear error buffer after flushing.
+ */
+int
+usal_errflush(SCSI *usalp)
+{
+ if (usalp->errfile == NULL)
+ return (0);
+
+ return (usal_errfflush(usalp, (FILE *)usalp->errfile));
+}
+
+/*
+ * Flush the SCSI error buffer to a file.
+ * Clear error buffer after flushing.
+ */
+int
+usal_errfflush(SCSI *usalp, FILE *f)
+{
+ int cnt;
+
+ cnt = usalp->errptr - usalp->errbeg;
+ if (cnt > 0) {
+ filewrite(f, usalp->errbeg, cnt);
+ fflush(f);
+ usalp->errbeg = usalp->errptr;
+ }
+ return (cnt);
+}