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