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