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