scsi_cmdparse.c revision 298753
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 298753 2016-04-28 18:41:55Z 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 10339209Sgibbsdo_buff_decode(u_int8_t *databuf, size_t len, 10439209Sgibbs void (*arg_put)(void *, int , void *, int, char *), 105298753Sngie void *puthook, const char *fmt, va_list *ap) 10639209Sgibbs{ 10739209Sgibbs int assigned = 0; 10839209Sgibbs int width; 10939209Sgibbs int suppress; 11039209Sgibbs int plus; 11139209Sgibbs int done = 0; 11239209Sgibbs static u_char mask[] = {0, 0x01, 0x03, 0x07, 0x0f, 11339209Sgibbs 0x1f, 0x3f, 0x7f, 0xff}; 11439209Sgibbs int value; 11539209Sgibbs u_char *base = databuf; 11688090Skbyanc char *intendp; 11739209Sgibbs char letter; 11839209Sgibbs char field_name[80]; 11939209Sgibbs 12039209Sgibbs# define ARG_PUT(ARG) \ 12139209Sgibbs do \ 12239209Sgibbs { \ 12339209Sgibbs if (!suppress) \ 12439209Sgibbs { \ 12539209Sgibbs if (arg_put) \ 12639209Sgibbs (*arg_put)(puthook, (letter == 't' ? \ 12739209Sgibbs 'b' : letter), \ 12864382Skbyanc (void *)((long)(ARG)), width, \ 12964382Skbyanc field_name); \ 13039209Sgibbs else \ 131298753Sngie *(va_arg(*ap, int *)) = (ARG); \ 13239209Sgibbs assigned++; \ 13339209Sgibbs } \ 13439209Sgibbs field_name[0] = 0; \ 13539209Sgibbs suppress = 0; \ 13639209Sgibbs } while (0) 13739209Sgibbs 13839209Sgibbs u_char bits = 0; /* For bit fields */ 13939209Sgibbs int shift = 0; /* Bits already shifted out */ 14039209Sgibbs suppress = 0; 14139209Sgibbs field_name[0] = 0; 14239209Sgibbs 14339209Sgibbs while (!done) { 14439209Sgibbs switch(letter = *fmt) { 14539209Sgibbs case ' ': /* White space */ 14639209Sgibbs case '\t': 14739209Sgibbs case '\r': 14839209Sgibbs case '\n': 14939209Sgibbs case '\f': 15039209Sgibbs fmt++; 15139209Sgibbs break; 15239209Sgibbs 15339209Sgibbs case '#': /* Comment */ 15439209Sgibbs while (*fmt && (*fmt != '\n')) 15539209Sgibbs fmt++; 15639209Sgibbs if (fmt) 15739209Sgibbs fmt++; /* Skip '\n' */ 15839209Sgibbs break; 15939209Sgibbs 16039209Sgibbs case '*': /* Suppress assignment */ 16139209Sgibbs fmt++; 16239209Sgibbs suppress = 1; 16339209Sgibbs break; 16439209Sgibbs 16539209Sgibbs case '{': /* Field Name */ 16639209Sgibbs { 16739209Sgibbs int i = 0; 16839209Sgibbs fmt++; /* Skip '{' */ 16939209Sgibbs while (*fmt && (*fmt != '}')) { 17039209Sgibbs if (i < sizeof(field_name)) 17139209Sgibbs field_name[i++] = *fmt; 17239209Sgibbs 17339209Sgibbs fmt++; 17439209Sgibbs } 17539209Sgibbs if (fmt) 17639209Sgibbs fmt++; /* Skip '}' */ 17739209Sgibbs field_name[i] = 0; 17839209Sgibbs break; 17939209Sgibbs } 18039209Sgibbs 18139209Sgibbs case 't': /* Bit (field) */ 18239209Sgibbs case 'b': /* Bits */ 18339209Sgibbs fmt++; 18488090Skbyanc width = strtol(fmt, &intendp, 10); 18588090Skbyanc fmt = intendp; 18639209Sgibbs if (width > 8) 18739209Sgibbs done = 1; 18839209Sgibbs else { 18939209Sgibbs if (shift <= 0) { 19039209Sgibbs bits = *databuf++; 19139209Sgibbs shift = 8; 19239209Sgibbs } 19339209Sgibbs value = (bits >> (shift - width)) & 19439209Sgibbs mask[width]; 19539209Sgibbs 19639209Sgibbs#if 0 19739209Sgibbs printf("shift %2d bits %02x value %02x width %2d mask %02x\n", 19839209Sgibbs shift, bits, value, width, mask[width]); 19939209Sgibbs#endif 20039209Sgibbs 20139209Sgibbs ARG_PUT(value); 20239209Sgibbs 20339209Sgibbs shift -= width; 20439209Sgibbs } 20539209Sgibbs break; 20639209Sgibbs 20739209Sgibbs case 'i': /* Integral values */ 20839209Sgibbs shift = 0; 20939209Sgibbs fmt++; 21088090Skbyanc width = strtol(fmt, &intendp, 10); 21188090Skbyanc fmt = intendp; 21239209Sgibbs switch(width) { 21339209Sgibbs case 1: 21439209Sgibbs ARG_PUT(*databuf); 21539209Sgibbs databuf++; 21639209Sgibbs break; 21739209Sgibbs 21839209Sgibbs case 2: 21939209Sgibbs ARG_PUT((*databuf) << 8 | *(databuf + 1)); 22039209Sgibbs databuf += 2; 22139209Sgibbs break; 22239209Sgibbs 22339209Sgibbs case 3: 22439209Sgibbs ARG_PUT((*databuf) << 16 | 22539209Sgibbs (*(databuf + 1)) << 8 | *(databuf + 2)); 22639209Sgibbs databuf += 3; 22739209Sgibbs break; 22839209Sgibbs 22939209Sgibbs case 4: 23039209Sgibbs ARG_PUT((*databuf) << 24 | 23139209Sgibbs (*(databuf + 1)) << 16 | 23239209Sgibbs (*(databuf + 2)) << 8 | 23339209Sgibbs *(databuf + 3)); 23439209Sgibbs databuf += 4; 23539209Sgibbs break; 23639209Sgibbs 23739209Sgibbs default: 23839209Sgibbs done = 1; 23939209Sgibbs break; 24039209Sgibbs } 24139209Sgibbs 24239209Sgibbs break; 24339209Sgibbs 24439209Sgibbs case 'c': /* Characters (i.e., not swapped) */ 24539209Sgibbs case 'z': /* Characters with zeroed trailing 24639209Sgibbs spaces */ 24739209Sgibbs shift = 0; 24839209Sgibbs fmt++; 24988090Skbyanc width = strtol(fmt, &intendp, 10); 25088090Skbyanc fmt = intendp; 25139209Sgibbs if (!suppress) { 25239209Sgibbs if (arg_put) 25339209Sgibbs (*arg_put)(puthook, 25439209Sgibbs (letter == 't' ? 'b' : letter), 25539209Sgibbs databuf, width, field_name); 25639209Sgibbs else { 25739209Sgibbs char *dest; 258298753Sngie dest = va_arg(*ap, char *); 25939209Sgibbs bcopy(databuf, dest, width); 26039209Sgibbs if (letter == 'z') { 26139209Sgibbs char *p; 26239209Sgibbs for (p = dest + width - 1; 26339209Sgibbs (p >= (char *)dest) 26439209Sgibbs && (*p == ' '); p--) 26539209Sgibbs *p = 0; 26639209Sgibbs } 26739209Sgibbs } 26839209Sgibbs assigned++; 26939209Sgibbs } 27039209Sgibbs databuf += width; 27139209Sgibbs field_name[0] = 0; 27239209Sgibbs suppress = 0; 27339209Sgibbs break; 27439209Sgibbs 27539209Sgibbs case 's': /* Seek */ 27639209Sgibbs shift = 0; 27739209Sgibbs fmt++; 27839209Sgibbs if (*fmt == '+') { 27939209Sgibbs plus = 1; 28039209Sgibbs fmt++; 28139209Sgibbs } else 28239209Sgibbs plus = 0; 28339209Sgibbs 28439209Sgibbs if (tolower(*fmt) == 'v') { 28539209Sgibbs /* 28639209Sgibbs * You can't suppress a seek value. You also 28739209Sgibbs * can't have a variable seek when you are using 28839209Sgibbs * "arg_put". 28939209Sgibbs */ 290298753Sngie width = (arg_put) ? 0 : va_arg(*ap, int); 29139209Sgibbs fmt++; 29288090Skbyanc } else { 29388090Skbyanc width = strtol(fmt, &intendp, 10); 29488090Skbyanc fmt = intendp; 29588090Skbyanc } 29639209Sgibbs 29739209Sgibbs if (plus) 29839209Sgibbs databuf += width; /* Relative seek */ 29939209Sgibbs else 30039209Sgibbs databuf = base + width; /* Absolute seek */ 30139209Sgibbs 30239209Sgibbs break; 30339209Sgibbs 30439209Sgibbs case 0: 30539209Sgibbs done = 1; 30639209Sgibbs break; 30739209Sgibbs 30839209Sgibbs default: 30939209Sgibbs fprintf(stderr, "Unknown letter in format: %c\n", 31039209Sgibbs letter); 31139209Sgibbs fmt++; 31239209Sgibbs break; 31339209Sgibbs } 31439209Sgibbs } 31539209Sgibbs 31639209Sgibbs return (assigned); 31739209Sgibbs} 31839209Sgibbs 31939209Sgibbs/* next_field: Return the next field in a command specifier. This 32039209Sgibbs * builds up a SCSI command using this trivial grammar: 32139209Sgibbs * 32239209Sgibbs * fields : field fields 32339209Sgibbs * ; 32439209Sgibbs * 32539209Sgibbs * field : value 32639209Sgibbs * | value ':' field_width 32739209Sgibbs * ; 32839209Sgibbs * 32939209Sgibbs * field_width : digit 33039209Sgibbs * | 'i' digit // i2 = 2 byte integer, i3 = 3 byte integer etc. 33139209Sgibbs * ; 33239209Sgibbs * 33339209Sgibbs * value : HEX_NUMBER 33439209Sgibbs * | 'v' // For indirection. 33539209Sgibbs * ; 33639209Sgibbs * 33739209Sgibbs * Notes: 33839209Sgibbs * Bit fields are specified MSB first to match the SCSI spec. 33939209Sgibbs * 34039209Sgibbs * Examples: 34139209Sgibbs * TUR: "0 0 0 0 0 0" 34239209Sgibbs * WRITE BUFFER: "38 v:3 0:2 0:3 v v:i3 v:i3 0", mode, buffer_id, list_length 34339209Sgibbs * 34439209Sgibbs * The function returns the value: 34539209Sgibbs * 0: For reached end, with error_p set if an error was found 34639209Sgibbs * 1: For valid stuff setup 34739209Sgibbs * 2: For "v" was entered as the value (implies use varargs) 34839209Sgibbs * 34939209Sgibbs */ 35039209Sgibbs 35139209Sgibbsstatic int 35288090Skbyancnext_field(const char **pp, char *fmt, int *width_p, int *value_p, char *name, 35339209Sgibbs int n_name, int *error_p, int *suppress_p) 35439209Sgibbs{ 35588090Skbyanc const char *p = *pp; 35688090Skbyanc char *intendp; 35739209Sgibbs 35839209Sgibbs int something = 0; 35939209Sgibbs 36039209Sgibbs enum { 36139209Sgibbs BETWEEN_FIELDS, 36239209Sgibbs START_FIELD, 36339209Sgibbs GET_FIELD, 36439209Sgibbs DONE, 36539209Sgibbs } state; 36639209Sgibbs 36739209Sgibbs int value = 0; 36839209Sgibbs int field_size; /* Default to byte field type... */ 36939209Sgibbs int field_width; /* 1 byte wide */ 37039209Sgibbs int is_error = 0; 37139209Sgibbs int suppress = 0; 37239209Sgibbs 37339209Sgibbs field_size = 8; /* Default to byte field type... */ 37439209Sgibbs *fmt = 'i'; 37539209Sgibbs field_width = 1; /* 1 byte wide */ 37639209Sgibbs if (name) 37739209Sgibbs *name = 0; 37839209Sgibbs 37939209Sgibbs state = BETWEEN_FIELDS; 38039209Sgibbs 38139209Sgibbs while (state != DONE) { 38239209Sgibbs switch(state) { 38339209Sgibbs case BETWEEN_FIELDS: 38439209Sgibbs if (*p == 0) 38539209Sgibbs state = DONE; 38639209Sgibbs else if (isspace(*p)) 38739209Sgibbs p++; 38839209Sgibbs else if (*p == '#') { 38939209Sgibbs while (*p && *p != '\n') 39039209Sgibbs p++; 39139209Sgibbs if (p) 39239209Sgibbs p++; 39339209Sgibbs } else if (*p == '{') { 39439209Sgibbs int i = 0; 39539209Sgibbs 39639209Sgibbs p++; 39739209Sgibbs 39839209Sgibbs while (*p && *p != '}') { 39939209Sgibbs if(name && i < n_name) { 40039209Sgibbs name[i] = *p; 40139209Sgibbs i++; 40239209Sgibbs } 40339209Sgibbs p++; 40439209Sgibbs } 40539209Sgibbs 40639209Sgibbs if(name && i < n_name) 40739209Sgibbs name[i] = 0; 40839209Sgibbs 40939209Sgibbs if (*p == '}') 41039209Sgibbs p++; 41139209Sgibbs } else if (*p == '*') { 41239209Sgibbs p++; 41339209Sgibbs suppress = 1; 41439209Sgibbs } else if (isxdigit(*p)) { 41539209Sgibbs something = 1; 41688090Skbyanc value = strtol(p, &intendp, 16); 41788090Skbyanc p = intendp; 41839209Sgibbs state = START_FIELD; 41939209Sgibbs } else if (tolower(*p) == 'v') { 42039209Sgibbs p++; 42139209Sgibbs something = 2; 42239209Sgibbs value = *value_p; 42339209Sgibbs state = START_FIELD; 42439209Sgibbs } else if (tolower(*p) == 'i') { 42539209Sgibbs /* 42639209Sgibbs * Try to work without the "v". 42739209Sgibbs */ 42839209Sgibbs something = 2; 42939209Sgibbs value = *value_p; 43039209Sgibbs p++; 43139209Sgibbs 43239209Sgibbs *fmt = 'i'; 43339209Sgibbs field_size = 8; 43488090Skbyanc field_width = strtol(p, &intendp, 10); 43588090Skbyanc p = intendp; 43639209Sgibbs state = DONE; 43739209Sgibbs 43839209Sgibbs } else if (tolower(*p) == 't') { 43939209Sgibbs /* 44039209Sgibbs * XXX: B can't work: Sees the 'b' as a 44139209Sgibbs * hex digit in "isxdigit". try "t" for 44239209Sgibbs * bit field. 44339209Sgibbs */ 44439209Sgibbs something = 2; 44539209Sgibbs value = *value_p; 44639209Sgibbs p++; 44739209Sgibbs 44839209Sgibbs *fmt = 'b'; 44939209Sgibbs field_size = 1; 45088090Skbyanc field_width = strtol(p, &intendp, 10); 45188090Skbyanc p = intendp; 45239209Sgibbs state = DONE; 45339209Sgibbs } else if (tolower(*p) == 's') { 45439209Sgibbs /* Seek */ 45539209Sgibbs *fmt = 's'; 45639209Sgibbs p++; 45739209Sgibbs if (tolower(*p) == 'v') { 45839209Sgibbs p++; 45939209Sgibbs something = 2; 46039209Sgibbs value = *value_p; 46139209Sgibbs } else { 46239209Sgibbs something = 1; 46388090Skbyanc value = strtol(p, &intendp, 0); 46488090Skbyanc p = intendp; 46539209Sgibbs } 46639209Sgibbs state = DONE; 46739209Sgibbs } else { 46839209Sgibbs fprintf(stderr, "Invalid starting " 46939209Sgibbs "character: %c\n", *p); 47039209Sgibbs is_error = 1; 47139209Sgibbs state = DONE; 47239209Sgibbs } 47339209Sgibbs break; 47439209Sgibbs 47539209Sgibbs case START_FIELD: 47639209Sgibbs if (*p == ':') { 47739209Sgibbs p++; 47839209Sgibbs field_size = 1; /* Default to bits 47939209Sgibbs when specified */ 48039209Sgibbs state = GET_FIELD; 48139209Sgibbs } else 48239209Sgibbs state = DONE; 48339209Sgibbs break; 48439209Sgibbs 48539209Sgibbs case GET_FIELD: 48639209Sgibbs if (isdigit(*p)) { 48739209Sgibbs *fmt = 'b'; 48839209Sgibbs field_size = 1; 48988090Skbyanc field_width = strtol(p, &intendp, 10); 49088090Skbyanc p = intendp; 49139209Sgibbs state = DONE; 49239209Sgibbs } else if (*p == 'i') { 49339209Sgibbs 49439209Sgibbs /* Integral (bytes) */ 49539209Sgibbs p++; 49639209Sgibbs 49739209Sgibbs *fmt = 'i'; 49839209Sgibbs field_size = 8; 49988090Skbyanc field_width = strtol(p, &intendp, 10); 50088090Skbyanc p = intendp; 50139209Sgibbs state = DONE; 50239209Sgibbs } else if (*p == 'b') { 50339209Sgibbs 50439209Sgibbs /* Bits */ 50539209Sgibbs p++; 50639209Sgibbs 50739209Sgibbs *fmt = 'b'; 50839209Sgibbs field_size = 1; 50988090Skbyanc field_width = strtol(p, &intendp, 10); 51088090Skbyanc p = intendp; 51139209Sgibbs state = DONE; 51239209Sgibbs } else { 51339209Sgibbs fprintf(stderr, "Invalid startfield %c " 51439209Sgibbs "(%02x)\n", *p, *p); 51539209Sgibbs is_error = 1; 51639209Sgibbs state = DONE; 51739209Sgibbs } 51839209Sgibbs break; 51939209Sgibbs 52039209Sgibbs case DONE: 52139209Sgibbs break; 52239209Sgibbs } 52339209Sgibbs } 52439209Sgibbs 52539209Sgibbs if (is_error) { 52639209Sgibbs *error_p = 1; 52739209Sgibbs return 0; 52839209Sgibbs } 52939209Sgibbs 53039209Sgibbs *error_p = 0; 53139209Sgibbs *pp = p; 53239209Sgibbs *width_p = field_width * field_size; 53339209Sgibbs *value_p = value; 53439209Sgibbs *suppress_p = suppress; 53539209Sgibbs 53639209Sgibbs return (something); 53739209Sgibbs} 53839209Sgibbs 53939209Sgibbsstatic int 54039209Sgibbsdo_encode(u_char *buff, size_t vec_max, size_t *used, 54188090Skbyanc int (*arg_get)(void *, char *), void *gethook, const char *fmt, 542298753Sngie va_list *ap) 54339209Sgibbs{ 54439209Sgibbs int ind; 54539209Sgibbs int shift; 54639209Sgibbs u_char val; 54739209Sgibbs int ret; 54839209Sgibbs int width, value, error, suppress; 54939209Sgibbs char c; 55039209Sgibbs int encoded = 0; 55139209Sgibbs char field_name[80]; 55239209Sgibbs 55339209Sgibbs ind = 0; 55439209Sgibbs shift = 0; 55539209Sgibbs val = 0; 55639209Sgibbs 55739209Sgibbs while ((ret = next_field(&fmt, &c, &width, &value, field_name, 55839209Sgibbs sizeof(field_name), &error, &suppress))) { 55939209Sgibbs encoded++; 56039209Sgibbs 56139209Sgibbs if (ret == 2) { 56239209Sgibbs if (suppress) 56339209Sgibbs value = 0; 56439209Sgibbs else 56539209Sgibbs value = arg_get ? 56639209Sgibbs (*arg_get)(gethook, field_name) : 567298753Sngie va_arg(*ap, int); 56839209Sgibbs } 56939209Sgibbs 57039209Sgibbs#if 0 57139209Sgibbs printf( 57239209Sgibbs"do_encode: ret %d fmt %c width %d value %d name \"%s\" error %d suppress %d\n", 57339209Sgibbs ret, c, width, value, field_name, error, suppress); 57439209Sgibbs#endif 57539209Sgibbs /* Absolute seek */ 57639209Sgibbs if (c == 's') { 57739209Sgibbs ind = value; 57839209Sgibbs continue; 57939209Sgibbs } 58039209Sgibbs 58139209Sgibbs /* A width of < 8 is a bit field. */ 58239209Sgibbs if (width < 8) { 58339209Sgibbs 58439209Sgibbs /* This is a bit field. We start with the high bits 58539209Sgibbs * so it reads the same as the SCSI spec. 58639209Sgibbs */ 58739209Sgibbs 58839209Sgibbs shift += width; 58939209Sgibbs 59039209Sgibbs val |= (value << (8 - shift)); 59139209Sgibbs 59239209Sgibbs if (shift == 8) { 59339209Sgibbs if (ind < vec_max) { 59439209Sgibbs buff[ind++] = val; 59539209Sgibbs val = 0; 59639209Sgibbs } 59739209Sgibbs shift = 0; 59839209Sgibbs } 59939209Sgibbs } else { 60039209Sgibbs if (shift) { 60139209Sgibbs if (ind < vec_max) { 60239209Sgibbs buff[ind++] = val; 60339209Sgibbs val = 0; 60439209Sgibbs } 60539209Sgibbs shift = 0; 60639209Sgibbs } 60739209Sgibbs switch(width) { 60839209Sgibbs case 8: /* 1 byte integer */ 60939209Sgibbs if (ind < vec_max) 61039209Sgibbs buff[ind++] = value; 61139209Sgibbs break; 61239209Sgibbs 61339209Sgibbs case 16: /* 2 byte integer */ 61439209Sgibbs if (ind < vec_max - 2 + 1) { 61539209Sgibbs buff[ind++] = value >> 8; 61639209Sgibbs buff[ind++] = value; 61739209Sgibbs } 61839209Sgibbs break; 61939209Sgibbs 62039209Sgibbs case 24: /* 3 byte integer */ 62139209Sgibbs if (ind < vec_max - 3 + 1) { 62239209Sgibbs buff[ind++] = value >> 16; 62339209Sgibbs buff[ind++] = value >> 8; 62439209Sgibbs buff[ind++] = value; 62539209Sgibbs } 62639209Sgibbs break; 62739209Sgibbs 62839209Sgibbs case 32: /* 4 byte integer */ 62939209Sgibbs if (ind < vec_max - 4 + 1) { 63039209Sgibbs buff[ind++] = value >> 24; 63139209Sgibbs buff[ind++] = value >> 16; 63239209Sgibbs buff[ind++] = value >> 8; 63339209Sgibbs buff[ind++] = value; 63439209Sgibbs } 63539209Sgibbs break; 63639209Sgibbs 63739209Sgibbs default: 63839209Sgibbs fprintf(stderr, "do_encode: Illegal width\n"); 63939209Sgibbs break; 64039209Sgibbs } 64139209Sgibbs } 64239209Sgibbs } 64339209Sgibbs 64439209Sgibbs /* Flush out any remaining bits 64539209Sgibbs */ 64639209Sgibbs if (shift && ind < vec_max) { 64739209Sgibbs buff[ind++] = val; 64839209Sgibbs val = 0; 64939209Sgibbs } 65039209Sgibbs 65139209Sgibbs 65239209Sgibbs if (used) 65339209Sgibbs *used = ind; 65439209Sgibbs 65539209Sgibbs if (error) 65639209Sgibbs return -1; 65739209Sgibbs 65839209Sgibbs return encoded; 65939209Sgibbs} 66039209Sgibbs 66139209Sgibbsint 66288090Skbyanccsio_decode(struct ccb_scsiio *csio, const char *fmt, ...) 66339209Sgibbs{ 66439209Sgibbs va_list ap; 665298753Sngie int retval; 66639209Sgibbs 66739209Sgibbs va_start(ap, fmt); 66839209Sgibbs 669298753Sngie retval = do_buff_decode(csio->data_ptr, (size_t)csio->dxfer_len, 0, 0, 670298753Sngie fmt, &ap); 671298753Sngie 672298753Sngie va_end(ap); 673298753Sngie 674298753Sngie return (retval); 67539209Sgibbs} 67639209Sgibbs 67739209Sgibbsint 67888090Skbyanccsio_decode_visit(struct ccb_scsiio *csio, const char *fmt, 67939209Sgibbs void (*arg_put)(void *, int, void *, int, char *), 68039209Sgibbs void *puthook) 68139209Sgibbs{ 68239209Sgibbs 68339381Sken /* 68439381Sken * We need some way to output things; we can't do it without 68539381Sken * the arg_put function. 68639381Sken */ 68739381Sken if (arg_put == NULL) 688298753Sngie return (-1); 68939209Sgibbs 690298753Sngie return (do_buff_decode(csio->data_ptr, (size_t)csio->dxfer_len, 691298753Sngie arg_put, puthook, fmt, NULL)); 69239209Sgibbs} 69339209Sgibbs 69439209Sgibbsint 69588090Skbyancbuff_decode(u_int8_t *buff, size_t len, const char *fmt, ...) 69639209Sgibbs{ 69739209Sgibbs va_list ap; 698298753Sngie int retval; 69939209Sgibbs 70039209Sgibbs va_start(ap, fmt); 70139209Sgibbs 702298753Sngie retval = do_buff_decode(buff, len, 0, 0, fmt, &ap); 703298753Sngie 704298753Sngie va_end(ap); 705298753Sngie 706298753Sngie return (retval); 70739209Sgibbs} 70839209Sgibbs 70939209Sgibbsint 71088090Skbyancbuff_decode_visit(u_int8_t *buff, size_t len, const char *fmt, 71139209Sgibbs void (*arg_put)(void *, int, void *, int, char *), 71239209Sgibbs void *puthook) 71339209Sgibbs{ 71439209Sgibbs 71539381Sken /* 71639381Sken * We need some way to output things; we can't do it without 71739381Sken * the arg_put function. 71839381Sken */ 71939381Sken if (arg_put == NULL) 72039381Sken return(-1); 72139209Sgibbs 722298753Sngie return (do_buff_decode(buff, len, arg_put, puthook, fmt, NULL)); 72339209Sgibbs} 72439209Sgibbs 72539209Sgibbs/* 72639209Sgibbs * Build a SCSI CCB, given the command and data pointers and a format 72739209Sgibbs * string describing the 72839209Sgibbs */ 72939209Sgibbsint 73039209Sgibbscsio_build(struct ccb_scsiio *csio, u_int8_t *data_ptr, u_int32_t dxfer_len, 73188090Skbyanc u_int32_t flags, int retry_count, int timeout, const char *cmd_spec, 73288090Skbyanc ...) 73339209Sgibbs{ 73439381Sken size_t cmdlen; 73539209Sgibbs int retval; 73639209Sgibbs va_list ap; 73739209Sgibbs 73839209Sgibbs if (csio == NULL) 739298753Sngie return (0); 74039209Sgibbs 74139209Sgibbs bzero(csio, sizeof(struct ccb_scsiio)); 74239209Sgibbs 74339209Sgibbs va_start(ap, cmd_spec); 74439209Sgibbs 74539209Sgibbs if ((retval = do_encode(csio->cdb_io.cdb_bytes, SCSI_MAX_CDBLEN, 746298753Sngie &cmdlen, NULL, NULL, cmd_spec, &ap)) == -1) 747298753Sngie goto done; 74839209Sgibbs 74939209Sgibbs cam_fill_csio(csio, 75039209Sgibbs /* retries */ retry_count, 75139209Sgibbs /* cbfcnp */ NULL, 75239209Sgibbs /* flags */ flags, 75339209Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 75439209Sgibbs /* data_ptr */ data_ptr, 75539209Sgibbs /* dxfer_len */ dxfer_len, 75639209Sgibbs /* sense_len */ SSD_FULL_SIZE, 75739209Sgibbs /* cdb_len */ cmdlen, 75839209Sgibbs /* timeout */ timeout ? timeout : 5000); 75939209Sgibbs 760298753Sngiedone: 761298753Sngie va_end(ap); 762298753Sngie 763298753Sngie return (retval); 76439209Sgibbs} 76539209Sgibbs 76639209Sgibbsint 76739209Sgibbscsio_build_visit(struct ccb_scsiio *csio, u_int8_t *data_ptr, 76839209Sgibbs u_int32_t dxfer_len, u_int32_t flags, int retry_count, 76988090Skbyanc int timeout, const char *cmd_spec, 77039209Sgibbs int (*arg_get)(void *hook, char *field_name), void *gethook) 77139209Sgibbs{ 77239381Sken size_t cmdlen; 77339381Sken int retval; 77439209Sgibbs 77539209Sgibbs if (csio == NULL) 77639209Sgibbs return(0); 77739209Sgibbs 77839381Sken /* 77939381Sken * We need something to encode, but we can't get it without the 78039381Sken * arg_get function. 78139381Sken */ 78239381Sken if (arg_get == NULL) 78339381Sken return(-1); 78439209Sgibbs 78539209Sgibbs bzero(csio, sizeof(struct ccb_scsiio)); 78639209Sgibbs 78739209Sgibbs if ((retval = do_encode(csio->cdb_io.cdb_bytes, SCSI_MAX_CDBLEN, 788298753Sngie &cmdlen, arg_get, gethook, cmd_spec, NULL)) == -1) 78939209Sgibbs return(retval); 79039209Sgibbs 79139209Sgibbs cam_fill_csio(csio, 79239209Sgibbs /* retries */ retry_count, 79339209Sgibbs /* cbfcnp */ NULL, 79439209Sgibbs /* flags */ flags, 79539209Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 79639209Sgibbs /* data_ptr */ data_ptr, 79739209Sgibbs /* dxfer_len */ dxfer_len, 79839209Sgibbs /* sense_len */ SSD_FULL_SIZE, 79939209Sgibbs /* cdb_len */ cmdlen, 80039209Sgibbs /* timeout */ timeout ? timeout : 5000); 80139209Sgibbs 80239209Sgibbs return(retval); 80339209Sgibbs} 80439209Sgibbs 80539209Sgibbsint 80688090Skbyanccsio_encode(struct ccb_scsiio *csio, const char *fmt, ...) 80739209Sgibbs{ 80839209Sgibbs va_list ap; 809298753Sngie int retval; 81039209Sgibbs 81139209Sgibbs if (csio == NULL) 812298753Sngie return (0); 81339209Sgibbs 81439209Sgibbs va_start(ap, fmt); 81539209Sgibbs 816298753Sngie retval = do_encode(csio->data_ptr, csio->dxfer_len, 0, 0, 0, fmt, &ap); 817298753Sngie 818298753Sngie va_end(ap); 819298753Sngie 820298753Sngie return (retval); 82139209Sgibbs} 82239209Sgibbs 82339209Sgibbsint 82488090Skbyancbuff_encode_visit(u_int8_t *buff, size_t len, const char *fmt, 82539209Sgibbs int (*arg_get)(void *hook, char *field_name), void *gethook) 82639209Sgibbs{ 82739209Sgibbs 82839381Sken /* 82939381Sken * We need something to encode, but we can't get it without the 83039381Sken * arg_get function. 83139381Sken */ 83239381Sken if (arg_get == NULL) 83339381Sken return(-1); 83439209Sgibbs 835298753Sngie return (do_encode(buff, len, 0, arg_get, gethook, fmt, NULL)); 83639209Sgibbs} 83739209Sgibbs 83839209Sgibbsint 83988090Skbyanccsio_encode_visit(struct ccb_scsiio *csio, const char *fmt, 84039209Sgibbs int (*arg_get)(void *hook, char *field_name), void *gethook) 84139209Sgibbs{ 84239209Sgibbs 84339381Sken /* 84439381Sken * We need something to encode, but we can't get it without the 84539381Sken * arg_get function. 84639381Sken */ 84739381Sken if (arg_get == NULL) 84839381Sken return(-1); 84939209Sgibbs 850298753Sngie return (do_encode(csio->data_ptr, csio->dxfer_len, 0, arg_get, 851298753Sngie gethook, fmt, NULL)); 85239209Sgibbs} 853