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 $
41 #include <sys/errno.h>
45 #include <bus/cam/cam.h>
46 #include <bus/cam/cam_ccb.h>
47 #include <bus/cam/scsi/scsi_message.h>
51 * Decode: Decode the data section of a scsireq. This decodes
54 * fields : field fields
57 * field : field_specifier
61 * control : 's' seek_value
62 * | 's' '+' seek_value
65 * seek_value : DECIMAL_NUMBER
66 * | 'v' // For indirect seek, i.e., value from the arg list
69 * field_specifier : type_specifier field_width
70 * | '{' NAME '}' type_specifier field_width
73 * field_width : DECIMAL_NUMBER
76 * type_specifier : 'i' // Integral types (i1, i2, i3, i4)
79 * | 'c' // Character arrays
80 * | 'z' // Character arrays with zeroed trailing spaces
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
93 * i and b types are promoted to ints.
98 do_buff_decode(u_int8_t *databuf, size_t len,
99 void (*arg_put)(void *, int , void *, int, char *),
100 void *puthook, const char *fmt, va_list ap)
107 static u_char mask[] = {0, 0x01, 0x03, 0x07, 0x0f,
108 0x1f, 0x3f, 0x7f, 0xff};
110 u_char *base = databuf;
115 # define ARG_PUT(ARG) \
121 (*arg_put)(puthook, (letter == 't' ? \
123 (void *)((long)(ARG)), width, \
126 *(va_arg(ap, int *)) = (ARG); \
133 u_char bits = 0; /* For bit fields */
134 int shift = 0; /* Bits already shifted out */
139 switch(letter = *fmt) {
140 case ' ': /* White space */
148 case '#': /* Comment */
149 while (*fmt && (*fmt != '\n'))
152 fmt++; /* Skip '\n' */
155 case '*': /* Suppress assignment */
160 case '{': /* Field Name */
163 fmt++; /* Skip '{' */
164 while (*fmt && (*fmt != '}')) {
165 if (i < sizeof(field_name))
166 field_name[i++] = *fmt;
171 fmt++; /* Skip '}' */
176 case 't': /* Bit (field) */
179 width = strtol(fmt, &intendp, 10);
188 value = (bits >> (shift - width)) &
192 printf("shift %2d bits %02x value %02x width %2d mask %02x\n",
193 shift, bits, value, width, mask[width]);
202 case 'i': /* Integral values */
205 width = strtol(fmt, &intendp, 10);
214 ARG_PUT((*databuf) << 8 | *(databuf + 1));
219 ARG_PUT((*databuf) << 16 |
220 (*(databuf + 1)) << 8 | *(databuf + 2));
225 ARG_PUT((*databuf) << 24 |
226 (*(databuf + 1)) << 16 |
227 (*(databuf + 2)) << 8 |
239 case 'c': /* Characters (i.e., not swapped) */
240 case 'z': /* Characters with zeroed trailing
244 width = strtol(fmt, &intendp, 10);
249 (letter == 't' ? 'b' : letter),
250 databuf, width, field_name);
253 dest = va_arg(ap, char *);
254 bcopy(databuf, dest, width);
257 for (p = dest + width - 1;
279 if (tolower(*fmt) == 'v') {
281 * You can't suppress a seek value. You also
282 * can't have a variable seek when you are using
285 width = (arg_put) ? 0 : va_arg(ap, int);
288 width = strtol(fmt, &intendp, 10);
293 databuf += width; /* Relative seek */
295 databuf = base + width; /* Absolute seek */
304 fprintf(stderr, "Unknown letter in format: %c\n",
314 /* next_field: Return the next field in a command specifier. This
315 * builds up a SCSI command using this trivial grammar:
317 * fields : field fields
321 * | value ':' field_width
324 * field_width : digit
325 * | 'i' digit // i2 = 2 byte integer, i3 = 3 byte integer etc.
329 * | 'v' // For indirection.
333 * Bit fields are specified MSB first to match the SCSI spec.
337 * WRITE BUFFER: "38 v:3 0:2 0:3 v v:i3 v:i3 0", mode, buffer_id, list_length
339 * The function returns the value:
340 * 0: For reached end, with error_p set if an error was found
341 * 1: For valid stuff setup
342 * 2: For "v" was entered as the value (implies use varargs)
347 next_field(const char **pp, char *fmt, int *width_p, int *value_p, char *name,
348 int n_name, int *error_p, int *suppress_p)
363 int field_size; /* Default to byte field type... */
364 int field_width; /* 1 byte wide */
368 field_size = 8; /* Default to byte field type... */
370 field_width = 1; /* 1 byte wide */
374 state = BETWEEN_FIELDS;
376 while (state != DONE) {
381 else if (isspace(*p))
383 else if (*p == '#') {
384 while (*p && *p != '\n')
388 } else if (*p == '{') {
393 while (*p && *p != '}') {
394 if(name && i < n_name) {
401 if(name && i < n_name)
406 } else if (*p == '*') {
409 } else if (isxdigit(*p)) {
411 value = strtol(p, &intendp, 16);
414 } else if (tolower(*p) == 'v') {
419 } else if (tolower(*p) == 'i') {
421 * Try to work without the "v".
429 field_width = strtol(p, &intendp, 10);
433 } else if (tolower(*p) == 't') {
435 * XXX: B can't work: Sees the 'b' as a
436 * hex digit in "isxdigit". try "t" for
445 field_width = strtol(p, &intendp, 10);
448 } else if (tolower(*p) == 's') {
452 if (tolower(*p) == 'v') {
458 value = strtol(p, &intendp, 0);
463 fprintf(stderr, "Invalid starting "
464 "character: %c\n", *p);
473 field_size = 1; /* Default to bits
484 field_width = strtol(p, &intendp, 10);
487 } else if (*p == 'i') {
489 /* Integral (bytes) */
494 field_width = strtol(p, &intendp, 10);
497 } else if (*p == 'b') {
504 field_width = strtol(p, &intendp, 10);
508 fprintf(stderr, "Invalid startfield %c "
527 *width_p = field_width * field_size;
529 *suppress_p = suppress;
535 do_encode(u_char *buff, size_t vec_max, size_t *used,
536 int (*arg_get)(void *, char *), void *gethook, const char *fmt,
543 int width, value, error, suppress;
552 while ((ret = next_field(&fmt, &c, &width, &value, field_name,
553 sizeof(field_name), &error, &suppress))) {
561 (*arg_get)(gethook, field_name) :
567 "do_encode: ret %d fmt %c width %d value %d name \"%s\" error %d suppress %d\n",
568 ret, c, width, value, field_name, error, suppress);
576 /* A width of < 8 is a bit field. */
579 /* This is a bit field. We start with the high bits
580 * so it reads the same as the SCSI spec.
585 val |= (value << (8 - shift));
603 case 8: /* 1 byte integer */
608 case 16: /* 2 byte integer */
609 if (ind < vec_max - 2 + 1) {
610 buff[ind++] = value >> 8;
615 case 24: /* 3 byte integer */
616 if (ind < vec_max - 3 + 1) {
617 buff[ind++] = value >> 16;
618 buff[ind++] = value >> 8;
623 case 32: /* 4 byte integer */
624 if (ind < vec_max - 4 + 1) {
625 buff[ind++] = value >> 24;
626 buff[ind++] = value >> 16;
627 buff[ind++] = value >> 8;
633 fprintf(stderr, "do_encode: Illegal width\n");
639 /* Flush out any remaining bits
641 if (shift && ind < vec_max)
654 csio_decode(struct ccb_scsiio *csio, const char *fmt, ...)
660 return(do_buff_decode(csio->data_ptr, (size_t)csio->dxfer_len,
665 csio_decode_visit(struct ccb_scsiio *csio, const char *fmt,
666 void (*arg_put)(void *, int, void *, int, char *),
672 * We need some way to output things; we can't do it without
673 * the arg_put function.
678 bzero(&ap, sizeof(ap));
680 return(do_buff_decode(csio->data_ptr, (size_t)csio->dxfer_len,
681 arg_put, puthook, fmt, ap));
685 buff_decode(u_int8_t *buff, size_t len, const char *fmt, ...)
691 return(do_buff_decode(buff, len, 0, 0, fmt, ap));
695 buff_decode_visit(u_int8_t *buff, size_t len, const char *fmt,
696 void (*arg_put)(void *, int, void *, int, char *),
702 * We need some way to output things; we can't do it without
703 * the arg_put function.
708 bzero(&ap, sizeof(ap));
710 return(do_buff_decode(buff, len, arg_put, puthook, fmt, ap));
714 * Build a SCSI CCB, given the command and data pointers and a format
715 * string describing the
718 csio_build(struct ccb_scsiio *csio, u_int8_t *data_ptr, u_int32_t dxfer_len,
719 u_int32_t flags, int retry_count, int timeout, const char *cmd_spec,
729 bzero(csio, sizeof(struct ccb_scsiio));
731 va_start(ap, cmd_spec);
733 if ((retval = do_encode(csio->cdb_io.cdb_bytes, SCSI_MAX_CDBLEN,
734 &cmdlen, NULL, NULL, cmd_spec, ap)) == -1)
738 /* retries */ retry_count,
741 /* tag_action */ MSG_SIMPLE_Q_TAG,
742 /* data_ptr */ data_ptr,
743 /* dxfer_len */ dxfer_len,
744 /* sense_len */ SSD_FULL_SIZE,
745 /* cdb_len */ cmdlen,
746 /* timeout */ timeout ? timeout : 5000);
752 csio_build_visit(struct ccb_scsiio *csio, u_int8_t *data_ptr,
753 u_int32_t dxfer_len, u_int32_t flags, int retry_count,
754 int timeout, const char *cmd_spec,
755 int (*arg_get)(void *hook, char *field_name), void *gethook)
765 * We need something to encode, but we can't get it without the
771 bzero(&ap, sizeof(ap));
773 bzero(csio, sizeof(struct ccb_scsiio));
775 if ((retval = do_encode(csio->cdb_io.cdb_bytes, SCSI_MAX_CDBLEN,
776 &cmdlen, arg_get, gethook, cmd_spec, ap)) == -1)
780 /* retries */ retry_count,
783 /* tag_action */ MSG_SIMPLE_Q_TAG,
784 /* data_ptr */ data_ptr,
785 /* dxfer_len */ dxfer_len,
786 /* sense_len */ SSD_FULL_SIZE,
787 /* cdb_len */ cmdlen,
788 /* timeout */ timeout ? timeout : 5000);
794 csio_encode(struct ccb_scsiio *csio, const char *fmt, ...)
803 return(do_encode(csio->data_ptr, csio->dxfer_len, 0, 0, 0, fmt, ap));
807 buff_encode_visit(u_int8_t *buff, size_t len, const char *fmt,
808 int (*arg_get)(void *hook, char *field_name), void *gethook)
813 * We need something to encode, but we can't get it without the
819 bzero(&ap, sizeof(ap));
821 return(do_encode(buff, len, 0, arg_get, gethook, fmt, ap));
825 csio_encode_visit(struct ccb_scsiio *csio, const char *fmt,
826 int (*arg_get)(void *hook, char *field_name), void *gethook)
831 * We need something to encode, but we can't get it without the
837 bzero(&ap, sizeof(ap));
839 return(do_encode(csio->data_ptr, csio->dxfer_len, 0, arg_get,