2 * Taken from the original FreeBSD user SCSI library.
5 * SPDX-License-Identifier: BSD-4-Clause
7 * Copyright (c) 1994 HD Associates
8 * (contact: dufault@hda.com)
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by HD Associates
22 * 4. Neither the name of the HD Associaates nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * From: scsi.c,v 1.8 1997/02/22 15:07:54 peter Exp $
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD$");
43 #include <sys/types.h>
49 #include <sys/errno.h>
54 #include <cam/cam_ccb.h>
55 #include <cam/scsi/scsi_message.h>
59 * Decode: Decode the data section of a scsireq. This decodes
62 * fields : field fields
65 * field : field_specifier
69 * control : 's' seek_value
70 * | 's' '+' seek_value
73 * seek_value : DECIMAL_NUMBER
74 * | 'v' // For indirect seek, i.e., value from the arg list
77 * field_specifier : type_specifier field_width
78 * | '{' NAME '}' type_specifier field_width
81 * field_width : DECIMAL_NUMBER
84 * type_specifier : 'i' // Integral types (i1, i2, i3, i4)
87 * | 'c' // Character arrays
88 * | 'z' // Character arrays with zeroed trailing spaces
92 * 1. Integral types are swapped into host order.
93 * 2. Bit fields are allocated MSB to LSB to match the SCSI spec documentation.
94 * 3. 's' permits "seeking" in the string. "s+DECIMAL" seeks relative to
95 * DECIMAL; "sDECIMAL" seeks absolute to decimal.
96 * 4. 's' permits an indirect reference. "sv" or "s+v" will get the
97 * next integer value from the arg array.
98 * 5. Field names can be anything between the braces
101 * i and b types are promoted to ints.
106 do_buff_decode(u_int8_t *buff, size_t len,
107 void (*arg_put)(void *, int , void *, int, char *),
108 void *puthook, const char *fmt, va_list *ap)
116 static u_char mask[] = {0, 0x01, 0x03, 0x07, 0x0f,
117 0x1f, 0x3f, 0x7f, 0xff};
123 #define ARG_PUT(ARG) \
127 (*arg_put)(puthook, (letter == 't' ? 'b' : \
128 letter), (void *)((long)(ARG)), width, \
131 *(va_arg(*ap, int *)) = (ARG); \
134 field_name[0] = '\0'; \
138 u_char bits = 0; /* For bit fields */
139 int shift = 0; /* Bits already shifted out */
141 field_name[0] = '\0';
144 switch(letter = *fmt) {
145 case ' ': /* White space */
153 case '#': /* Comment */
154 while (*fmt && (*fmt != '\n'))
157 fmt++; /* Skip '\n' */
160 case '*': /* Suppress assignment */
165 case '{': /* Field Name */
168 fmt++; /* Skip '{' */
169 while (*fmt && (*fmt != '}')) {
170 if (i < sizeof(field_name))
171 field_name[i++] = *fmt;
176 fmt++; /* Skip '}' */
177 field_name[i] = '\0';
181 case 't': /* Bit (field) */
184 width = strtol(fmt, &intendp, 10);
197 value = (bits >> (shift - width)) &
201 printf("shift %2d bits %02x value %02x width %2d mask %02x\n",
202 shift, bits, value, width, mask[width]);
211 case 'i': /* Integral values */
214 width = strtol(fmt, &intendp, 10);
216 if (ind + width > len) {
227 ARG_PUT(buff[ind] << 8 | buff[ind + 1]);
232 ARG_PUT(buff[ind] << 16 |
233 buff[ind + 1] << 8 | buff[ind + 2]);
238 ARG_PUT(buff[ind] << 24 | buff[ind + 1] << 16 |
239 buff[ind + 2] << 8 | buff[ind + 3]);
250 case 'c': /* Characters (i.e., not swapped) */
251 case 'z': /* Characters with zeroed trailing spaces */
254 width = strtol(fmt, &intendp, 10);
256 if (ind + width > len) {
263 (letter == 't' ? 'b' : letter),
264 &buff[ind], width, field_name);
267 dest = va_arg(*ap, char *);
268 bcopy(&buff[ind], dest, width);
271 for (p = dest + width - 1;
272 p >= dest && *p == ' ';
293 if (tolower(*fmt) == 'v') {
295 * You can't suppress a seek value. You also
296 * can't have a variable seek when you are using
299 width = (arg_put) ? 0 : va_arg(*ap, int);
302 width = strtol(fmt, &intendp, 10);
307 ind += width; /* Relative seek */
309 ind = width; /* Absolute seek */
318 fprintf(stderr, "Unknown letter in format: %c\n",
328 /* next_field: Return the next field in a command specifier. This
329 * builds up a SCSI command using this trivial grammar:
331 * fields : field fields
335 * | value ':' field_width
338 * field_width : digit
339 * | 'i' digit // i2 = 2 byte integer, i3 = 3 byte integer etc.
343 * | 'v' // For indirection.
347 * Bit fields are specified MSB first to match the SCSI spec.
351 * WRITE BUFFER: "38 v:3 0:2 0:3 v v:i3 v:i3 0", mode, buffer_id, list_length
353 * The function returns the value:
354 * 0: For reached end, with error_p set if an error was found
355 * 1: For valid stuff setup
356 * 2: For "v" was entered as the value (implies use varargs)
361 next_field(const char **pp, char *fmt, int *width_p, int *value_p, char *name,
362 int n_name, int *error_p, int *suppress_p)
377 int field_size; /* Default to byte field type... */
378 int field_width; /* 1 byte wide */
382 field_size = 8; /* Default to byte field type... */
384 field_width = 1; /* 1 byte wide */
388 state = BETWEEN_FIELDS;
390 while (state != DONE) {
395 else if (isspace(*p))
397 else if (*p == '#') {
398 while (*p && *p != '\n')
402 } else if (*p == '{') {
407 while (*p && *p != '}') {
408 if(name && i < n_name) {
415 if(name && i < n_name)
420 } else if (*p == '*') {
423 } else if (isxdigit(*p)) {
425 value = strtol(p, &intendp, 16);
428 } else if (tolower(*p) == 'v') {
433 } else if (tolower(*p) == 'i') {
435 * Try to work without the "v".
443 field_width = strtol(p, &intendp, 10);
447 } else if (tolower(*p) == 't') {
449 * XXX: B can't work: Sees the 'b' as a
450 * hex digit in "isxdigit". try "t" for
459 field_width = strtol(p, &intendp, 10);
462 } else if (tolower(*p) == 's') {
466 if (tolower(*p) == 'v') {
472 value = strtol(p, &intendp, 0);
477 fprintf(stderr, "Invalid starting "
478 "character: %c\n", *p);
487 field_size = 1; /* Default to bits
498 field_width = strtol(p, &intendp, 10);
501 } else if (*p == 'i') {
503 /* Integral (bytes) */
508 field_width = strtol(p, &intendp, 10);
511 } else if (*p == 'b') {
518 field_width = strtol(p, &intendp, 10);
522 fprintf(stderr, "Invalid startfield %c "
541 *width_p = field_width * field_size;
543 *suppress_p = suppress;
549 do_encode(u_char *buff, size_t vec_max, size_t *used,
550 int (*arg_get)(void *, char *), void *gethook, const char *fmt,
557 int width, value, error, suppress;
566 while ((ret = next_field(&fmt, &c, &width, &value, field_name,
567 sizeof(field_name), &error, &suppress))) {
574 value = arg_get != NULL ?
575 (*arg_get)(gethook, field_name) :
581 "do_encode: ret %d fmt %c width %d value %d name \"%s\" error %d suppress %d\n",
582 ret, c, width, value, field_name, error, suppress);
590 /* A width of < 8 is a bit field. */
593 /* This is a bit field. We start with the high bits
594 * so it reads the same as the SCSI spec.
599 val |= (value << (8 - shift));
617 case 8: /* 1 byte integer */
622 case 16: /* 2 byte integer */
623 if (ind < vec_max - 2 + 1) {
624 buff[ind++] = value >> 8;
629 case 24: /* 3 byte integer */
630 if (ind < vec_max - 3 + 1) {
631 buff[ind++] = value >> 16;
632 buff[ind++] = value >> 8;
637 case 32: /* 4 byte integer */
638 if (ind < vec_max - 4 + 1) {
639 buff[ind++] = value >> 24;
640 buff[ind++] = value >> 16;
641 buff[ind++] = value >> 8;
647 fprintf(stderr, "do_encode: Illegal width\n");
653 /* Flush out any remaining bits
655 if (shift && ind < vec_max) {
671 csio_decode(struct ccb_scsiio *csio, const char *fmt, ...)
678 retval = do_buff_decode(csio->data_ptr, (size_t)csio->dxfer_len,
679 NULL, NULL, fmt, &ap);
687 csio_decode_visit(struct ccb_scsiio *csio, const char *fmt,
688 void (*arg_put)(void *, int, void *, int, char *),
693 * We need some way to output things; we can't do it without
694 * the arg_put function.
699 return (do_buff_decode(csio->data_ptr, (size_t)csio->dxfer_len,
700 arg_put, puthook, fmt, NULL));
704 buff_decode(u_int8_t *buff, size_t len, const char *fmt, ...)
711 retval = do_buff_decode(buff, len, NULL, NULL, fmt, &ap);
719 buff_decode_visit(u_int8_t *buff, size_t len, const char *fmt,
720 void (*arg_put)(void *, int, void *, int, char *),
725 * We need some way to output things; we can't do it without
726 * the arg_put function.
731 return (do_buff_decode(buff, len, arg_put, puthook, fmt, NULL));
735 * Build a SCSI CCB, given the command and data pointers and a format
736 * string describing the
739 csio_build(struct ccb_scsiio *csio, u_int8_t *data_ptr, u_int32_t dxfer_len,
740 u_int32_t flags, int retry_count, int timeout, const char *cmd_spec,
750 bzero(csio, sizeof(struct ccb_scsiio));
752 va_start(ap, cmd_spec);
754 if ((retval = do_encode(csio->cdb_io.cdb_bytes, SCSI_MAX_CDBLEN,
755 &cmdlen, NULL, NULL, cmd_spec, &ap)) == -1)
759 /* retries */ retry_count,
762 /* tag_action */ MSG_SIMPLE_Q_TAG,
763 /* data_ptr */ data_ptr,
764 /* dxfer_len */ dxfer_len,
765 /* sense_len */ SSD_FULL_SIZE,
766 /* cdb_len */ cmdlen,
767 /* timeout */ timeout ? timeout : 5000);
776 csio_build_visit(struct ccb_scsiio *csio, u_int8_t *data_ptr,
777 u_int32_t dxfer_len, u_int32_t flags, int retry_count,
778 int timeout, const char *cmd_spec,
779 int (*arg_get)(void *hook, char *field_name), void *gethook)
788 * We need something to encode, but we can't get it without the
794 bzero(csio, sizeof(struct ccb_scsiio));
796 if ((retval = do_encode(csio->cdb_io.cdb_bytes, SCSI_MAX_CDBLEN,
797 &cmdlen, arg_get, gethook, cmd_spec, NULL)) == -1)
801 /* retries */ retry_count,
804 /* tag_action */ MSG_SIMPLE_Q_TAG,
805 /* data_ptr */ data_ptr,
806 /* dxfer_len */ dxfer_len,
807 /* sense_len */ SSD_FULL_SIZE,
808 /* cdb_len */ cmdlen,
809 /* timeout */ timeout ? timeout : 5000);
815 csio_encode(struct ccb_scsiio *csio, const char *fmt, ...)
825 retval = do_encode(csio->data_ptr, csio->dxfer_len, NULL, NULL, NULL,
834 buff_encode_visit(u_int8_t *buff, size_t len, const char *fmt,
835 int (*arg_get)(void *hook, char *field_name), void *gethook)
839 * We need something to encode, but we can't get it without the
845 return (do_encode(buff, len, NULL, arg_get, gethook, fmt, NULL));
849 csio_encode_visit(struct ccb_scsiio *csio, const char *fmt,
850 int (*arg_get)(void *hook, char *field_name), void *gethook)
854 * We need something to encode, but we can't get it without the
860 return (do_encode(csio->data_ptr, csio->dxfer_len, NULL, arg_get,
861 gethook, fmt, NULL));