xref: /dragonfly/lib/libcam/scsi_cmdparse.c (revision 4842621b77994e080c8c776db4dbc3b02a7e9bc2)
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
do_buff_decode(u_int8_t * databuf,size_t len,void (* arg_put)(void *,int,void *,int,char *),void * puthook,const char * fmt,va_list ap)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
next_field(const char ** pp,char * fmt,int * width_p,int * value_p,char * name,int n_name,int * error_p,int * suppress_p)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
do_encode(u_char * buff,size_t vec_max,size_t * used,int (* arg_get)(void *,char *),void * gethook,const char * fmt,va_list ap)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
csio_decode(struct ccb_scsiio * csio,const char * fmt,...)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
csio_decode_visit(struct ccb_scsiio * csio,const char * fmt,void (* arg_put)(void *,int,void *,int,char *),void * puthook)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
buff_decode(u_int8_t * buff,size_t len,const char * fmt,...)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
buff_decode_visit(u_int8_t * buff,size_t len,const char * fmt,void (* arg_put)(void *,int,void *,int,char *),void * puthook)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
csio_build(struct ccb_scsiio * csio,u_int8_t * data_ptr,u_int32_t dxfer_len,u_int32_t flags,int retry_count,int timeout,const char * cmd_spec,...)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
csio_build_visit(struct ccb_scsiio * csio,u_int8_t * data_ptr,u_int32_t dxfer_len,u_int32_t flags,int retry_count,int timeout,const char * cmd_spec,int (* arg_get)(void * hook,char * field_name),void * gethook)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
csio_encode(struct ccb_scsiio * csio,const char * fmt,...)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
buff_encode_visit(u_int8_t * buff,size_t len,const char * fmt,int (* arg_get)(void * hook,char * field_name),void * gethook)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
csio_encode_visit(struct ccb_scsiio * csio,const char * fmt,int (* arg_get)(void * hook,char * field_name),void * gethook)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 }
842