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