diff options
author | Justin T. Gibbs <gibbs@FreeBSD.org> | 1998-09-17 03:56:23 +0000 |
---|---|---|
committer | Justin T. Gibbs <gibbs@FreeBSD.org> | 1998-09-17 03:56:23 +0000 |
commit | c3deaba902031c915559093181751f6d1a079a34 (patch) | |
tree | c988d9f37982056cf07ff832cd839633a2027d0b /lib/libscsi/scsi.c | |
parent | c4ea283d54e6dd276b0bfade5bfc78f635284da9 (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.c | 1192 |
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; -} |