aboutsummaryrefslogtreecommitdiff
path: root/lib/libscsi/scsi.c
diff options
context:
space:
mode:
authorJustin T. Gibbs <gibbs@FreeBSD.org>1998-09-17 03:56:23 +0000
committerJustin T. Gibbs <gibbs@FreeBSD.org>1998-09-17 03:56:23 +0000
commitc3deaba902031c915559093181751f6d1a079a34 (patch)
treec988d9f37982056cf07ff832cd839633a2027d0b /lib/libscsi/scsi.c
parentc4ea283d54e6dd276b0bfade5bfc78f635284da9 (diff)
libscsi is obsoleted by CAM.
Notes
Notes: svn path=/head/; revision=39402
Diffstat (limited to 'lib/libscsi/scsi.c')
-rw-r--r--lib/libscsi/scsi.c1192
1 files changed, 0 insertions, 1192 deletions
diff --git a/lib/libscsi/scsi.c b/lib/libscsi/scsi.c
deleted file mode 100644
index 3293a72e9568..000000000000
--- a/lib/libscsi/scsi.c
+++ /dev/null
@@ -1,1192 +0,0 @@
-/* scsi: SCSI user library
- */
-/* Copyright (c) 1994 HD Associates
- * (contact: dufault@hda.com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by HD Associates
- * 4. Neither the name of the HD Associaates nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * $Id$
- */
-#include <stdlib.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <string.h>
-#include <sys/scsiio.h>
-#include <sys/errno.h>
-#include <stdarg.h>
-#include <fcntl.h>
-
-#include "scsi.h"
-
-static struct
-{
- FILE *db_f;
- int db_level;
- int db_trunc;
-} behave;
-
-/* scsireq_reset: Reset a scsireq structure.
- */
-scsireq_t *scsireq_reset(scsireq_t *scsireq)
-{
- if (scsireq == 0)
- return scsireq;
-
- scsireq->flags = 0; /* info about the request status and type */
- scsireq->timeout = 2000; /* 2 seconds */
- bzero(scsireq->cmd, sizeof(scsireq->cmd));
- scsireq->cmdlen = 0;
- /* Leave scsireq->databuf alone */
- /* Leave scsireq->datalen alone */
- scsireq->datalen_used = 0;
- bzero(scsireq->sense, sizeof(scsireq->sense));
- scsireq->senselen = sizeof(scsireq->sense);
- scsireq->senselen_used = 0;
- scsireq->status = 0;
- scsireq->retsts = 0;
- scsireq->error = 0;
-
- return scsireq;
-}
-
-/* scsireq_new: Allocate and initialize a new scsireq.
- */
-scsireq_t *scsireq_new(void)
-{
- scsireq_t *p = (scsireq_t *)malloc(sizeof(scsireq_t));
-
- if (p)
- scsireq_reset(p);
-
- return p;
-}
-
-/*
- * Decode: Decode the data section of a scsireq. This decodes
- * trivial grammar:
- *
- * fields : field fields
- * ;
- *
- * field : field_specifier
- * | control
- * ;
- *
- * control : 's' seek_value
- * | 's' '+' seek_value
- * ;
- *
- * seek_value : DECIMAL_NUMBER
- * | 'v' // For indirect seek, i.e., value from the arg list
- * ;
- *
- * field_specifier : type_specifier field_width
- * | '{' NAME '}' type_specifier field_width
- * ;
- *
- * field_width : DECIMAL_NUMBER
- * ;
- *
- * type_specifier : 'i' // Integral types (i1, i2, i3, i4)
- * | 'b' // Bits
- * | 't' // Bits
- * | 'c' // Character arrays
- * | 'z' // Character arrays with zeroed trailing spaces
- * ;
- *
- * Notes:
- * 1. Integral types are swapped into host order.
- * 2. Bit fields are allocated MSB to LSB to match the SCSI spec documentation.
- * 3. 's' permits "seeking" in the string. "s+DECIMAL" seeks relative to
- * DECIMAL; "sDECIMAL" seeks absolute to decimal.
- * 4. 's' permits an indirect reference. "sv" or "s+v" will get the
- * next integer value from the arg array.
- * 5. Field names can be anything between the braces
- *
- * BUGS:
- * i and b types are promoted to ints.
- *
- */
-
-static int do_buff_decode(u_char *databuf, size_t len,
-void (*arg_put)(void *, int , void *, int, char *), void *puthook,
-char *fmt, va_list ap)
-{
- int assigned = 0;
- int width;
- int suppress;
- int plus;
- int done = 0;
- static u_char mask[] = {0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
- int value;
- u_char *base = databuf;
- char letter;
- char field_name[80];
-
-# define ARG_PUT(ARG) \
- do \
- { \
- if (!suppress) \
- { \
- if (arg_put) \
- (*arg_put)(puthook, (letter == 't' ? 'b' : letter), \
- (void *)((long)(ARG)), 1, field_name); \
- else \
- *(va_arg(ap, int *)) = (ARG); \
- assigned++; \
- } \
- field_name[0] = 0; \
- suppress = 0; \
- } while (0)
-
- u_char bits = 0; /* For bit fields */
- int shift = 0; /* Bits already shifted out */
- suppress = 0;
- field_name[0] = 0;
-
- while (!done)
- {
- switch(letter = *fmt)
- {
- case ' ': /* White space */
- case '\t':
- case '\r':
- case '\n':
- case '\f':
- fmt++;
- break;
-
- case '#': /* Comment */
- while (*fmt && (*fmt != '\n'))
- fmt++;
- if (fmt)
- fmt++; /* Skip '\n' */
- break;
-
- case '*': /* Suppress assignment */
- fmt++;
- suppress = 1;
- break;
-
- case '{': /* Field Name */
- {
- int i = 0;
- fmt++; /* Skip '{' */
- while (*fmt && (*fmt != '}'))
- {
- if (i < sizeof(field_name))
- field_name[i++] = *fmt;
-
- fmt++;
- }
- if (fmt)
- fmt++; /* Skip '}' */
- field_name[i] = 0;
- }
- break;
-
- case 't': /* Bit (field) */
- case 'b': /* Bits */
- fmt++;
- width = strtol(fmt, &fmt, 10);
- if (width > 8)
- done = 1;
- else
- {
- if (shift <= 0)
- {
- bits = *databuf++;
- shift = 8;
- }
- value = (bits >> (shift - width)) & mask[width];
-
-#if 0
- printf("shift %2d bits %02x value %02x width %2d mask %02x\n",
- shift, bits, value, width, mask[width]);
-#endif
-
- ARG_PUT(value);
-
- shift -= width;
- }
-
- break;
-
- case 'i': /* Integral values */
- shift = 0;
- fmt++;
- width = strtol(fmt, &fmt, 10);
- switch(width)
- {
- case 1:
- ARG_PUT(*databuf);
- databuf++;
- break;
-
- case 2:
- ARG_PUT(
- (*databuf) << 8 |
- *(databuf + 1));
- databuf += 2;
- break;
-
- case 3:
- ARG_PUT(
- (*databuf) << 16 |
- (*(databuf + 1)) << 8 |
- *(databuf + 2));
- databuf += 3;
- break;
-
- case 4:
- ARG_PUT(
- (*databuf) << 24 |
- (*(databuf + 1)) << 16 |
- (*(databuf + 2)) << 8 |
- *(databuf + 3));
- databuf += 4;
- break;
-
- default:
- done = 1;
- }
-
- break;
-
- case 'c': /* Characters (i.e., not swapped) */
- case 'z': /* Characters with zeroed trailing spaces */
- shift = 0;
- fmt++;
- width = strtol(fmt, &fmt, 10);
- if (!suppress)
- {
- if (arg_put)
- (*arg_put)(puthook, (letter == 't' ? 'b' : letter),
- databuf, width, field_name);
- else
- {
- char *dest;
- dest = va_arg(ap, char *);
- bcopy(databuf, dest, width);
- if (letter == 'z')
- {
- char *p;
- for (p = dest + width - 1;
- (p >= (char *)dest) && (*p == ' '); p--)
- *p = 0;
- }
- }
- assigned++;
- }
- databuf += width;
- field_name[0] = 0;
- suppress = 0;
- break;
-
- case 's': /* Seek */
- shift = 0;
- fmt++;
- if (*fmt == '+')
- {
- plus = 1;
- fmt++;
- }
- else
- plus = 0;
-
- if (tolower(*fmt) == 'v')
- {
- /* You can't suppress a seek value. You also
- * can't have a variable seek when you are using
- * "arg_put".
- */
- width = (arg_put) ? 0 : va_arg(ap, int);
- fmt++;
- }
- else
- width = strtol(fmt, &fmt, 10);
-
- if (plus)
- databuf += width; /* Relative seek */
- else
- databuf = base + width; /* Absolute seek */
-
- break;
-
- case 0:
- done = 1;
- break;
-
- default:
- fprintf(stderr, "Unknown letter in format: %c\n", letter);
- fmt++;
- }
- }
-
- return assigned;
-}
-
-int scsireq_decode(scsireq_t *scsireq, char *fmt, ...)
-{
- va_list ap;
- va_start (ap, fmt);
- return do_buff_decode(scsireq->databuf, (size_t)scsireq->datalen,
- 0, 0, fmt, ap);
-}
-
-int scsireq_decode_visit(scsireq_t *scsireq, char *fmt,
-void (*arg_put)(void *, int , void *, int, char *), void *puthook)
-{
- va_list ap = (va_list)0;
- return do_buff_decode(scsireq->databuf, (size_t)scsireq->datalen,
- arg_put, puthook, fmt, ap);
-}
-
-int scsireq_buff_decode(u_char *buff, size_t len, char *fmt, ...)
-{
- va_list ap;
- va_start (ap, fmt);
- return do_buff_decode(buff, len, 0, 0, fmt, ap);
-}
-
-int scsireq_buff_decode_visit(u_char *buff, size_t len, char *fmt,
-void (*arg_put)(void *, int, void *, int, char *), void *puthook)
-{
- va_list ap = (va_list)0;
- return do_buff_decode(buff, len, arg_put, puthook, fmt, ap);
-}
-
-/* next_field: Return the next field in a command specifier. This
- * builds up a SCSI command using this trivial grammar:
- *
- * fields : field fields
- * ;
- *
- * field : value
- * | value ':' field_width
- * ;
- *
- * field_width : digit
- * | 'i' digit // i2 = 2 byte integer, i3 = 3 byte integer etc.
- * ;
- *
- * value : HEX_NUMBER
- * | 'v' // For indirection.
- * ;
- *
- * Notes:
- * Bit fields are specified MSB first to match the SCSI spec.
- *
- * Examples:
- * TUR: "0 0 0 0 0 0"
- * WRITE BUFFER: "38 v:3 0:2 0:3 v v:i3 v:i3 0", mode, buffer_id, list_length
- *
- * The function returns the value:
- * 0: For reached end, with error_p set if an error was found
- * 1: For valid stuff setup
- * 2: For "v" was entered as the value (implies use varargs)
- *
- */
-
-static int next_field(char **pp,
-char *fmt, int *width_p, int *value_p, char *name, int n_name, int *error_p,
-int *suppress_p)
-{
- char *p = *pp;
-
- int something = 0;
-
- enum
- {
- BETWEEN_FIELDS,
- START_FIELD,
- GET_FIELD,
- DONE,
- } state;
-
- int value = 0;
- int field_size; /* Default to byte field type... */
- int field_width; /* 1 byte wide */
- int is_error = 0;
- int suppress = 0;
-
- field_size = 8; /* Default to byte field type... */
- *fmt = 'i';
- field_width = 1; /* 1 byte wide */
- if (name)
- *name = 0;
-
- state = BETWEEN_FIELDS;
-
- while (state != DONE)
- {
- switch(state)
- {
- case BETWEEN_FIELDS:
- if (*p == 0)
- state = DONE;
- else if (isspace(*p))
- p++;
- else if (*p == '#')
- {
- while (*p && *p != '\n')
- p++;
- if (p)
- p++;
- }
- else if (*p == '{')
- {
- int i = 0;
-
- p++;
-
- while (*p && *p != '}')
- {
- if(name && i < n_name)
- {
- name[i] = *p;
- i++;
- }
- p++;
- }
-
- if(name && i < n_name)
- name[i] = 0;
-
- if (*p == '}')
- p++;
- }
- else if (*p == '*')
- {
- p++;
- suppress = 1;
- }
- else if (isxdigit(*p))
- {
- something = 1;
- value = strtol(p, &p, 16);
- state = START_FIELD;
- }
- else if (tolower(*p) == 'v')
- {
- p++;
- something = 2;
- value = *value_p;
- state = START_FIELD;
- }
-/* Try to work without the "v".
- */
- else if (tolower(*p) == 'i')
- {
- something = 2;
- value = *value_p;
- p++;
-
- *fmt = 'i';
- field_size = 8;
- field_width = strtol(p, &p, 10);
- state = DONE;
- }
-
-/* XXX: B can't work: Sees the 'b' as a hex digit in "isxdigit".
- * try "t" for bit field.
- */
- else if (tolower(*p) == 't')
- {
- something = 2;
- value = *value_p;
- p++;
-
- *fmt = 'b';
- field_size = 1;
- field_width = strtol(p, &p, 10);
- state = DONE;
- }
- else if (tolower(*p) == 's') /* Seek */
- {
- *fmt = 's';
- p++;
- if (tolower(*p) == 'v')
- {
- p++;
- something = 2;
- value = *value_p;
- }
- else
- {
- something = 1;
- value = strtol(p, &p, 0);
- }
- state = DONE;
- }
- else
- {
- fprintf(stderr, "Invalid starting character: %c\n", *p);
- is_error = 1;
- state = DONE;
- }
- break;
-
- case START_FIELD:
- if (*p == ':')
- {
- p++;
- field_size = 1; /* Default to bits when specified */
- state = GET_FIELD;
- }
- else
- state = DONE;
- break;
-
- case GET_FIELD:
- if (isdigit(*p))
- {
- *fmt = 'b';
- field_size = 1;
- field_width = strtol(p, &p, 10);
- state = DONE;
- }
- else if (*p == 'i') /* Integral (bytes) */
- {
- p++;
-
- *fmt = 'i';
- field_size = 8;
- field_width = strtol(p, &p, 10);
- state = DONE;
- }
- else if (*p == 'b') /* Bits */
- {
- p++;
-
- *fmt = 'b';
- field_size = 1;
- field_width = strtol(p, &p, 10);
- state = DONE;
- }
- else
- {
- fprintf(stderr, "Invalid startfield %c (%02x)\n",
- *p, *p);
- is_error = 1;
- state = DONE;
- }
- break;
-
- case DONE:
- break;
- }
- }
-
- if (is_error)
- {
- *error_p = 1;
- return 0;
- }
-
- *error_p = 0;
- *pp = p;
- *width_p = field_width * field_size;
- *value_p = value;
- *suppress_p = suppress;
-
- return something;
-}
-
-static int do_encode(u_char *buff, size_t vec_max, size_t *used,
-int (*arg_get)(void *, char *), void *gethook,
-char *fmt, va_list ap)
-{
- int ind;
- int shift;
- u_char val;
- int ret;
- int width, value, error, suppress;
- char c;
- int encoded = 0;
- char field_name[80];
-
- ind = 0;
- shift = 0;
- val = 0;
-
- while ((ret = next_field(&fmt,
- &c, &width, &value, field_name, sizeof(field_name), &error, &suppress)))
- {
- encoded++;
-
- if (ret == 2) {
- if (suppress)
- value = 0;
- else
- value = arg_get ? (*arg_get)(gethook, field_name) : va_arg(ap, int);
- }
-
-#if 0
- printf(
-"do_encode: ret %d fmt %c width %d value %d name \"%s\" error %d suppress %d\n",
- ret, c, width, value, field_name, error, suppress);
-#endif
-
- if (c == 's') /* Absolute seek */
- {
- ind = value;
- continue;
- }
-
- if (width < 8) /* A width of < 8 is a bit field. */
- {
-
- /* This is a bit field. We start with the high bits
- * so it reads the same as the SCSI spec.
- */
-
- shift += width;
-
- val |= (value << (8 - shift));
-
- if (shift == 8)
- {
- if (ind < vec_max)
- {
- buff[ind++] = val;
- val = 0;
- }
- shift = 0;
- }
- }
- else
- {
- if (shift)
- {
- if (ind < vec_max)
- {
- buff[ind++] = val;
- val = 0;
- }
- shift = 0;
- }
- switch(width)
- {
- case 8: /* 1 byte integer */
- if (ind < vec_max)
- buff[ind++] = value;
- break;
-
- case 16: /* 2 byte integer */
- if (ind < vec_max - 2 + 1)
- {
- buff[ind++] = value >> 8;
- buff[ind++] = value;
- }
- break;
-
- case 24: /* 3 byte integer */
- if (ind < vec_max - 3 + 1)
- {
- buff[ind++] = value >> 16;
- buff[ind++] = value >> 8;
- buff[ind++] = value;
- }
- break;
-
- case 32: /* 4 byte integer */
- if (ind < vec_max - 4 + 1)
- {
- buff[ind++] = value >> 24;
- buff[ind++] = value >> 16;
- buff[ind++] = value >> 8;
- buff[ind++] = value;
- }
- break;
-
- default:
- fprintf(stderr, "do_encode: Illegal width\n");
- break;
- }
- }
- }
-
- /* Flush out any remaining bits
- */
- if (shift && ind < vec_max)
- {
- buff[ind++] = val;
- val = 0;
- }
-
-
- if (used)
- *used = ind;
-
- if (error)
- return -1;
-
- return encoded;
-}
-
-/* XXX: Should be a constant in scsiio.h
- */
-#define CMD_BUFLEN 16
-
-scsireq_t *scsireq_build(scsireq_t *scsireq,
- u_long datalen, caddr_t databuf, u_long flags,
- char *cmd_spec, ...)
-{
- int cmdlen;
- va_list ap;
-
- if (scsireq == 0)
- return 0;
-
- scsireq_reset(scsireq);
-
- if (databuf)
- {
- scsireq->databuf = databuf;
- scsireq->datalen = datalen;
- scsireq->flags = flags;
- }
- else if (datalen)
- {
- /* XXX: Good way to get a memory leak. Perhaps this should be
- * removed.
- */
- if ( (scsireq->databuf = malloc(datalen)) == 0)
- return 0;
-
- scsireq->datalen = datalen;
- scsireq->flags = flags;
- }
-
- va_start(ap, cmd_spec);
-
- if (do_encode(scsireq->cmd, CMD_BUFLEN, &cmdlen, 0, 0, cmd_spec, ap) == -1)
- return 0;
-
- scsireq->cmdlen = cmdlen;
- return scsireq;
-}
-
-scsireq_t
-*scsireq_build_visit(scsireq_t *scsireq,
- u_long datalen, caddr_t databuf, u_long flags, char *cmd_spec,
- int (*arg_get)(void *hook, char *field_name), void *gethook)
-{
- int cmdlen;
- va_list ap = (va_list) 0;
-
- if (scsireq == 0)
- return 0;
-
- scsireq_reset(scsireq);
-
- if (databuf)
- {
- scsireq->databuf = databuf;
- scsireq->datalen = datalen;
- scsireq->flags = flags;
- }
- else if (datalen)
- {
- /* XXX: Good way to get a memory leak. Perhaps this should be
- * removed.
- */
- if ( (scsireq->databuf = malloc(datalen)) == 0)
- return 0;
-
- scsireq->datalen = datalen;
- scsireq->flags = flags;
- }
-
- if (do_encode(scsireq->cmd, CMD_BUFLEN, &cmdlen, arg_get, gethook,
- cmd_spec, ap) == -1)
- return 0;
-
- scsireq->cmdlen = cmdlen;
-
- return scsireq;
-}
-
-int scsireq_encode(scsireq_t *scsireq, char *fmt, ...)
-{
- va_list ap;
-
- if (scsireq == 0)
- return 0;
-
- va_start(ap, fmt);
-
- return do_encode(scsireq->databuf,
- scsireq->datalen, 0, 0, 0, fmt, ap);
-}
-
-int scsireq_buff_encode_visit(u_char *buff, size_t len, char *fmt,
- int (*arg_get)(void *hook, char *field_name), void *gethook)
-{
- va_list ap = (va_list)0;
- return do_encode(buff, len, 0,
- arg_get, gethook, fmt, ap);
-}
-
-int scsireq_encode_visit(scsireq_t *scsireq, char *fmt,
- int (*arg_get)(void *hook, char *field_name), void *gethook)
-{
- va_list ap = (va_list)0;
- return do_encode(scsireq->databuf, scsireq->datalen, 0,
- arg_get, gethook, fmt, ap);
-}
-
-FILE *scsi_debug_output(char *s)
-{
- if (s == 0)
- behave.db_f = 0;
- else
- {
- behave.db_f = fopen(s, "w");
-
- if (behave.db_f == 0)
- behave.db_f = stderr;
- }
-
- return behave.db_f;
-}
-
-#define SCSI_TRUNCATE -1
-
-typedef struct scsi_assoc
-{
- int code;
- char *text;
-} scsi_assoc_t;
-
-static scsi_assoc_t retsts[] =
-{
- { SCCMD_OK, "No error" },
- { SCCMD_TIMEOUT, "Command Timeout" },
- { SCCMD_BUSY, "Busy" },
- { SCCMD_SENSE, "Sense Returned" },
- { SCCMD_UNKNOWN, "Unknown return status" },
-
- { 0, 0 }
-};
-
-static char *scsi_assoc_text(int code, scsi_assoc_t *tab)
-{
- while (tab->text)
- {
- if (tab->code == code)
- return tab->text;
-
- tab++;
- }
-
- return "Unknown code";
-}
-
-void scsi_dump(FILE *f, char *text, u_char *p, int req, int got, int dump_print)
-{
- int i;
- int trunc = 0;
-
- if (f == 0 || req == 0)
- return;
-
- fprintf(f, "%s (%d of %d):\n", text, got, req);
-
- if (behave.db_trunc != -1 && got > behave.db_trunc)
- {
- trunc = 1;
- got = behave.db_trunc;
- }
-
- for (i = 0; i < got; i++)
- {
- fprintf(f, "%02x", p[i]);
-
- putc(' ', f);
-
- if ((i % 16) == 15 || i == got - 1)
- {
- int j;
- if (dump_print)
- {
- fprintf(f, " # ");
- for (j = i - 15; j <= i; j++)
- putc((isprint(p[j]) ? p[j] : '.'), f);
-
- putc('\n', f);
- }
- else
- putc('\n', f);
- }
- }
-
- fprintf(f, "%s", (trunc) ? "(truncated)...\n" : "\n");
-}
-
-/* XXX: sense_7x_dump and scsi_sense dump was just sort of
- * grabbed out of the old ds
- * library and not really merged in carefully. It should use the
- * new buffer decoding stuff.
- */
-
-/* Get unsigned long.
- */
-static u_long g_u_long(u_char *s)
-{
- return (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
-}
-
-/* In the old software you could patch in a special error table:
- */
-scsi_assoc_t *error_table = 0;
-
-static void sense_7x_dump(FILE *f, scsireq_t *scsireq)
-{
- int code;
- u_char *s = (u_char *)scsireq->sense;
- int valid = (*s) & 0x80;
- u_long val;
-
- static scsi_assoc_t sense[] = {
- { 0, "No sense" },
- { 1, "Recovered error" },
- { 2, "Not Ready" },
- { 3, "Medium error" },
- { 4, "Hardware error" },
- { 5, "Illegal request" },
- { 6, "Unit attention" },
- { 7, "Data protect" },
- { 8, "Blank check" },
- { 9, "Vendor specific" },
- { 0xa, "Copy aborted" },
- { 0xb, "Aborted Command" },
- { 0xc, "Equal" },
- { 0xd, "Volume overflow" },
- { 0xe, "Miscompare" },
- { 0, 0 },
- };
-
- static scsi_assoc_t code_tab[] = {
- {0x70, "current errors"},
- {0x71, "deferred errors"},
- };
-
- fprintf(f, "Error code is \"%s\"\n", scsi_assoc_text(s[0]&0x7F, code_tab));
- fprintf(f, "Segment number is %02x\n", s[1]);
-
- if (s[2] & 0x20)
- fprintf(f, "Incorrect Length Indicator is set.\n");
-
- fprintf(f, "Sense key is \"%s\"\n", scsi_assoc_text(s[2] & 0x7, sense));
-
- val = g_u_long(s + 3);
- fprintf(f, "The Information field is%s %08lx (%ld).\n",
- valid ? "" : " not valid but contains", (long)val, (long)val);
-
- val = g_u_long(s + 8);
- fprintf(f, "The Command Specific Information field is %08lx (%ld).\n",
- (long)val, (long)val);
-
- fprintf(f, "Additional sense code: %02x\n", s[12]);
- fprintf(f, "Additional sense code qualifier: %02x\n", s[13]);
-
- code = (s[12] << 8) | s[13];
-
- if (error_table)
- fprintf(f, "%s\n", scsi_assoc_text(code, error_table));
-
- if (s[15] & 0x80)
- {
- if ((s[2] & 0x7) == 0x05) /* Illegal request */
- {
- int byte;
- u_char value, bit;
- int bad_par = ((s[15] & 0x40) == 0);
- fprintf(f, "Illegal value in the %s.\n",
- (bad_par ? "parameter list" : "command descriptor block"));
- byte = ((s[16] << 8) | s[17]);
- value = bad_par ? (u_char)scsireq->databuf[byte] : (u_char)scsireq->cmd[byte];
- bit = s[15] & 0x7;
- if (s[15] & 0x08)
- fprintf(f, "Bit %d of byte %d (value %02x) is illegal.\n",
- bit, byte, value);
- else
- fprintf(f, "Byte %d (value %02x) is illegal.\n", byte, value);
- }
- else
- {
- fprintf(f, "Sense Key Specific (valid but not illegal request):\n");
- fprintf(f,
- "%02x %02x %02x\n", s[15] & 0x7f, s[16], s[17]);
- }
- }
-}
-
-/* scsi_sense_dump: Dump the sense portion of the scsireq structure.
- */
-void scsi_sense_dump(FILE *f, scsireq_t *scsireq)
-{
- u_char *s = (u_char *)scsireq->sense;
- int code = (*s) & 0x7f;
-
- if (scsireq->senselen_used == 0)
- {
- fprintf(f, "No sense sent.\n");
- return;
- }
-
-#if 0
- if (!valid)
- fprintf(f, "The sense data is not valid.\n");
-#endif
-
- switch(code)
- {
- case 0x70:
- case 0x71:
- sense_7x_dump(f, scsireq);
- break;
-
- default:
- fprintf(f, "No sense dump for error code %02x.\n", code);
- }
- scsi_dump(f, "sense", s, scsireq->senselen, scsireq->senselen_used, 0);
-}
-
-void scsi_retsts_dump(FILE *f, scsireq_t *scsireq)
-{
- if (scsireq->retsts == 0)
- return;
-
- fprintf(f, "return status %d (%s)",
- scsireq->retsts, scsi_assoc_text(scsireq->retsts, retsts));
-
- switch(scsireq->retsts)
- {
- case SCCMD_TIMEOUT:
- fprintf(f, " after %ld ms", scsireq->timeout);
- break;
-
- default:
- break;
- }
-}
-
-int scsi_debug(FILE *f, int ret, scsireq_t *scsireq)
-{
- char *d;
- if (f == 0)
- return 0;
-
- fprintf(f, "SCIOCCOMMAND ioctl");
-
- if (ret == 0)
- fprintf(f, ": Command accepted.");
- else
- {
- if (ret != -1)
- fprintf(f, ", return value %d?", ret);
-
- if (errno)
- {
- fprintf(f, ": %s", strerror(errno));
- errno = 0;
- }
- }
-
- fputc('\n', f);
-
- if (ret == 0 && (scsireq->status || scsireq->retsts || behave.db_level))
- {
- scsi_retsts_dump(f, scsireq);
-
- if (scsireq->status)
- fprintf(f, " host adapter status %d\n", scsireq->status);
-
- if (scsireq->flags & SCCMD_READ)
- d = "Data in";
- else if (scsireq->flags & SCCMD_WRITE)
- d = "Data out";
- else
- d = "No data transfer?";
-
- if (scsireq->cmdlen == 0)
- fprintf(f, "Zero length command????\n");
-
- scsi_dump(f, "Command out",
- (u_char *)scsireq->cmd, scsireq->cmdlen, scsireq->cmdlen, 0);
- scsi_dump(f, d,
- (u_char *)scsireq->databuf, scsireq->datalen,
- scsireq->datalen_used, 1);
- scsi_sense_dump(f, scsireq);
- }
-
- fflush(f);
-
- return ret;
-}
-
-static char *debug_output;
-
-int scsi_open(const char *path, int flags)
-{
- int fd = open(path, flags);
-
- if (fd != -1)
- {
- char *p;
- debug_output = getenv("SU_DEBUG_OUTPUT");
- (void)scsi_debug_output(debug_output);
-
- if ((p = getenv("SU_DEBUG_LEVEL")))
- sscanf(p, "%d", &behave.db_level);
-
- if ((p = getenv("SU_DEBUG_TRUNCATE")))
- sscanf(p, "%d", &behave.db_trunc);
- else
- behave.db_trunc = SCSI_TRUNCATE;
- }
-
- return fd;
-}
-
-int scsireq_enter(int fid, scsireq_t *scsireq)
-{
- int ret;
-
- if (scsireq == 0)
- return EFAULT;
-
- ret = ioctl(fid, SCIOCCOMMAND, (void *)scsireq);
-
- if (behave.db_f) scsi_debug(behave.db_f, ret, scsireq);
-
- return ret;
-}