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.h> 42 #include <stdarg.h> 43 #include <fcntl.h> 44 45 #include "libscsi.h" 46 47 static struct { 48 FILE *db_f; 49 int db_level; 50 int db_trunc; 51 } behave; 52 53 /* scsireq_reset: Reset a scsireq structure. 54 */ 55 scsireq_t * 56 scsireq_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 */ 80 scsireq_t * 81 scsireq_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 */ 137 static int 138 do_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) \ 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 *)) = (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); 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); 243 databuf++; 244 break; 245 246 case 2: 247 ARG_PUT((*databuf) << 8 | *(databuf + 1)); 248 databuf += 2; 249 break; 250 251 case 3: 252 ARG_PUT( 253 (*databuf) << 16 | 254 (*(databuf + 1)) << 8 | 255 *(databuf + 2)); 256 databuf += 3; 257 break; 258 259 case 4: 260 ARG_PUT( 261 (*databuf) << 24 | 262 (*(databuf + 1)) << 16 | 263 (*(databuf + 2)) << 8 | 264 *(databuf + 3)); 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 *); 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); 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, "Unknown letter in format: %c\n", letter); 333 fmt++; 334 } 335 } 336 337 return assigned; 338 } 339 340 int 341 scsireq_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); 350 return (ret); 351 } 352 353 int 354 scsireq_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 */ 394 static int 395 next_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) 414 *name = 0; 415 416 state = BETWEEN_FIELDS; 417 418 while (state != DONE) 419 switch (state) 420 { 421 case BETWEEN_FIELDS: 422 if (*p == 0) 423 state = DONE; 424 else if (isspace((unsigned char)*p)) 425 p++; 426 else if (*p == '#') { 427 while (*p && *p != '\n') 428 p++; 429 430 if (p) 431 p++; 432 } else if (*p == '{') { 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 == '*') { 451 p++; 452 suppress = 1; 453 } else if (isxdigit((unsigned char)*p)) { 454 something = 1; 455 value = strtol(p, &p, 16); 456 state = START_FIELD; 457 } else if (tolower((unsigned char)*p) == 'v') { 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') { 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') { 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; 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, "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, "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 560 static int 561 do_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; 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, 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); 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, "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 683 scsireq_t * 684 scsireq_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) 705 return 0; 706 707 scsireq->datalen = datalen; 708 scsireq->flags = flags; 709 } 710 711 va_start(ap, cmd_spec); 712 713 if (do_encode(scsireq->cmd, CMDBUFLEN, &cmdlen, 0, 0, cmd_spec, ap) == -1) 714 return 0; 715 va_end (ap); 716 717 scsireq->cmdlen = cmdlen; 718 return scsireq; 719 } 720 721 scsireq_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) 743 return 0; 744 745 scsireq->datalen = datalen; 746 scsireq->flags = flags; 747 } 748 749 if (do_encode(scsireq->cmd, CMDBUFLEN, &cmdlen, arg_get, gethook, 750 cmd_spec, ap) == -1) 751 return 0; 752 753 scsireq->cmdlen = cmdlen; 754 755 return scsireq; 756 } 757 758 int 759 scsireq_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 766 int 767 scsireq_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, 772 arg_get, gethook, fmt, ap); 773 } 774 775 FILE * 776 scsi_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; 785 } 786 787 return behave.db_f; 788 } 789 790 #define SCSI_TRUNCATE -1 791 792 typedef struct scsi_assoc { 793 int code; 794 char *text; 795 } scsi_assoc_t; 796 797 static scsi_assoc_t retsts[] = 798 { 799 { SCCMD_OK, "No error" }, 800 { SCCMD_TIMEOUT, "Command Timeout" }, 801 { SCCMD_BUSY, "Busy" }, 802 { SCCMD_SENSE, "Sense Returned" }, 803 { SCCMD_UNKNOWN, "Unknown return status" }, 804 805 { 0, 0 } 806 }; 807 808 static char * 809 scsi_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 821 void 822 scsi_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); 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); 848 849 putc('\n', f); 850 } else 851 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 */ 866 static u_long 867 g_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 */ 874 static scsi_assoc_t *error_table = 0; 875 876 static void 877 sense_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 */ 957 static void 958 scsi_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 985 static void 986 scsi_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_TIMEOUT: 996 fprintf(f, " after %ld ms", scsireq->timeout); 997 break; 998 999 default: 1000 break; 1001 } 1002 } 1003 1004 int 1005 scsi_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) { 1020 fprintf(f, ": %s", strerror(errno)); 1021 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_READ) 1035 d = "Data in"; 1036 else if (scsireq->flags & SCCMD_WRITE) 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 1057 static char *debug_output; 1058 1059 int 1060 scsi_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; 1076 } 1077 1078 return fd; 1079 } 1080 1081 int 1082 scsireq_enter(int fid, scsireq_t *scsireq) 1083 { 1084 int ret; 1085 1086 ret = ioctl(fid, SCIOCCOMMAND, (void *)scsireq); 1087 1088 if (behave.db_f) 1089 scsi_debug(behave.db_f, ret, scsireq); 1090 1091 return ret; 1092 } 1093