xref: /freebsd-src/lib/libcam/scsi_cmdparse.c (revision a2f733abcff64628b7771a47089628b7327a88bd)
1f736a450SJustin T. Gibbs /*
2f736a450SJustin T. Gibbs  * Taken from the original FreeBSD user SCSI library.
3f736a450SJustin T. Gibbs  */
4df57947fSPedro F. Giffuni /*-
5df57947fSPedro F. Giffuni  * SPDX-License-Identifier: BSD-4-Clause
6df57947fSPedro F. Giffuni  *
7df57947fSPedro F. Giffuni  * Copyright (c) 1994 HD Associates
8f736a450SJustin T. Gibbs  * (contact: dufault@hda.com)
9f736a450SJustin T. Gibbs  * All rights reserved.
10f736a450SJustin T. Gibbs  *
11f736a450SJustin T. Gibbs  * Redistribution and use in source and binary forms, with or without
12f736a450SJustin T. Gibbs  * modification, are permitted provided that the following conditions
13f736a450SJustin T. Gibbs  * are met:
14f736a450SJustin T. Gibbs  * 1. Redistributions of source code must retain the above copyright
15f736a450SJustin T. Gibbs  *    notice, this list of conditions and the following disclaimer.
16f736a450SJustin T. Gibbs  * 2. Redistributions in binary form must reproduce the above copyright
17f736a450SJustin T. Gibbs  *    notice, this list of conditions and the following disclaimer in the
18f736a450SJustin T. Gibbs  *    documentation and/or other materials provided with the distribution.
19f736a450SJustin T. Gibbs  * 3. All advertising materials mentioning features or use of this software
20f736a450SJustin T. Gibbs  *    must display the following acknowledgement:
21f736a450SJustin T. Gibbs  * This product includes software developed by HD Associates
22f736a450SJustin T. Gibbs  * 4. Neither the name of the HD Associaates nor the names of its contributors
23f736a450SJustin T. Gibbs  *    may be used to endorse or promote products derived from this software
24f736a450SJustin T. Gibbs  *    without specific prior written permission.
25f736a450SJustin T. Gibbs  *
26f736a450SJustin T. Gibbs  * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES``AS IS'' AND
27f736a450SJustin T. Gibbs  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28f736a450SJustin T. Gibbs  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29f736a450SJustin T. Gibbs  * ARE DISCLAIMED.  IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE
30f736a450SJustin T. Gibbs  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31f736a450SJustin T. Gibbs  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32f736a450SJustin T. Gibbs  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33f736a450SJustin T. Gibbs  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34f736a450SJustin T. Gibbs  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35f736a450SJustin T. Gibbs  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36f736a450SJustin T. Gibbs  * SUCH DAMAGE.
37f736a450SJustin T. Gibbs  * From: scsi.c,v 1.8 1997/02/22 15:07:54 peter Exp $
38f736a450SJustin T. Gibbs  */
39090f02d9SMatthew Dillon 
4052082f69SMike Barcroft #include <sys/types.h>
4152082f69SMike Barcroft 
42f736a450SJustin T. Gibbs #include <stdlib.h>
43f736a450SJustin T. Gibbs #include <stdio.h>
44f736a450SJustin T. Gibbs #include <ctype.h>
45f736a450SJustin T. Gibbs #include <string.h>
46f736a450SJustin T. Gibbs #include <sys/errno.h>
47f736a450SJustin T. Gibbs #include <stdarg.h>
48f736a450SJustin T. Gibbs #include <fcntl.h>
49f736a450SJustin T. Gibbs 
50f736a450SJustin T. Gibbs #include <cam/cam.h>
51f736a450SJustin T. Gibbs #include <cam/cam_ccb.h>
52f736a450SJustin T. Gibbs #include <cam/scsi/scsi_message.h>
53f736a450SJustin T. Gibbs #include "camlib.h"
54f736a450SJustin T. Gibbs 
55f736a450SJustin T. Gibbs /*
56f736a450SJustin T. Gibbs  * Decode: Decode the data section of a scsireq.  This decodes
57f736a450SJustin T. Gibbs  * trivial grammar:
58f736a450SJustin T. Gibbs  *
59f736a450SJustin T. Gibbs  * fields : field fields
60f736a450SJustin T. Gibbs  *        ;
61f736a450SJustin T. Gibbs  *
62f736a450SJustin T. Gibbs  * field : field_specifier
63f736a450SJustin T. Gibbs  *       | control
64f736a450SJustin T. Gibbs  *       ;
65f736a450SJustin T. Gibbs  *
66f736a450SJustin T. Gibbs  * control : 's' seek_value
67f736a450SJustin T. Gibbs  *       | 's' '+' seek_value
68f736a450SJustin T. Gibbs  *       ;
69f736a450SJustin T. Gibbs  *
70f736a450SJustin T. Gibbs  * seek_value : DECIMAL_NUMBER
71f736a450SJustin T. Gibbs  *       | 'v'				// For indirect seek, i.e., value from the arg list
72f736a450SJustin T. Gibbs  *       ;
73f736a450SJustin T. Gibbs  *
74f736a450SJustin T. Gibbs  * field_specifier : type_specifier field_width
75f736a450SJustin T. Gibbs  *       | '{' NAME '}' type_specifier field_width
76f736a450SJustin T. Gibbs  *       ;
77f736a450SJustin T. Gibbs  *
78f736a450SJustin T. Gibbs  * field_width : DECIMAL_NUMBER
79f736a450SJustin T. Gibbs  *       ;
80f736a450SJustin T. Gibbs  *
81f736a450SJustin T. Gibbs  * type_specifier : 'i'	// Integral types (i1, i2, i3, i4)
82f736a450SJustin T. Gibbs  *       | 'b'				// Bits
83f736a450SJustin T. Gibbs  *       | 't'				// Bits
84f736a450SJustin T. Gibbs  *       | 'c'				// Character arrays
85f736a450SJustin T. Gibbs  *       | 'z'				// Character arrays with zeroed trailing spaces
86f736a450SJustin T. Gibbs  *       ;
87f736a450SJustin T. Gibbs  *
88f736a450SJustin T. Gibbs  * Notes:
89f736a450SJustin T. Gibbs  * 1. Integral types are swapped into host order.
90f736a450SJustin T. Gibbs  * 2. Bit fields are allocated MSB to LSB to match the SCSI spec documentation.
91f736a450SJustin T. Gibbs  * 3. 's' permits "seeking" in the string.  "s+DECIMAL" seeks relative to
92f736a450SJustin T. Gibbs  *    DECIMAL; "sDECIMAL" seeks absolute to decimal.
93f736a450SJustin T. Gibbs  * 4. 's' permits an indirect reference.  "sv" or "s+v" will get the
94f736a450SJustin T. Gibbs  *    next integer value from the arg array.
95f736a450SJustin T. Gibbs  * 5. Field names can be anything between the braces
96f736a450SJustin T. Gibbs  *
97f736a450SJustin T. Gibbs  * BUGS:
98f736a450SJustin T. Gibbs  * i and b types are promoted to ints.
99f736a450SJustin T. Gibbs  *
100f736a450SJustin T. Gibbs  */
101f736a450SJustin T. Gibbs 
102f736a450SJustin T. Gibbs static int
do_buff_decode(uint8_t * buff,size_t len,void (* arg_put)(void *,int,void *,int,char *),void * puthook,const char * fmt,va_list * ap)103*f9ffa1efSWarner Losh do_buff_decode(uint8_t *buff, size_t len,
104f736a450SJustin T. Gibbs 	       void (*arg_put)(void *, int , void *, int, char *),
1052357dac4SEnji Cooper 	       void *puthook, const char *fmt, va_list *ap)
106f736a450SJustin T. Gibbs {
10726b1288fSAlexander Motin 	int ind = 0;
108f736a450SJustin T. Gibbs 	int assigned = 0;
109f736a450SJustin T. Gibbs 	int width;
110f736a450SJustin T. Gibbs 	int suppress;
111f736a450SJustin T. Gibbs 	int plus;
112f736a450SJustin T. Gibbs 	int done = 0;
113f736a450SJustin T. Gibbs 	static u_char mask[] = {0, 0x01, 0x03, 0x07, 0x0f,
114f736a450SJustin T. Gibbs 				   0x1f, 0x3f, 0x7f, 0xff};
115f736a450SJustin T. Gibbs 	int value;
116cb28eb78SKelly Yancey 	char *intendp;
117f736a450SJustin T. Gibbs 	char letter;
118f736a450SJustin T. Gibbs 	char field_name[80];
119f736a450SJustin T. Gibbs 
120f736a450SJustin T. Gibbs #define ARG_PUT(ARG) \
12126b1288fSAlexander Motin 	do { \
12226b1288fSAlexander Motin 		if (!suppress) { \
123f736a450SJustin T. Gibbs 			if (arg_put) \
12426b1288fSAlexander Motin 				(*arg_put)(puthook, (letter == 't' ? 'b' : \
12526b1288fSAlexander Motin 				    letter), (void *)((long)(ARG)), width, \
1267e32b20dSKelly Yancey 				    field_name); \
127f736a450SJustin T. Gibbs 			else \
1282357dac4SEnji Cooper 				*(va_arg(*ap, int *)) = (ARG); \
129f736a450SJustin T. Gibbs 			assigned++; \
130f736a450SJustin T. Gibbs 		} \
13169c703b9SEnji Cooper 		field_name[0] = '\0'; \
132f736a450SJustin T. Gibbs 		suppress = 0; \
133f736a450SJustin T. Gibbs 	} while (0)
134f736a450SJustin T. Gibbs 
135f736a450SJustin T. Gibbs 	u_char bits = 0;	/* For bit fields */
136f736a450SJustin T. Gibbs 	int shift = 0;		/* Bits already shifted out */
137f736a450SJustin T. Gibbs 	suppress = 0;
13869c703b9SEnji Cooper 	field_name[0] = '\0';
139f736a450SJustin T. Gibbs 
140f736a450SJustin T. Gibbs 	while (!done) {
141f736a450SJustin T. Gibbs 		switch(letter = *fmt) {
142f736a450SJustin T. Gibbs 		case ' ':	/* White space */
143f736a450SJustin T. Gibbs 		case '\t':
144f736a450SJustin T. Gibbs 		case '\r':
145f736a450SJustin T. Gibbs 		case '\n':
146f736a450SJustin T. Gibbs 		case '\f':
147f736a450SJustin T. Gibbs 			fmt++;
148f736a450SJustin T. Gibbs 			break;
149f736a450SJustin T. Gibbs 
150f736a450SJustin T. Gibbs 		case '#':	/* Comment */
151f736a450SJustin T. Gibbs 			while (*fmt && (*fmt != '\n'))
152f736a450SJustin T. Gibbs 				fmt++;
153f736a450SJustin T. Gibbs 			if (fmt)
154f736a450SJustin T. Gibbs 				fmt++;	/* Skip '\n' */
155f736a450SJustin T. Gibbs 			break;
156f736a450SJustin T. Gibbs 
157f736a450SJustin T. Gibbs 		case '*':	/* Suppress assignment */
158f736a450SJustin T. Gibbs 			fmt++;
159f736a450SJustin T. Gibbs 			suppress = 1;
160f736a450SJustin T. Gibbs 			break;
161f736a450SJustin T. Gibbs 
162f736a450SJustin T. Gibbs 		case '{':	/* Field Name */
163f736a450SJustin T. Gibbs 		{
164f736a450SJustin T. Gibbs 			int i = 0;
165f736a450SJustin T. Gibbs 			fmt++;	/* Skip '{' */
166f736a450SJustin T. Gibbs 			while (*fmt && (*fmt != '}')) {
167f736a450SJustin T. Gibbs 				if (i < sizeof(field_name))
168f736a450SJustin T. Gibbs 					field_name[i++] = *fmt;
169f736a450SJustin T. Gibbs 
170f736a450SJustin T. Gibbs 				fmt++;
171f736a450SJustin T. Gibbs 			}
1728f7861b2SEnji Cooper 			if (*fmt != '\0')
173f736a450SJustin T. Gibbs 				fmt++;	/* Skip '}' */
17469c703b9SEnji Cooper 			field_name[i] = '\0';
175f736a450SJustin T. Gibbs 			break;
176f736a450SJustin T. Gibbs 		}
177f736a450SJustin T. Gibbs 
178f736a450SJustin T. Gibbs 		case 't':	/* Bit (field) */
179f736a450SJustin T. Gibbs 		case 'b':	/* Bits */
180f736a450SJustin T. Gibbs 			fmt++;
181cb28eb78SKelly Yancey 			width = strtol(fmt, &intendp, 10);
182cb28eb78SKelly Yancey 			fmt = intendp;
183f736a450SJustin T. Gibbs 			if (width > 8)
184f736a450SJustin T. Gibbs 				done = 1;
185f736a450SJustin T. Gibbs 			else {
186f736a450SJustin T. Gibbs 				if (shift <= 0) {
18726b1288fSAlexander Motin 					if (ind >= len) {
18826b1288fSAlexander Motin 						done = 1;
18926b1288fSAlexander Motin 						break;
19026b1288fSAlexander Motin 					}
19126b1288fSAlexander Motin 					bits = buff[ind++];
192f736a450SJustin T. Gibbs 					shift = 8;
193f736a450SJustin T. Gibbs 				}
194f736a450SJustin T. Gibbs 				value = (bits >> (shift - width)) &
195f736a450SJustin T. Gibbs 					 mask[width];
196f736a450SJustin T. Gibbs 
197f736a450SJustin T. Gibbs #if 0
198f736a450SJustin T. Gibbs 				printf("shift %2d bits %02x value %02x width %2d mask %02x\n",
199f736a450SJustin T. Gibbs 				shift, bits, value, width, mask[width]);
200f736a450SJustin T. Gibbs #endif
201f736a450SJustin T. Gibbs 
202f736a450SJustin T. Gibbs 				ARG_PUT(value);
203f736a450SJustin T. Gibbs 
204f736a450SJustin T. Gibbs 				shift -= width;
205f736a450SJustin T. Gibbs 			}
206f736a450SJustin T. Gibbs 			break;
207f736a450SJustin T. Gibbs 
208f736a450SJustin T. Gibbs 		case 'i':	/* Integral values */
209f736a450SJustin T. Gibbs 			shift = 0;
210f736a450SJustin T. Gibbs 			fmt++;
211cb28eb78SKelly Yancey 			width = strtol(fmt, &intendp, 10);
212cb28eb78SKelly Yancey 			fmt = intendp;
21326b1288fSAlexander Motin 			if (ind + width > len) {
21426b1288fSAlexander Motin 				done = 1;
21526b1288fSAlexander Motin 				break;
21626b1288fSAlexander Motin 			}
217f736a450SJustin T. Gibbs 			switch(width) {
218f736a450SJustin T. Gibbs 			case 1:
21926b1288fSAlexander Motin 				ARG_PUT(buff[ind]);
22026b1288fSAlexander Motin 				ind++;
221f736a450SJustin T. Gibbs 				break;
222f736a450SJustin T. Gibbs 
223f736a450SJustin T. Gibbs 			case 2:
22426b1288fSAlexander Motin 				ARG_PUT(buff[ind] << 8 | buff[ind + 1]);
22526b1288fSAlexander Motin 				ind += 2;
226f736a450SJustin T. Gibbs 				break;
227f736a450SJustin T. Gibbs 
228f736a450SJustin T. Gibbs 			case 3:
22926b1288fSAlexander Motin 				ARG_PUT(buff[ind] << 16 |
23026b1288fSAlexander Motin 					buff[ind + 1] << 8 | buff[ind + 2]);
23126b1288fSAlexander Motin 				ind += 3;
232f736a450SJustin T. Gibbs 				break;
233f736a450SJustin T. Gibbs 
234f736a450SJustin T. Gibbs 			case 4:
23526b1288fSAlexander Motin 				ARG_PUT(buff[ind] << 24 | buff[ind + 1] << 16 |
23626b1288fSAlexander Motin 					buff[ind + 2] << 8 | buff[ind + 3]);
23726b1288fSAlexander Motin 				ind += 4;
238f736a450SJustin T. Gibbs 				break;
239f736a450SJustin T. Gibbs 
240f736a450SJustin T. Gibbs 			default:
241f736a450SJustin T. Gibbs 				done = 1;
242f736a450SJustin T. Gibbs 				break;
243f736a450SJustin T. Gibbs 			}
244f736a450SJustin T. Gibbs 
245f736a450SJustin T. Gibbs 			break;
246f736a450SJustin T. Gibbs 
247f736a450SJustin T. Gibbs 		case 'c':	/* Characters (i.e., not swapped) */
24826b1288fSAlexander Motin 		case 'z':	/* Characters with zeroed trailing spaces */
249f736a450SJustin T. Gibbs 			shift = 0;
250f736a450SJustin T. Gibbs 			fmt++;
251cb28eb78SKelly Yancey 			width = strtol(fmt, &intendp, 10);
252cb28eb78SKelly Yancey 			fmt = intendp;
25326b1288fSAlexander Motin 			if (ind + width > len) {
25426b1288fSAlexander Motin 				done = 1;
25526b1288fSAlexander Motin 				break;
25626b1288fSAlexander Motin 			}
257f736a450SJustin T. Gibbs 			if (!suppress) {
25869c703b9SEnji Cooper 				if (arg_put != NULL)
259f736a450SJustin T. Gibbs 					(*arg_put)(puthook,
260f736a450SJustin T. Gibbs 					    (letter == 't' ? 'b' : letter),
26126b1288fSAlexander Motin 					    &buff[ind], width, field_name);
262f736a450SJustin T. Gibbs 				else {
263f736a450SJustin T. Gibbs 					char *dest;
2642357dac4SEnji Cooper 					dest = va_arg(*ap, char *);
26526b1288fSAlexander Motin 					bcopy(&buff[ind], dest, width);
266f736a450SJustin T. Gibbs 					if (letter == 'z') {
267f736a450SJustin T. Gibbs 						char *p;
268f736a450SJustin T. Gibbs 						for (p = dest + width - 1;
26926b1288fSAlexander Motin 						    p >= dest && *p == ' ';
27026b1288fSAlexander Motin 						    p--)
27169c703b9SEnji Cooper 							*p = '\0';
272f736a450SJustin T. Gibbs 					}
273f736a450SJustin T. Gibbs 				}
274f736a450SJustin T. Gibbs 				assigned++;
275f736a450SJustin T. Gibbs 			}
27626b1288fSAlexander Motin 			ind += width;
277f736a450SJustin T. Gibbs 			field_name[0] = 0;
278f736a450SJustin T. Gibbs 			suppress = 0;
279f736a450SJustin T. Gibbs 			break;
280f736a450SJustin T. Gibbs 
281f736a450SJustin T. Gibbs 		case 's':	/* Seek */
282f736a450SJustin T. Gibbs 			shift = 0;
283f736a450SJustin T. Gibbs 			fmt++;
284f736a450SJustin T. Gibbs 			if (*fmt == '+') {
285f736a450SJustin T. Gibbs 				plus = 1;
286f736a450SJustin T. Gibbs 				fmt++;
287f736a450SJustin T. Gibbs 			} else
288f736a450SJustin T. Gibbs 				plus = 0;
289f736a450SJustin T. Gibbs 
290f736a450SJustin T. Gibbs 			if (tolower(*fmt) == 'v') {
291f736a450SJustin T. Gibbs 				/*
292f736a450SJustin T. Gibbs 				 * You can't suppress a seek value.  You also
293f736a450SJustin T. Gibbs 				 * can't have a variable seek when you are using
294f736a450SJustin T. Gibbs 				 * "arg_put".
295f736a450SJustin T. Gibbs 				 */
2962357dac4SEnji Cooper 				width = (arg_put) ? 0 : va_arg(*ap, int);
297f736a450SJustin T. Gibbs 				fmt++;
298cb28eb78SKelly Yancey 			} else {
299cb28eb78SKelly Yancey 				width = strtol(fmt, &intendp, 10);
300cb28eb78SKelly Yancey 				fmt = intendp;
301cb28eb78SKelly Yancey 			}
302f736a450SJustin T. Gibbs 
303f736a450SJustin T. Gibbs 			if (plus)
30426b1288fSAlexander Motin 				ind += width;	/* Relative seek */
305f736a450SJustin T. Gibbs 			else
30626b1288fSAlexander Motin 				ind = width;	/* Absolute seek */
307f736a450SJustin T. Gibbs 
308f736a450SJustin T. Gibbs 			break;
309f736a450SJustin T. Gibbs 
310f736a450SJustin T. Gibbs 		case 0:
311f736a450SJustin T. Gibbs 			done = 1;
312f736a450SJustin T. Gibbs 			break;
313f736a450SJustin T. Gibbs 
314f736a450SJustin T. Gibbs 		default:
315f736a450SJustin T. Gibbs 			fprintf(stderr, "Unknown letter in format: %c\n",
316f736a450SJustin T. Gibbs 				letter);
317f736a450SJustin T. Gibbs 			fmt++;
318f736a450SJustin T. Gibbs 			break;
319f736a450SJustin T. Gibbs 		}
320f736a450SJustin T. Gibbs 	}
321f736a450SJustin T. Gibbs 
322f736a450SJustin T. Gibbs 	return (assigned);
323f736a450SJustin T. Gibbs }
324f736a450SJustin T. Gibbs 
325f736a450SJustin T. Gibbs /* next_field: Return the next field in a command specifier.  This
326f736a450SJustin T. Gibbs  * builds up a SCSI command using this trivial grammar:
327f736a450SJustin T. Gibbs  *
328f736a450SJustin T. Gibbs  * fields : field fields
329f736a450SJustin T. Gibbs  *        ;
330f736a450SJustin T. Gibbs  *
331f736a450SJustin T. Gibbs  * field : value
332f736a450SJustin T. Gibbs  *       | value ':' field_width
333f736a450SJustin T. Gibbs  *       ;
334f736a450SJustin T. Gibbs  *
335f736a450SJustin T. Gibbs  * field_width : digit
336f736a450SJustin T. Gibbs  *       | 'i' digit		// i2 = 2 byte integer, i3 = 3 byte integer etc.
337f736a450SJustin T. Gibbs  *       ;
338f736a450SJustin T. Gibbs  *
339f736a450SJustin T. Gibbs  * value : HEX_NUMBER
340f736a450SJustin T. Gibbs  *       | 'v'				// For indirection.
341f736a450SJustin T. Gibbs  *       ;
342f736a450SJustin T. Gibbs  *
343f736a450SJustin T. Gibbs  * Notes:
344f736a450SJustin T. Gibbs  *  Bit fields are specified MSB first to match the SCSI spec.
345f736a450SJustin T. Gibbs  *
346f736a450SJustin T. Gibbs  * Examples:
347f736a450SJustin T. Gibbs  *  TUR: "0 0 0 0 0 0"
348f736a450SJustin T. Gibbs  *  WRITE BUFFER: "38 v:3 0:2 0:3 v v:i3 v:i3 0", mode, buffer_id, list_length
349f736a450SJustin T. Gibbs  *
350f736a450SJustin T. Gibbs  * The function returns the value:
351f736a450SJustin T. Gibbs  *  0: For reached end, with error_p set if an error was found
352f736a450SJustin T. Gibbs  *  1: For valid stuff setup
353f736a450SJustin T. Gibbs  *  2: For "v" was entered as the value (implies use varargs)
354f736a450SJustin T. Gibbs  *
355f736a450SJustin T. Gibbs  */
356f736a450SJustin T. Gibbs 
357f736a450SJustin T. Gibbs static int
next_field(const char ** pp,char * fmt,int * width_p,int * value_p,char * name,int n_name,int * error_p,int * suppress_p)358cb28eb78SKelly Yancey next_field(const char **pp, char *fmt, int *width_p, int *value_p, char *name,
359f736a450SJustin T. Gibbs 	   int n_name, int *error_p, int *suppress_p)
360f736a450SJustin T. Gibbs {
361cb28eb78SKelly Yancey 	const char *p = *pp;
362cb28eb78SKelly Yancey 	char *intendp;
363f736a450SJustin T. Gibbs 
364f736a450SJustin T. Gibbs 	int something = 0;
365f736a450SJustin T. Gibbs 
366f736a450SJustin T. Gibbs 	enum {
367f736a450SJustin T. Gibbs 		BETWEEN_FIELDS,
368f736a450SJustin T. Gibbs 		START_FIELD,
369f736a450SJustin T. Gibbs 		GET_FIELD,
370f736a450SJustin T. Gibbs 		DONE,
371f736a450SJustin T. Gibbs 	} state;
372f736a450SJustin T. Gibbs 
373f736a450SJustin T. Gibbs 	int value = 0;
374f736a450SJustin T. Gibbs 	int field_size;		/* Default to byte field type... */
375f736a450SJustin T. Gibbs 	int field_width;	/* 1 byte wide */
376f736a450SJustin T. Gibbs 	int is_error = 0;
377f736a450SJustin T. Gibbs 	int suppress = 0;
378f736a450SJustin T. Gibbs 
379f736a450SJustin T. Gibbs 	field_size = 8;		/* Default to byte field type... */
380f736a450SJustin T. Gibbs 	*fmt = 'i';
381f736a450SJustin T. Gibbs 	field_width = 1;	/* 1 byte wide */
38269c703b9SEnji Cooper 	if (name != NULL)
38369c703b9SEnji Cooper 		*name = '\0';
384f736a450SJustin T. Gibbs 
385f736a450SJustin T. Gibbs 	state = BETWEEN_FIELDS;
386f736a450SJustin T. Gibbs 
387f736a450SJustin T. Gibbs 	while (state != DONE) {
388f736a450SJustin T. Gibbs 		switch(state) {
389f736a450SJustin T. Gibbs 		case BETWEEN_FIELDS:
39069c703b9SEnji Cooper 			if (*p == '\0')
391f736a450SJustin T. Gibbs 				state = DONE;
392f736a450SJustin T. Gibbs 			else if (isspace(*p))
393f736a450SJustin T. Gibbs 				p++;
394f736a450SJustin T. Gibbs 			else if (*p == '#') {
395f736a450SJustin T. Gibbs 				while (*p && *p != '\n')
396f736a450SJustin T. Gibbs 					p++;
39769c703b9SEnji Cooper 				if (*p != '\0')
398f736a450SJustin T. Gibbs 					p++;
399f736a450SJustin T. Gibbs 			} else if (*p == '{') {
400f736a450SJustin T. Gibbs 				int i = 0;
401f736a450SJustin T. Gibbs 
402f736a450SJustin T. Gibbs 				p++;
403f736a450SJustin T. Gibbs 
404f736a450SJustin T. Gibbs 				while (*p && *p != '}') {
405f736a450SJustin T. Gibbs 					if(name && i < n_name) {
406f736a450SJustin T. Gibbs 						name[i] = *p;
407f736a450SJustin T. Gibbs 						i++;
408f736a450SJustin T. Gibbs 					}
409f736a450SJustin T. Gibbs 					p++;
410f736a450SJustin T. Gibbs 				}
411f736a450SJustin T. Gibbs 
412f736a450SJustin T. Gibbs 				if(name && i < n_name)
41369c703b9SEnji Cooper 					name[i] = '\0';
414f736a450SJustin T. Gibbs 
415f736a450SJustin T. Gibbs 				if (*p == '}')
416f736a450SJustin T. Gibbs 					p++;
417f736a450SJustin T. Gibbs 			} else if (*p == '*') {
418f736a450SJustin T. Gibbs 				p++;
419f736a450SJustin T. Gibbs 				suppress = 1;
420f736a450SJustin T. Gibbs 			} else if (isxdigit(*p)) {
421f736a450SJustin T. Gibbs 				something = 1;
422cb28eb78SKelly Yancey 				value = strtol(p, &intendp, 16);
423cb28eb78SKelly Yancey 				p = intendp;
424f736a450SJustin T. Gibbs 				state = START_FIELD;
425f736a450SJustin T. Gibbs 			} else if (tolower(*p) == 'v') {
426f736a450SJustin T. Gibbs 				p++;
427f736a450SJustin T. Gibbs 				something = 2;
428f736a450SJustin T. Gibbs 				value = *value_p;
429f736a450SJustin T. Gibbs 				state = START_FIELD;
430f736a450SJustin T. Gibbs 			} else if (tolower(*p) == 'i') {
431f736a450SJustin T. Gibbs 				/*
432f736a450SJustin T. Gibbs 				 * Try to work without the "v".
433f736a450SJustin T. Gibbs 				 */
434f736a450SJustin T. Gibbs 				something = 2;
435f736a450SJustin T. Gibbs 				value = *value_p;
436f736a450SJustin T. Gibbs 				p++;
437f736a450SJustin T. Gibbs 
438f736a450SJustin T. Gibbs 				*fmt = 'i';
439f736a450SJustin T. Gibbs 				field_size = 8;
440cb28eb78SKelly Yancey 				field_width = strtol(p, &intendp, 10);
441cb28eb78SKelly Yancey 				p = intendp;
442f736a450SJustin T. Gibbs 				state = DONE;
443f736a450SJustin T. Gibbs 
444f736a450SJustin T. Gibbs 			} else if (tolower(*p) == 't') {
445f736a450SJustin T. Gibbs 				/*
446f736a450SJustin T. Gibbs 				 * XXX: B can't work: Sees the 'b' as a
447f736a450SJustin T. Gibbs 				 * hex digit in "isxdigit".  try "t" for
448f736a450SJustin T. Gibbs 				 * bit field.
449f736a450SJustin T. Gibbs 				 */
450f736a450SJustin T. Gibbs 				something = 2;
451f736a450SJustin T. Gibbs 				value = *value_p;
452f736a450SJustin T. Gibbs 				p++;
453f736a450SJustin T. Gibbs 
454f736a450SJustin T. Gibbs 				*fmt = 'b';
455f736a450SJustin T. Gibbs 				field_size = 1;
456cb28eb78SKelly Yancey 				field_width = strtol(p, &intendp, 10);
457cb28eb78SKelly Yancey 				p = intendp;
458f736a450SJustin T. Gibbs 				state = DONE;
459f736a450SJustin T. Gibbs 			} else if (tolower(*p) == 's') {
460f736a450SJustin T. Gibbs 				/* Seek */
461f736a450SJustin T. Gibbs 				*fmt = 's';
462f736a450SJustin T. Gibbs 				p++;
463f736a450SJustin T. Gibbs 				if (tolower(*p) == 'v') {
464f736a450SJustin T. Gibbs 					p++;
465f736a450SJustin T. Gibbs 					something = 2;
466f736a450SJustin T. Gibbs 					value = *value_p;
467f736a450SJustin T. Gibbs 				} else {
468f736a450SJustin T. Gibbs 					something = 1;
469cb28eb78SKelly Yancey 					value = strtol(p, &intendp, 0);
470cb28eb78SKelly Yancey 					p = intendp;
471f736a450SJustin T. Gibbs 				}
472f736a450SJustin T. Gibbs 				state = DONE;
473f736a450SJustin T. Gibbs 			} else {
474f736a450SJustin T. Gibbs 				fprintf(stderr, "Invalid starting "
475f736a450SJustin T. Gibbs 					"character: %c\n", *p);
476f736a450SJustin T. Gibbs 				is_error = 1;
477f736a450SJustin T. Gibbs 				state = DONE;
478f736a450SJustin T. Gibbs 			}
479f736a450SJustin T. Gibbs 			break;
480f736a450SJustin T. Gibbs 
481f736a450SJustin T. Gibbs 		case START_FIELD:
482f736a450SJustin T. Gibbs 			if (*p == ':') {
483f736a450SJustin T. Gibbs 				p++;
484f736a450SJustin T. Gibbs 				field_size = 1;		/* Default to bits
485f736a450SJustin T. Gibbs 							   when specified */
486f736a450SJustin T. Gibbs 				state = GET_FIELD;
487f736a450SJustin T. Gibbs 			} else
488f736a450SJustin T. Gibbs 				state = DONE;
489f736a450SJustin T. Gibbs 			break;
490f736a450SJustin T. Gibbs 
491f736a450SJustin T. Gibbs 		case GET_FIELD:
492f736a450SJustin T. Gibbs 			if (isdigit(*p)) {
493f736a450SJustin T. Gibbs 				*fmt = 'b';
494f736a450SJustin T. Gibbs 				field_size = 1;
495cb28eb78SKelly Yancey 				field_width = strtol(p, &intendp, 10);
496cb28eb78SKelly Yancey 				p = intendp;
497f736a450SJustin T. Gibbs 				state = DONE;
498f736a450SJustin T. Gibbs 			} else if (*p == 'i') {
499f736a450SJustin T. Gibbs 
500f736a450SJustin T. Gibbs 				/* Integral (bytes) */
501f736a450SJustin T. Gibbs 				p++;
502f736a450SJustin T. Gibbs 
503f736a450SJustin T. Gibbs 				*fmt = 'i';
504f736a450SJustin T. Gibbs 				field_size = 8;
505cb28eb78SKelly Yancey 				field_width = strtol(p, &intendp, 10);
506cb28eb78SKelly Yancey 				p = intendp;
507f736a450SJustin T. Gibbs 				state = DONE;
508f736a450SJustin T. Gibbs 			} else if (*p == 'b') {
509f736a450SJustin T. Gibbs 
510f736a450SJustin T. Gibbs 				/* Bits */
511f736a450SJustin T. Gibbs 				p++;
512f736a450SJustin T. Gibbs 
513f736a450SJustin T. Gibbs 				*fmt = 'b';
514f736a450SJustin T. Gibbs 				field_size = 1;
515cb28eb78SKelly Yancey 				field_width = strtol(p, &intendp, 10);
516cb28eb78SKelly Yancey 				p = intendp;
517f736a450SJustin T. Gibbs 				state = DONE;
518f736a450SJustin T. Gibbs 			} else {
519f736a450SJustin T. Gibbs 				fprintf(stderr, "Invalid startfield %c "
520f736a450SJustin T. Gibbs 					"(%02x)\n", *p, *p);
521f736a450SJustin T. Gibbs 				is_error = 1;
522f736a450SJustin T. Gibbs 				state = DONE;
523f736a450SJustin T. Gibbs 			}
524f736a450SJustin T. Gibbs 			break;
525f736a450SJustin T. Gibbs 
526f736a450SJustin T. Gibbs 		case DONE:
527f736a450SJustin T. Gibbs 			break;
528f736a450SJustin T. Gibbs 		}
529f736a450SJustin T. Gibbs 	}
530f736a450SJustin T. Gibbs 
531f736a450SJustin T. Gibbs 	if (is_error) {
532f736a450SJustin T. Gibbs 		*error_p = 1;
53329d14889SEnji Cooper 		return (0);
534f736a450SJustin T. Gibbs 	}
535f736a450SJustin T. Gibbs 
536f736a450SJustin T. Gibbs 	*error_p = 0;
537f736a450SJustin T. Gibbs 	*pp = p;
538f736a450SJustin T. Gibbs 	*width_p = field_width * field_size;
539f736a450SJustin T. Gibbs 	*value_p = value;
540f736a450SJustin T. Gibbs 	*suppress_p = suppress;
541f736a450SJustin T. Gibbs 
542f736a450SJustin T. Gibbs 	return (something);
543f736a450SJustin T. Gibbs }
544f736a450SJustin T. Gibbs 
545f736a450SJustin T. Gibbs static int
do_encode(u_char * buff,size_t vec_max,size_t * used,int (* arg_get)(void *,char *),void * gethook,const char * fmt,va_list * ap)546f736a450SJustin T. Gibbs do_encode(u_char *buff, size_t vec_max, size_t *used,
547cb28eb78SKelly Yancey 	  int (*arg_get)(void *, char *), void *gethook, const char *fmt,
5482357dac4SEnji Cooper 	  va_list *ap)
549f736a450SJustin T. Gibbs {
550f736a450SJustin T. Gibbs 	int ind;
551f736a450SJustin T. Gibbs 	int shift;
552f736a450SJustin T. Gibbs 	u_char val;
553f736a450SJustin T. Gibbs 	int ret;
554f736a450SJustin T. Gibbs 	int width, value, error, suppress;
555f736a450SJustin T. Gibbs 	char c;
556f736a450SJustin T. Gibbs 	int encoded = 0;
557f736a450SJustin T. Gibbs 	char field_name[80];
558f736a450SJustin T. Gibbs 
559f736a450SJustin T. Gibbs 	ind = 0;
560f736a450SJustin T. Gibbs 	shift = 0;
561f736a450SJustin T. Gibbs 	val = 0;
562f736a450SJustin T. Gibbs 
563f736a450SJustin T. Gibbs  	while ((ret = next_field(&fmt, &c, &width, &value, field_name,
564f736a450SJustin T. Gibbs 				 sizeof(field_name), &error, &suppress))) {
565f736a450SJustin T. Gibbs 		encoded++;
566f736a450SJustin T. Gibbs 
567f736a450SJustin T. Gibbs 		if (ret == 2) {
568f736a450SJustin T. Gibbs 			if (suppress)
569f736a450SJustin T. Gibbs 				value = 0;
570f736a450SJustin T. Gibbs 			else
57169c703b9SEnji Cooper 				value = arg_get != NULL ?
572f736a450SJustin T. Gibbs 					(*arg_get)(gethook, field_name) :
5732357dac4SEnji Cooper 					va_arg(*ap, int);
574f736a450SJustin T. Gibbs 		}
575f736a450SJustin T. Gibbs 
576f736a450SJustin T. Gibbs #if 0
577f736a450SJustin T. Gibbs 		printf(
578f736a450SJustin T. Gibbs "do_encode: ret %d fmt %c width %d value %d name \"%s\" error %d suppress %d\n",
579f736a450SJustin T. Gibbs 		ret, c, width, value, field_name, error, suppress);
580f736a450SJustin T. Gibbs #endif
581f736a450SJustin T. Gibbs 		/* Absolute seek */
582f736a450SJustin T. Gibbs 		if (c == 's') {
583f736a450SJustin T. Gibbs 			ind = value;
584f736a450SJustin T. Gibbs 			continue;
585f736a450SJustin T. Gibbs 		}
586f736a450SJustin T. Gibbs 
587f736a450SJustin T. Gibbs 		/* A width of < 8 is a bit field. */
588f736a450SJustin T. Gibbs 		if (width < 8) {
589f736a450SJustin T. Gibbs 
590f736a450SJustin T. Gibbs 			/* This is a bit field.  We start with the high bits
591f736a450SJustin T. Gibbs 			 * so it reads the same as the SCSI spec.
592f736a450SJustin T. Gibbs 			 */
593f736a450SJustin T. Gibbs 
594f736a450SJustin T. Gibbs 			shift += width;
595f736a450SJustin T. Gibbs 
596f736a450SJustin T. Gibbs 			val |= (value << (8 - shift));
597f736a450SJustin T. Gibbs 
598f736a450SJustin T. Gibbs 			if (shift == 8) {
599f736a450SJustin T. Gibbs 				if (ind < vec_max) {
600f736a450SJustin T. Gibbs 					buff[ind++] = val;
601f736a450SJustin T. Gibbs 					val = 0;
602f736a450SJustin T. Gibbs 				}
603f736a450SJustin T. Gibbs 				shift = 0;
604f736a450SJustin T. Gibbs 			}
605f736a450SJustin T. Gibbs 		} else {
606f736a450SJustin T. Gibbs 			if (shift) {
607f736a450SJustin T. Gibbs 				if (ind < vec_max) {
608f736a450SJustin T. Gibbs 					buff[ind++] = val;
609f736a450SJustin T. Gibbs 					val = 0;
610f736a450SJustin T. Gibbs 				}
611f736a450SJustin T. Gibbs 				shift = 0;
612f736a450SJustin T. Gibbs 			}
613f736a450SJustin T. Gibbs 			switch(width) {
614f736a450SJustin T. Gibbs 			case 8:		/* 1 byte integer */
615f736a450SJustin T. Gibbs 				if (ind < vec_max)
616f736a450SJustin T. Gibbs 					buff[ind++] = value;
617f736a450SJustin T. Gibbs 				break;
618f736a450SJustin T. Gibbs 
619f736a450SJustin T. Gibbs 			case 16:	/* 2 byte integer */
620f736a450SJustin T. Gibbs 				if (ind < vec_max - 2 + 1) {
621f736a450SJustin T. Gibbs 					buff[ind++] = value >> 8;
622f736a450SJustin T. Gibbs 					buff[ind++] = value;
623f736a450SJustin T. Gibbs 				}
624f736a450SJustin T. Gibbs 				break;
625f736a450SJustin T. Gibbs 
626f736a450SJustin T. Gibbs 			case 24:	/* 3 byte integer */
627f736a450SJustin T. Gibbs 				if (ind < vec_max - 3 + 1) {
628f736a450SJustin T. Gibbs 					buff[ind++] = value >> 16;
629f736a450SJustin T. Gibbs 					buff[ind++] = value >> 8;
630f736a450SJustin T. Gibbs 					buff[ind++] = value;
631f736a450SJustin T. Gibbs 				}
632f736a450SJustin T. Gibbs 				break;
633f736a450SJustin T. Gibbs 
634f736a450SJustin T. Gibbs 			case 32:	/* 4 byte integer */
635f736a450SJustin T. Gibbs 				if (ind < vec_max - 4 + 1) {
636f736a450SJustin T. Gibbs 					buff[ind++] = value >> 24;
637f736a450SJustin T. Gibbs 					buff[ind++] = value >> 16;
638f736a450SJustin T. Gibbs 					buff[ind++] = value >> 8;
639f736a450SJustin T. Gibbs 					buff[ind++] = value;
640f736a450SJustin T. Gibbs 				}
641f736a450SJustin T. Gibbs 				break;
642f736a450SJustin T. Gibbs 
643f736a450SJustin T. Gibbs 			default:
644f736a450SJustin T. Gibbs 				fprintf(stderr, "do_encode: Illegal width\n");
645f736a450SJustin T. Gibbs 				break;
646f736a450SJustin T. Gibbs 			}
647f736a450SJustin T. Gibbs 		}
648f736a450SJustin T. Gibbs 	}
649f736a450SJustin T. Gibbs 
650f736a450SJustin T. Gibbs 	/* Flush out any remaining bits
651f736a450SJustin T. Gibbs 	 */
652f736a450SJustin T. Gibbs 	if (shift && ind < vec_max) {
653f736a450SJustin T. Gibbs 		buff[ind++] = val;
654f736a450SJustin T. Gibbs 		val = 0;
655f736a450SJustin T. Gibbs 	}
656f736a450SJustin T. Gibbs 
657f736a450SJustin T. Gibbs 
658f736a450SJustin T. Gibbs 	if (used)
659f736a450SJustin T. Gibbs 		*used = ind;
660f736a450SJustin T. Gibbs 
661f736a450SJustin T. Gibbs 	if (error)
66229d14889SEnji Cooper 		return (-1);
663f736a450SJustin T. Gibbs 
66429d14889SEnji Cooper 	return (encoded);
665f736a450SJustin T. Gibbs }
666f736a450SJustin T. Gibbs 
667f736a450SJustin T. Gibbs int
csio_decode(struct ccb_scsiio * csio,const char * fmt,...)668cb28eb78SKelly Yancey csio_decode(struct ccb_scsiio *csio, const char *fmt, ...)
669f736a450SJustin T. Gibbs {
670f736a450SJustin T. Gibbs 	va_list ap;
6712357dac4SEnji Cooper 	int retval;
672f736a450SJustin T. Gibbs 
673f736a450SJustin T. Gibbs 	va_start(ap, fmt);
674f736a450SJustin T. Gibbs 
67569c703b9SEnji Cooper 	retval = do_buff_decode(csio->data_ptr, (size_t)csio->dxfer_len,
67669c703b9SEnji Cooper 	    NULL, NULL, fmt, &ap);
6772357dac4SEnji Cooper 
6782357dac4SEnji Cooper 	va_end(ap);
6792357dac4SEnji Cooper 
6802357dac4SEnji Cooper 	return (retval);
681f736a450SJustin T. Gibbs }
682f736a450SJustin T. Gibbs 
683f736a450SJustin T. Gibbs int
csio_decode_visit(struct ccb_scsiio * csio,const char * fmt,void (* arg_put)(void *,int,void *,int,char *),void * puthook)684cb28eb78SKelly Yancey csio_decode_visit(struct ccb_scsiio *csio, const char *fmt,
685f736a450SJustin T. Gibbs 		  void (*arg_put)(void *, int, void *, int, char *),
686f736a450SJustin T. Gibbs 		  void *puthook)
687f736a450SJustin T. Gibbs {
688f736a450SJustin T. Gibbs 
68953398df2SKenneth D. Merry 	/*
69053398df2SKenneth D. Merry 	 * We need some way to output things; we can't do it without
69153398df2SKenneth D. Merry 	 * the arg_put function.
69253398df2SKenneth D. Merry 	 */
69353398df2SKenneth D. Merry 	if (arg_put == NULL)
69453398df2SKenneth D. Merry 		return (-1);
69553398df2SKenneth D. Merry 
696f736a450SJustin T. Gibbs 	return (do_buff_decode(csio->data_ptr, (size_t)csio->dxfer_len,
6972357dac4SEnji Cooper 		    arg_put, puthook, fmt, NULL));
698f736a450SJustin T. Gibbs }
699f736a450SJustin T. Gibbs 
700f736a450SJustin T. Gibbs int
buff_decode(uint8_t * buff,size_t len,const char * fmt,...)701*f9ffa1efSWarner Losh buff_decode(uint8_t *buff, size_t len, const char *fmt, ...)
702f736a450SJustin T. Gibbs {
703f736a450SJustin T. Gibbs 	va_list ap;
7042357dac4SEnji Cooper 	int retval;
705f736a450SJustin T. Gibbs 
706f736a450SJustin T. Gibbs 	va_start(ap, fmt);
707f736a450SJustin T. Gibbs 
70869c703b9SEnji Cooper 	retval = do_buff_decode(buff, len, NULL, NULL, fmt, &ap);
7092357dac4SEnji Cooper 
7102357dac4SEnji Cooper 	va_end(ap);
7112357dac4SEnji Cooper 
7122357dac4SEnji Cooper 	return (retval);
713f736a450SJustin T. Gibbs }
714f736a450SJustin T. Gibbs 
715f736a450SJustin T. Gibbs int
buff_decode_visit(uint8_t * buff,size_t len,const char * fmt,void (* arg_put)(void *,int,void *,int,char *),void * puthook)716*f9ffa1efSWarner Losh buff_decode_visit(uint8_t *buff, size_t len, const char *fmt,
717f736a450SJustin T. Gibbs 		  void (*arg_put)(void *, int, void *, int, char *),
718f736a450SJustin T. Gibbs 		  void *puthook)
719f736a450SJustin T. Gibbs {
720f736a450SJustin T. Gibbs 
72153398df2SKenneth D. Merry 	/*
72253398df2SKenneth D. Merry 	 * We need some way to output things; we can't do it without
72353398df2SKenneth D. Merry 	 * the arg_put function.
72453398df2SKenneth D. Merry 	 */
72553398df2SKenneth D. Merry 	if (arg_put == NULL)
72653398df2SKenneth D. Merry 		return (-1);
72753398df2SKenneth D. Merry 
7282357dac4SEnji Cooper 	return (do_buff_decode(buff, len, arg_put, puthook, fmt, NULL));
729f736a450SJustin T. Gibbs }
730f736a450SJustin T. Gibbs 
731f736a450SJustin T. Gibbs /*
732f736a450SJustin T. Gibbs  * Build a SCSI CCB, given the command and data pointers and a format
733f736a450SJustin T. Gibbs  * string describing the
734f736a450SJustin T. Gibbs  */
735f736a450SJustin T. Gibbs int
csio_build(struct ccb_scsiio * csio,uint8_t * data_ptr,uint32_t dxfer_len,uint32_t flags,int retry_count,int timeout,const char * cmd_spec,...)736*f9ffa1efSWarner Losh csio_build(struct ccb_scsiio *csio, uint8_t *data_ptr, uint32_t dxfer_len,
737*f9ffa1efSWarner Losh 	   uint32_t flags, int retry_count, int timeout, const char *cmd_spec,
738cb28eb78SKelly Yancey 	   ...)
739f736a450SJustin T. Gibbs {
74053398df2SKenneth D. Merry 	size_t cmdlen;
741f736a450SJustin T. Gibbs 	int retval;
742f736a450SJustin T. Gibbs 	va_list ap;
743f736a450SJustin T. Gibbs 
744f736a450SJustin T. Gibbs 	if (csio == NULL)
745f736a450SJustin T. Gibbs 		return (0);
746f736a450SJustin T. Gibbs 
747f736a450SJustin T. Gibbs 	bzero(csio, sizeof(struct ccb_scsiio));
748f736a450SJustin T. Gibbs 
749f736a450SJustin T. Gibbs 	va_start(ap, cmd_spec);
750f736a450SJustin T. Gibbs 
751f736a450SJustin T. Gibbs 	if ((retval = do_encode(csio->cdb_io.cdb_bytes, SCSI_MAX_CDBLEN,
7522357dac4SEnji Cooper 				&cmdlen, NULL, NULL, cmd_spec, &ap)) == -1)
7532357dac4SEnji Cooper 		goto done;
754f736a450SJustin T. Gibbs 
755f736a450SJustin T. Gibbs 	cam_fill_csio(csio,
756f736a450SJustin T. Gibbs 		      /* retries */ retry_count,
757f736a450SJustin T. Gibbs 		      /* cbfcnp */ NULL,
758f736a450SJustin T. Gibbs 		      /* flags */ flags,
759f736a450SJustin T. Gibbs 		      /* tag_action */ MSG_SIMPLE_Q_TAG,
760f736a450SJustin T. Gibbs 		      /* data_ptr */ data_ptr,
761f736a450SJustin T. Gibbs 		      /* dxfer_len */ dxfer_len,
762f736a450SJustin T. Gibbs 		      /* sense_len */ SSD_FULL_SIZE,
763f736a450SJustin T. Gibbs 		      /* cdb_len */ cmdlen,
764f736a450SJustin T. Gibbs 		      /* timeout */ timeout ? timeout : 5000);
765f736a450SJustin T. Gibbs 
7662357dac4SEnji Cooper done:
7672357dac4SEnji Cooper 	va_end(ap);
7682357dac4SEnji Cooper 
769f736a450SJustin T. Gibbs 	return (retval);
770f736a450SJustin T. Gibbs }
771f736a450SJustin T. Gibbs 
772f736a450SJustin T. Gibbs int
csio_build_visit(struct ccb_scsiio * csio,uint8_t * data_ptr,uint32_t dxfer_len,uint32_t flags,int retry_count,int timeout,const char * cmd_spec,int (* arg_get)(void * hook,char * field_name),void * gethook)773*f9ffa1efSWarner Losh csio_build_visit(struct ccb_scsiio *csio, uint8_t *data_ptr,
774*f9ffa1efSWarner Losh 		 uint32_t dxfer_len, uint32_t flags, int retry_count,
775cb28eb78SKelly Yancey 		 int timeout, const char *cmd_spec,
776f736a450SJustin T. Gibbs 		 int (*arg_get)(void *hook, char *field_name), void *gethook)
777f736a450SJustin T. Gibbs {
77853398df2SKenneth D. Merry 	size_t cmdlen;
77953398df2SKenneth D. Merry 	int retval;
780f736a450SJustin T. Gibbs 
781f736a450SJustin T. Gibbs 	if (csio == NULL)
782f736a450SJustin T. Gibbs 		return (0);
783f736a450SJustin T. Gibbs 
78453398df2SKenneth D. Merry 	/*
78553398df2SKenneth D. Merry 	 * We need something to encode, but we can't get it without the
78653398df2SKenneth D. Merry 	 * arg_get function.
78753398df2SKenneth D. Merry 	 */
78853398df2SKenneth D. Merry 	if (arg_get == NULL)
78953398df2SKenneth D. Merry 		return (-1);
79053398df2SKenneth D. Merry 
791f736a450SJustin T. Gibbs 	bzero(csio, sizeof(struct ccb_scsiio));
792f736a450SJustin T. Gibbs 
793f736a450SJustin T. Gibbs 	if ((retval = do_encode(csio->cdb_io.cdb_bytes, SCSI_MAX_CDBLEN,
7942357dac4SEnji Cooper 				&cmdlen, arg_get, gethook, cmd_spec, NULL)) == -1)
795f736a450SJustin T. Gibbs 		return (retval);
796f736a450SJustin T. Gibbs 
797f736a450SJustin T. Gibbs 	cam_fill_csio(csio,
798f736a450SJustin T. Gibbs 		      /* retries */ retry_count,
799f736a450SJustin T. Gibbs 		      /* cbfcnp */ NULL,
800f736a450SJustin T. Gibbs 		      /* flags */ flags,
801f736a450SJustin T. Gibbs 		      /* tag_action */ MSG_SIMPLE_Q_TAG,
802f736a450SJustin T. Gibbs 		      /* data_ptr */ data_ptr,
803f736a450SJustin T. Gibbs 		      /* dxfer_len */ dxfer_len,
804f736a450SJustin T. Gibbs 		      /* sense_len */ SSD_FULL_SIZE,
805f736a450SJustin T. Gibbs 		      /* cdb_len */ cmdlen,
806f736a450SJustin T. Gibbs 		      /* timeout */ timeout ? timeout : 5000);
807f736a450SJustin T. Gibbs 
808f736a450SJustin T. Gibbs 	return (retval);
809f736a450SJustin T. Gibbs }
810f736a450SJustin T. Gibbs 
811f736a450SJustin T. Gibbs int
csio_encode(struct ccb_scsiio * csio,const char * fmt,...)812cb28eb78SKelly Yancey csio_encode(struct ccb_scsiio *csio, const char *fmt, ...)
813f736a450SJustin T. Gibbs {
814f736a450SJustin T. Gibbs 	va_list ap;
8152357dac4SEnji Cooper 	int retval;
816f736a450SJustin T. Gibbs 
817f736a450SJustin T. Gibbs 	if (csio == NULL)
818f736a450SJustin T. Gibbs 		return (0);
819f736a450SJustin T. Gibbs 
820f736a450SJustin T. Gibbs 	va_start(ap, fmt);
821f736a450SJustin T. Gibbs 
82269c703b9SEnji Cooper 	retval = do_encode(csio->data_ptr, csio->dxfer_len, NULL, NULL, NULL,
82369c703b9SEnji Cooper 	    fmt, &ap);
8242357dac4SEnji Cooper 
8252357dac4SEnji Cooper 	va_end(ap);
8262357dac4SEnji Cooper 
8272357dac4SEnji Cooper 	return (retval);
828f736a450SJustin T. Gibbs }
829f736a450SJustin T. Gibbs 
830f736a450SJustin T. Gibbs int
buff_encode_visit(uint8_t * buff,size_t len,const char * fmt,int (* arg_get)(void * hook,char * field_name),void * gethook)831*f9ffa1efSWarner Losh buff_encode_visit(uint8_t *buff, size_t len, const char *fmt,
832f736a450SJustin T. Gibbs 		  int (*arg_get)(void *hook, char *field_name), void *gethook)
833f736a450SJustin T. Gibbs {
834f736a450SJustin T. Gibbs 
83553398df2SKenneth D. Merry 	/*
83653398df2SKenneth D. Merry 	 * We need something to encode, but we can't get it without the
83753398df2SKenneth D. Merry 	 * arg_get function.
83853398df2SKenneth D. Merry 	 */
83953398df2SKenneth D. Merry 	if (arg_get == NULL)
84053398df2SKenneth D. Merry 		return (-1);
84153398df2SKenneth D. Merry 
84269c703b9SEnji Cooper 	return (do_encode(buff, len, NULL, arg_get, gethook, fmt, NULL));
843f736a450SJustin T. Gibbs }
844f736a450SJustin T. Gibbs 
845f736a450SJustin T. Gibbs int
csio_encode_visit(struct ccb_scsiio * csio,const char * fmt,int (* arg_get)(void * hook,char * field_name),void * gethook)846cb28eb78SKelly Yancey csio_encode_visit(struct ccb_scsiio *csio, const char *fmt,
847f736a450SJustin T. Gibbs 		  int (*arg_get)(void *hook, char *field_name), void *gethook)
848f736a450SJustin T. Gibbs {
849f736a450SJustin T. Gibbs 
85053398df2SKenneth D. Merry 	/*
85153398df2SKenneth D. Merry 	 * We need something to encode, but we can't get it without the
85253398df2SKenneth D. Merry 	 * arg_get function.
85353398df2SKenneth D. Merry 	 */
85453398df2SKenneth D. Merry 	if (arg_get == NULL)
85553398df2SKenneth D. Merry 		return (-1);
85653398df2SKenneth D. Merry 
85769c703b9SEnji Cooper 	return (do_encode(csio->data_ptr, csio->dxfer_len, NULL, arg_get,
8582357dac4SEnji Cooper 			 gethook, fmt, NULL));
859f736a450SJustin T. Gibbs }
860