1//----------------------------------------------------------------------------- 2// Includes 3//----------------------------------------------------------------------------- 4 5#include <string.h> 6#include <unistd.h> 7#include <getopt.h> 8#include <fcntl.h> 9#include <sysexits.h> 10#include <stdint.h> 11#include <IOKit/IOKitLib.h> 12#include <IOKit/storage/IOStorageDeviceCharacteristics.h> 13#include <IOKit/storage/IOStorageProtocolCharacteristics.h> 14#include <CoreFoundation/CoreFoundation.h> 15#include <IOKit/scsi/SCSITask.h> 16#include <IOKit/scsi/SCSICmds_REPORT_LUNS_Definitions.h> 17#include <IOKit/scsi/SCSICommandOperationCodes.h> 18#include <IOKit/scsi/SCSICmds_INQUIRY_Definitions.h> 19#include <CoreFoundation/CoreFoundation.h> 20 21#include "AppleSCSIEmulatorAdapterUC.h" 22#include "AppleSCSIEmulatorDefines.h" 23 24//----------------------------------------------------------------------------- 25// Macros 26//----------------------------------------------------------------------------- 27 28#define DEBUG 0 29 30#define DEBUG_ASSERT_COMPONENT_NAME_STRING "Emulator" 31 32#if DEBUG 33#define PRINT(x) printf x 34#else 35#define PRINT(x) 36#endif 37 38#if DEBUG 39#define DEBUG_ASSERT_MESSAGE(componentNameString, \ 40 assertionString, \ 41 exceptionLabelString, \ 42 errorString, \ 43 fileName, \ 44 lineNumber, \ 45 errorCode) \ 46DebugAssert(componentNameString, \ 47 assertionString, \ 48 exceptionLabelString, \ 49 errorString, \ 50 fileName, \ 51 lineNumber, \ 52 errorCode) \ 53 54static void 55DebugAssert ( const char * componentNameString, 56 const char * assertionString, 57 const char * exceptionLabelString, 58 const char * errorString, 59 const char * fileName, 60 long lineNumber, 61 int errorCode ) 62{ 63 64 if ( ( assertionString != NULL ) && ( *assertionString != '\0' ) ) 65 printf ( "Assertion failed: %s: %s\n", componentNameString, assertionString ); 66 else 67 printf ( "Check failed: %s:\n", componentNameString ); 68 if ( exceptionLabelString != NULL ) 69 printf ( " %s\n", exceptionLabelString ); 70 if ( errorString != NULL ) 71 printf ( " %s\n", errorString ); 72 if ( fileName != NULL ) 73 printf ( " file: %s\n", fileName ); 74 if ( lineNumber != 0 ) 75 printf ( " line: %ld\n", lineNumber ); 76 if ( errorCode != 0 ) 77 printf ( " error: %d\n", errorCode ); 78 79} 80 81#endif /* DEBUG */ 82 83#include <AssertMacros.h> 84 85 86//----------------------------------------------------------------------------- 87// Constants 88//----------------------------------------------------------------------------- 89 90#define kAppleSCSIEmulatorAdapterClassString "AppleSCSIEmulatorAdapter" 91#define kIOSCSIParallelInterfaceDeviceString "IOSCSIParallelInterfaceDevice" 92#define kIOSCSITargetDeviceString "IOSCSITargetDevice" 93#define kIOSCSIHierarchicalLogicalUnitString "IOSCSIHierarchicalLogicalUnit" 94 95//----------------------------------------------------------------------------- 96// Structures 97//----------------------------------------------------------------------------- 98 99#pragma pack(1) 100 101typedef struct EmulatorSCSIInquiryPage00Data 102{ 103 UInt8 page00; 104 UInt8 page80; 105 UInt8 page83; 106} EmulatorSCSIInquiryPage00Data; 107 108typedef struct EmulatorSCSIInquiryPage83Data 109{ 110 SCSICmd_INQUIRY_Page83_Identification_Descriptor descriptor1; 111 UInt8 descriptor1bytes[7]; 112 SCSICmd_INQUIRY_Page83_Identification_Descriptor descriptor2; 113 UInt8 descriptor2bytes[15]; 114} EmulatorSCSIInquiryPage83Data; 115 116typedef struct EmulatorSCSIInquiryPage80Data 117{ 118 UInt8 serialBytes[31]; 119} EmulatorSCSIInquiryPage80Data; 120 121typedef struct EmulatorSCSIInquiryPage00 122{ 123 SCSICmd_INQUIRY_Page00_Header header; 124 EmulatorSCSIInquiryPage00Data data; 125} EmulatorSCSIInquiryPage00; 126 127typedef struct EmulatorSCSIInquiryPage80 128{ 129 SCSICmd_INQUIRY_Page80_Header header; 130 EmulatorSCSIInquiryPage80Data data; 131} EmulatorSCSIInquiryPage80; 132 133typedef struct EmulatorSCSIInquiryPage83 134{ 135 SCSICmd_INQUIRY_Page83_Header header; 136 EmulatorSCSIInquiryPage83Data data; 137} EmulatorSCSIInquiryPage83; 138 139#pragma options align=reset 140 141 142//----------------------------------------------------------------------------- 143// Globals 144//----------------------------------------------------------------------------- 145 146SCSICmd_INQUIRY_StandardData gInquiryData = 147{ 148 kINQUIRY_PERIPHERAL_TYPE_DirectAccessSBCDevice, // PERIPHERAL_DEVICE_TYPE 149 0, // RMB; 150 5, // VERSION 151 2, // RESPONSE_DATA_FORMAT 152 sizeof ( SCSICmd_INQUIRY_StandardData ) - 5, // ADDITIONAL_LENGTH 153 0, // SCCSReserved 154 0, // flags1 155 0, // flags2 156 "APPLE", 157 "SCSI Emulator", 158 "1.0", 159}; 160 161static EmulatorSCSIInquiryPage00 gInquiryPage00Data = 162{ 163 0, // PERIPHERAL_DEVICE_TYPE 164 kINQUIRY_Page00_PageCode, // PAGE_CODE 165 0, // RESERVED 166 sizeof ( EmulatorSCSIInquiryPage00Data ), // PAGE_LENGTH 167 kINQUIRY_Page00_PageCode, 168 kINQUIRY_Page80_PageCode, 169 kINQUIRY_Page83_PageCode 170}; 171 172static EmulatorSCSIInquiryPage80 gInquiryPage80Data = 173{ 174 0, // PERIPHERAL_DEVICE_TYPE 175 kINQUIRY_Page80_PageCode, // PAGE_CODE 176 0, // RESERVED 177 sizeof ( EmulatorSCSIInquiryPage80Data ) + 1, // PAGE_LENGTH 178 'A', 179 'P', 180 'P', 181 'L', 182 'E', 183 ' ', 184 'V', 185 'i', 186 'r', 187 't', 188 'u', 189 'a', 190 'l', 191 ' ', 192 'L', 193 'U', 194 'N', 195 '0', 196 0 197}; 198 199static EmulatorSCSIInquiryPage83 gInquiryPage83Data = 200{ 201 0, // PERIPHERAL_DEVICE_TYPE 202 kINQUIRY_Page83_PageCode, // PAGE_CODE 203 0, // RESERVED 204 sizeof ( EmulatorSCSIInquiryPage83Data ), // PAGE_LENGTH 205 { 206 { // Descriptor1 207 kINQUIRY_Page83_CodeSetBinaryData, // CODE_SET 208 kINQUIRY_Page83_AssociationTargetDevice | kINQUIRY_Page83_IdentifierTypeFCNameIdentifier, // IDENTIFIER_TYPE 209 0x00, // Reserved 210 0x08, // IDENTIFIER_LENGTH 211 0x50 // IDENTIFIER 212 }, 213 { 214 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 215 }, 216 { // Descriptor2 217 kINQUIRY_Page83_CodeSetBinaryData, // CODE_SET 218 kINQUIRY_Page83_IdentifierTypeFCNameIdentifier, // IDENTIFIER_TYPE 219 0x00, // Reserved 220 0x10, // IDENTIFIER_LENGTH 221 0x60 // IDENTIFIER 222 }, 223 { 224 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 225 } 226 }, 227}; 228 229 230//----------------------------------------------------------------------------- 231// Prototypes 232//----------------------------------------------------------------------------- 233 234static void 235CreateTargetLUN ( 236 SCSITargetIdentifier targetID, 237 SCSILogicalUnitNumber logicalUnit, 238 UInt64 capacity, 239 boolean_t unique ); 240 241static void 242DestroyTargetLUN ( 243 SCSITargetIdentifier targetID, 244 SCSILogicalUnitNumber logicalUnit ); 245 246static void 247DestroyTarget ( 248 SCSITargetIdentifier targetID ); 249 250static io_object_t 251GetController ( void ); 252 253static void 254PrintUsage ( void ); 255 256static void 257PrintController ( io_object_t controller ); 258 259static void 260PrintTarget ( io_object_t target ); 261 262static void 263PrintLogicalUnit ( io_object_t logicalUnit ); 264 265static void 266ReportInventory ( void ); 267 268 269//----------------------------------------------------------------------------- 270// main - Our main entry point 271//----------------------------------------------------------------------------- 272 273int 274main ( int argc, const char * argv[] ) 275{ 276 277 boolean_t create = false; 278 boolean_t destroy = false; 279 boolean_t inventory = false; 280 boolean_t unique = true; 281 int64_t targetID = -1; 282 int64_t lun = -1; 283 uint64_t size = 0; 284 char c; 285 286 static struct option long_options [ ] = 287 { 288 { "target", required_argument, 0, 't' }, 289 { "lun", required_argument, 0, 'l' }, 290 { "size", required_argument, 0, 's' }, 291 { "inventory", no_argument, 0, 'i' }, 292 { "create", no_argument, 0, 'c' }, 293 { "destroy", no_argument, 0, 'd' }, 294 { "help", no_argument, 0, 'h' }, 295 { "nounique", no_argument, 0, 'n' }, 296 { 0, 0, 0, 0 } 297 }; 298 299 while ( ( c = getopt_long ( argc, ( char * const * ) argv, "t:l:s:icdhn?", long_options, NULL ) ) != -1 ) 300 { 301 302 switch ( c ) 303 { 304 305 case 't': 306 { 307 308 targetID = strtoull ( optarg, ( char ** ) NULL, 10 ); 309 if ( ( targetID > 255 ) || ( targetID == kInitiatorID ) ) 310 { 311 PRINT ( ( "Invalid targetID.\n" ) ); 312 PrintUsage ( ); 313 exit ( EX_USAGE ); 314 } 315 316 } 317 break; 318 319 case 'l': 320 { 321 322 lun = strtoull ( optarg, ( char ** ) NULL, 10 ); 323 if ( ( lun > 16383 ) || ( lun == 0 ) ) 324 { 325 PRINT ( ( "Invalid LUN.\n" ) ); 326 PrintUsage ( ); 327 exit ( EX_USAGE ); 328 } 329 330 } 331 break; 332 333 case 's': 334 { 335 336 char * expr; 337 338 size = strtoull ( optarg, &expr, 10 ); 339 340 switch ( *expr ) 341 { 342 343 case 'k': 344 size *= 1 << 10; 345 break; 346 347 case 'm': 348 size *= 1 << 20; 349 break; 350 351 case 'g': 352 size *= 1 << 30; 353 break; 354 355 default: 356 break; 357 358 } 359 360 if ( size % 512 ) 361 { 362 PRINT ( ( "Invalid byte count. Must be a multiple of 512 bytes\n" ) ); 363 PrintUsage ( ); 364 exit ( EX_USAGE ); 365 } 366 367 } 368 break; 369 370 case 'i': 371 { 372 373 if ( ( create ) || ( destroy ) ) 374 { 375 PRINT ( ( "Create, Destroy, and Inventory are mutually exclusive.\n" ) ); 376 PrintUsage ( ); 377 exit ( EX_USAGE ); 378 } 379 380 inventory = true; 381 382 } 383 break; 384 385 case 'c': 386 { 387 388 if ( ( inventory ) || ( destroy ) ) 389 { 390 PRINT ( ( "Create, Destroy, and Inventory are mutually exclusive.\n" ) ); 391 PrintUsage ( ); 392 exit ( EX_USAGE ); 393 } 394 395 create = true; 396 397 } 398 break; 399 400 case 'd': 401 { 402 403 if ( ( create ) || ( inventory ) ) 404 { 405 PRINT ( ( "Create, Destroy, and Inventory are mutually exclusive.\n" ) ); 406 PrintUsage ( ); 407 exit ( EX_USAGE ); 408 } 409 410 destroy = true; 411 412 } 413 break; 414 415 case 'n': 416 { 417 unique = false; 418 } 419 break; 420 421 case 'h': 422 default: 423 { 424 425 PrintUsage ( ); 426 exit ( EX_USAGE ); 427 428 } 429 break; 430 431 } 432 433 } 434 435 if ( inventory ) 436 { 437 438 ReportInventory ( ); 439 exit ( 0 ); 440 441 } 442 443 if ( create ) 444 { 445 446 if ( ( targetID == -1 ) || ( lun == -1 ) || ( size == 0 ) ) 447 { 448 449 PrintUsage ( ); 450 exit ( EX_USAGE ); 451 452 } 453 454 CreateTargetLUN ( targetID, lun, size, unique ); 455 456 } 457 458 else if ( destroy ) 459 { 460 461 if ( targetID == -1 ) 462 { 463 464 PrintUsage ( ); 465 exit ( EX_USAGE ); 466 467 } 468 469 if ( lun == -1 ) 470 { 471 DestroyTarget ( targetID ); 472 } 473 474 else 475 { 476 DestroyTargetLUN ( targetID, lun ); 477 } 478 479 } 480 481 else 482 { 483 484 PrintUsage ( ); 485 exit ( EX_USAGE ); 486 487 } 488 489 return 0; 490 491} 492 493 494//----------------------------------------------------------------------------- 495// CreateTargetLUN - Creates a Logical Unit attached to a target. 496//----------------------------------------------------------------------------- 497 498static void 499CreateTargetLUN ( 500 SCSITargetIdentifier targetID, 501 SCSILogicalUnitNumber logicalUnit, 502 UInt64 capacity, 503 boolean_t unique ) 504{ 505 506 io_object_t controller = IO_OBJECT_NULL; 507 508 PRINT ( ( "CreateTargetLUN, targetID = %qd, logicalUnit = %qd, capacity = %qd\n", targetID, logicalUnit, capacity ) ); 509 510 controller = GetController ( ); 511 if ( controller != IO_OBJECT_NULL ) 512 { 513 514 io_connect_t connection = IO_OBJECT_NULL; 515 IOReturn status = kIOReturnSuccess; 516 517 status = IOServiceOpen ( 518 controller, 519 mach_task_self ( ), 520 kSCSIEmulatorAdapterUserClientConnection, 521 &connection ); 522 523 if ( status == kIOReturnSuccess ) 524 { 525 526 EmulatorTargetParamsStruct target; 527 EmulatorLUNParamsStruct lun; 528 size_t outCount = 0; 529 EmulatorSCSIInquiryPage80 page80 = gInquiryPage80Data; 530 EmulatorSCSIInquiryPage83 page83 = gInquiryPage83Data; 531 char serial[32]; 532 533 bzero ( &target, sizeof ( EmulatorTargetParamsStruct ) ); 534 bzero ( &lun, sizeof ( EmulatorLUNParamsStruct ) ); 535 536 lun.logicalUnit = logicalUnit; 537 lun.capacity = capacity; 538 539 lun.inquiryData = ( mach_vm_address_t ) ( uintptr_t ) &gInquiryData; 540 lun.inquiryPage00Data = ( mach_vm_address_t ) ( uintptr_t ) &gInquiryPage00Data; 541 lun.inquiryPage80Data = ( mach_vm_address_t ) ( uintptr_t ) &page80; 542 lun.inquiryPage83Data = ( mach_vm_address_t ) ( uintptr_t ) &page83; 543 544 lun.inquiryDataLength = sizeof ( gInquiryData ); 545 lun.inquiryPage00DataLength = sizeof ( gInquiryPage00Data ); 546 lun.inquiryPage80DataLength = sizeof ( page80 ); 547 lun.inquiryPage83DataLength = sizeof ( page83 ); 548 549 target.targetID = targetID; 550 target.lun = lun; 551 552 PRINT ( ( "lun.inquiryData = %p\n", &gInquiryData ) ); 553 PRINT ( ( "lun.inquiryData = %p\n", &gInquiryPage00Data ) ); 554 PRINT ( ( "lun.inquiryData = %p\n", &page80 ) ); 555 PRINT ( ( "lun.inquiryData = %p\n", &page83 ) ); 556 557 PRINT ( ( "gInquiryPage00Data = 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", 558 gInquiryPage00Data.header.PERIPHERAL_DEVICE_TYPE, 559 gInquiryPage00Data.header.PAGE_CODE, 560 gInquiryPage00Data.header.RESERVED, 561 gInquiryPage00Data.header.PAGE_LENGTH, 562 gInquiryPage00Data.data.page00, 563 gInquiryPage00Data.data.page80, 564 gInquiryPage00Data.data.page83 ) ); 565 566 PRINT ( ( "sizeof ( gInquiryData ) = %ld\n", sizeof ( gInquiryData ) ) ); 567 PRINT ( ( "sizeof ( gInquiryPage00Data ) = %ld\n", sizeof ( gInquiryPage00Data ) ) ); 568 PRINT ( ( "sizeof ( page80 ) = %ld\n", sizeof ( page80 ) ) ); 569 PRINT ( ( "sizeof ( page83 ) = %ld\n", sizeof ( page83 ) ) ); 570 PRINT ( ( "sizeof ( EmulatorTargetParamsStruct ) = %ld\n", sizeof ( EmulatorTargetParamsStruct ) ) ); 571 PRINT ( ( "sizeof ( EmulatorLUNParamsStruct ) = %ld\n", sizeof ( EmulatorLUNParamsStruct ) ) ); 572 573 // Fill in LUN information for page 80. 574 snprintf ( serial, 32, "APPLE Virtual LUN %qd", logicalUnit ); 575 bcopy ( serial, ( char * ) &page80.header.PRODUCT_SERIAL_NUMBER, 32 ); 576 577 if ( unique ) 578 { 579 580 int fd = -1; 581 char randomBytes[15]; 582 int amount; 583 584 // Get some random bytes from /dev/random. 585 fd = open ( "/dev/random", O_RDONLY, 0 ); 586 if ( fd == -1 ) 587 { 588 589 PRINT ( ( "Open /dev/random failed\n" ) ); 590 exit ( -1 ); 591 592 } 593 594 amount = read ( fd, randomBytes, sizeof ( randomBytes ) ); 595 if ( amount != sizeof ( randomBytes ) ) 596 { 597 598 PRINT ( ( "Reading from /dev/random failed\n" ) ); 599 exit ( -1 ); 600 601 } 602 603 // Make sure that the page 83 data is unique for this LUN. 604 bcopy ( randomBytes, page83.data.descriptor2bytes, sizeof ( page83.data.descriptor2bytes ) ); 605 606 close ( fd ); 607 608 } 609 610 IOConnectCallStructMethod ( 611 connection, 612 kUserClientCreateLUN, 613 &target, 614 sizeof ( EmulatorTargetParamsStruct ), 615 NULL, 616 &outCount ); 617 618 IOServiceClose ( connection ); 619 620 } 621 622 IOObjectRelease ( controller ); 623 624 } 625 626} 627 628 629//----------------------------------------------------------------------------- 630// DestroyTargetLUN - Destroys a Logical Unit attached to a target. 631//----------------------------------------------------------------------------- 632 633static void 634DestroyTargetLUN ( 635 SCSITargetIdentifier targetID, 636 SCSILogicalUnitNumber logicalUnit ) 637{ 638 639 io_object_t controller = IO_OBJECT_NULL; 640 641 PRINT ( ( "DestroyTargetLUN, targetID = %qd, logicalUnit = %qd\n", targetID, logicalUnit ) ); 642 643 controller = GetController ( ); 644 if ( controller != IO_OBJECT_NULL ) 645 { 646 647 io_connect_t connection = IO_OBJECT_NULL; 648 IOReturn status = kIOReturnSuccess; 649 650 status = IOServiceOpen ( 651 controller, 652 mach_task_self ( ), 653 kSCSIEmulatorAdapterUserClientConnection, 654 &connection ); 655 656 if ( status == kIOReturnSuccess ) 657 { 658 659 uint32_t outCount = 0; 660 uint64_t params[2]; 661 662 params[0] = targetID; 663 params[1] = logicalUnit; 664 665 IOConnectCallScalarMethod ( 666 connection, 667 kUserClientDestroyLUN, 668 ( const uint64_t * ) params, 669 2, 670 NULL, 671 &outCount ); 672 673 IOServiceClose ( connection ); 674 675 } 676 677 IOObjectRelease ( controller ); 678 679 } 680 681} 682 683 684//----------------------------------------------------------------------------- 685// DestroyTarget - Destroys a target. 686//----------------------------------------------------------------------------- 687 688static void 689DestroyTarget ( 690 SCSITargetIdentifier targetID ) 691{ 692 693 io_object_t controller = IO_OBJECT_NULL; 694 695 PRINT ( ( "DestroyTarget, targetID = %qd\n", targetID ) ); 696 697 controller = GetController ( ); 698 if ( controller != IO_OBJECT_NULL ) 699 { 700 701 io_connect_t connection = IO_OBJECT_NULL; 702 IOReturn status = kIOReturnSuccess; 703 704 status = IOServiceOpen ( 705 controller, 706 mach_task_self ( ), 707 kSCSIEmulatorAdapterUserClientConnection, 708 &connection ); 709 710 if ( status == kIOReturnSuccess ) 711 { 712 713 uint32_t outCount = 0; 714 uint64_t params[1]; 715 716 params[0] = targetID; 717 718 IOConnectCallScalarMethod ( 719 connection, 720 kUserClientDestroyTarget, 721 ( const uint64_t * ) params, 722 1, 723 NULL, 724 &outCount ); 725 726 IOServiceClose ( connection ); 727 728 } 729 730 IOObjectRelease ( controller ); 731 732 } 733 734} 735 736 737//----------------------------------------------------------------------------- 738// GetController - Gets the controller object. 739//----------------------------------------------------------------------------- 740 741static io_object_t 742GetController ( void ) 743{ 744 745 io_object_t controller = IO_OBJECT_NULL; 746 747 controller = IOServiceGetMatchingService ( 748 kIOMasterPortDefault, 749 IOServiceMatching ( kAppleSCSIEmulatorAdapterClassString ) ); 750 751 return controller; 752 753} 754 755 756//----------------------------------------------------------------------------- 757// ReportInventory - Reports the target/lun inventory 758//----------------------------------------------------------------------------- 759 760static void 761ReportInventory ( void ) 762{ 763 764 io_object_t controller = IO_OBJECT_NULL; 765 766 controller = GetController ( ); 767 if ( controller != IO_OBJECT_NULL ) 768 { 769 770 IOReturn result = kIOReturnSuccess; 771 io_iterator_t iterator = IO_OBJECT_NULL; 772 io_registry_entry_t child = IO_OBJECT_NULL; 773 774 PrintController ( controller ); 775 776 // Look for devices on this bus 777 result = IORegistryEntryCreateIterator ( controller, kIOServicePlane, kNilOptions, &iterator ); 778 if ( result != kIOReturnSuccess ) 779 { 780 goto ErrorExit; 781 } 782 783 child = IOIteratorNext ( iterator ); 784 785 while ( child != IO_OBJECT_NULL ) 786 { 787 788 if ( IOObjectConformsTo ( child, kIOSCSIParallelInterfaceDeviceString ) ) 789 { 790 791 io_iterator_t iterator2 = IO_OBJECT_NULL; 792 793 result = IORegistryEntryCreateIterator ( child, kIOServicePlane, kNilOptions, &iterator2 ); 794 if ( result == kIOReturnSuccess ) 795 { 796 797 io_registry_entry_t grandchild = IO_OBJECT_NULL; 798 799 grandchild = IOIteratorNext ( iterator2 ); 800 801 while ( grandchild != IO_OBJECT_NULL ) 802 { 803 804 if ( IOObjectConformsTo ( grandchild, kIOSCSITargetDeviceString ) ) 805 { 806 807 io_iterator_t iterator3 = IO_OBJECT_NULL; 808 809 PrintTarget ( grandchild ); 810 811 result = IORegistryEntryCreateIterator ( grandchild, kIOServicePlane, kNilOptions, &iterator3 ); 812 if ( result == kIOReturnSuccess ) 813 { 814 815 io_registry_entry_t greatgrandchild = IO_OBJECT_NULL; 816 817 greatgrandchild = IOIteratorNext ( iterator3 ); 818 819 while ( greatgrandchild != IO_OBJECT_NULL ) 820 { 821 822 if ( IOObjectConformsTo ( greatgrandchild, kIOSCSIHierarchicalLogicalUnitString ) ) 823 { 824 825 PrintLogicalUnit ( greatgrandchild ); 826 827 } 828 829 IOObjectRelease ( greatgrandchild ); 830 greatgrandchild = IOIteratorNext ( iterator3 ); 831 832 } 833 834 IOObjectRelease ( iterator3 ); 835 836 } 837 838 printf ( "-------------------------------------------------------------------------------\n" ); 839 840 } 841 842 IOObjectRelease ( grandchild ); 843 grandchild = IOIteratorNext ( iterator2 ); 844 845 } 846 847 IOObjectRelease ( iterator2 ); 848 849 } 850 851 } 852 853 IOObjectRelease ( child ); 854 child = IOIteratorNext ( iterator ); 855 856 } 857 858 IOObjectRelease ( iterator ); 859 860 } 861 862 else 863 { 864 865 printf ( "No AppleSCSIEmulatorAdapter class found, please make sure the kext is loaded and try again.\n" ); 866 867 } 868 869ErrorExit: 870 871 872 IOObjectRelease ( controller ); 873 874} 875 876 877//----------------------------------------------------------------------------- 878// PrintController - Dump controller information 879//----------------------------------------------------------------------------- 880 881static void 882PrintController ( io_object_t controller ) 883{ 884 885 CFNumberRef number; 886 CFDictionaryRef dict; 887 888 printf ( "Controller\n" ); 889 890 dict = ( CFDictionaryRef ) IORegistryEntrySearchCFProperty ( controller, kIOServicePlane, CFSTR ( kIOPropertyProtocolCharacteristicsKey ), kCFAllocatorDefault, kIORegistryIterateRecursively ); 891 if ( dict != NULL ) 892 { 893 894 number = ( CFNumberRef ) CFDictionaryGetValue ( dict, CFSTR ( kIOPropertySCSIDomainIdentifierKey ) ); 895 if ( number != NULL ) 896 { 897 898 int domain = 0; 899 900 CFNumberGetValue ( number, kCFNumberIntType, &domain ); 901 printf ( "\tDomain ID: %d\n", domain ); 902 903 } 904 905 CFRelease ( dict ); 906 dict = NULL; 907 908 } 909 910} 911 912 913//----------------------------------------------------------------------------- 914// PrintTarget - Dump target information 915//----------------------------------------------------------------------------- 916 917static void 918PrintTarget ( io_object_t target ) 919{ 920 921 SCSITargetIdentifier targetID = 0; 922 CFNumberRef number; 923 CFDictionaryRef dict; 924 925 printf ( "-------------------------------------------------------------------------------\n" ); 926 927 dict = ( CFDictionaryRef ) IORegistryEntrySearchCFProperty ( target, kIOServicePlane, CFSTR ( kIOPropertyProtocolCharacteristicsKey ), kCFAllocatorDefault, kIORegistryIterateRecursively ); 928 if ( dict != NULL ) 929 { 930 931 number = ( CFNumberRef ) CFDictionaryGetValue ( dict, CFSTR ( kIOPropertySCSITargetIdentifierKey ) ); 932 if ( number != NULL ) 933 { 934 935 CFNumberGetValue ( number, kCFNumberSInt64Type, &targetID ); 936 printf ( "\nTargetDevice@%qd\n", targetID ); 937 938 } 939 940 CFRelease ( dict ); 941 dict = NULL; 942 943 } 944 945} 946 947 948//----------------------------------------------------------------------------- 949// PrintLogicalUnit - Dump logical unit information 950//----------------------------------------------------------------------------- 951 952static void 953PrintLogicalUnit ( io_object_t logicalUnit ) 954{ 955 956 CFNumberRef number = NULL; 957 CFDictionaryRef dict = NULL; 958 CFStringRef string = NULL; 959 960 dict = ( CFDictionaryRef ) IORegistryEntrySearchCFProperty ( logicalUnit, kIOServicePlane, CFSTR ( kIOPropertyProtocolCharacteristicsKey ), kCFAllocatorDefault, kIORegistryIterateRecursively ); 961 if ( dict != NULL ) 962 { 963 964#if USE_LUN_BYTES 965 966 CFDataRef data = NULL; 967 968 data = ( CFDataRef ) CFDictionaryGetValue ( dict, CFSTR ( kIOPropertySCSILogicalUnitBytesKey ) ); 969 if ( data != NULL ) 970 { 971 972 const UInt8 * ptr = ( UInt8 * ) CFDataGetBytePtr ( data ); 973 printf ( "\nLogicalUnit: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", 974 ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7] ); 975 976 } 977 978#else 979 980 number = ( CFNumberRef ) CFDictionaryGetValue ( dict, CFSTR ( kIOPropertySCSILogicalUnitNumberKey ) ); 981 if ( number != NULL ) 982 { 983 984 UInt64 LUN = 0; 985 986 CFNumberGetValue ( number, kCFNumberLongLongType, &LUN ); 987 988 printf ( "\nLogicalUnit: 0x%qd\n", LUN ); 989 990 } 991 992#endif /* USE_LUN_BYTES */ 993 994 CFRelease ( dict ); 995 dict = NULL; 996 997 } 998 999 // Describe the device type 1000 string = ( CFStringRef ) IORegistryEntrySearchCFProperty ( logicalUnit, kIOServicePlane, CFSTR ( kIOPropertySCSIVendorIdentification ), kCFAllocatorDefault, kIORegistryIterateRecursively ); 1001 if ( string != NULL ) 1002 { 1003 1004 printf ( "\tVendor: %s\n", CFStringGetCStringPtr ( string, kCFStringEncodingMacRoman ) ); 1005 CFRelease ( string ); 1006 string = NULL; 1007 1008 } 1009 1010 // Describe the device type 1011 string = ( CFStringRef ) IORegistryEntrySearchCFProperty ( logicalUnit, kIOServicePlane, CFSTR ( kIOPropertySCSIProductIdentification ), kCFAllocatorDefault, kIORegistryIterateRecursively ); 1012 if ( string != NULL ) 1013 { 1014 1015 printf ( "\tProduct: %s\n", CFStringGetCStringPtr ( string, kCFStringEncodingMacRoman ) ); 1016 CFRelease ( string ); 1017 string = NULL; 1018 1019 } 1020 1021 // Describe the device type 1022 string = ( CFStringRef ) IORegistryEntrySearchCFProperty ( logicalUnit, kIOServicePlane, CFSTR ( kIOPropertySCSIProductRevisionLevel ), kCFAllocatorDefault, kIORegistryIterateRecursively ); 1023 if ( string != NULL ) 1024 { 1025 1026 printf ( "\tProduct Revision Level: %s\n", CFStringGetCStringPtr ( string, kCFStringEncodingMacRoman ) ); 1027 CFRelease ( string ); 1028 string = NULL; 1029 1030 } 1031 1032 1033 // Describe the device type 1034 number = ( CFNumberRef )IORegistryEntrySearchCFProperty ( logicalUnit, kIOServicePlane, CFSTR ( kIOPropertySCSIPeripheralDeviceType ), kCFAllocatorDefault, kIORegistryIterateRecursively ); 1035 if ( number != NULL ) 1036 { 1037 1038 int pdt = 0; 1039 1040 CFNumberGetValue ( number, kCFNumberIntType, &pdt ); 1041 printf ( "\tPeripheral Device Type: %d\n", pdt ); 1042 CFRelease ( number ); 1043 number = NULL; 1044 1045 } 1046 1047} 1048 1049 1050//----------------------------------------------------------------------------- 1051// PrintUsage - Prints usage string 1052//----------------------------------------------------------------------------- 1053 1054static void 1055PrintUsage ( void ) 1056{ 1057 1058 printf ( "Usage: emulator [--create, -c] [--destroy, -d] [--inventory, -i] [--target, -t] [--lun, -l] [--unique, -u] [--size, -s]\n" ); 1059 printf ( " --create and --destroy are mutually exclusive\n" ); 1060 printf ( " --target accepts targetIDs in the rang of [0...14][16...255]. ID 15 is reserved for the initiator.\n" ); 1061 printf ( " --lun accepts LUNs in the range of [1...16383] inclusive.\n" ); 1062 printf ( " --size can be in bytes, kilobytes, megabytes, or gigabytes, suffix usage similar to dd\n" ); 1063 printf ( " --unique is used to specify if the logical unit being created has a unique identifier in INQUIRY VPD Page 83h. If --unique is not used, the default (shared) INQUIRY VPD Page 83h identifier will be used\n" ); 1064 fflush ( stdout ); 1065 1066}