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