Merge branch 'vendor/TCPDUMP' (version 4.3.0 -> 4.9.3)
[dragonfly.git] / lib / libcam / scsi_cmdparse.c
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: src/lib/libcam/scsi_cmdparse.c,v 1.3.2.1 2000/08/14 05:42:30 kbyanc Exp $
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 <bus/cam/cam.h>
46 #include <bus/cam/cam_ccb.h>
47 #include <bus/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
97 static int
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)
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 *intendp;
112         char letter;
113         char field_name[80];
114
115 #       define ARG_PUT(ARG) \
116         do \
117         { \
118                 if (!suppress) \
119                 { \
120                         if (arg_put) \
121                                 (*arg_put)(puthook, (letter == 't' ? \
122                                         'b' : letter), \
123                                         (void *)((long)(ARG)), width, \
124                                         field_name); \
125                         else \
126                                 *(va_arg(ap, int *)) = (ARG); \
127                         assigned++; \
128                 } \
129                 field_name[0] = 0; \
130                 suppress = 0; \
131         } while (0)
132
133         u_char bits = 0;        /* For bit fields */
134         int shift = 0;          /* Bits already shifted out */
135         suppress = 0;
136         field_name[0] = 0;
137
138         while (!done) {
139                 switch(letter = *fmt) {
140                 case ' ':       /* White space */
141                 case '\t':
142                 case '\r':
143                 case '\n':
144                 case '\f':
145                         fmt++;
146                         break;
147
148                 case '#':       /* Comment */
149                         while (*fmt && (*fmt != '\n'))
150                                 fmt++;
151                         if (fmt)
152                                 fmt++;  /* Skip '\n' */
153                         break;
154
155                 case '*':       /* Suppress assignment */
156                         fmt++;
157                         suppress = 1;
158                         break;
159
160                 case '{':       /* Field Name */
161                 {
162                         int i = 0;
163                         fmt++;  /* Skip '{' */
164                         while (*fmt && (*fmt != '}')) {
165                                 if (i < sizeof(field_name))
166                                         field_name[i++] = *fmt;
167
168                                 fmt++;
169                         }
170                         if (fmt)
171                                 fmt++;  /* Skip '}' */
172                         field_name[i] = 0;
173                         break;
174                 }
175
176                 case 't':       /* Bit (field) */
177                 case 'b':       /* Bits */
178                         fmt++;
179                         width = strtol(fmt, &intendp, 10);
180                         fmt = intendp;
181                         if (width > 8)
182                                 done = 1;
183                         else {
184                                 if (shift <= 0) {
185                                         bits = *databuf++;
186                                         shift = 8;
187                                 }
188                                 value = (bits >> (shift - width)) &
189                                          mask[width];
190
191 #if 0
192                                 printf("shift %2d bits %02x value %02x width %2d mask %02x\n",
193                                 shift, bits, value, width, mask[width]);
194 #endif
195
196                                 ARG_PUT(value);
197
198                                 shift -= width;
199                         }
200                         break;
201
202                 case 'i':       /* Integral values */
203                         shift = 0;
204                         fmt++;
205                         width = strtol(fmt, &intendp, 10);
206                         fmt = intendp;
207                         switch(width) {
208                         case 1:
209                                 ARG_PUT(*databuf);
210                                 databuf++;
211                                 break;
212
213                         case 2:
214                                 ARG_PUT((*databuf) << 8 | *(databuf + 1));
215                                 databuf += 2;
216                                 break;
217
218                         case 3:
219                                 ARG_PUT((*databuf) << 16 |
220                                         (*(databuf + 1)) << 8 | *(databuf + 2));
221                                 databuf += 3;
222                                 break;
223
224                         case 4:
225                                 ARG_PUT((*databuf) << 24 |
226                                         (*(databuf + 1)) << 16 |
227                                         (*(databuf + 2)) << 8 |
228                                         *(databuf + 3));
229                                 databuf += 4;
230                                 break;
231
232                         default:
233                                 done = 1;
234                                 break;
235                         }
236
237                         break;
238
239                 case 'c':       /* Characters (i.e., not swapped) */
240                 case 'z':       /* Characters with zeroed trailing
241                                            spaces  */
242                         shift = 0;
243                         fmt++;
244                         width = strtol(fmt, &intendp, 10);
245                         fmt = intendp;
246                         if (!suppress) {
247                                 if (arg_put)
248                                         (*arg_put)(puthook,
249                                                 (letter == 't' ? 'b' : letter),
250                                                 databuf, width, field_name);
251                                 else {
252                                         char *dest;
253                                         dest = va_arg(ap, char *);
254                                         bcopy(databuf, dest, width);
255                                         if (letter == 'z') {
256                                                 char *p;
257                                                 for (p = dest + width - 1;
258                                                      (p >= (char *)dest)
259                                                      && (*p == ' '); p--)
260                                                         *p = 0;
261                                         }
262                                 }
263                                 assigned++;
264                         }
265                         databuf += width;
266                         field_name[0] = 0;
267                         suppress = 0;
268                         break;
269
270                 case 's':       /* Seek */
271                         shift = 0;
272                         fmt++;
273                         if (*fmt == '+') {
274                                 plus = 1;
275                                 fmt++;
276                         } else
277                                 plus = 0;
278
279                         if (tolower(*fmt) == 'v') {
280                                 /*
281                                  * You can't suppress a seek value.  You also
282                                  * can't have a variable seek when you are using
283                                  * "arg_put".
284                                  */
285                                 width = (arg_put) ? 0 : va_arg(ap, int);
286                                 fmt++;
287                         } else {
288                                 width = strtol(fmt, &intendp, 10);
289                                 fmt = intendp;
290                         }
291
292                         if (plus)
293                                 databuf += width;       /* Relative seek */
294                         else
295                                 databuf = base + width; /* Absolute seek */
296
297                         break;
298
299                 case 0:
300                         done = 1;
301                         break;
302
303                 default:
304                         fprintf(stderr, "Unknown letter in format: %c\n",
305                                 letter);
306                         fmt++;
307                         break;
308                 }
309         }
310
311         return (assigned);
312 }
313
314 /* next_field: Return the next field in a command specifier.  This
315  * builds up a SCSI command using this trivial grammar:
316  *
317  * fields : field fields
318  *        ;
319  *
320  * field : value
321  *       | value ':' field_width
322  *       ;
323  *
324  * field_width : digit
325  *       | 'i' digit            // i2 = 2 byte integer, i3 = 3 byte integer etc.
326  *       ;
327  *
328  * value : HEX_NUMBER
329  *       | 'v'                          // For indirection.
330  *       ;
331  *
332  * Notes:
333  *  Bit fields are specified MSB first to match the SCSI spec.
334  *
335  * Examples:
336  *  TUR: "0 0 0 0 0 0"
337  *  WRITE BUFFER: "38 v:3 0:2 0:3 v v:i3 v:i3 0", mode, buffer_id, list_length
338  *
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)
343  *
344  */
345
346 static int
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)
349 {
350         const char *p = *pp;
351         char *intendp;
352
353         int something = 0;
354
355         enum {
356                 BETWEEN_FIELDS,
357                 START_FIELD,
358                 GET_FIELD,
359                 DONE,
360         } state;
361
362         int value = 0;
363         int field_size;         /* Default to byte field type... */
364         int field_width;        /* 1 byte wide */
365         int is_error = 0;
366         int suppress = 0;
367
368         field_size = 8;         /* Default to byte field type... */
369         *fmt = 'i';
370         field_width = 1;        /* 1 byte wide */
371         if (name)
372                 *name = 0;
373
374         state = BETWEEN_FIELDS;
375
376         while (state != DONE) {
377                 switch(state) {
378                 case BETWEEN_FIELDS:
379                         if (*p == 0)
380                                 state = DONE;
381                         else if (isspace(*p))
382                                 p++;
383                         else if (*p == '#') {
384                                 while (*p && *p != '\n')
385                                         p++;
386                                 if (p)
387                                         p++;
388                         } else if (*p == '{') {
389                                 int i = 0;
390
391                                 p++;
392
393                                 while (*p && *p != '}') {
394                                         if(name && i < n_name) {
395                                                 name[i] = *p;
396                                                 i++;
397                                         }
398                                         p++;
399                                 }
400
401                                 if(name && i < n_name)
402                                         name[i] = 0;
403
404                                 if (*p == '}')
405                                         p++;
406                         } else if (*p == '*') {
407                                 p++;
408                                 suppress = 1;
409                         } else if (isxdigit(*p)) {
410                                 something = 1;
411                                 value = strtol(p, &intendp, 16);
412                                 p = intendp;
413                                 state = START_FIELD;
414                         } else if (tolower(*p) == 'v') {
415                                 p++;
416                                 something = 2;
417                                 value = *value_p;
418                                 state = START_FIELD;
419                         } else if (tolower(*p) == 'i') {
420                                 /*
421                                  * Try to work without the "v".
422                                  */
423                                 something = 2;
424                                 value = *value_p;
425                                 p++;
426
427                                 *fmt = 'i';
428                                 field_size = 8;
429                                 field_width = strtol(p, &intendp, 10);
430                                 p = intendp;
431                                 state = DONE;
432
433                         } else if (tolower(*p) == 't') {
434                                 /*
435                                  * XXX: B can't work: Sees the 'b' as a
436                                  * hex digit in "isxdigit".  try "t" for
437                                  * bit field.
438                                  */
439                                 something = 2;
440                                 value = *value_p;
441                                 p++;
442
443                                 *fmt = 'b';
444                                 field_size = 1;
445                                 field_width = strtol(p, &intendp, 10);
446                                 p = intendp;
447                                 state = DONE;
448                         } else if (tolower(*p) == 's') {
449                                 /* Seek */
450                                 *fmt = 's';
451                                 p++;
452                                 if (tolower(*p) == 'v') {
453                                         p++;
454                                         something = 2;
455                                         value = *value_p;
456                                 } else {
457                                         something = 1;
458                                         value = strtol(p, &intendp, 0);
459                                         p = intendp;
460                                 }
461                                 state = DONE;
462                         } else {
463                                 fprintf(stderr, "Invalid starting "
464                                         "character: %c\n", *p);
465                                 is_error = 1;
466                                 state = DONE;
467                         }
468                         break;
469
470                 case START_FIELD:
471                         if (*p == ':') {
472                                 p++;
473                                 field_size = 1;         /* Default to bits
474                                                            when specified */
475                                 state = GET_FIELD;
476                         } else
477                                 state = DONE;
478                         break;
479
480                 case GET_FIELD:
481                         if (isdigit(*p)) {
482                                 *fmt = 'b';
483                                 field_size = 1;
484                                 field_width = strtol(p, &intendp, 10);
485                                 p = intendp;
486                                 state = DONE;
487                         } else if (*p == 'i') {
488
489                                 /* Integral (bytes) */
490                                 p++;
491
492                                 *fmt = 'i';
493                                 field_size = 8;
494                                 field_width = strtol(p, &intendp, 10);
495                                 p = intendp;
496                                 state = DONE;
497                         } else if (*p == 'b') {
498
499                                 /* Bits */
500                                 p++;
501
502                                 *fmt = 'b';
503                                 field_size = 1;
504                                 field_width = strtol(p, &intendp, 10);
505                                 p = intendp;
506                                 state = DONE;
507                         } else {
508                                 fprintf(stderr, "Invalid startfield %c "
509                                         "(%02x)\n", *p, *p);
510                                 is_error = 1;
511                                 state = DONE;
512                         }
513                         break;
514
515                 case DONE:
516                         break;
517                 }
518         }
519
520         if (is_error) {
521                 *error_p = 1;
522                 return 0;
523         }
524
525         *error_p = 0;
526         *pp = p;
527         *width_p = field_width * field_size;
528         *value_p = value;
529         *suppress_p = suppress;
530
531         return (something);
532 }
533
534 static int
535 do_encode(u_char *buff, size_t vec_max, size_t *used,
536           int (*arg_get)(void *, char *), void *gethook, const char *fmt,
537           va_list ap)
538 {
539         int ind;
540         int shift;
541         u_char val;
542         int ret;
543         int width, value, error, suppress;
544         char c;
545         int encoded = 0;
546         char field_name[80];
547
548         ind = 0;
549         shift = 0;
550         val = 0;
551
552         while ((ret = next_field(&fmt, &c, &width, &value, field_name,
553                                  sizeof(field_name), &error, &suppress))) {
554                 encoded++;
555
556                 if (ret == 2) {
557                         if (suppress)
558                                 value = 0;
559                         else
560                                 value = arg_get ?
561                                         (*arg_get)(gethook, field_name) :
562                                         va_arg(ap, int);
563                 }
564
565 #if 0
566                 printf(
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);
569 #endif
570                 /* Absolute seek */
571                 if (c == 's') {
572                         ind = value;
573                         continue;
574                 }
575
576                 /* A width of < 8 is a bit field. */
577                 if (width < 8) {
578
579                         /* This is a bit field.  We start with the high bits
580                          * so it reads the same as the SCSI spec.
581                          */
582
583                         shift += width;
584
585                         val |= (value << (8 - shift));
586
587                         if (shift == 8) {
588                                 if (ind < vec_max) {
589                                         buff[ind++] = val;
590                                         val = 0;
591                                 }
592                                 shift = 0;
593                         }
594                 } else {
595                         if (shift) {
596                                 if (ind < vec_max) {
597                                         buff[ind++] = val;
598                                         val = 0;
599                                 }
600                                 shift = 0;
601                         }
602                         switch(width) {
603                         case 8:         /* 1 byte integer */
604                                 if (ind < vec_max)
605                                         buff[ind++] = value;
606                                 break;
607
608                         case 16:        /* 2 byte integer */
609                                 if (ind < vec_max - 2 + 1) {
610                                         buff[ind++] = value >> 8;
611                                         buff[ind++] = value;
612                                 }
613                                 break;
614
615                         case 24:        /* 3 byte integer */
616                                 if (ind < vec_max - 3 + 1) {
617                                         buff[ind++] = value >> 16;
618                                         buff[ind++] = value >> 8;
619                                         buff[ind++] = value;
620                                 }
621                                 break;
622
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;
628                                         buff[ind++] = value;
629                                 }
630                                 break;
631
632                         default:
633                                 fprintf(stderr, "do_encode: Illegal width\n");
634                                 break;
635                         }
636                 }
637         }
638
639         /* Flush out any remaining bits
640          */
641         if (shift && ind < vec_max)
642                 buff[ind++] = val;
643
644         if (used)
645                 *used = ind;
646
647         if (error)
648                 return -1;
649
650         return encoded;
651 }
652
653 int
654 csio_decode(struct ccb_scsiio *csio, const char *fmt, ...)
655 {
656         va_list ap;
657
658         va_start(ap, fmt);
659
660         return(do_buff_decode(csio->data_ptr, (size_t)csio->dxfer_len,
661                               0, 0, fmt, ap));
662 }
663
664 int
665 csio_decode_visit(struct ccb_scsiio *csio, const char *fmt,
666                   void (*arg_put)(void *, int, void *, int, char *),
667                   void *puthook)
668 {
669         va_list ap;
670
671         /*
672          * We need some way to output things; we can't do it without
673          * the arg_put function.
674          */
675         if (arg_put == NULL)
676                 return(-1);
677
678         bzero(&ap, sizeof(ap));
679
680         return(do_buff_decode(csio->data_ptr, (size_t)csio->dxfer_len,
681                               arg_put, puthook, fmt, ap));
682 }
683
684 int
685 buff_decode(u_int8_t *buff, size_t len, const char *fmt, ...)
686 {
687         va_list ap;
688
689         va_start(ap, fmt);
690
691         return(do_buff_decode(buff, len, 0, 0, fmt, ap));
692 }
693
694 int
695 buff_decode_visit(u_int8_t *buff, size_t len, const char *fmt,
696                   void (*arg_put)(void *, int, void *, int, char *),
697                   void *puthook)
698 {
699         va_list ap;
700
701         /*
702          * We need some way to output things; we can't do it without
703          * the arg_put function.
704          */
705         if (arg_put == NULL)
706                 return(-1);
707
708         bzero(&ap, sizeof(ap));
709
710         return(do_buff_decode(buff, len, arg_put, puthook, fmt, ap));
711 }
712
713 /*
714  * Build a SCSI CCB, given the command and data pointers and a format
715  * string describing the 
716  */
717 int
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,
720            ...)
721 {
722         size_t cmdlen;
723         int retval;
724         va_list ap;
725
726         if (csio == NULL)
727                 return(0);
728
729         bzero(csio, sizeof(struct ccb_scsiio));
730
731         va_start(ap, cmd_spec);
732
733         if ((retval = do_encode(csio->cdb_io.cdb_bytes, SCSI_MAX_CDBLEN,
734                                 &cmdlen, NULL, NULL, cmd_spec, ap)) == -1)
735                 return(retval);
736
737         cam_fill_csio(csio,
738                       /* retries */ retry_count,
739                       /* cbfcnp */ NULL,
740                       /* flags */ flags,
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);
747
748         return(retval);
749 }
750
751 int
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)
756 {
757         va_list ap;
758         size_t cmdlen;
759         int retval;
760
761         if (csio == NULL)
762                 return(0);
763
764         /*
765          * We need something to encode, but we can't get it without the
766          * arg_get function.
767          */
768         if (arg_get == NULL)
769                 return(-1);
770
771         bzero(&ap, sizeof(ap));
772
773         bzero(csio, sizeof(struct ccb_scsiio));
774
775         if ((retval = do_encode(csio->cdb_io.cdb_bytes, SCSI_MAX_CDBLEN,
776                                 &cmdlen, arg_get, gethook, cmd_spec, ap)) == -1)
777                 return(retval);
778
779         cam_fill_csio(csio,
780                       /* retries */ retry_count,
781                       /* cbfcnp */ NULL,
782                       /* flags */ flags,
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);
789
790         return(retval);
791 }
792
793 int
794 csio_encode(struct ccb_scsiio *csio, const char *fmt, ...)
795 {
796         va_list ap;
797
798         if (csio == NULL)
799                 return(0);
800
801         va_start(ap, fmt);
802
803         return(do_encode(csio->data_ptr, csio->dxfer_len, 0, 0, 0, fmt, ap));
804 }
805
806 int
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)
809 {
810         va_list ap;
811
812         /*
813          * We need something to encode, but we can't get it without the
814          * arg_get function.
815          */
816         if (arg_get == NULL)
817                 return(-1);
818
819         bzero(&ap, sizeof(ap));
820
821         return(do_encode(buff, len, 0, arg_get, gethook, fmt, ap));
822 }
823
824 int
825 csio_encode_visit(struct ccb_scsiio *csio, const char *fmt,
826                   int (*arg_get)(void *hook, char *field_name), void *gethook)
827 {
828         va_list ap;
829
830         /*
831          * We need something to encode, but we can't get it without the
832          * arg_get function.
833          */
834         if (arg_get == NULL)
835                 return(-1);
836
837         bzero(&ap, sizeof(ap));
838
839         return(do_encode(csio->data_ptr, csio->dxfer_len, 0, arg_get,
840                          gethook, fmt, ap));
841 }