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