Bug Summary

File:src/sbin/scsi/libscsi.c
Warning:line 479, column 12
Assigned value is garbage or undefined

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name libscsi.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sbin/scsi/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/sbin/scsi/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/sbin/scsi/libscsi.c
1/* $OpenBSD: libscsi.c,v 1.11 2016/01/28 17:26:10 gsoares Exp $ */
2
3/* Copyright (c) 1994 HD Associates
4 * (contact: dufault@hda.com)
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by HD Associates
18 * 4. Neither the name of the HD Associaates nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * $FreeBSD: scsi.c,v 1.6 1995/05/30 05:47:26 rgrimes Exp $
35 */
36#include <stdlib.h>
37#include <stdio.h>
38#include <ctype.h>
39#include <string.h>
40#include <sys/scsiio.h>
41#include <errno(*__errno()).h>
42#include <stdarg.h>
43#include <fcntl.h>
44
45#include "libscsi.h"
46
47static struct {
48 FILE *db_f;
49 int db_level;
50 int db_trunc;
51} behave;
52
53/* scsireq_reset: Reset a scsireq structure.
54 */
55scsireq_t *
56scsireq_reset(scsireq_t *scsireq)
57{
58 if (scsireq == 0)
59 return scsireq;
60
61 scsireq->flags = 0; /* info about the request status and type */
62 scsireq->timeout = 2000; /* 2 seconds */
63 bzero(scsireq->cmd, sizeof(scsireq->cmd));
64 scsireq->cmdlen = 0;
65 /* Leave scsireq->databuf alone */
66 /* Leave scsireq->datalen alone */
67 scsireq->datalen_used = 0;
68 bzero(scsireq->sense, sizeof(scsireq->sense));
69 scsireq->senselen = sizeof(scsireq->sense);
70 scsireq->senselen_used = 0;
71 scsireq->status = 0;
72 scsireq->retsts = 0;
73 scsireq->error = 0;
74
75 return scsireq;
76}
77
78/* scsireq_new: Allocate and initialize a new scsireq.
79 */
80scsireq_t *
81scsireq_new(void)
82{
83 scsireq_t *p = malloc(sizeof(scsireq_t));
84
85 if (p)
86 scsireq_reset(p);
87
88 return p;
89}
90
91/*
92 * Decode: Decode the data section of a scsireq. This decodes
93 * trivial grammar:
94 *
95 * fields : field fields
96 * ;
97 *
98 * field : field_specifier
99 * | control
100 * ;
101 *
102 * control : 's' seek_value
103 * | 's' '+' seek_value
104 * ;
105 *
106 * seek_value : DECIMAL_NUMBER
107 * | 'v' // For indirect seek, i.e., value from the arg list
108 * ;
109 *
110 * field_specifier : type_specifier field_width
111 * | '{' NAME '}' type_specifier field_width
112 * ;
113 *
114 * field_width : DECIMAL_NUMBER
115 * ;
116 *
117 * type_specifier : 'i' // Integral types (i1, i2, i3, i4)
118 * | 'b' // Bits
119 * | 't' // Bits
120 * | 'c' // Character arrays
121 * | 'z' // Character arrays with zeroed trailing spaces
122 * ;
123 *
124 * Notes:
125 * 1. Integral types are swapped into host order.
126 * 2. Bit fields are allocated MSB to LSB to match the SCSI spec documentation.
127 * 3. 's' permits "seeking" in the string. "s+DECIMAL" seeks relative to
128 * DECIMAL; "sDECIMAL" seeks absolute to decimal.
129 * 4. 's' permits an indirect reference. "sv" or "s+v" will get the
130 * next integer value from the arg array.
131 * 5. Field names can be anything between the braces
132 *
133 * BUGS:
134 * i and b types are promoted to ints.
135 *
136 */
137static int
138do_buff_decode(u_char *databuf, size_t len,
139 void (*arg_put)(void *, int , void *, int, char *),
140 void *puthook, char *fmt, va_list ap)
141{
142 int assigned = 0;
143 int width;
144 int suppress;
145 int plus;
146 int done = 0;
147 static u_char mask[] = {0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
148 int value;
149 u_char *base = databuf;
150 char letter;
151 char field_name[80];
152
153# define ARG_PUT(ARG)do { if (!suppress) { if (arg_put) (*arg_put)(puthook, (letter
== 't' ? 'b' : letter), (void *)((long)(ARG)), 1, field_name
); else *(__builtin_va_arg(ap, int *)) = (ARG); assigned++; }
field_name[0] = 0; suppress = 0; } while (0)
\
154 do \
155 { \
156 if (!suppress) { \
157 if (arg_put) \
158 (*arg_put)(puthook, (letter == 't' ? 'b' : letter), \
159 (void *)((long)(ARG)), 1, field_name); \
160 else \
161 *(va_arg(ap, int *)__builtin_va_arg(ap, int *)) = (ARG); \
162 assigned++; \
163 } \
164 field_name[0] = 0; \
165 suppress = 0; \
166 } while (0)
167
168 u_char bits = 0; /* For bit fields */
169 int shift = 0; /* Bits already shifted out */
170 suppress = 0;
171 field_name[0] = 0;
172
173 while (!done) {
174 switch (letter = *fmt) {
175 case ' ': /* White space */
176 case '\t':
177 case '\r':
178 case '\n':
179 case '\f':
180 fmt++;
181 break;
182
183 case '#': /* Comment */
184 while (*fmt && (*fmt != '\n'))
185 fmt++;
186 if (fmt)
187 fmt++; /* Skip '\n' */
188 break;
189
190 case '*': /* Suppress assignment */
191 fmt++;
192 suppress = 1;
193 break;
194
195 case '{': /* Field Name */
196 {
197 int i = 0;
198 fmt++; /* Skip '{' */
199 while (*fmt && (*fmt != '}')) {
200 if (i < sizeof(field_name)-1)
201 field_name[i++] = *fmt;
202
203 fmt++;
204 }
205 if (fmt)
206 fmt++; /* Skip '}' */
207 field_name[i] = 0;
208 }
209 break;
210
211 case 't': /* Bit (field) */
212 case 'b': /* Bits */
213 fmt++;
214 width = strtol(fmt, &fmt, 10);
215 if (width > 8)
216 done = 1;
217 else {
218 if (shift <= 0) {
219 bits = *databuf++;
220 shift = 8;
221 }
222 value = (bits >> (shift - width)) & mask[width];
223
224#if 0
225 printf("shift %2d bits %02x value %02x width %2d mask %02x\n",
226 shift, bits, value, width, mask[width]);
227#endif
228
229 ARG_PUT(value)do { if (!suppress) { if (arg_put) (*arg_put)(puthook, (letter
== 't' ? 'b' : letter), (void *)((long)(value)), 1, field_name
); else *(__builtin_va_arg(ap, int *)) = (value); assigned++;
} field_name[0] = 0; suppress = 0; } while (0)
;
230
231 shift -= width;
232 }
233
234 break;
235
236 case 'i': /* Integral values */
237 shift = 0;
238 fmt++;
239 width = strtol(fmt, &fmt, 10);
240 switch (width) {
241 case 1:
242 ARG_PUT(*databuf)do { if (!suppress) { if (arg_put) (*arg_put)(puthook, (letter
== 't' ? 'b' : letter), (void *)((long)(*databuf)), 1, field_name
); else *(__builtin_va_arg(ap, int *)) = (*databuf); assigned
++; } field_name[0] = 0; suppress = 0; } while (0)
;
243 databuf++;
244 break;
245
246 case 2:
247 ARG_PUT((*databuf) << 8 | *(databuf + 1))do { if (!suppress) { if (arg_put) (*arg_put)(puthook, (letter
== 't' ? 'b' : letter), (void *)((long)((*databuf) << 8
| *(databuf + 1))), 1, field_name); else *(__builtin_va_arg(
ap, int *)) = ((*databuf) << 8 | *(databuf + 1)); assigned
++; } field_name[0] = 0; suppress = 0; } while (0)
;
248 databuf += 2;
249 break;
250
251 case 3:
252 ARG_PUT(do { if (!suppress) { if (arg_put) (*arg_put)(puthook, (letter
== 't' ? 'b' : letter), (void *)((long)((*databuf) << 16
| (*(databuf + 1)) << 8 | *(databuf + 2))), 1, field_name
); else *(__builtin_va_arg(ap, int *)) = ((*databuf) <<
16 | (*(databuf + 1)) << 8 | *(databuf + 2)); assigned
++; } field_name[0] = 0; suppress = 0; } while (0)
253 (*databuf) << 16 |do { if (!suppress) { if (arg_put) (*arg_put)(puthook, (letter
== 't' ? 'b' : letter), (void *)((long)((*databuf) << 16
| (*(databuf + 1)) << 8 | *(databuf + 2))), 1, field_name
); else *(__builtin_va_arg(ap, int *)) = ((*databuf) <<
16 | (*(databuf + 1)) << 8 | *(databuf + 2)); assigned
++; } field_name[0] = 0; suppress = 0; } while (0)
254 (*(databuf + 1)) << 8 |do { if (!suppress) { if (arg_put) (*arg_put)(puthook, (letter
== 't' ? 'b' : letter), (void *)((long)((*databuf) << 16
| (*(databuf + 1)) << 8 | *(databuf + 2))), 1, field_name
); else *(__builtin_va_arg(ap, int *)) = ((*databuf) <<
16 | (*(databuf + 1)) << 8 | *(databuf + 2)); assigned
++; } field_name[0] = 0; suppress = 0; } while (0)
255 *(databuf + 2))do { if (!suppress) { if (arg_put) (*arg_put)(puthook, (letter
== 't' ? 'b' : letter), (void *)((long)((*databuf) << 16
| (*(databuf + 1)) << 8 | *(databuf + 2))), 1, field_name
); else *(__builtin_va_arg(ap, int *)) = ((*databuf) <<
16 | (*(databuf + 1)) << 8 | *(databuf + 2)); assigned
++; } field_name[0] = 0; suppress = 0; } while (0)
;
256 databuf += 3;
257 break;
258
259 case 4:
260 ARG_PUT(do { if (!suppress) { if (arg_put) (*arg_put)(puthook, (letter
== 't' ? 'b' : letter), (void *)((long)((*databuf) << 24
| (*(databuf + 1)) << 16 | (*(databuf + 2)) << 8
| *(databuf + 3))), 1, field_name); else *(__builtin_va_arg(
ap, int *)) = ((*databuf) << 24 | (*(databuf + 1)) <<
16 | (*(databuf + 2)) << 8 | *(databuf + 3)); assigned
++; } field_name[0] = 0; suppress = 0; } while (0)
261 (*databuf) << 24 |do { if (!suppress) { if (arg_put) (*arg_put)(puthook, (letter
== 't' ? 'b' : letter), (void *)((long)((*databuf) << 24
| (*(databuf + 1)) << 16 | (*(databuf + 2)) << 8
| *(databuf + 3))), 1, field_name); else *(__builtin_va_arg(
ap, int *)) = ((*databuf) << 24 | (*(databuf + 1)) <<
16 | (*(databuf + 2)) << 8 | *(databuf + 3)); assigned
++; } field_name[0] = 0; suppress = 0; } while (0)
262 (*(databuf + 1)) << 16 |do { if (!suppress) { if (arg_put) (*arg_put)(puthook, (letter
== 't' ? 'b' : letter), (void *)((long)((*databuf) << 24
| (*(databuf + 1)) << 16 | (*(databuf + 2)) << 8
| *(databuf + 3))), 1, field_name); else *(__builtin_va_arg(
ap, int *)) = ((*databuf) << 24 | (*(databuf + 1)) <<
16 | (*(databuf + 2)) << 8 | *(databuf + 3)); assigned
++; } field_name[0] = 0; suppress = 0; } while (0)
263 (*(databuf + 2)) << 8 |do { if (!suppress) { if (arg_put) (*arg_put)(puthook, (letter
== 't' ? 'b' : letter), (void *)((long)((*databuf) << 24
| (*(databuf + 1)) << 16 | (*(databuf + 2)) << 8
| *(databuf + 3))), 1, field_name); else *(__builtin_va_arg(
ap, int *)) = ((*databuf) << 24 | (*(databuf + 1)) <<
16 | (*(databuf + 2)) << 8 | *(databuf + 3)); assigned
++; } field_name[0] = 0; suppress = 0; } while (0)
264 *(databuf + 3))do { if (!suppress) { if (arg_put) (*arg_put)(puthook, (letter
== 't' ? 'b' : letter), (void *)((long)((*databuf) << 24
| (*(databuf + 1)) << 16 | (*(databuf + 2)) << 8
| *(databuf + 3))), 1, field_name); else *(__builtin_va_arg(
ap, int *)) = ((*databuf) << 24 | (*(databuf + 1)) <<
16 | (*(databuf + 2)) << 8 | *(databuf + 3)); assigned
++; } field_name[0] = 0; suppress = 0; } while (0)
;
265 databuf += 4;
266 break;
267
268 default:
269 done = 1;
270 }
271
272 break;
273
274 case 'c': /* Characters (i.e., not swapped) */
275 case 'z': /* Characters with zeroed trailing spaces */
276 shift = 0;
277 fmt++;
278 width = strtol(fmt, &fmt, 10);
279 if (!suppress) {
280 if (arg_put)
281 (*arg_put)(puthook, (letter == 't' ? 'b' : letter),
282 databuf, width, field_name);
283 else {
284 char *dest;
285 dest = va_arg(ap, char *)__builtin_va_arg(ap, char *);
286 bcopy(databuf, dest, width);
287 if (letter == 'z') {
288 char *p;
289 for (p = dest + width - 1;
290 (p >= (char *)dest) && (*p == ' '); p--)
291 *p = 0;
292 }
293 }
294 assigned++;
295 }
296 databuf += width;
297 field_name[0] = 0;
298 suppress = 0;
299 break;
300
301 case 's': /* Seek */
302 shift = 0;
303 fmt++;
304 if (*fmt == '+') {
305 plus = 1;
306 fmt++;
307 } else
308 plus = 0;
309
310 if (tolower((unsigned char)*fmt) == 'v') {
311 /* You can't suppress a seek value. You also
312 * can't have a variable seek when you are using
313 * "arg_put".
314 */
315 width = (arg_put) ? 0 : va_arg(ap, int)__builtin_va_arg(ap, int);
316 fmt++;
317 } else
318 width = strtol(fmt, &fmt, 10);
319
320 if (plus)
321 databuf += width; /* Relative seek */
322 else
323 databuf = base + width; /* Absolute seek */
324
325 break;
326
327 case 0:
328 done = 1;
329 break;
330
331 default:
332 fprintf(stderr(&__sF[2]), "Unknown letter in format: %c\n", letter);
333 fmt++;
334 }
335 }
336
337 return assigned;
338}
339
340int
341scsireq_decode_visit(scsireq_t *scsireq, char *fmt,
342 void (*arg_put)(void *, int , void *, int, char *), void *puthook)
343{
344 va_list ap;
345 int ret;
346
347 ret = do_buff_decode(scsireq->databuf, (size_t)scsireq->datalen,
348 arg_put, puthook, fmt, ap);
349 va_end (ap)__builtin_va_end(ap);
350 return (ret);
351}
352
353int
354scsireq_buff_decode_visit(u_char *buff, size_t len, char *fmt,
355 void (*arg_put)(void *, int, void *, int, char *), void *puthook)
356{
357 va_list ap;
358
359 /* XXX */
360 return do_buff_decode(buff, len, arg_put, puthook, fmt, ap);
361}
362
363/* next_field: Return the next field in a command specifier. This
364 * builds up a SCSI command using this trivial grammar:
365 *
366 * fields : field fields
367 * ;
368 *
369 * field : value
370 * | value ':' field_width
371 * ;
372 *
373 * field_width : digit
374 * | 'i' digit // i2 = 2 byte integer, i3 = 3 byte integer etc.
375 * ;
376 *
377 * value : HEX_NUMBER
378 * | 'v' // For indirection.
379 * ;
380 *
381 * Notes:
382 * Bit fields are specified MSB first to match the SCSI spec.
383 *
384 * Examples:
385 * TUR: "0 0 0 0 0 0"
386 * WRITE BUFFER: "38 v:3 0:2 0:3 v v:i3 v:i3 0", mode, buffer_id, list_length
387 *
388 * The function returns the value:
389 * 0: For reached end, with error_p set if an error was found
390 * 1: For valid stuff setup
391 * 2: For "v" was entered as the value (implies use varargs)
392 *
393 */
394static int
395next_field(char **pp, char *fmt, int *width_p, int *value_p, char *name,
396 int n_name, int *error_p, int *suppress_p)
397{
398 char *p = *pp;
399
400 int something = 0;
401
402 enum { BETWEEN_FIELDS, START_FIELD, GET_FIELD, DONE } state;
403
404 int value = 0;
405 int field_size; /* Default to byte field type... */
406 int field_width; /* 1 byte wide */
407 int is_error = 0;
408 int suppress = 0;
409
410 field_size = 8; /* Default to byte field type... */
411 *fmt = 'i';
412 field_width = 1; /* 1 byte wide */
413 if (name
3.1
'name' is non-null
)
4
Taking true branch
414 *name = 0;
415
416 state = BETWEEN_FIELDS;
417
418 while (state != DONE)
5
Loop condition is true. Entering loop body
419 switch (state)
6
Control jumps to 'case BETWEEN_FIELDS:' at line 421
420 {
421 case BETWEEN_FIELDS:
422 if (*p == 0)
7
Assuming the condition is false
8
Taking false branch
423 state = DONE;
424 else if (isspace((unsigned char)*p))
9
Taking false branch
425 p++;
426 else if (*p == '#') {
10
Assuming the condition is false
11
Taking false branch
427 while (*p && *p != '\n')
428 p++;
429
430 if (p)
431 p++;
432 } else if (*p == '{') {
12
Assuming the condition is false
13
Taking false branch
433 int i = 0;
434
435 p++;
436
437 while (*p && *p != '}') {
438 if (name && i < n_name) {
439 name[i] = *p;
440 i++;
441 }
442 p++;
443 }
444
445 if (name && i < n_name)
446 name[i] = 0;
447
448 if (*p == '}')
449 p++;
450 } else if (*p == '*') {
14
Assuming the condition is false
15
Taking false branch
451 p++;
452 suppress = 1;
453 } else if (isxdigit((unsigned char)*p)) {
16
Taking false branch
454 something = 1;
455 value = strtol(p, &p, 16);
456 state = START_FIELD;
457 } else if (tolower((unsigned char)*p) == 'v') {
17
Assuming the condition is false
18
Taking false branch
458 p++;
459 something = 2;
460 value = *value_p;
461 state = START_FIELD;
462 }
463 /* try to work without the 'v' */
464 else if (tolower((unsigned char)*p) == 'i') {
19
Assuming the condition is false
20
Taking false branch
465 something = 2;
466 value = *value_p;
467 p++;
468
469 *fmt = 'i';
470 field_size = 8;
471 field_width = strtol(p, &p, 10);
472 state = DONE;
473 } else if (tolower((unsigned char)*p) == 't') {
21
Assuming the condition is true
22
Taking true branch
474 /* XXX: B can't work: Sees the 'b'
475 * as a hex digit in "isxdigit".
476 * try "t" for bit field.
477 */
478 something = 2;
479 value = *value_p;
23
Assigned value is garbage or undefined
480 p++;
481
482 *fmt = 'b';
483 field_size = 1;
484 field_width = strtol(p, &p, 10);
485 state = DONE;
486 } else if (tolower((unsigned char)*p) == 's') { /* Seek */
487 *fmt = 's';
488 p++;
489 if (tolower((unsigned char)*p) == 'v') {
490 p++;
491 something = 2;
492 value = *value_p;
493 } else {
494 something = 1;
495 value = strtol(p, &p, 0);
496 }
497 state = DONE;
498 } else {
499 fprintf(stderr(&__sF[2]), "Invalid starting character: %c\n", *p);
500 is_error = 1;
501 state = DONE;
502 }
503 break;
504
505 case START_FIELD:
506 if (*p == ':') {
507 p++;
508 field_size = 1; /* Default to bits when specified */
509 state = GET_FIELD;
510 } else
511 state = DONE;
512 break;
513
514 case GET_FIELD:
515 if (isdigit((unsigned char)*p)) {
516 *fmt = 'b';
517 field_size = 1;
518 field_width = strtol(p, &p, 10);
519 state = DONE;
520 } else if (*p == 'i') { /* Integral (bytes) */
521 p++;
522
523 *fmt = 'i';
524 field_size = 8;
525 field_width = strtol(p, &p, 10);
526 state = DONE;
527 } else if (*p == 'b') { /* Bits */
528 p++;
529
530 *fmt = 'b';
531 field_size = 1;
532 field_width = strtol(p, &p, 10);
533 state = DONE;
534 } else {
535 fprintf(stderr(&__sF[2]), "Invalid startfield %c (%02x)\n",
536 *p, *p);
537 is_error = 1;
538 state = DONE;
539 }
540 break;
541
542 case DONE:
543 break;
544 }
545
546 if (is_error) {
547 *error_p = 1;
548 return 0;
549 }
550
551 *error_p = 0;
552 *pp = p;
553 *width_p = field_width * field_size;
554 *value_p = value;
555 *suppress_p = suppress;
556
557 return something;
558}
559
560static int
561do_encode(u_char *buff, size_t vec_max, size_t *used,
562 int (*arg_get)(void *, char *),
563 void *gethook, char *fmt, va_list ap)
564{
565 int ind;
566 int shift;
567 u_char val;
568 int ret;
569 int width, value, error, suppress;
2
'value' declared without an initial value
570 char c;
571 int encoded = 0;
572 char field_name[80];
573
574 ind = 0;
575 shift = 0;
576 val = 0;
577
578 while ((ret = next_field(&fmt, &c, &width, &value, field_name,
3
Calling 'next_field'
579 sizeof(field_name), &error, &suppress)))
580 {
581 encoded++;
582
583 if (ret == 2) {
584 if (suppress)
585 value = 0;
586 else
587 value = arg_get ? (*arg_get)(gethook, field_name) : va_arg(ap, int)__builtin_va_arg(ap, int);
588 }
589
590#if 0
591 printf(
592 "do_encode: ret %d fmt %c width %d value %d name \"%s\""
593 "error %d suppress %d\n",
594 ret, c, width, value, field_name, error, suppress);
595#endif
596
597 if (c == 's') /* Absolute seek */
598 {
599 ind = value;
600 continue;
601 }
602
603 if (width < 8) /* A width of < 8 is a bit field. */
604 {
605
606 /* This is a bit field. We start with the high bits
607 * so it reads the same as the SCSI spec.
608 */
609
610 shift += width;
611
612 val |= (value << (8 - shift));
613
614 if (shift == 8) {
615 if (ind < vec_max) {
616 buff[ind++] = val;
617 val = 0;
618 }
619 shift = 0;
620 }
621 } else {
622 if (shift) {
623 if (ind < vec_max) {
624 buff[ind++] = val;
625 val = 0;
626 }
627 shift = 0;
628 }
629 switch (width)
630 {
631 case 8: /* 1 byte integer */
632 if (ind < vec_max)
633 buff[ind++] = value;
634 break;
635
636 case 16: /* 2 byte integer */
637 if (ind < vec_max - 2 + 1) {
638 buff[ind++] = value >> 8;
639 buff[ind++] = value;
640 }
641 break;
642
643 case 24: /* 3 byte integer */
644 if (ind < vec_max - 3 + 1) {
645 buff[ind++] = value >> 16;
646 buff[ind++] = value >> 8;
647 buff[ind++] = value;
648 }
649 break;
650
651 case 32: /* 4 byte integer */
652 if (ind < vec_max - 4 + 1) {
653 buff[ind++] = value >> 24;
654 buff[ind++] = value >> 16;
655 buff[ind++] = value >> 8;
656 buff[ind++] = value;
657 }
658 break;
659
660 default:
661 fprintf(stderr(&__sF[2]), "do_encode: Illegal width\n");
662 break;
663 }
664 }
665 }
666
667 /* Flush out any remaining bits */
668 if (shift && ind < vec_max) {
669 buff[ind++] = val;
670 val = 0;
671 }
672
673
674 if (used)
675 *used = ind;
676
677 if (error)
678 return -1;
679
680 return encoded;
681}
682
683scsireq_t *
684scsireq_build(scsireq_t *scsireq, u_long datalen, caddr_t databuf,
685 u_long flags, char *cmd_spec, ...)
686{
687 size_t cmdlen;
688 va_list ap;
689
690 if (scsireq == 0)
691 return 0;
692
693 scsireq_reset(scsireq);
694
695 if (databuf) {
696 scsireq->databuf = databuf;
697 scsireq->datalen = datalen;
698 scsireq->flags = flags;
699 }
700 else if (datalen) {
701 /* XXX: Good way to get a memory leak. Perhaps this should be
702 * removed.
703 */
704 if ( (scsireq->databuf = malloc(datalen)) == NULL((void *)0))
705 return 0;
706
707 scsireq->datalen = datalen;
708 scsireq->flags = flags;
709 }
710
711 va_start(ap, cmd_spec)__builtin_va_start(ap, cmd_spec);
712
713 if (do_encode(scsireq->cmd, CMDBUFLEN16, &cmdlen, 0, 0, cmd_spec, ap) == -1)
714 return 0;
715 va_end (ap)__builtin_va_end(ap);
716
717 scsireq->cmdlen = cmdlen;
718 return scsireq;
719}
720
721scsireq_t
722*scsireq_build_visit(scsireq_t *scsireq, u_long datalen, caddr_t databuf,
723 u_long flags, char *cmd_spec,
724 int (*arg_get)(void *hook, char *field_name), void *gethook)
725{
726 size_t cmdlen;
727 va_list ap;
728
729 if (scsireq == 0)
730 return 0;
731
732 scsireq_reset(scsireq);
733
734 if (databuf) {
735 scsireq->databuf = databuf;
736 scsireq->datalen = datalen;
737 scsireq->flags = flags;
738 } else if (datalen) {
739 /* XXX: Good way to get a memory leak. Perhaps this should be
740 * removed.
741 */
742 if ( (scsireq->databuf = malloc(datalen)) == NULL((void *)0))
743 return 0;
744
745 scsireq->datalen = datalen;
746 scsireq->flags = flags;
747 }
748
749 if (do_encode(scsireq->cmd, CMDBUFLEN16, &cmdlen, arg_get, gethook,
750 cmd_spec, ap) == -1)
751 return 0;
752
753 scsireq->cmdlen = cmdlen;
754
755 return scsireq;
756}
757
758int
759scsireq_buff_encode_visit(u_char *buff, size_t len, char *fmt,
760 int (*arg_get)(void *hook, char *field_name), void *gethook)
761{
762 va_list ap;
763 return do_encode(buff, len, 0, arg_get, gethook, fmt, ap);
764}
765
766int
767scsireq_encode_visit(scsireq_t *scsireq, char *fmt,
768 int (*arg_get)(void *hook, char *field_name), void *gethook)
769{
770 va_list ap;
771 return do_encode(scsireq->databuf, scsireq->datalen, 0,
1
Calling 'do_encode'
772 arg_get, gethook, fmt, ap);
773}
774
775FILE *
776scsi_debug_output(char *s)
777{
778 if (s == 0)
779 behave.db_f = 0;
780 else {
781 behave.db_f = fopen(s, "w");
782
783 if (behave.db_f == 0)
784 behave.db_f = stderr(&__sF[2]);
785 }
786
787 return behave.db_f;
788}
789
790#define SCSI_TRUNCATE-1 -1
791
792typedef struct scsi_assoc {
793 int code;
794 char *text;
795} scsi_assoc_t;
796
797static scsi_assoc_t retsts[] =
798{
799 { SCCMD_OK0x00, "No error" },
800 { SCCMD_TIMEOUT0x01, "Command Timeout" },
801 { SCCMD_BUSY0x02, "Busy" },
802 { SCCMD_SENSE0x03, "Sense Returned" },
803 { SCCMD_UNKNOWN0x04, "Unknown return status" },
804
805 { 0, 0 }
806};
807
808static char *
809scsi_assoc_text(int code, scsi_assoc_t *tab)
810{
811 while (tab->text) {
812 if (tab->code == code)
813 return tab->text;
814
815 tab++;
816 }
817
818 return "Unknown code";
819}
820
821void
822scsi_dump(FILE *f, char *text, u_char *p, int req, int got, int dump_print)
823{
824 int i;
825 int trunc = 0;
826
827 if (f == 0 || req == 0)
828 return;
829
830 fprintf(f, "%s (%d of %d):\n", text, got, req);
831
832 if (behave.db_trunc != -1 && got > behave.db_trunc) {
833 trunc = 1;
834 got = behave.db_trunc;
835 }
836
837 for (i = 0; i < got; i++) {
838 fprintf(f, "%02x", p[i]);
839
840 putc(' ', f)(!__isthreaded ? __sputc(' ', f) : (putc)(' ', f));
841
842 if ((i % 16) == 15 || i == got - 1) {
843 int j;
844 if (dump_print) {
845 fprintf(f, " # ");
846 for (j = i - 15; j <= i; j++)
847 putc((isprint(p[j]) ? p[j] : '.'), f)(!__isthreaded ? __sputc((isprint(p[j]) ? p[j] : '.'), f) : (
putc)((isprint(p[j]) ? p[j] : '.'), f))
;
848
849 putc('\n', f)(!__isthreaded ? __sputc('\n', f) : (putc)('\n', f));
850 } else
851 putc('\n', f)(!__isthreaded ? __sputc('\n', f) : (putc)('\n', f));
852 }
853 }
854
855 fprintf(f, "%s", (trunc) ? "(truncated)...\n" : "\n");
856}
857
858/* XXX: sense_7x_dump and scsi_sense dump was just sort of
859 * grabbed out of the old ds
860 * library and not really merged in carefully. It should use the
861 * new buffer decoding stuff.
862 */
863
864/* Get unsigned long.
865 */
866static u_long
867g_u_long(u_char *s)
868{
869 return (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
870}
871
872/* In the old software you could patch in a special error table:
873 */
874static scsi_assoc_t *error_table = 0;
875
876static void
877sense_7x_dump(FILE *f, scsireq_t *scsireq)
878{
879 int code;
880 u_char *s = (u_char *)scsireq->sense;
881 int valid = (*s) & 0x80;
882 u_long val;
883
884 static scsi_assoc_t sense[] = {
885 { 0, "No sense" },
886 { 1, "Recovered error" },
887 { 2, "Not Ready" },
888 { 3, "Medium error" },
889 { 4, "Hardware error" },
890 { 5, "Illegal request" },
891 { 6, "Unit attention" },
892 { 7, "Data protect" },
893 { 8, "Blank check" },
894 { 9, "Vendor specific" },
895 { 0xa, "Copy aborted" },
896 { 0xb, "Aborted Command" },
897 { 0xc, "Equal" },
898 { 0xd, "Volume overflow" },
899 { 0xe, "Miscompare" },
900 { 0, 0 },
901 };
902
903 static scsi_assoc_t code_tab[] = {
904 {0x70, "current errors"},
905 {0x71, "deferred errors"},
906 };
907
908 fprintf(f, "Error code is \"%s\"\n", scsi_assoc_text(s[0]&0x7F, code_tab));
909 fprintf(f, "Segment number is %02x\n", s[1]);
910
911 if (s[2] & 0x20)
912 fprintf(f, "Incorrect Length Indicator is set.\n");
913
914 fprintf(f, "Sense key is \"%s\"\n", scsi_assoc_text(s[2] & 0x7, sense));
915
916 val = g_u_long(s + 3);
917 fprintf(f, "The Information field is%s %08lx (%ld).\n",
918 valid ? "" : " not valid but contains", (long)val, (long)val);
919
920 val = g_u_long(s + 8);
921 fprintf(f, "The Command Specific Information field is %08lx (%ld).\n",
922 (long)val, (long)val);
923
924 fprintf(f, "Additional sense code: %02x\n", s[12]);
925 fprintf(f, "Additional sense code qualifier: %02x\n", s[13]);
926
927 code = (s[12] << 8) | s[13];
928
929 if (error_table)
930 fprintf(f, "%s\n", scsi_assoc_text(code, error_table));
931
932 if (s[15] & 0x80) {
933 if ((s[2] & 0x7) == 0x05) /* Illegal request */
934 {
935 int byte;
936 u_char value, bit;
937 int bad_par = ((s[15] & 0x40) == 0);
938 fprintf(f, "Illegal value in the %s.\n",
939 (bad_par ? "parameter list" : "command descriptor block"));
940 byte = ((s[16] << 8) | s[17]);
941 value = bad_par ? (u_char)scsireq->databuf[byte] : (u_char)scsireq->cmd[byte];
942 bit = s[15] & 0x7;
943 if (s[15] & 0x08)
944 fprintf(f, "Bit %d of byte %d (value %02x) is illegal.\n",
945 bit, byte, value);
946 else
947 fprintf(f, "Byte %d (value %02x) is illegal.\n", byte, value);
948 } else {
949 fprintf(f, "Sense Key Specific (valid but not illegal request):\n");
950 fprintf(f, "%02x %02x %02x\n", s[15] & 0x7f, s[16], s[17]);
951 }
952 }
953}
954
955/* scsi_sense_dump: Dump the sense portion of the scsireq structure.
956 */
957static void
958scsi_sense_dump(FILE *f, scsireq_t *scsireq)
959{
960 u_char *s = (u_char *)scsireq->sense;
961 int code = (*s) & 0x7f;
962
963 if (scsireq->senselen_used == 0) {
964 fprintf(f, "No sense sent.\n");
965 return;
966 }
967
968#if 0
969 if (!valid)
970 fprintf(f, "The sense data is not valid.\n");
971#endif
972
973 switch (code) {
974 case 0x70:
975 case 0x71:
976 sense_7x_dump(f, scsireq);
977 break;
978
979 default:
980 fprintf(f, "No sense dump for error code %02x.\n", code);
981 }
982 scsi_dump(f, "sense", s, scsireq->senselen, scsireq->senselen_used, 0);
983}
984
985static void
986scsi_retsts_dump(FILE *f, scsireq_t *scsireq)
987{
988 if (scsireq->retsts == 0)
989 return;
990
991 fprintf(f, "return status %d (%s)",
992 scsireq->retsts, scsi_assoc_text(scsireq->retsts, retsts));
993
994 switch (scsireq->retsts) {
995 case SCCMD_TIMEOUT0x01:
996 fprintf(f, " after %ld ms", scsireq->timeout);
997 break;
998
999 default:
1000 break;
1001 }
1002}
1003
1004int
1005scsi_debug(FILE *f, int ret, scsireq_t *scsireq)
1006{
1007 char *d;
1008 if (f == 0)
1009 return 0;
1010
1011 fprintf(f, "SCIOCCOMMAND ioctl");
1012
1013 if (ret == 0)
1014 fprintf(f, ": Command accepted.");
1015 else {
1016 if (ret != -1)
1017 fprintf(f, ", return value %d?", ret);
1018
1019 if (errno(*__errno())) {
1020 fprintf(f, ": %s", strerror(errno(*__errno())));
1021 errno(*__errno()) = 0;
1022 }
1023 }
1024
1025 fputc('\n', f);
1026
1027 if (ret == 0 && (scsireq->status || scsireq->retsts || behave.db_level))
1028 {
1029 scsi_retsts_dump(f, scsireq);
1030
1031 if (scsireq->status)
1032 fprintf(f, " host adapter status %d\n", scsireq->status);
1033
1034 if (scsireq->flags & SCCMD_READ0x00000001)
1035 d = "Data in";
1036 else if (scsireq->flags & SCCMD_WRITE0x00000002)
1037 d = "Data out";
1038 else
1039 d = "No data transfer?";
1040
1041 if (scsireq->cmdlen == 0)
1042 fprintf(f, "Zero length command????\n");
1043
1044 scsi_dump(f, "Command out",
1045 (u_char *)scsireq->cmd, scsireq->cmdlen, scsireq->cmdlen, 0);
1046 scsi_dump(f, d,
1047 (u_char *)scsireq->databuf, scsireq->datalen,
1048 scsireq->datalen_used, 1);
1049 scsi_sense_dump(f, scsireq);
1050 }
1051
1052 fflush(f);
1053
1054 return ret;
1055}
1056
1057static char *debug_output;
1058
1059int
1060scsi_open(const char *path, int flags)
1061{
1062 int fd = open(path, flags);
1063
1064 if (fd != -1) {
1065 char *p;
1066 debug_output = getenv("SU_DEBUG_OUTPUT");
1067 (void)scsi_debug_output(debug_output);
1068
1069 if ((p = getenv("SU_DEBUG_LEVEL")))
1070 sscanf(p, "%d", &behave.db_level);
1071
1072 if ((p = getenv("SU_DEBUG_TRUNCATE")))
1073 sscanf(p, "%d", &behave.db_trunc);
1074 else
1075 behave.db_trunc = SCSI_TRUNCATE-1;
1076 }
1077
1078 return fd;
1079}
1080
1081int
1082scsireq_enter(int fid, scsireq_t *scsireq)
1083{
1084 int ret;
1085
1086 ret = ioctl(fid, SCIOCCOMMAND(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(scsireq_t) & 0x1fff) << 16) | ((('Q')) << 8)
| ((1)))
, (void *)scsireq);
1087
1088 if (behave.db_f)
1089 scsi_debug(behave.db_f, ret, scsireq);
1090
1091 return ret;
1092}