diff options
Diffstat (limited to 'audio/tosha/patches/patch-ae')
-rw-r--r-- | audio/tosha/patches/patch-ae | 1199 |
1 files changed, 1199 insertions, 0 deletions
diff --git a/audio/tosha/patches/patch-ae b/audio/tosha/patches/patch-ae new file mode 100644 index 00000000000..e1f79911e96 --- /dev/null +++ b/audio/tosha/patches/patch-ae @@ -0,0 +1,1199 @@ +$NetBSD: patch-ae,v 1.1 1999/03/12 16:44:14 hubertf Exp $ + +--- scsi.c.orig Fri Mar 12 17:41:59 1999 ++++ scsi.c Fri Mar 12 17:42:26 1999 +@@ -0,0 +1,1194 @@ ++/* $OpenBSD: scsi.c,v 1.2 1996/07/31 09:25:48 niklas Exp $ */ ++ ++/* 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. ++ * ++ * $FreeBSD: scsi.c,v 1.6 1995/05/30 05:47:26 rgrimes Exp $ ++ */ ++#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 <errno.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; ++ 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; ++ 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, ...) ++{ ++ size_t 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) ++{ ++ size_t 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; ++ } ++ ++ 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; ++ 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; ++ 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; ++} |