scsi_cmdparse.c revision 84199
139209Sgibbs/* 239209Sgibbs * Taken from the original FreeBSD user SCSI library. 339209Sgibbs */ 439209Sgibbs/* Copyright (c) 1994 HD Associates 539209Sgibbs * (contact: dufault@hda.com) 639209Sgibbs * All rights reserved. 739209Sgibbs * 839209Sgibbs * Redistribution and use in source and binary forms, with or without 939209Sgibbs * modification, are permitted provided that the following conditions 1039209Sgibbs * are met: 1139209Sgibbs * 1. Redistributions of source code must retain the above copyright 1239209Sgibbs * notice, this list of conditions and the following disclaimer. 1339209Sgibbs * 2. Redistributions in binary form must reproduce the above copyright 1439209Sgibbs * notice, this list of conditions and the following disclaimer in the 1539209Sgibbs * documentation and/or other materials provided with the distribution. 1639209Sgibbs * 3. All advertising materials mentioning features or use of this software 1739209Sgibbs * must display the following acknowledgement: 1839209Sgibbs * This product includes software developed by HD Associates 1939209Sgibbs * 4. Neither the name of the HD Associaates nor the names of its contributors 2039209Sgibbs * may be used to endorse or promote products derived from this software 2139209Sgibbs * without specific prior written permission. 2239209Sgibbs * 2339209Sgibbs * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES``AS IS'' AND 2439209Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2539209Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2639209Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE 2739209Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2839209Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2939209Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3039209Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3139209Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3239209Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3339209Sgibbs * SUCH DAMAGE. 3439209Sgibbs * From: scsi.c,v 1.8 1997/02/22 15:07:54 peter Exp $ 3539209Sgibbs */ 3684199Sdillon 3784199Sdillon#include <sys/cdefs.h> 3884199Sdillon__FBSDID("$FreeBSD: head/lib/libcam/scsi_cmdparse.c 84199 2001-09-30 21:13:43Z dillon $"); 3984199Sdillon 4039209Sgibbs#include <stdlib.h> 4139209Sgibbs#include <stdio.h> 4239209Sgibbs#include <ctype.h> 4339209Sgibbs#include <string.h> 4439209Sgibbs#include <sys/errno.h> 4539209Sgibbs#include <stdarg.h> 4639209Sgibbs#include <fcntl.h> 4739209Sgibbs 4839209Sgibbs#include <cam/cam.h> 4939209Sgibbs#include <cam/cam_ccb.h> 5039209Sgibbs#include <cam/scsi/scsi_message.h> 5139209Sgibbs#include "camlib.h" 5239209Sgibbs 5339209Sgibbs/* 5439209Sgibbs * Decode: Decode the data section of a scsireq. This decodes 5539209Sgibbs * trivial grammar: 5639209Sgibbs * 5739209Sgibbs * fields : field fields 5839209Sgibbs * ; 5939209Sgibbs * 6039209Sgibbs * field : field_specifier 6139209Sgibbs * | control 6239209Sgibbs * ; 6339209Sgibbs * 6439209Sgibbs * control : 's' seek_value 6539209Sgibbs * | 's' '+' seek_value 6639209Sgibbs * ; 6739209Sgibbs * 6839209Sgibbs * seek_value : DECIMAL_NUMBER 6939209Sgibbs * | 'v' // For indirect seek, i.e., value from the arg list 7039209Sgibbs * ; 7139209Sgibbs * 7239209Sgibbs * field_specifier : type_specifier field_width 7339209Sgibbs * | '{' NAME '}' type_specifier field_width 7439209Sgibbs * ; 7539209Sgibbs * 7639209Sgibbs * field_width : DECIMAL_NUMBER 7739209Sgibbs * ; 7839209Sgibbs * 7939209Sgibbs * type_specifier : 'i' // Integral types (i1, i2, i3, i4) 8039209Sgibbs * | 'b' // Bits 8139209Sgibbs * | 't' // Bits 8239209Sgibbs * | 'c' // Character arrays 8339209Sgibbs * | 'z' // Character arrays with zeroed trailing spaces 8439209Sgibbs * ; 8539209Sgibbs * 8639209Sgibbs * Notes: 8739209Sgibbs * 1. Integral types are swapped into host order. 8839209Sgibbs * 2. Bit fields are allocated MSB to LSB to match the SCSI spec documentation. 8939209Sgibbs * 3. 's' permits "seeking" in the string. "s+DECIMAL" seeks relative to 9039209Sgibbs * DECIMAL; "sDECIMAL" seeks absolute to decimal. 9139209Sgibbs * 4. 's' permits an indirect reference. "sv" or "s+v" will get the 9239209Sgibbs * next integer value from the arg array. 9339209Sgibbs * 5. Field names can be anything between the braces 9439209Sgibbs * 9539209Sgibbs * BUGS: 9639209Sgibbs * i and b types are promoted to ints. 9739209Sgibbs * 9839209Sgibbs */ 9939209Sgibbs 10039209Sgibbsstatic int 10139209Sgibbsdo_buff_decode(u_int8_t *databuf, size_t len, 10239209Sgibbs void (*arg_put)(void *, int , void *, int, char *), 10339209Sgibbs void *puthook, char *fmt, va_list ap) 10439209Sgibbs{ 10539209Sgibbs int assigned = 0; 10639209Sgibbs int width; 10739209Sgibbs int suppress; 10839209Sgibbs int plus; 10939209Sgibbs int done = 0; 11039209Sgibbs static u_char mask[] = {0, 0x01, 0x03, 0x07, 0x0f, 11139209Sgibbs 0x1f, 0x3f, 0x7f, 0xff}; 11239209Sgibbs int value; 11339209Sgibbs u_char *base = databuf; 11439209Sgibbs char letter; 11539209Sgibbs char field_name[80]; 11639209Sgibbs 11739209Sgibbs# define ARG_PUT(ARG) \ 11839209Sgibbs do \ 11939209Sgibbs { \ 12039209Sgibbs if (!suppress) \ 12139209Sgibbs { \ 12239209Sgibbs if (arg_put) \ 12339209Sgibbs (*arg_put)(puthook, (letter == 't' ? \ 12439209Sgibbs 'b' : letter), \ 12564382Skbyanc (void *)((long)(ARG)), width, \ 12664382Skbyanc field_name); \ 12739209Sgibbs else \ 12839209Sgibbs *(va_arg(ap, int *)) = (ARG); \ 12939209Sgibbs assigned++; \ 13039209Sgibbs } \ 13139209Sgibbs field_name[0] = 0; \ 13239209Sgibbs suppress = 0; \ 13339209Sgibbs } while (0) 13439209Sgibbs 13539209Sgibbs u_char bits = 0; /* For bit fields */ 13639209Sgibbs int shift = 0; /* Bits already shifted out */ 13739209Sgibbs suppress = 0; 13839209Sgibbs field_name[0] = 0; 13939209Sgibbs 14039209Sgibbs while (!done) { 14139209Sgibbs switch(letter = *fmt) { 14239209Sgibbs case ' ': /* White space */ 14339209Sgibbs case '\t': 14439209Sgibbs case '\r': 14539209Sgibbs case '\n': 14639209Sgibbs case '\f': 14739209Sgibbs fmt++; 14839209Sgibbs break; 14939209Sgibbs 15039209Sgibbs case '#': /* Comment */ 15139209Sgibbs while (*fmt && (*fmt != '\n')) 15239209Sgibbs fmt++; 15339209Sgibbs if (fmt) 15439209Sgibbs fmt++; /* Skip '\n' */ 15539209Sgibbs break; 15639209Sgibbs 15739209Sgibbs case '*': /* Suppress assignment */ 15839209Sgibbs fmt++; 15939209Sgibbs suppress = 1; 16039209Sgibbs break; 16139209Sgibbs 16239209Sgibbs case '{': /* Field Name */ 16339209Sgibbs { 16439209Sgibbs int i = 0; 16539209Sgibbs fmt++; /* Skip '{' */ 16639209Sgibbs while (*fmt && (*fmt != '}')) { 16739209Sgibbs if (i < sizeof(field_name)) 16839209Sgibbs field_name[i++] = *fmt; 16939209Sgibbs 17039209Sgibbs fmt++; 17139209Sgibbs } 17239209Sgibbs if (fmt) 17339209Sgibbs fmt++; /* Skip '}' */ 17439209Sgibbs field_name[i] = 0; 17539209Sgibbs break; 17639209Sgibbs } 17739209Sgibbs 17839209Sgibbs case 't': /* Bit (field) */ 17939209Sgibbs case 'b': /* Bits */ 18039209Sgibbs fmt++; 18139209Sgibbs width = strtol(fmt, &fmt, 10); 18239209Sgibbs if (width > 8) 18339209Sgibbs done = 1; 18439209Sgibbs else { 18539209Sgibbs if (shift <= 0) { 18639209Sgibbs bits = *databuf++; 18739209Sgibbs shift = 8; 18839209Sgibbs } 18939209Sgibbs value = (bits >> (shift - width)) & 19039209Sgibbs mask[width]; 19139209Sgibbs 19239209Sgibbs#if 0 19339209Sgibbs printf("shift %2d bits %02x value %02x width %2d mask %02x\n", 19439209Sgibbs shift, bits, value, width, mask[width]); 19539209Sgibbs#endif 19639209Sgibbs 19739209Sgibbs ARG_PUT(value); 19839209Sgibbs 19939209Sgibbs shift -= width; 20039209Sgibbs } 20139209Sgibbs break; 20239209Sgibbs 20339209Sgibbs case 'i': /* Integral values */ 20439209Sgibbs shift = 0; 20539209Sgibbs fmt++; 20639209Sgibbs width = strtol(fmt, &fmt, 10); 20739209Sgibbs switch(width) { 20839209Sgibbs case 1: 20939209Sgibbs ARG_PUT(*databuf); 21039209Sgibbs databuf++; 21139209Sgibbs break; 21239209Sgibbs 21339209Sgibbs case 2: 21439209Sgibbs ARG_PUT((*databuf) << 8 | *(databuf + 1)); 21539209Sgibbs databuf += 2; 21639209Sgibbs break; 21739209Sgibbs 21839209Sgibbs case 3: 21939209Sgibbs ARG_PUT((*databuf) << 16 | 22039209Sgibbs (*(databuf + 1)) << 8 | *(databuf + 2)); 22139209Sgibbs databuf += 3; 22239209Sgibbs break; 22339209Sgibbs 22439209Sgibbs case 4: 22539209Sgibbs ARG_PUT((*databuf) << 24 | 22639209Sgibbs (*(databuf + 1)) << 16 | 22739209Sgibbs (*(databuf + 2)) << 8 | 22839209Sgibbs *(databuf + 3)); 22939209Sgibbs databuf += 4; 23039209Sgibbs break; 23139209Sgibbs 23239209Sgibbs default: 23339209Sgibbs done = 1; 23439209Sgibbs break; 23539209Sgibbs } 23639209Sgibbs 23739209Sgibbs break; 23839209Sgibbs 23939209Sgibbs case 'c': /* Characters (i.e., not swapped) */ 24039209Sgibbs case 'z': /* Characters with zeroed trailing 24139209Sgibbs spaces */ 24239209Sgibbs shift = 0; 24339209Sgibbs fmt++; 24439209Sgibbs width = strtol(fmt, &fmt, 10); 24539209Sgibbs if (!suppress) { 24639209Sgibbs if (arg_put) 24739209Sgibbs (*arg_put)(puthook, 24839209Sgibbs (letter == 't' ? 'b' : letter), 24939209Sgibbs databuf, width, field_name); 25039209Sgibbs else { 25139209Sgibbs char *dest; 25239209Sgibbs dest = va_arg(ap, char *); 25339209Sgibbs bcopy(databuf, dest, width); 25439209Sgibbs if (letter == 'z') { 25539209Sgibbs char *p; 25639209Sgibbs for (p = dest + width - 1; 25739209Sgibbs (p >= (char *)dest) 25839209Sgibbs && (*p == ' '); p--) 25939209Sgibbs *p = 0; 26039209Sgibbs } 26139209Sgibbs } 26239209Sgibbs assigned++; 26339209Sgibbs } 26439209Sgibbs databuf += width; 26539209Sgibbs field_name[0] = 0; 26639209Sgibbs suppress = 0; 26739209Sgibbs break; 26839209Sgibbs 26939209Sgibbs case 's': /* Seek */ 27039209Sgibbs shift = 0; 27139209Sgibbs fmt++; 27239209Sgibbs if (*fmt == '+') { 27339209Sgibbs plus = 1; 27439209Sgibbs fmt++; 27539209Sgibbs } else 27639209Sgibbs plus = 0; 27739209Sgibbs 27839209Sgibbs if (tolower(*fmt) == 'v') { 27939209Sgibbs /* 28039209Sgibbs * You can't suppress a seek value. You also 28139209Sgibbs * can't have a variable seek when you are using 28239209Sgibbs * "arg_put". 28339209Sgibbs */ 28439209Sgibbs width = (arg_put) ? 0 : va_arg(ap, int); 28539209Sgibbs fmt++; 28639209Sgibbs } else 28739209Sgibbs width = strtol(fmt, &fmt, 10); 28839209Sgibbs 28939209Sgibbs if (plus) 29039209Sgibbs databuf += width; /* Relative seek */ 29139209Sgibbs else 29239209Sgibbs databuf = base + width; /* Absolute seek */ 29339209Sgibbs 29439209Sgibbs break; 29539209Sgibbs 29639209Sgibbs case 0: 29739209Sgibbs done = 1; 29839209Sgibbs break; 29939209Sgibbs 30039209Sgibbs default: 30139209Sgibbs fprintf(stderr, "Unknown letter in format: %c\n", 30239209Sgibbs letter); 30339209Sgibbs fmt++; 30439209Sgibbs break; 30539209Sgibbs } 30639209Sgibbs } 30739209Sgibbs 30839209Sgibbs return (assigned); 30939209Sgibbs} 31039209Sgibbs 31139209Sgibbs/* next_field: Return the next field in a command specifier. This 31239209Sgibbs * builds up a SCSI command using this trivial grammar: 31339209Sgibbs * 31439209Sgibbs * fields : field fields 31539209Sgibbs * ; 31639209Sgibbs * 31739209Sgibbs * field : value 31839209Sgibbs * | value ':' field_width 31939209Sgibbs * ; 32039209Sgibbs * 32139209Sgibbs * field_width : digit 32239209Sgibbs * | 'i' digit // i2 = 2 byte integer, i3 = 3 byte integer etc. 32339209Sgibbs * ; 32439209Sgibbs * 32539209Sgibbs * value : HEX_NUMBER 32639209Sgibbs * | 'v' // For indirection. 32739209Sgibbs * ; 32839209Sgibbs * 32939209Sgibbs * Notes: 33039209Sgibbs * Bit fields are specified MSB first to match the SCSI spec. 33139209Sgibbs * 33239209Sgibbs * Examples: 33339209Sgibbs * TUR: "0 0 0 0 0 0" 33439209Sgibbs * WRITE BUFFER: "38 v:3 0:2 0:3 v v:i3 v:i3 0", mode, buffer_id, list_length 33539209Sgibbs * 33639209Sgibbs * The function returns the value: 33739209Sgibbs * 0: For reached end, with error_p set if an error was found 33839209Sgibbs * 1: For valid stuff setup 33939209Sgibbs * 2: For "v" was entered as the value (implies use varargs) 34039209Sgibbs * 34139209Sgibbs */ 34239209Sgibbs 34339209Sgibbsstatic int 34439209Sgibbsnext_field(char **pp, char *fmt, int *width_p, int *value_p, char *name, 34539209Sgibbs int n_name, int *error_p, int *suppress_p) 34639209Sgibbs{ 34739209Sgibbs char *p = *pp; 34839209Sgibbs 34939209Sgibbs int something = 0; 35039209Sgibbs 35139209Sgibbs enum { 35239209Sgibbs BETWEEN_FIELDS, 35339209Sgibbs START_FIELD, 35439209Sgibbs GET_FIELD, 35539209Sgibbs DONE, 35639209Sgibbs } state; 35739209Sgibbs 35839209Sgibbs int value = 0; 35939209Sgibbs int field_size; /* Default to byte field type... */ 36039209Sgibbs int field_width; /* 1 byte wide */ 36139209Sgibbs int is_error = 0; 36239209Sgibbs int suppress = 0; 36339209Sgibbs 36439209Sgibbs field_size = 8; /* Default to byte field type... */ 36539209Sgibbs *fmt = 'i'; 36639209Sgibbs field_width = 1; /* 1 byte wide */ 36739209Sgibbs if (name) 36839209Sgibbs *name = 0; 36939209Sgibbs 37039209Sgibbs state = BETWEEN_FIELDS; 37139209Sgibbs 37239209Sgibbs while (state != DONE) { 37339209Sgibbs switch(state) { 37439209Sgibbs case BETWEEN_FIELDS: 37539209Sgibbs if (*p == 0) 37639209Sgibbs state = DONE; 37739209Sgibbs else if (isspace(*p)) 37839209Sgibbs p++; 37939209Sgibbs else if (*p == '#') { 38039209Sgibbs while (*p && *p != '\n') 38139209Sgibbs p++; 38239209Sgibbs if (p) 38339209Sgibbs p++; 38439209Sgibbs } else if (*p == '{') { 38539209Sgibbs int i = 0; 38639209Sgibbs 38739209Sgibbs p++; 38839209Sgibbs 38939209Sgibbs while (*p && *p != '}') { 39039209Sgibbs if(name && i < n_name) { 39139209Sgibbs name[i] = *p; 39239209Sgibbs i++; 39339209Sgibbs } 39439209Sgibbs p++; 39539209Sgibbs } 39639209Sgibbs 39739209Sgibbs if(name && i < n_name) 39839209Sgibbs name[i] = 0; 39939209Sgibbs 40039209Sgibbs if (*p == '}') 40139209Sgibbs p++; 40239209Sgibbs } else if (*p == '*') { 40339209Sgibbs p++; 40439209Sgibbs suppress = 1; 40539209Sgibbs } else if (isxdigit(*p)) { 40639209Sgibbs something = 1; 40739209Sgibbs value = strtol(p, &p, 16); 40839209Sgibbs state = START_FIELD; 40939209Sgibbs } else if (tolower(*p) == 'v') { 41039209Sgibbs p++; 41139209Sgibbs something = 2; 41239209Sgibbs value = *value_p; 41339209Sgibbs state = START_FIELD; 41439209Sgibbs } else if (tolower(*p) == 'i') { 41539209Sgibbs /* 41639209Sgibbs * Try to work without the "v". 41739209Sgibbs */ 41839209Sgibbs something = 2; 41939209Sgibbs value = *value_p; 42039209Sgibbs p++; 42139209Sgibbs 42239209Sgibbs *fmt = 'i'; 42339209Sgibbs field_size = 8; 42439209Sgibbs field_width = strtol(p, &p, 10); 42539209Sgibbs state = DONE; 42639209Sgibbs 42739209Sgibbs } else if (tolower(*p) == 't') { 42839209Sgibbs /* 42939209Sgibbs * XXX: B can't work: Sees the 'b' as a 43039209Sgibbs * hex digit in "isxdigit". try "t" for 43139209Sgibbs * bit field. 43239209Sgibbs */ 43339209Sgibbs something = 2; 43439209Sgibbs value = *value_p; 43539209Sgibbs p++; 43639209Sgibbs 43739209Sgibbs *fmt = 'b'; 43839209Sgibbs field_size = 1; 43939209Sgibbs field_width = strtol(p, &p, 10); 44039209Sgibbs state = DONE; 44139209Sgibbs } else if (tolower(*p) == 's') { 44239209Sgibbs /* Seek */ 44339209Sgibbs *fmt = 's'; 44439209Sgibbs p++; 44539209Sgibbs if (tolower(*p) == 'v') { 44639209Sgibbs p++; 44739209Sgibbs something = 2; 44839209Sgibbs value = *value_p; 44939209Sgibbs } else { 45039209Sgibbs something = 1; 45139209Sgibbs value = strtol(p, &p, 0); 45239209Sgibbs } 45339209Sgibbs state = DONE; 45439209Sgibbs } else { 45539209Sgibbs fprintf(stderr, "Invalid starting " 45639209Sgibbs "character: %c\n", *p); 45739209Sgibbs is_error = 1; 45839209Sgibbs state = DONE; 45939209Sgibbs } 46039209Sgibbs break; 46139209Sgibbs 46239209Sgibbs case START_FIELD: 46339209Sgibbs if (*p == ':') { 46439209Sgibbs p++; 46539209Sgibbs field_size = 1; /* Default to bits 46639209Sgibbs when specified */ 46739209Sgibbs state = GET_FIELD; 46839209Sgibbs } else 46939209Sgibbs state = DONE; 47039209Sgibbs break; 47139209Sgibbs 47239209Sgibbs case GET_FIELD: 47339209Sgibbs if (isdigit(*p)) { 47439209Sgibbs *fmt = 'b'; 47539209Sgibbs field_size = 1; 47639209Sgibbs field_width = strtol(p, &p, 10); 47739209Sgibbs state = DONE; 47839209Sgibbs } else if (*p == 'i') { 47939209Sgibbs 48039209Sgibbs /* Integral (bytes) */ 48139209Sgibbs p++; 48239209Sgibbs 48339209Sgibbs *fmt = 'i'; 48439209Sgibbs field_size = 8; 48539209Sgibbs field_width = strtol(p, &p, 10); 48639209Sgibbs state = DONE; 48739209Sgibbs } else if (*p == 'b') { 48839209Sgibbs 48939209Sgibbs /* Bits */ 49039209Sgibbs p++; 49139209Sgibbs 49239209Sgibbs *fmt = 'b'; 49339209Sgibbs field_size = 1; 49439209Sgibbs field_width = strtol(p, &p, 10); 49539209Sgibbs state = DONE; 49639209Sgibbs } else { 49739209Sgibbs fprintf(stderr, "Invalid startfield %c " 49839209Sgibbs "(%02x)\n", *p, *p); 49939209Sgibbs is_error = 1; 50039209Sgibbs state = DONE; 50139209Sgibbs } 50239209Sgibbs break; 50339209Sgibbs 50439209Sgibbs case DONE: 50539209Sgibbs break; 50639209Sgibbs } 50739209Sgibbs } 50839209Sgibbs 50939209Sgibbs if (is_error) { 51039209Sgibbs *error_p = 1; 51139209Sgibbs return 0; 51239209Sgibbs } 51339209Sgibbs 51439209Sgibbs *error_p = 0; 51539209Sgibbs *pp = p; 51639209Sgibbs *width_p = field_width * field_size; 51739209Sgibbs *value_p = value; 51839209Sgibbs *suppress_p = suppress; 51939209Sgibbs 52039209Sgibbs return (something); 52139209Sgibbs} 52239209Sgibbs 52339209Sgibbsstatic int 52439209Sgibbsdo_encode(u_char *buff, size_t vec_max, size_t *used, 52539209Sgibbs int (*arg_get)(void *, char *), void *gethook, char *fmt, va_list ap) 52639209Sgibbs{ 52739209Sgibbs int ind; 52839209Sgibbs int shift; 52939209Sgibbs u_char val; 53039209Sgibbs int ret; 53139209Sgibbs int width, value, error, suppress; 53239209Sgibbs char c; 53339209Sgibbs int encoded = 0; 53439209Sgibbs char field_name[80]; 53539209Sgibbs 53639209Sgibbs ind = 0; 53739209Sgibbs shift = 0; 53839209Sgibbs val = 0; 53939209Sgibbs 54039209Sgibbs while ((ret = next_field(&fmt, &c, &width, &value, field_name, 54139209Sgibbs sizeof(field_name), &error, &suppress))) { 54239209Sgibbs encoded++; 54339209Sgibbs 54439209Sgibbs if (ret == 2) { 54539209Sgibbs if (suppress) 54639209Sgibbs value = 0; 54739209Sgibbs else 54839209Sgibbs value = arg_get ? 54939209Sgibbs (*arg_get)(gethook, field_name) : 55039209Sgibbs va_arg(ap, int); 55139209Sgibbs } 55239209Sgibbs 55339209Sgibbs#if 0 55439209Sgibbs printf( 55539209Sgibbs"do_encode: ret %d fmt %c width %d value %d name \"%s\" error %d suppress %d\n", 55639209Sgibbs ret, c, width, value, field_name, error, suppress); 55739209Sgibbs#endif 55839209Sgibbs /* Absolute seek */ 55939209Sgibbs if (c == 's') { 56039209Sgibbs ind = value; 56139209Sgibbs continue; 56239209Sgibbs } 56339209Sgibbs 56439209Sgibbs /* A width of < 8 is a bit field. */ 56539209Sgibbs if (width < 8) { 56639209Sgibbs 56739209Sgibbs /* This is a bit field. We start with the high bits 56839209Sgibbs * so it reads the same as the SCSI spec. 56939209Sgibbs */ 57039209Sgibbs 57139209Sgibbs shift += width; 57239209Sgibbs 57339209Sgibbs val |= (value << (8 - shift)); 57439209Sgibbs 57539209Sgibbs if (shift == 8) { 57639209Sgibbs if (ind < vec_max) { 57739209Sgibbs buff[ind++] = val; 57839209Sgibbs val = 0; 57939209Sgibbs } 58039209Sgibbs shift = 0; 58139209Sgibbs } 58239209Sgibbs } else { 58339209Sgibbs if (shift) { 58439209Sgibbs if (ind < vec_max) { 58539209Sgibbs buff[ind++] = val; 58639209Sgibbs val = 0; 58739209Sgibbs } 58839209Sgibbs shift = 0; 58939209Sgibbs } 59039209Sgibbs switch(width) { 59139209Sgibbs case 8: /* 1 byte integer */ 59239209Sgibbs if (ind < vec_max) 59339209Sgibbs buff[ind++] = value; 59439209Sgibbs break; 59539209Sgibbs 59639209Sgibbs case 16: /* 2 byte integer */ 59739209Sgibbs if (ind < vec_max - 2 + 1) { 59839209Sgibbs buff[ind++] = value >> 8; 59939209Sgibbs buff[ind++] = value; 60039209Sgibbs } 60139209Sgibbs break; 60239209Sgibbs 60339209Sgibbs case 24: /* 3 byte integer */ 60439209Sgibbs if (ind < vec_max - 3 + 1) { 60539209Sgibbs buff[ind++] = value >> 16; 60639209Sgibbs buff[ind++] = value >> 8; 60739209Sgibbs buff[ind++] = value; 60839209Sgibbs } 60939209Sgibbs break; 61039209Sgibbs 61139209Sgibbs case 32: /* 4 byte integer */ 61239209Sgibbs if (ind < vec_max - 4 + 1) { 61339209Sgibbs buff[ind++] = value >> 24; 61439209Sgibbs buff[ind++] = value >> 16; 61539209Sgibbs buff[ind++] = value >> 8; 61639209Sgibbs buff[ind++] = value; 61739209Sgibbs } 61839209Sgibbs break; 61939209Sgibbs 62039209Sgibbs default: 62139209Sgibbs fprintf(stderr, "do_encode: Illegal width\n"); 62239209Sgibbs break; 62339209Sgibbs } 62439209Sgibbs } 62539209Sgibbs } 62639209Sgibbs 62739209Sgibbs /* Flush out any remaining bits 62839209Sgibbs */ 62939209Sgibbs if (shift && ind < vec_max) { 63039209Sgibbs buff[ind++] = val; 63139209Sgibbs val = 0; 63239209Sgibbs } 63339209Sgibbs 63439209Sgibbs 63539209Sgibbs if (used) 63639209Sgibbs *used = ind; 63739209Sgibbs 63839209Sgibbs if (error) 63939209Sgibbs return -1; 64039209Sgibbs 64139209Sgibbs return encoded; 64239209Sgibbs} 64339209Sgibbs 64439209Sgibbsint 64539209Sgibbscsio_decode(struct ccb_scsiio *csio, char *fmt, ...) 64639209Sgibbs{ 64739209Sgibbs va_list ap; 64839209Sgibbs 64939209Sgibbs va_start(ap, fmt); 65039209Sgibbs 65139209Sgibbs return(do_buff_decode(csio->data_ptr, (size_t)csio->dxfer_len, 65239209Sgibbs 0, 0, fmt, ap)); 65339209Sgibbs} 65439209Sgibbs 65539209Sgibbsint 65639209Sgibbscsio_decode_visit(struct ccb_scsiio *csio, char *fmt, 65739209Sgibbs void (*arg_put)(void *, int, void *, int, char *), 65839209Sgibbs void *puthook) 65939209Sgibbs{ 66039209Sgibbs va_list ap; 66139209Sgibbs 66239381Sken /* 66339381Sken * We need some way to output things; we can't do it without 66439381Sken * the arg_put function. 66539381Sken */ 66639381Sken if (arg_put == NULL) 66739381Sken return(-1); 66839209Sgibbs 66939381Sken bzero(&ap, sizeof(ap)); 67039381Sken 67139209Sgibbs return(do_buff_decode(csio->data_ptr, (size_t)csio->dxfer_len, 67239209Sgibbs arg_put, puthook, fmt, ap)); 67339209Sgibbs} 67439209Sgibbs 67539209Sgibbsint 67639209Sgibbsbuff_decode(u_int8_t *buff, size_t len, char *fmt, ...) 67739209Sgibbs{ 67839209Sgibbs va_list ap; 67939209Sgibbs 68039209Sgibbs va_start(ap, fmt); 68139209Sgibbs 68239209Sgibbs return(do_buff_decode(buff, len, 0, 0, fmt, ap)); 68339209Sgibbs} 68439209Sgibbs 68539209Sgibbsint 68639209Sgibbsbuff_decode_visit(u_int8_t *buff, size_t len, char *fmt, 68739209Sgibbs void (*arg_put)(void *, int, void *, int, char *), 68839209Sgibbs void *puthook) 68939209Sgibbs{ 69039209Sgibbs va_list ap; 69139209Sgibbs 69239381Sken /* 69339381Sken * We need some way to output things; we can't do it without 69439381Sken * the arg_put function. 69539381Sken */ 69639381Sken if (arg_put == NULL) 69739381Sken return(-1); 69839209Sgibbs 69939381Sken bzero(&ap, sizeof(ap)); 70039381Sken 70139209Sgibbs return(do_buff_decode(buff, len, arg_put, puthook, fmt, ap)); 70239209Sgibbs} 70339209Sgibbs 70439209Sgibbs/* 70539209Sgibbs * Build a SCSI CCB, given the command and data pointers and a format 70639209Sgibbs * string describing the 70739209Sgibbs */ 70839209Sgibbsint 70939209Sgibbscsio_build(struct ccb_scsiio *csio, u_int8_t *data_ptr, u_int32_t dxfer_len, 71039209Sgibbs u_int32_t flags, int retry_count, int timeout, char *cmd_spec, ...) 71139209Sgibbs{ 71239381Sken size_t cmdlen; 71339209Sgibbs int retval; 71439209Sgibbs va_list ap; 71539209Sgibbs 71639209Sgibbs if (csio == NULL) 71739209Sgibbs return(0); 71839209Sgibbs 71939209Sgibbs bzero(csio, sizeof(struct ccb_scsiio)); 72039209Sgibbs 72139209Sgibbs va_start(ap, cmd_spec); 72239209Sgibbs 72339209Sgibbs if ((retval = do_encode(csio->cdb_io.cdb_bytes, SCSI_MAX_CDBLEN, 72439209Sgibbs &cmdlen, NULL, NULL, cmd_spec, ap)) == -1) 72539209Sgibbs return(retval); 72639209Sgibbs 72739209Sgibbs cam_fill_csio(csio, 72839209Sgibbs /* retries */ retry_count, 72939209Sgibbs /* cbfcnp */ NULL, 73039209Sgibbs /* flags */ flags, 73139209Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 73239209Sgibbs /* data_ptr */ data_ptr, 73339209Sgibbs /* dxfer_len */ dxfer_len, 73439209Sgibbs /* sense_len */ SSD_FULL_SIZE, 73539209Sgibbs /* cdb_len */ cmdlen, 73639209Sgibbs /* timeout */ timeout ? timeout : 5000); 73739209Sgibbs 73839209Sgibbs return(retval); 73939209Sgibbs} 74039209Sgibbs 74139209Sgibbsint 74239209Sgibbscsio_build_visit(struct ccb_scsiio *csio, u_int8_t *data_ptr, 74339209Sgibbs u_int32_t dxfer_len, u_int32_t flags, int retry_count, 74439209Sgibbs int timeout, char *cmd_spec, 74539209Sgibbs int (*arg_get)(void *hook, char *field_name), void *gethook) 74639209Sgibbs{ 74739209Sgibbs va_list ap; 74839381Sken size_t cmdlen; 74939381Sken int retval; 75039209Sgibbs 75139209Sgibbs if (csio == NULL) 75239209Sgibbs return(0); 75339209Sgibbs 75439381Sken /* 75539381Sken * We need something to encode, but we can't get it without the 75639381Sken * arg_get function. 75739381Sken */ 75839381Sken if (arg_get == NULL) 75939381Sken return(-1); 76039209Sgibbs 76139381Sken bzero(&ap, sizeof(ap)); 76239381Sken 76339209Sgibbs bzero(csio, sizeof(struct ccb_scsiio)); 76439209Sgibbs 76539209Sgibbs if ((retval = do_encode(csio->cdb_io.cdb_bytes, SCSI_MAX_CDBLEN, 76639209Sgibbs &cmdlen, arg_get, gethook, cmd_spec, ap)) == -1) 76739209Sgibbs return(retval); 76839209Sgibbs 76939209Sgibbs cam_fill_csio(csio, 77039209Sgibbs /* retries */ retry_count, 77139209Sgibbs /* cbfcnp */ NULL, 77239209Sgibbs /* flags */ flags, 77339209Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 77439209Sgibbs /* data_ptr */ data_ptr, 77539209Sgibbs /* dxfer_len */ dxfer_len, 77639209Sgibbs /* sense_len */ SSD_FULL_SIZE, 77739209Sgibbs /* cdb_len */ cmdlen, 77839209Sgibbs /* timeout */ timeout ? timeout : 5000); 77939209Sgibbs 78039209Sgibbs return(retval); 78139209Sgibbs} 78239209Sgibbs 78339209Sgibbsint 78439209Sgibbscsio_encode(struct ccb_scsiio *csio, char *fmt, ...) 78539209Sgibbs{ 78639209Sgibbs va_list ap; 78739209Sgibbs 78839209Sgibbs if (csio == NULL) 78939209Sgibbs return(0); 79039209Sgibbs 79139209Sgibbs va_start(ap, fmt); 79239209Sgibbs 79339209Sgibbs return(do_encode(csio->data_ptr, csio->dxfer_len, 0, 0, 0, fmt, ap)); 79439209Sgibbs} 79539209Sgibbs 79639209Sgibbsint 79739209Sgibbsbuff_encode_visit(u_int8_t *buff, size_t len, char *fmt, 79839209Sgibbs int (*arg_get)(void *hook, char *field_name), void *gethook) 79939209Sgibbs{ 80039209Sgibbs va_list ap; 80139209Sgibbs 80239381Sken /* 80339381Sken * We need something to encode, but we can't get it without the 80439381Sken * arg_get function. 80539381Sken */ 80639381Sken if (arg_get == NULL) 80739381Sken return(-1); 80839209Sgibbs 80939381Sken bzero(&ap, sizeof(ap)); 81039381Sken 81139209Sgibbs return(do_encode(buff, len, 0, arg_get, gethook, fmt, ap)); 81239209Sgibbs} 81339209Sgibbs 81439209Sgibbsint 81539209Sgibbscsio_encode_visit(struct ccb_scsiio *csio, char *fmt, 81639209Sgibbs int (*arg_get)(void *hook, char *field_name), void *gethook) 81739209Sgibbs{ 81839209Sgibbs va_list ap; 81939209Sgibbs 82039381Sken /* 82139381Sken * We need something to encode, but we can't get it without the 82239381Sken * arg_get function. 82339381Sken */ 82439381Sken if (arg_get == NULL) 82539381Sken return(-1); 82639209Sgibbs 82739381Sken bzero(&ap, sizeof(ap)); 82839381Sken 82939209Sgibbs return(do_encode(csio->data_ptr, csio->dxfer_len, 0, arg_get, 83039209Sgibbs gethook, fmt, ap)); 83139209Sgibbs} 832