2 * Taken from the original FreeBSD user SCSI library.
4 /* Copyright (c) 1994 HD Associates
5 * (contact: dufault@hda.com)
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
34 * From: scsi.c,v 1.8 1997/02/22 15:07:54 peter Exp $
35 * $FreeBSD: src/lib/libcam/scsi_cmdparse.c,v 1.3.2.1 2000/08/14 05:42:30 kbyanc Exp $
36 * $DragonFly: src/lib/libcam/scsi_cmdparse.c,v 1.3 2007/11/24 01:53:50 pavalos Exp $
42 #include <sys/errno.h>
47 #include <cam/cam_ccb.h>
48 #include <cam/scsi/scsi_message.h>
52 * Decode: Decode the data section of a scsireq. This decodes
55 * fields : field fields
58 * field : field_specifier
62 * control : 's' seek_value
63 * | 's' '+' seek_value
66 * seek_value : DECIMAL_NUMBER
67 * | 'v' // For indirect seek, i.e., value from the arg list
70 * field_specifier : type_specifier field_width
71 * | '{' NAME '}' type_specifier field_width
74 * field_width : DECIMAL_NUMBER
77 * type_specifier : 'i' // Integral types (i1, i2, i3, i4)
80 * | 'c' // Character arrays
81 * | 'z' // Character arrays with zeroed trailing spaces
85 * 1. Integral types are swapped into host order.
86 * 2. Bit fields are allocated MSB to LSB to match the SCSI spec documentation.
87 * 3. 's' permits "seeking" in the string. "s+DECIMAL" seeks relative to
88 * DECIMAL; "sDECIMAL" seeks absolute to decimal.
89 * 4. 's' permits an indirect reference. "sv" or "s+v" will get the
90 * next integer value from the arg array.
91 * 5. Field names can be anything between the braces
94 * i and b types are promoted to ints.
99 do_buff_decode(u_int8_t
*databuf
, size_t len
,
100 void (*arg_put
)(void *, int , void *, int, char *),
101 void *puthook
, const char *fmt
, va_list ap
)
108 static u_char mask
[] = {0, 0x01, 0x03, 0x07, 0x0f,
109 0x1f, 0x3f, 0x7f, 0xff};
111 u_char
*base
= databuf
;
116 # define ARG_PUT(ARG) \
122 (*arg_put)(puthook, (letter == 't' ? \
124 (void *)((long)(ARG)), width, \
127 *(va_arg(ap, int *)) = (ARG); \
134 u_char bits
= 0; /* For bit fields */
135 int shift
= 0; /* Bits already shifted out */
140 switch(letter
= *fmt
) {
141 case ' ': /* White space */
149 case '#': /* Comment */
150 while (*fmt
&& (*fmt
!= '\n'))
153 fmt
++; /* Skip '\n' */
156 case '*': /* Suppress assignment */
161 case '{': /* Field Name */
164 fmt
++; /* Skip '{' */
165 while (*fmt
&& (*fmt
!= '}')) {
166 if (i
< sizeof(field_name
))
167 field_name
[i
++] = *fmt
;
172 fmt
++; /* Skip '}' */
177 case 't': /* Bit (field) */
180 width
= strtol(fmt
, &intendp
, 10);
189 value
= (bits
>> (shift
- width
)) &
193 printf("shift %2d bits %02x value %02x width %2d mask %02x\n",
194 shift
, bits
, value
, width
, mask
[width
]);
203 case 'i': /* Integral values */
206 width
= strtol(fmt
, &intendp
, 10);
215 ARG_PUT((*databuf
) << 8 | *(databuf
+ 1));
220 ARG_PUT((*databuf
) << 16 |
221 (*(databuf
+ 1)) << 8 | *(databuf
+ 2));
226 ARG_PUT((*databuf
) << 24 |
227 (*(databuf
+ 1)) << 16 |
228 (*(databuf
+ 2)) << 8 |
240 case 'c': /* Characters (i.e., not swapped) */
241 case 'z': /* Characters with zeroed trailing
245 width
= strtol(fmt
, &intendp
, 10);
250 (letter
== 't' ? 'b' : letter
),
251 databuf
, width
, field_name
);
254 dest
= va_arg(ap
, char *);
255 bcopy(databuf
, dest
, width
);
258 for (p
= dest
+ width
- 1;
280 if (tolower(*fmt
) == 'v') {
282 * You can't suppress a seek value. You also
283 * can't have a variable seek when you are using
286 width
= (arg_put
) ? 0 : va_arg(ap
, int);
289 width
= strtol(fmt
, &intendp
, 10);
294 databuf
+= width
; /* Relative seek */
296 databuf
= base
+ width
; /* Absolute seek */
305 fprintf(stderr
, "Unknown letter in format: %c\n",
315 /* next_field: Return the next field in a command specifier. This
316 * builds up a SCSI command using this trivial grammar:
318 * fields : field fields
322 * | value ':' field_width
325 * field_width : digit
326 * | 'i' digit // i2 = 2 byte integer, i3 = 3 byte integer etc.
330 * | 'v' // For indirection.
334 * Bit fields are specified MSB first to match the SCSI spec.
338 * WRITE BUFFER: "38 v:3 0:2 0:3 v v:i3 v:i3 0", mode, buffer_id, list_length
340 * The function returns the value:
341 * 0: For reached end, with error_p set if an error was found
342 * 1: For valid stuff setup
343 * 2: For "v" was entered as the value (implies use varargs)
348 next_field(const char **pp
, char *fmt
, int *width_p
, int *value_p
, char *name
,
349 int n_name
, int *error_p
, int *suppress_p
)
364 int field_size
; /* Default to byte field type... */
365 int field_width
; /* 1 byte wide */
369 field_size
= 8; /* Default to byte field type... */
371 field_width
= 1; /* 1 byte wide */
375 state
= BETWEEN_FIELDS
;
377 while (state
!= DONE
) {
382 else if (isspace(*p
))
384 else if (*p
== '#') {
385 while (*p
&& *p
!= '\n')
389 } else if (*p
== '{') {
394 while (*p
&& *p
!= '}') {
395 if(name
&& i
< n_name
) {
402 if(name
&& i
< n_name
)
407 } else if (*p
== '*') {
410 } else if (isxdigit(*p
)) {
412 value
= strtol(p
, &intendp
, 16);
415 } else if (tolower(*p
) == 'v') {
420 } else if (tolower(*p
) == 'i') {
422 * Try to work without the "v".
430 field_width
= strtol(p
, &intendp
, 10);
434 } else if (tolower(*p
) == 't') {
436 * XXX: B can't work: Sees the 'b' as a
437 * hex digit in "isxdigit". try "t" for
446 field_width
= strtol(p
, &intendp
, 10);
449 } else if (tolower(*p
) == 's') {
453 if (tolower(*p
) == 'v') {
459 value
= strtol(p
, &intendp
, 0);
464 fprintf(stderr
, "Invalid starting "
465 "character: %c\n", *p
);
474 field_size
= 1; /* Default to bits
485 field_width
= strtol(p
, &intendp
, 10);
488 } else if (*p
== 'i') {
490 /* Integral (bytes) */
495 field_width
= strtol(p
, &intendp
, 10);
498 } else if (*p
== 'b') {
505 field_width
= strtol(p
, &intendp
, 10);
509 fprintf(stderr
, "Invalid startfield %c "
528 *width_p
= field_width
* field_size
;
530 *suppress_p
= suppress
;
536 do_encode(u_char
*buff
, size_t vec_max
, size_t *used
,
537 int (*arg_get
)(void *, char *), void *gethook
, const char *fmt
,
544 int width
, value
, error
, suppress
;
553 while ((ret
= next_field(&fmt
, &c
, &width
, &value
, field_name
,
554 sizeof(field_name
), &error
, &suppress
))) {
562 (*arg_get
)(gethook
, field_name
) :
568 "do_encode: ret %d fmt %c width %d value %d name \"%s\" error %d suppress %d\n",
569 ret
, c
, width
, value
, field_name
, error
, suppress
);
577 /* A width of < 8 is a bit field. */
580 /* This is a bit field. We start with the high bits
581 * so it reads the same as the SCSI spec.
586 val
|= (value
<< (8 - shift
));
604 case 8: /* 1 byte integer */
609 case 16: /* 2 byte integer */
610 if (ind
< vec_max
- 2 + 1) {
611 buff
[ind
++] = value
>> 8;
616 case 24: /* 3 byte integer */
617 if (ind
< vec_max
- 3 + 1) {
618 buff
[ind
++] = value
>> 16;
619 buff
[ind
++] = value
>> 8;
624 case 32: /* 4 byte integer */
625 if (ind
< vec_max
- 4 + 1) {
626 buff
[ind
++] = value
>> 24;
627 buff
[ind
++] = value
>> 16;
628 buff
[ind
++] = value
>> 8;
634 fprintf(stderr
, "do_encode: Illegal width\n");
640 /* Flush out any remaining bits
642 if (shift
&& ind
< vec_max
) {
658 csio_decode(struct ccb_scsiio
*csio
, const char *fmt
, ...)
664 return(do_buff_decode(csio
->data_ptr
, (size_t)csio
->dxfer_len
,
669 csio_decode_visit(struct ccb_scsiio
*csio
, const char *fmt
,
670 void (*arg_put
)(void *, int, void *, int, char *),
676 * We need some way to output things; we can't do it without
677 * the arg_put function.
682 bzero(&ap
, sizeof(ap
));
684 return(do_buff_decode(csio
->data_ptr
, (size_t)csio
->dxfer_len
,
685 arg_put
, puthook
, fmt
, ap
));
689 buff_decode(u_int8_t
*buff
, size_t len
, const char *fmt
, ...)
695 return(do_buff_decode(buff
, len
, 0, 0, fmt
, ap
));
699 buff_decode_visit(u_int8_t
*buff
, size_t len
, const char *fmt
,
700 void (*arg_put
)(void *, int, void *, int, char *),
706 * We need some way to output things; we can't do it without
707 * the arg_put function.
712 bzero(&ap
, sizeof(ap
));
714 return(do_buff_decode(buff
, len
, arg_put
, puthook
, fmt
, ap
));
718 * Build a SCSI CCB, given the command and data pointers and a format
719 * string describing the
722 csio_build(struct ccb_scsiio
*csio
, u_int8_t
*data_ptr
, u_int32_t dxfer_len
,
723 u_int32_t flags
, int retry_count
, int timeout
, const char *cmd_spec
,
733 bzero(csio
, sizeof(struct ccb_scsiio
));
735 va_start(ap
, cmd_spec
);
737 if ((retval
= do_encode(csio
->cdb_io
.cdb_bytes
, SCSI_MAX_CDBLEN
,
738 &cmdlen
, NULL
, NULL
, cmd_spec
, ap
)) == -1)
742 /* retries */ retry_count
,
745 /* tag_action */ MSG_SIMPLE_Q_TAG
,
746 /* data_ptr */ data_ptr
,
747 /* dxfer_len */ dxfer_len
,
748 /* sense_len */ SSD_FULL_SIZE
,
749 /* cdb_len */ cmdlen
,
750 /* timeout */ timeout
? timeout
: 5000);
756 csio_build_visit(struct ccb_scsiio
*csio
, u_int8_t
*data_ptr
,
757 u_int32_t dxfer_len
, u_int32_t flags
, int retry_count
,
758 int timeout
, const char *cmd_spec
,
759 int (*arg_get
)(void *hook
, char *field_name
), void *gethook
)
769 * We need something to encode, but we can't get it without the
775 bzero(&ap
, sizeof(ap
));
777 bzero(csio
, sizeof(struct ccb_scsiio
));
779 if ((retval
= do_encode(csio
->cdb_io
.cdb_bytes
, SCSI_MAX_CDBLEN
,
780 &cmdlen
, arg_get
, gethook
, cmd_spec
, ap
)) == -1)
784 /* retries */ retry_count
,
787 /* tag_action */ MSG_SIMPLE_Q_TAG
,
788 /* data_ptr */ data_ptr
,
789 /* dxfer_len */ dxfer_len
,
790 /* sense_len */ SSD_FULL_SIZE
,
791 /* cdb_len */ cmdlen
,
792 /* timeout */ timeout
? timeout
: 5000);
798 csio_encode(struct ccb_scsiio
*csio
, const char *fmt
, ...)
807 return(do_encode(csio
->data_ptr
, csio
->dxfer_len
, 0, 0, 0, fmt
, ap
));
811 buff_encode_visit(u_int8_t
*buff
, size_t len
, const char *fmt
,
812 int (*arg_get
)(void *hook
, char *field_name
), void *gethook
)
817 * We need something to encode, but we can't get it without the
823 bzero(&ap
, sizeof(ap
));
825 return(do_encode(buff
, len
, 0, arg_get
, gethook
, fmt
, ap
));
829 csio_encode_visit(struct ccb_scsiio
*csio
, const char *fmt
,
830 int (*arg_get
)(void *hook
, char *field_name
), void *gethook
)
835 * We need something to encode, but we can't get it without the
841 bzero(&ap
, sizeof(ap
));
843 return(do_encode(csio
->data_ptr
, csio
->dxfer_len
, 0, arg_get
,