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