139209Sgibbs/* 239209Sgibbs * Taken from the original FreeBSD user SCSI library. 339209Sgibbs */ 4331722Seadler/* 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: stable/11/lib/libcam/scsi_cmdparse.c 315123 2017-03-12 04:53:48Z ngie $"); 3984199Sdillon 40103382Smike#include <sys/types.h> 41103382Smike 4239209Sgibbs#include <stdlib.h> 4339209Sgibbs#include <stdio.h> 4439209Sgibbs#include <ctype.h> 4539209Sgibbs#include <string.h> 4639209Sgibbs#include <sys/errno.h> 4739209Sgibbs#include <stdarg.h> 4839209Sgibbs#include <fcntl.h> 4939209Sgibbs 5039209Sgibbs#include <cam/cam.h> 5139209Sgibbs#include <cam/cam_ccb.h> 5239209Sgibbs#include <cam/scsi/scsi_message.h> 5339209Sgibbs#include "camlib.h" 5439209Sgibbs 5539209Sgibbs/* 5639209Sgibbs * Decode: Decode the data section of a scsireq. This decodes 5739209Sgibbs * trivial grammar: 5839209Sgibbs * 5939209Sgibbs * fields : field fields 6039209Sgibbs * ; 6139209Sgibbs * 6239209Sgibbs * field : field_specifier 6339209Sgibbs * | control 6439209Sgibbs * ; 6539209Sgibbs * 6639209Sgibbs * control : 's' seek_value 6739209Sgibbs * | 's' '+' seek_value 6839209Sgibbs * ; 6939209Sgibbs * 7039209Sgibbs * seek_value : DECIMAL_NUMBER 7139209Sgibbs * | 'v' // For indirect seek, i.e., value from the arg list 7239209Sgibbs * ; 7339209Sgibbs * 7439209Sgibbs * field_specifier : type_specifier field_width 7539209Sgibbs * | '{' NAME '}' type_specifier field_width 7639209Sgibbs * ; 7739209Sgibbs * 7839209Sgibbs * field_width : DECIMAL_NUMBER 7939209Sgibbs * ; 8039209Sgibbs * 8139209Sgibbs * type_specifier : 'i' // Integral types (i1, i2, i3, i4) 8239209Sgibbs * | 'b' // Bits 8339209Sgibbs * | 't' // Bits 8439209Sgibbs * | 'c' // Character arrays 8539209Sgibbs * | 'z' // Character arrays with zeroed trailing spaces 8639209Sgibbs * ; 8739209Sgibbs * 8839209Sgibbs * Notes: 8939209Sgibbs * 1. Integral types are swapped into host order. 9039209Sgibbs * 2. Bit fields are allocated MSB to LSB to match the SCSI spec documentation. 9139209Sgibbs * 3. 's' permits "seeking" in the string. "s+DECIMAL" seeks relative to 9239209Sgibbs * DECIMAL; "sDECIMAL" seeks absolute to decimal. 9339209Sgibbs * 4. 's' permits an indirect reference. "sv" or "s+v" will get the 9439209Sgibbs * next integer value from the arg array. 9539209Sgibbs * 5. Field names can be anything between the braces 9639209Sgibbs * 9739209Sgibbs * BUGS: 9839209Sgibbs * i and b types are promoted to ints. 9939209Sgibbs * 10039209Sgibbs */ 10139209Sgibbs 10239209Sgibbsstatic int 103312564Smavdo_buff_decode(u_int8_t *buff, size_t len, 10439209Sgibbs void (*arg_put)(void *, int , void *, int, char *), 105298753Sngie void *puthook, const char *fmt, va_list *ap) 10639209Sgibbs{ 107312564Smav int ind = 0; 10839209Sgibbs int assigned = 0; 10939209Sgibbs int width; 11039209Sgibbs int suppress; 11139209Sgibbs int plus; 11239209Sgibbs int done = 0; 11339209Sgibbs static u_char mask[] = {0, 0x01, 0x03, 0x07, 0x0f, 11439209Sgibbs 0x1f, 0x3f, 0x7f, 0xff}; 11539209Sgibbs int value; 11688090Skbyanc char *intendp; 11739209Sgibbs char letter; 11839209Sgibbs char field_name[80]; 11939209Sgibbs 120312564Smav#define ARG_PUT(ARG) \ 121312564Smav do { \ 122312564Smav if (!suppress) { \ 12339209Sgibbs if (arg_put) \ 124312564Smav (*arg_put)(puthook, (letter == 't' ? 'b' : \ 125312564Smav letter), (void *)((long)(ARG)), width, \ 126312564Smav field_name); \ 12739209Sgibbs else \ 128298753Sngie *(va_arg(*ap, int *)) = (ARG); \ 12939209Sgibbs assigned++; \ 13039209Sgibbs } \ 131315123Sngie 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; 138315123Sngie 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 } 172315123Sngie if (*fmt != '\0') 17339209Sgibbs fmt++; /* Skip '}' */ 174315123Sngie field_name[i] = '\0'; 17539209Sgibbs break; 17639209Sgibbs } 17739209Sgibbs 17839209Sgibbs case 't': /* Bit (field) */ 17939209Sgibbs case 'b': /* Bits */ 18039209Sgibbs fmt++; 18188090Skbyanc width = strtol(fmt, &intendp, 10); 18288090Skbyanc fmt = intendp; 18339209Sgibbs if (width > 8) 18439209Sgibbs done = 1; 18539209Sgibbs else { 18639209Sgibbs if (shift <= 0) { 187312564Smav if (ind >= len) { 188312564Smav done = 1; 189312564Smav break; 190312564Smav } 191312564Smav bits = buff[ind++]; 19239209Sgibbs shift = 8; 19339209Sgibbs } 19439209Sgibbs value = (bits >> (shift - width)) & 19539209Sgibbs mask[width]; 19639209Sgibbs 19739209Sgibbs#if 0 19839209Sgibbs printf("shift %2d bits %02x value %02x width %2d mask %02x\n", 19939209Sgibbs shift, bits, value, width, mask[width]); 20039209Sgibbs#endif 20139209Sgibbs 20239209Sgibbs ARG_PUT(value); 20339209Sgibbs 20439209Sgibbs shift -= width; 20539209Sgibbs } 20639209Sgibbs break; 20739209Sgibbs 20839209Sgibbs case 'i': /* Integral values */ 20939209Sgibbs shift = 0; 21039209Sgibbs fmt++; 21188090Skbyanc width = strtol(fmt, &intendp, 10); 21288090Skbyanc fmt = intendp; 213312564Smav if (ind + width > len) { 214312564Smav done = 1; 215312564Smav break; 216312564Smav } 21739209Sgibbs switch(width) { 21839209Sgibbs case 1: 219312564Smav ARG_PUT(buff[ind]); 220312564Smav ind++; 22139209Sgibbs break; 22239209Sgibbs 22339209Sgibbs case 2: 224312564Smav ARG_PUT(buff[ind] << 8 | buff[ind + 1]); 225312564Smav ind += 2; 22639209Sgibbs break; 22739209Sgibbs 22839209Sgibbs case 3: 229312564Smav ARG_PUT(buff[ind] << 16 | 230312564Smav buff[ind + 1] << 8 | buff[ind + 2]); 231312564Smav ind += 3; 23239209Sgibbs break; 23339209Sgibbs 23439209Sgibbs case 4: 235312564Smav ARG_PUT(buff[ind] << 24 | buff[ind + 1] << 16 | 236312564Smav buff[ind + 2] << 8 | buff[ind + 3]); 237312564Smav ind += 4; 23839209Sgibbs break; 23939209Sgibbs 24039209Sgibbs default: 24139209Sgibbs done = 1; 24239209Sgibbs break; 24339209Sgibbs } 24439209Sgibbs 24539209Sgibbs break; 24639209Sgibbs 24739209Sgibbs case 'c': /* Characters (i.e., not swapped) */ 248312564Smav case 'z': /* Characters with zeroed trailing spaces */ 24939209Sgibbs shift = 0; 25039209Sgibbs fmt++; 25188090Skbyanc width = strtol(fmt, &intendp, 10); 25288090Skbyanc fmt = intendp; 253312564Smav if (ind + width > len) { 254312564Smav done = 1; 255312564Smav break; 256312564Smav } 25739209Sgibbs if (!suppress) { 258315123Sngie if (arg_put != NULL) 25939209Sgibbs (*arg_put)(puthook, 260312564Smav (letter == 't' ? 'b' : letter), 261312564Smav &buff[ind], width, field_name); 26239209Sgibbs else { 26339209Sgibbs char *dest; 264298753Sngie dest = va_arg(*ap, char *); 265312564Smav bcopy(&buff[ind], dest, width); 26639209Sgibbs if (letter == 'z') { 26739209Sgibbs char *p; 26839209Sgibbs for (p = dest + width - 1; 269312564Smav p >= dest && *p == ' '; 270312564Smav p--) 271315123Sngie *p = '\0'; 27239209Sgibbs } 27339209Sgibbs } 27439209Sgibbs assigned++; 27539209Sgibbs } 276312564Smav ind += width; 27739209Sgibbs field_name[0] = 0; 27839209Sgibbs suppress = 0; 27939209Sgibbs break; 28039209Sgibbs 28139209Sgibbs case 's': /* Seek */ 28239209Sgibbs shift = 0; 28339209Sgibbs fmt++; 28439209Sgibbs if (*fmt == '+') { 28539209Sgibbs plus = 1; 28639209Sgibbs fmt++; 28739209Sgibbs } else 28839209Sgibbs plus = 0; 28939209Sgibbs 29039209Sgibbs if (tolower(*fmt) == 'v') { 29139209Sgibbs /* 29239209Sgibbs * You can't suppress a seek value. You also 29339209Sgibbs * can't have a variable seek when you are using 29439209Sgibbs * "arg_put". 29539209Sgibbs */ 296298753Sngie width = (arg_put) ? 0 : va_arg(*ap, int); 29739209Sgibbs fmt++; 29888090Skbyanc } else { 29988090Skbyanc width = strtol(fmt, &intendp, 10); 30088090Skbyanc fmt = intendp; 30188090Skbyanc } 30239209Sgibbs 30339209Sgibbs if (plus) 304312564Smav ind += width; /* Relative seek */ 30539209Sgibbs else 306312564Smav ind = width; /* Absolute seek */ 30739209Sgibbs 30839209Sgibbs break; 30939209Sgibbs 31039209Sgibbs case 0: 31139209Sgibbs done = 1; 31239209Sgibbs break; 31339209Sgibbs 31439209Sgibbs default: 31539209Sgibbs fprintf(stderr, "Unknown letter in format: %c\n", 31639209Sgibbs letter); 31739209Sgibbs fmt++; 31839209Sgibbs break; 31939209Sgibbs } 32039209Sgibbs } 32139209Sgibbs 32239209Sgibbs return (assigned); 32339209Sgibbs} 32439209Sgibbs 32539209Sgibbs/* next_field: Return the next field in a command specifier. This 32639209Sgibbs * builds up a SCSI command using this trivial grammar: 32739209Sgibbs * 32839209Sgibbs * fields : field fields 32939209Sgibbs * ; 33039209Sgibbs * 33139209Sgibbs * field : value 33239209Sgibbs * | value ':' field_width 33339209Sgibbs * ; 33439209Sgibbs * 33539209Sgibbs * field_width : digit 33639209Sgibbs * | 'i' digit // i2 = 2 byte integer, i3 = 3 byte integer etc. 33739209Sgibbs * ; 33839209Sgibbs * 33939209Sgibbs * value : HEX_NUMBER 34039209Sgibbs * | 'v' // For indirection. 34139209Sgibbs * ; 34239209Sgibbs * 34339209Sgibbs * Notes: 34439209Sgibbs * Bit fields are specified MSB first to match the SCSI spec. 34539209Sgibbs * 34639209Sgibbs * Examples: 34739209Sgibbs * TUR: "0 0 0 0 0 0" 34839209Sgibbs * WRITE BUFFER: "38 v:3 0:2 0:3 v v:i3 v:i3 0", mode, buffer_id, list_length 34939209Sgibbs * 35039209Sgibbs * The function returns the value: 35139209Sgibbs * 0: For reached end, with error_p set if an error was found 35239209Sgibbs * 1: For valid stuff setup 35339209Sgibbs * 2: For "v" was entered as the value (implies use varargs) 35439209Sgibbs * 35539209Sgibbs */ 35639209Sgibbs 35739209Sgibbsstatic int 35888090Skbyancnext_field(const char **pp, char *fmt, int *width_p, int *value_p, char *name, 35939209Sgibbs int n_name, int *error_p, int *suppress_p) 36039209Sgibbs{ 36188090Skbyanc const char *p = *pp; 36288090Skbyanc char *intendp; 36339209Sgibbs 36439209Sgibbs int something = 0; 36539209Sgibbs 36639209Sgibbs enum { 36739209Sgibbs BETWEEN_FIELDS, 36839209Sgibbs START_FIELD, 36939209Sgibbs GET_FIELD, 37039209Sgibbs DONE, 37139209Sgibbs } state; 37239209Sgibbs 37339209Sgibbs int value = 0; 37439209Sgibbs int field_size; /* Default to byte field type... */ 37539209Sgibbs int field_width; /* 1 byte wide */ 37639209Sgibbs int is_error = 0; 37739209Sgibbs int suppress = 0; 37839209Sgibbs 37939209Sgibbs field_size = 8; /* Default to byte field type... */ 38039209Sgibbs *fmt = 'i'; 38139209Sgibbs field_width = 1; /* 1 byte wide */ 382315123Sngie if (name != NULL) 383315123Sngie *name = '\0'; 38439209Sgibbs 38539209Sgibbs state = BETWEEN_FIELDS; 38639209Sgibbs 38739209Sgibbs while (state != DONE) { 38839209Sgibbs switch(state) { 38939209Sgibbs case BETWEEN_FIELDS: 390315123Sngie if (*p == '\0') 39139209Sgibbs state = DONE; 39239209Sgibbs else if (isspace(*p)) 39339209Sgibbs p++; 39439209Sgibbs else if (*p == '#') { 39539209Sgibbs while (*p && *p != '\n') 39639209Sgibbs p++; 397315123Sngie if (*p != '\0') 39839209Sgibbs p++; 39939209Sgibbs } else if (*p == '{') { 40039209Sgibbs int i = 0; 40139209Sgibbs 40239209Sgibbs p++; 40339209Sgibbs 40439209Sgibbs while (*p && *p != '}') { 40539209Sgibbs if(name && i < n_name) { 40639209Sgibbs name[i] = *p; 40739209Sgibbs i++; 40839209Sgibbs } 40939209Sgibbs p++; 41039209Sgibbs } 41139209Sgibbs 41239209Sgibbs if(name && i < n_name) 413315123Sngie name[i] = '\0'; 41439209Sgibbs 41539209Sgibbs if (*p == '}') 41639209Sgibbs p++; 41739209Sgibbs } else if (*p == '*') { 41839209Sgibbs p++; 41939209Sgibbs suppress = 1; 42039209Sgibbs } else if (isxdigit(*p)) { 42139209Sgibbs something = 1; 42288090Skbyanc value = strtol(p, &intendp, 16); 42388090Skbyanc p = intendp; 42439209Sgibbs state = START_FIELD; 42539209Sgibbs } else if (tolower(*p) == 'v') { 42639209Sgibbs p++; 42739209Sgibbs something = 2; 42839209Sgibbs value = *value_p; 42939209Sgibbs state = START_FIELD; 43039209Sgibbs } else if (tolower(*p) == 'i') { 43139209Sgibbs /* 43239209Sgibbs * Try to work without the "v". 43339209Sgibbs */ 43439209Sgibbs something = 2; 43539209Sgibbs value = *value_p; 43639209Sgibbs p++; 43739209Sgibbs 43839209Sgibbs *fmt = 'i'; 43939209Sgibbs field_size = 8; 44088090Skbyanc field_width = strtol(p, &intendp, 10); 44188090Skbyanc p = intendp; 44239209Sgibbs state = DONE; 44339209Sgibbs 44439209Sgibbs } else if (tolower(*p) == 't') { 44539209Sgibbs /* 44639209Sgibbs * XXX: B can't work: Sees the 'b' as a 44739209Sgibbs * hex digit in "isxdigit". try "t" for 44839209Sgibbs * bit field. 44939209Sgibbs */ 45039209Sgibbs something = 2; 45139209Sgibbs value = *value_p; 45239209Sgibbs p++; 45339209Sgibbs 45439209Sgibbs *fmt = 'b'; 45539209Sgibbs field_size = 1; 45688090Skbyanc field_width = strtol(p, &intendp, 10); 45788090Skbyanc p = intendp; 45839209Sgibbs state = DONE; 45939209Sgibbs } else if (tolower(*p) == 's') { 46039209Sgibbs /* Seek */ 46139209Sgibbs *fmt = 's'; 46239209Sgibbs p++; 46339209Sgibbs if (tolower(*p) == 'v') { 46439209Sgibbs p++; 46539209Sgibbs something = 2; 46639209Sgibbs value = *value_p; 46739209Sgibbs } else { 46839209Sgibbs something = 1; 46988090Skbyanc value = strtol(p, &intendp, 0); 47088090Skbyanc p = intendp; 47139209Sgibbs } 47239209Sgibbs state = DONE; 47339209Sgibbs } else { 47439209Sgibbs fprintf(stderr, "Invalid starting " 47539209Sgibbs "character: %c\n", *p); 47639209Sgibbs is_error = 1; 47739209Sgibbs state = DONE; 47839209Sgibbs } 47939209Sgibbs break; 48039209Sgibbs 48139209Sgibbs case START_FIELD: 48239209Sgibbs if (*p == ':') { 48339209Sgibbs p++; 48439209Sgibbs field_size = 1; /* Default to bits 48539209Sgibbs when specified */ 48639209Sgibbs state = GET_FIELD; 48739209Sgibbs } else 48839209Sgibbs state = DONE; 48939209Sgibbs break; 49039209Sgibbs 49139209Sgibbs case GET_FIELD: 49239209Sgibbs if (isdigit(*p)) { 49339209Sgibbs *fmt = 'b'; 49439209Sgibbs field_size = 1; 49588090Skbyanc field_width = strtol(p, &intendp, 10); 49688090Skbyanc p = intendp; 49739209Sgibbs state = DONE; 49839209Sgibbs } else if (*p == 'i') { 49939209Sgibbs 50039209Sgibbs /* Integral (bytes) */ 50139209Sgibbs p++; 50239209Sgibbs 50339209Sgibbs *fmt = 'i'; 50439209Sgibbs field_size = 8; 50588090Skbyanc field_width = strtol(p, &intendp, 10); 50688090Skbyanc p = intendp; 50739209Sgibbs state = DONE; 50839209Sgibbs } else if (*p == 'b') { 50939209Sgibbs 51039209Sgibbs /* Bits */ 51139209Sgibbs p++; 51239209Sgibbs 51339209Sgibbs *fmt = 'b'; 51439209Sgibbs field_size = 1; 51588090Skbyanc field_width = strtol(p, &intendp, 10); 51688090Skbyanc p = intendp; 51739209Sgibbs state = DONE; 51839209Sgibbs } else { 51939209Sgibbs fprintf(stderr, "Invalid startfield %c " 52039209Sgibbs "(%02x)\n", *p, *p); 52139209Sgibbs is_error = 1; 52239209Sgibbs state = DONE; 52339209Sgibbs } 52439209Sgibbs break; 52539209Sgibbs 52639209Sgibbs case DONE: 52739209Sgibbs break; 52839209Sgibbs } 52939209Sgibbs } 53039209Sgibbs 53139209Sgibbs if (is_error) { 53239209Sgibbs *error_p = 1; 533315123Sngie return (0); 53439209Sgibbs } 53539209Sgibbs 53639209Sgibbs *error_p = 0; 53739209Sgibbs *pp = p; 53839209Sgibbs *width_p = field_width * field_size; 53939209Sgibbs *value_p = value; 54039209Sgibbs *suppress_p = suppress; 54139209Sgibbs 54239209Sgibbs return (something); 54339209Sgibbs} 54439209Sgibbs 54539209Sgibbsstatic int 54639209Sgibbsdo_encode(u_char *buff, size_t vec_max, size_t *used, 54788090Skbyanc int (*arg_get)(void *, char *), void *gethook, const char *fmt, 548298753Sngie va_list *ap) 54939209Sgibbs{ 55039209Sgibbs int ind; 55139209Sgibbs int shift; 55239209Sgibbs u_char val; 55339209Sgibbs int ret; 55439209Sgibbs int width, value, error, suppress; 55539209Sgibbs char c; 55639209Sgibbs int encoded = 0; 55739209Sgibbs char field_name[80]; 55839209Sgibbs 55939209Sgibbs ind = 0; 56039209Sgibbs shift = 0; 56139209Sgibbs val = 0; 56239209Sgibbs 56339209Sgibbs while ((ret = next_field(&fmt, &c, &width, &value, field_name, 56439209Sgibbs sizeof(field_name), &error, &suppress))) { 56539209Sgibbs encoded++; 56639209Sgibbs 56739209Sgibbs if (ret == 2) { 56839209Sgibbs if (suppress) 56939209Sgibbs value = 0; 57039209Sgibbs else 571315123Sngie value = arg_get != NULL ? 57239209Sgibbs (*arg_get)(gethook, field_name) : 573298753Sngie va_arg(*ap, int); 57439209Sgibbs } 57539209Sgibbs 57639209Sgibbs#if 0 57739209Sgibbs printf( 57839209Sgibbs"do_encode: ret %d fmt %c width %d value %d name \"%s\" error %d suppress %d\n", 57939209Sgibbs ret, c, width, value, field_name, error, suppress); 58039209Sgibbs#endif 58139209Sgibbs /* Absolute seek */ 58239209Sgibbs if (c == 's') { 58339209Sgibbs ind = value; 58439209Sgibbs continue; 58539209Sgibbs } 58639209Sgibbs 58739209Sgibbs /* A width of < 8 is a bit field. */ 58839209Sgibbs if (width < 8) { 58939209Sgibbs 59039209Sgibbs /* This is a bit field. We start with the high bits 59139209Sgibbs * so it reads the same as the SCSI spec. 59239209Sgibbs */ 59339209Sgibbs 59439209Sgibbs shift += width; 59539209Sgibbs 59639209Sgibbs val |= (value << (8 - shift)); 59739209Sgibbs 59839209Sgibbs if (shift == 8) { 59939209Sgibbs if (ind < vec_max) { 60039209Sgibbs buff[ind++] = val; 60139209Sgibbs val = 0; 60239209Sgibbs } 60339209Sgibbs shift = 0; 60439209Sgibbs } 60539209Sgibbs } else { 60639209Sgibbs if (shift) { 60739209Sgibbs if (ind < vec_max) { 60839209Sgibbs buff[ind++] = val; 60939209Sgibbs val = 0; 61039209Sgibbs } 61139209Sgibbs shift = 0; 61239209Sgibbs } 61339209Sgibbs switch(width) { 61439209Sgibbs case 8: /* 1 byte integer */ 61539209Sgibbs if (ind < vec_max) 61639209Sgibbs buff[ind++] = value; 61739209Sgibbs break; 61839209Sgibbs 61939209Sgibbs case 16: /* 2 byte integer */ 62039209Sgibbs if (ind < vec_max - 2 + 1) { 62139209Sgibbs buff[ind++] = value >> 8; 62239209Sgibbs buff[ind++] = value; 62339209Sgibbs } 62439209Sgibbs break; 62539209Sgibbs 62639209Sgibbs case 24: /* 3 byte integer */ 62739209Sgibbs if (ind < vec_max - 3 + 1) { 62839209Sgibbs buff[ind++] = value >> 16; 62939209Sgibbs buff[ind++] = value >> 8; 63039209Sgibbs buff[ind++] = value; 63139209Sgibbs } 63239209Sgibbs break; 63339209Sgibbs 63439209Sgibbs case 32: /* 4 byte integer */ 63539209Sgibbs if (ind < vec_max - 4 + 1) { 63639209Sgibbs buff[ind++] = value >> 24; 63739209Sgibbs buff[ind++] = value >> 16; 63839209Sgibbs buff[ind++] = value >> 8; 63939209Sgibbs buff[ind++] = value; 64039209Sgibbs } 64139209Sgibbs break; 64239209Sgibbs 64339209Sgibbs default: 64439209Sgibbs fprintf(stderr, "do_encode: Illegal width\n"); 64539209Sgibbs break; 64639209Sgibbs } 64739209Sgibbs } 64839209Sgibbs } 64939209Sgibbs 65039209Sgibbs /* Flush out any remaining bits 65139209Sgibbs */ 65239209Sgibbs if (shift && ind < vec_max) { 65339209Sgibbs buff[ind++] = val; 65439209Sgibbs val = 0; 65539209Sgibbs } 65639209Sgibbs 65739209Sgibbs 65839209Sgibbs if (used) 65939209Sgibbs *used = ind; 66039209Sgibbs 66139209Sgibbs if (error) 662315123Sngie return (-1); 66339209Sgibbs 664315123Sngie return (encoded); 66539209Sgibbs} 66639209Sgibbs 66739209Sgibbsint 66888090Skbyanccsio_decode(struct ccb_scsiio *csio, const char *fmt, ...) 66939209Sgibbs{ 67039209Sgibbs va_list ap; 671298753Sngie int retval; 67239209Sgibbs 67339209Sgibbs va_start(ap, fmt); 67439209Sgibbs 675315123Sngie retval = do_buff_decode(csio->data_ptr, (size_t)csio->dxfer_len, 676315123Sngie NULL, NULL, fmt, &ap); 677298753Sngie 678298753Sngie va_end(ap); 679298753Sngie 680298753Sngie return (retval); 68139209Sgibbs} 68239209Sgibbs 68339209Sgibbsint 68488090Skbyanccsio_decode_visit(struct ccb_scsiio *csio, const char *fmt, 68539209Sgibbs void (*arg_put)(void *, int, void *, int, char *), 68639209Sgibbs void *puthook) 68739209Sgibbs{ 68839209Sgibbs 68939381Sken /* 69039381Sken * We need some way to output things; we can't do it without 69139381Sken * the arg_put function. 69239381Sken */ 69339381Sken if (arg_put == NULL) 694298753Sngie return (-1); 69539209Sgibbs 696298753Sngie return (do_buff_decode(csio->data_ptr, (size_t)csio->dxfer_len, 697298753Sngie arg_put, puthook, fmt, NULL)); 69839209Sgibbs} 69939209Sgibbs 70039209Sgibbsint 70188090Skbyancbuff_decode(u_int8_t *buff, size_t len, const char *fmt, ...) 70239209Sgibbs{ 70339209Sgibbs va_list ap; 704298753Sngie int retval; 70539209Sgibbs 70639209Sgibbs va_start(ap, fmt); 70739209Sgibbs 708315123Sngie retval = do_buff_decode(buff, len, NULL, NULL, fmt, &ap); 709298753Sngie 710298753Sngie va_end(ap); 711298753Sngie 712298753Sngie return (retval); 71339209Sgibbs} 71439209Sgibbs 71539209Sgibbsint 71688090Skbyancbuff_decode_visit(u_int8_t *buff, size_t len, const char *fmt, 71739209Sgibbs void (*arg_put)(void *, int, void *, int, char *), 71839209Sgibbs void *puthook) 71939209Sgibbs{ 72039209Sgibbs 72139381Sken /* 72239381Sken * We need some way to output things; we can't do it without 72339381Sken * the arg_put function. 72439381Sken */ 72539381Sken if (arg_put == NULL) 726315123Sngie return (-1); 72739209Sgibbs 728298753Sngie return (do_buff_decode(buff, len, arg_put, puthook, fmt, NULL)); 72939209Sgibbs} 73039209Sgibbs 73139209Sgibbs/* 73239209Sgibbs * Build a SCSI CCB, given the command and data pointers and a format 73339209Sgibbs * string describing the 73439209Sgibbs */ 73539209Sgibbsint 73639209Sgibbscsio_build(struct ccb_scsiio *csio, u_int8_t *data_ptr, u_int32_t dxfer_len, 73788090Skbyanc u_int32_t flags, int retry_count, int timeout, const char *cmd_spec, 73888090Skbyanc ...) 73939209Sgibbs{ 74039381Sken size_t cmdlen; 74139209Sgibbs int retval; 74239209Sgibbs va_list ap; 74339209Sgibbs 74439209Sgibbs if (csio == NULL) 745298753Sngie return (0); 74639209Sgibbs 74739209Sgibbs bzero(csio, sizeof(struct ccb_scsiio)); 74839209Sgibbs 74939209Sgibbs va_start(ap, cmd_spec); 75039209Sgibbs 75139209Sgibbs if ((retval = do_encode(csio->cdb_io.cdb_bytes, SCSI_MAX_CDBLEN, 752298753Sngie &cmdlen, NULL, NULL, cmd_spec, &ap)) == -1) 753298753Sngie goto done; 75439209Sgibbs 75539209Sgibbs cam_fill_csio(csio, 75639209Sgibbs /* retries */ retry_count, 75739209Sgibbs /* cbfcnp */ NULL, 75839209Sgibbs /* flags */ flags, 75939209Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 76039209Sgibbs /* data_ptr */ data_ptr, 76139209Sgibbs /* dxfer_len */ dxfer_len, 76239209Sgibbs /* sense_len */ SSD_FULL_SIZE, 76339209Sgibbs /* cdb_len */ cmdlen, 76439209Sgibbs /* timeout */ timeout ? timeout : 5000); 76539209Sgibbs 766298753Sngiedone: 767298753Sngie va_end(ap); 768298753Sngie 769298753Sngie return (retval); 77039209Sgibbs} 77139209Sgibbs 77239209Sgibbsint 77339209Sgibbscsio_build_visit(struct ccb_scsiio *csio, u_int8_t *data_ptr, 77439209Sgibbs u_int32_t dxfer_len, u_int32_t flags, int retry_count, 77588090Skbyanc int timeout, const char *cmd_spec, 77639209Sgibbs int (*arg_get)(void *hook, char *field_name), void *gethook) 77739209Sgibbs{ 77839381Sken size_t cmdlen; 77939381Sken int retval; 78039209Sgibbs 78139209Sgibbs if (csio == NULL) 782315123Sngie return (0); 78339209Sgibbs 78439381Sken /* 78539381Sken * We need something to encode, but we can't get it without the 78639381Sken * arg_get function. 78739381Sken */ 78839381Sken if (arg_get == NULL) 789315123Sngie return (-1); 79039209Sgibbs 79139209Sgibbs bzero(csio, sizeof(struct ccb_scsiio)); 79239209Sgibbs 79339209Sgibbs if ((retval = do_encode(csio->cdb_io.cdb_bytes, SCSI_MAX_CDBLEN, 794298753Sngie &cmdlen, arg_get, gethook, cmd_spec, NULL)) == -1) 795315123Sngie return (retval); 79639209Sgibbs 79739209Sgibbs cam_fill_csio(csio, 79839209Sgibbs /* retries */ retry_count, 79939209Sgibbs /* cbfcnp */ NULL, 80039209Sgibbs /* flags */ flags, 80139209Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 80239209Sgibbs /* data_ptr */ data_ptr, 80339209Sgibbs /* dxfer_len */ dxfer_len, 80439209Sgibbs /* sense_len */ SSD_FULL_SIZE, 80539209Sgibbs /* cdb_len */ cmdlen, 80639209Sgibbs /* timeout */ timeout ? timeout : 5000); 80739209Sgibbs 808315123Sngie return (retval); 80939209Sgibbs} 81039209Sgibbs 81139209Sgibbsint 81288090Skbyanccsio_encode(struct ccb_scsiio *csio, const char *fmt, ...) 81339209Sgibbs{ 81439209Sgibbs va_list ap; 815298753Sngie int retval; 81639209Sgibbs 81739209Sgibbs if (csio == NULL) 818298753Sngie return (0); 81939209Sgibbs 82039209Sgibbs va_start(ap, fmt); 82139209Sgibbs 822315123Sngie retval = do_encode(csio->data_ptr, csio->dxfer_len, NULL, NULL, NULL, 823315123Sngie fmt, &ap); 824298753Sngie 825298753Sngie va_end(ap); 826298753Sngie 827298753Sngie return (retval); 82839209Sgibbs} 82939209Sgibbs 83039209Sgibbsint 83188090Skbyancbuff_encode_visit(u_int8_t *buff, size_t len, const char *fmt, 83239209Sgibbs int (*arg_get)(void *hook, char *field_name), void *gethook) 83339209Sgibbs{ 83439209Sgibbs 83539381Sken /* 83639381Sken * We need something to encode, but we can't get it without the 83739381Sken * arg_get function. 83839381Sken */ 83939381Sken if (arg_get == NULL) 840315123Sngie return (-1); 84139209Sgibbs 842315123Sngie return (do_encode(buff, len, NULL, arg_get, gethook, fmt, NULL)); 84339209Sgibbs} 84439209Sgibbs 84539209Sgibbsint 84688090Skbyanccsio_encode_visit(struct ccb_scsiio *csio, const char *fmt, 84739209Sgibbs int (*arg_get)(void *hook, char *field_name), void *gethook) 84839209Sgibbs{ 84939209Sgibbs 85039381Sken /* 85139381Sken * We need something to encode, but we can't get it without the 85239381Sken * arg_get function. 85339381Sken */ 85439381Sken if (arg_get == NULL) 855315123Sngie return (-1); 85639209Sgibbs 857315123Sngie return (do_encode(csio->data_ptr, csio->dxfer_len, NULL, arg_get, 858298753Sngie gethook, fmt, NULL)); 85939209Sgibbs} 860