Logo Search packages:      
Sourcecode: cdrkit version File versions  Download package

scsitransp.c

/*
 * 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);
}

Generated by  Doxygen 1.6.0   Back to index