1/* 2 * SCSI_media.c - 3 * 4 * Written by Eryk Vershen 5 */ 6 7/* 8 * Copyright 1997,1998 by Apple Computer, Inc. 9 * All Rights Reserved 10 * 11 * Permission to use, copy, modify, and distribute this software and 12 * its documentation for any purpose and without fee is hereby granted, 13 * provided that the above copyright notice appears in all copies and 14 * that both the copyright notice and this permission notice appear in 15 * supporting documentation. 16 * 17 * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 18 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 19 * FOR A PARTICULAR PURPOSE. 20 * 21 * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 22 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 23 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 24 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 25 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 26 */ 27 28 29// for printf() & sprintf() 30#include <stdio.h> 31// for malloc() & free() 32#include <stdlib.h> 33#include "DoSCSICommand.h" 34#include "SCSI_media.h" 35#include "util.h" 36 37 38/* 39 * Defines 40 */ 41#define DriverRefNumToSCSI(x) ((signed short) (~(x) - 32)) 42 43 44/* 45 * Types 46 */ 47typedef struct SCSI_media *SCSI_MEDIA; 48 49struct SCSI_media { 50 struct media m; 51 long bus; 52 long id; 53}; 54 55struct bus_entry { 56 long bus; 57 long sort_value; 58 long max_id; 59 long master_id; 60}; 61 62struct SCSI_manager { 63 long exists; 64 long kind; 65 long bus_count; 66 struct bus_entry *bus_list; 67}; 68 69typedef struct SCSI_media_iterator *SCSI_MEDIA_ITERATOR; 70 71struct SCSI_media_iterator { 72 struct media_iterator m; 73 long bus_index; 74 long bus; 75 long id; 76}; 77 78struct linux_order_cache { 79 struct cache_item *first; 80 struct cache_item *last; 81 long next_disk; 82 long next_cdrom; 83 long loaded; 84}; 85 86struct cache_item { 87 struct cache_item *next; 88 long bus; 89 long id; 90 long value; 91 long is_cdrom; 92 long unsure; 93}; 94 95 96/* 97 * Global Constants 98 */ 99enum { 100 kNoDevice = 0x00FF 101}; 102 103enum { 104 kRequiredSCSIinquiryLength = 36 105}; 106 107 108/* 109 * Global Variables 110 */ 111static long scsi_inited = 0; 112static struct SCSI_manager scsi_mgr; 113static struct linux_order_cache linux_order; 114 115 116/* 117 * Forward declarations 118 */ 119int AsyncSCSIPresent(void); 120void scsi_init(void); 121SCSI_MEDIA new_scsi_media(void); 122long read_scsi_media(MEDIA m, long long offset, unsigned long count, void *address); 123long write_scsi_media(MEDIA m, long long offset, unsigned long count, void *address); 124long close_scsi_media(MEDIA m); 125long os_reload_scsi_media(MEDIA m); 126long compute_id(long bus, long device); 127int SCSI_ReadBlock(UInt32 id, UInt32 bus, UInt32 block_size, UInt32 block, UInt8 *address); 128int SCSI_WriteBlock(UInt32 id, UInt32 bus, UInt32 block_size, UInt32 block, UInt8 *address); 129int DoTestUnitReady(UInt8 targetID, int bus); 130int DoReadCapacity(UInt32 id, UInt32 bus, UInt32 *blockCount, UInt32 *blockSize); 131SCSI_MEDIA_ITERATOR new_scsi_iterator(void); 132void reset_scsi_iterator(MEDIA_ITERATOR m); 133char *step_scsi_iterator(MEDIA_ITERATOR m); 134void delete_scsi_iterator(MEDIA_ITERATOR m); 135void fill_bus_entry(struct bus_entry *entry, long bus); 136/*long get_bus_sort_value(long bus);*/ 137int bus_entry_compare(const void* a, const void* b); 138int DoInquiry(UInt32 id, UInt32 bus, UInt32 *devType); 139void probe_all(void); 140void probe_scsi_device(long bus, long id, int unsure); 141long lookup_scsi_device(long bus, long id, int *is_cdrom, int *unsure); 142long lookup_scsi_index(long index, int is_cdrom, long *bus, long *id); 143void add_to_cache(long bus, long id, int is_cdrom, int unsure); 144void init_linux_cache(void); 145void clear_linux_cache(void); 146void mark_linux_cache_loaded(void); 147int linux_cache_loaded(void); 148 149 150/* 151 * Routines 152 */ 153int 154AsyncSCSIPresent(void) 155{ 156 return (TrapAvailable(_SCSIAtomic)); 157} 158 159 160void 161scsi_init(void) 162{ 163 int i; 164 int old_scsi; 165 166 if (scsi_inited != 0) { 167 return; 168 } 169 scsi_inited = 1; 170 171 scsi_mgr.exists = 1; 172 scsi_mgr.kind = allocate_media_kind(); 173 174 if (AsyncSCSIPresent()) { 175 AllocatePB(); 176 177 scsi_mgr.bus_count = gSCSIHiBusID + 1; 178 old_scsi = 0; 179 } else { 180 scsi_mgr.bus_count = 1; 181 old_scsi = 1; 182 } 183 184 scsi_mgr.bus_list = (struct bus_entry *) 185 calloc(scsi_mgr.bus_count, sizeof(struct bus_entry)); 186 187 if (scsi_mgr.bus_list == 0) { 188 scsi_mgr.bus_count = 0; 189 } else { 190 for (i = 0; i < scsi_mgr.bus_count; i++) { 191 if (old_scsi) { 192 scsi_mgr.bus_list[i].bus = 0xFF; 193 } else { 194 scsi_mgr.bus_list[i].bus = i; 195 } 196 fill_bus_entry(&scsi_mgr.bus_list[i], i); 197 } 198 qsort((void *)scsi_mgr.bus_list, /* address of array */ 199 scsi_mgr.bus_count, /* number of elements */ 200 sizeof(struct bus_entry), /* size of element */ 201 bus_entry_compare); /* element comparison routine */ 202 } 203 204 init_linux_cache(); 205} 206 207void 208fill_bus_entry(struct bus_entry *entry, long bus) 209{ 210 OSErr status; 211 SCSIBusInquiryPB pb; 212 long len; 213 long result; 214 long x, y; 215 216 if (!AsyncSCSIPresent()) { 217 entry->sort_value = 0; 218 entry->max_id = 7; 219 entry->master_id = 7; 220 return; 221 } 222 len = sizeof(SCSIBusInquiryPB); 223 clear_memory((Ptr) &pb, len); 224 pb.scsiPBLength = len; 225 pb.scsiFunctionCode = SCSIBusInquiry; 226 pb.scsiDevice.bus = bus; 227 status = SCSIAction((SCSI_PB *) &pb); 228 if (status != noErr) { 229 result = 6; 230 } else { 231 switch (pb.scsiHBAslotType) { 232 case scsiMotherboardBus: x = 0; break; 233 case scsiPDSBus: x = 1; break; 234 case scsiNuBus: x = 2; break; 235 case scsiPCIBus: x = 3; break; 236 case scsiFireWireBridgeBus: x = 4; break; 237 case scsiPCMCIABus: x = 5; break; 238 default: x = 7 + pb.scsiHBAslotType; break; 239 }; 240 241 switch (pb.scsiFeatureFlags & scsiBusInternalExternalMask) { 242 case scsiBusInternal: y = 0; break; 243 case scsiBusInternalExternal: y = 1; break; 244 case scsiBusExternal: y = 2; break; 245 default: 246 case scsiBusInternalExternalUnknown: y = 3; break; 247 }; 248 result = x * 4 + y; 249 } 250 entry->sort_value = result; 251 entry->max_id = pb.scsiMaxLUN; 252 entry->master_id = pb.scsiInitiatorID; 253} 254 255 256int 257bus_entry_compare(const void* a, const void* b) 258{ 259 long result; 260 261 const struct bus_entry *x = (const struct bus_entry *) a; 262 const struct bus_entry *y = (const struct bus_entry *) b; 263 264 result = x->sort_value - y->sort_value; 265 if (result == 0) { 266 result = x->bus - y->bus; 267 } 268 return result; 269} 270 271 272SCSI_MEDIA 273new_scsi_media(void) 274{ 275 return (SCSI_MEDIA) new_media(sizeof(struct SCSI_media)); 276} 277 278 279MEDIA 280open_old_scsi_as_media(long device) 281{ 282 return open_scsi_as_media(kOriginalSCSIBusAdaptor, device); 283} 284 285 286MEDIA 287open_scsi_as_media(long bus, long device) 288{ 289 SCSI_MEDIA a; 290 UInt32 blockCount; 291 UInt32 blockSize; 292 293 if (scsi_inited == 0) { 294 scsi_init(); 295 } 296 297 if (scsi_mgr.exists == 0) { 298 return 0; 299 } 300 301 a = 0; 302 if (DoTestUnitReady(device, bus) > 0) { 303 if (DoReadCapacity(device, bus, &blockCount, &blockSize) != 0) { 304 a = new_scsi_media(); 305 if (a != 0) { 306 a->m.kind = scsi_mgr.kind; 307 a->m.grain = blockSize; 308 a->m.size_in_bytes = ((long long)blockCount) * blockSize; 309 a->m.do_read = read_scsi_media; 310 a->m.do_write = write_scsi_media; 311 a->m.do_close = close_scsi_media; 312 a->m.do_os_reload = os_reload_scsi_media; 313 a->bus = bus; 314 a->id = device; 315 } 316 } 317 } 318 return (MEDIA) a; 319} 320 321 322long 323read_scsi_media(MEDIA m, long long offset, unsigned long count, void *address) 324{ 325 SCSI_MEDIA a; 326 long rtn_value; 327 long block; 328 long block_count; 329 long block_size; 330 unsigned char *buffer; 331 int i; 332 333 block = (long) offset; 334//printf("scsi %d count %d\n", block, count); 335 a = (SCSI_MEDIA) m; 336 rtn_value = 0; 337 if (a == 0) { 338 /* no media */ 339 } else if (a->m.kind != scsi_mgr.kind) { 340 /* wrong kind - XXX need to error here - this is an internal problem */ 341 } else if (count <= 0 || count % a->m.grain != 0) { 342 /* can't handle size */ 343 } else if (offset < 0 || offset % a->m.grain != 0) { 344 /* can't handle offset */ 345 } else if (offset + count > a->m.size_in_bytes) { 346 /* check for offset (and offset+count) too large */ 347 } else { 348 /* XXX do a read on the physical device */ 349 block_size = a->m.grain; 350 block = offset / block_size; 351 block_count = count / block_size; 352 buffer = address; 353 rtn_value = 1; 354 for (i = 0; i < block_count; i++) { 355 if (SCSI_ReadBlock(a->id, a->bus, block_size, block, buffer) == 0) { 356 rtn_value = 0; 357 break; 358 } 359 buffer += block_size; 360 block += 1; 361 } 362 } 363 return rtn_value; 364} 365 366 367long 368write_scsi_media(MEDIA m, long long offset, unsigned long count, void *address) 369{ 370 SCSI_MEDIA a; 371 long rtn_value; 372 long block; 373 long block_count; 374 long block_size; 375 unsigned char *buffer; 376 int i; 377 378 a = (SCSI_MEDIA) m; 379 rtn_value = 0; 380 if (a == 0) { 381 /* no media */ 382 } else if (a->m.kind != scsi_mgr.kind) { 383 /* XXX need to error here - this is an internal problem */ 384 } else if (count <= 0 || count % a->m.grain != 0) { 385 /* can't handle size */ 386 } else if (offset < 0 || offset % a->m.grain != 0) { 387 /* can't handle offset */ 388 } else if (offset + count > a->m.size_in_bytes) { 389 /* check for offset (and offset+count) too large */ 390 } else { 391 /* XXX do a write on the physical device */ 392 block_size = a->m.grain; 393 block = offset / block_size; 394 block_count = count / block_size; 395 buffer = address; 396 rtn_value = 1; 397 for (i = 0; i < block_count; i++) { 398 if (SCSI_WriteBlock(a->id, a->bus, block_size, block, buffer) == 0) { 399 rtn_value = 0; 400 break; 401 } 402 buffer += block_size; 403 block += 1; 404 } 405 } 406 return rtn_value; 407} 408 409 410long 411close_scsi_media(MEDIA m) 412{ 413 SCSI_MEDIA a; 414 415 a = (SCSI_MEDIA) m; 416 if (a == 0) { 417 return 0; 418 } else if (a->m.kind != scsi_mgr.kind) { 419 /* XXX need to error here - this is an internal problem */ 420 return 0; 421 } 422 /* XXX nothing to do - I think? */ 423 return 1; 424} 425 426 427long 428os_reload_scsi_media(MEDIA m) 429{ 430 printf("Reboot your system so the partition table will be reread.\n"); 431 return 1; 432} 433 434 435#pragma mark - 436 437 438int 439DoTestUnitReady(UInt8 targetID, int bus) 440{ 441 OSErr status; 442 Str255 errorText; 443 char* msg; 444 static const SCSI_6_Byte_Command gTestUnitReadyCommand = { 445 kScsiCmdTestUnitReady, 0, 0, 0, 0, 0 446 }; 447 SCSI_Sense_Data senseData; 448 DeviceIdent scsiDevice; 449 int rtn_value; 450 451 scsiDevice.diReserved = 0; 452 scsiDevice.bus = bus; 453 scsiDevice.targetID = targetID; 454 scsiDevice.LUN = 0; 455 456 status = DoSCSICommand( 457 scsiDevice, 458 "\pTest Unit Ready", 459 (SCSI_CommandPtr) &gTestUnitReadyCommand, 460 NULL, 461 0, 462 scsiDirectionNone, 463 NULL, 464 &senseData, 465 errorText 466 ); 467 if (status == scsiNonZeroStatus) { 468 rtn_value = -1; 469 } else if (status != noErr) { 470 rtn_value = 0; 471 } else { 472 rtn_value = 1; 473 } 474 return rtn_value; 475} 476 477 478int 479SCSI_ReadBlock(UInt32 id, UInt32 bus, UInt32 block_size, UInt32 block, UInt8 *address) 480{ 481 OSErr status; 482 Str255 errorText; 483 char* msg; 484 static SCSI_10_Byte_Command gReadCommand = { 485 kScsiCmdRead10, 0, 0, 0, 0, 0, 0, 0, 0, 0 486 }; 487 SCSI_Sense_Data senseData; 488 DeviceIdent scsiDevice; 489 int rtn_value; 490 long count; 491 492//printf("scsi read %d:%d block %d size %d\n", bus, id, block, block_size); 493 scsiDevice.diReserved = 0; 494 scsiDevice.bus = bus; 495 scsiDevice.targetID = id; 496 scsiDevice.LUN = 0; 497 498 gReadCommand.lbn4 = (block >> 24) & 0xFF; 499 gReadCommand.lbn3 = (block >> 16) & 0xFF; 500 gReadCommand.lbn2 = (block >> 8) & 0xFF; 501 gReadCommand.lbn1 = block & 0xFF; 502 503 count = 1; 504 gReadCommand.len2 = (count >> 8) & 0xFF; 505 gReadCommand.len1 = count & 0xFF; 506 507 status = DoSCSICommand( 508 scsiDevice, 509 "\pRead", 510 (SCSI_CommandPtr) &gReadCommand, 511 (Ptr) address, 512 count * block_size, 513 scsiDirectionIn, 514 NULL, 515 &senseData, 516 errorText 517 ); 518 if (status == noErr) { 519 rtn_value = 1; 520 } else { 521 rtn_value = 0; 522 } 523 return rtn_value; 524} 525 526 527int 528SCSI_WriteBlock(UInt32 id, UInt32 bus, UInt32 block_size, UInt32 block, UInt8 *address) 529{ 530 OSErr status; 531 Str255 errorText; 532 char* msg; 533 static SCSI_10_Byte_Command gWriteCommand = { 534 kScsiCmdWrite10, 0, 0, 0, 0, 0, 0, 0, 0, 0 535 }; 536 SCSI_Sense_Data senseData; 537 DeviceIdent scsiDevice; 538 int rtn_value; 539 long count; 540 541 scsiDevice.diReserved = 0; 542 scsiDevice.bus = bus; 543 scsiDevice.targetID = id; 544 scsiDevice.LUN = 0; 545 546 gWriteCommand.lbn4 = (block >> 24) & 0xFF; 547 gWriteCommand.lbn3 = (block >> 16) & 0xFF; 548 gWriteCommand.lbn2 = (block >> 8) & 0xFF; 549 gWriteCommand.lbn1 = block & 0xFF; 550 551 count = 1; 552 gWriteCommand.len2 = (count >> 8) & 0xFF; 553 gWriteCommand.len1 = count & 0xFF; 554 555 status = DoSCSICommand( 556 scsiDevice, 557 "\pWrite", 558 (SCSI_CommandPtr) &gWriteCommand, 559 (Ptr) address, 560 count * block_size, 561 scsiDirectionOut, 562 NULL, 563 &senseData, 564 errorText 565 ); 566 if (status == noErr) { 567 rtn_value = 1; 568 } else { 569 rtn_value = 0; 570 } 571 return rtn_value; 572} 573 574 575int 576DoReadCapacity(UInt32 id, UInt32 bus, UInt32 *blockCount, UInt32 *blockSize) 577{ 578 OSErr status; 579 Str255 errorText; 580 static const SCSI_10_Byte_Command gCapacityCommand = { 581 kScsiCmdReadCapacity, 0, 0, 0, 0, 0, 0, 0, 0, 0 582 }; 583 SCSI_Sense_Data senseData; 584 DeviceIdent scsiDevice; 585 SCSI_Capacity_Data capacityData; 586 UInt32 temp; 587 int rtn_value; 588 589 scsiDevice.diReserved = 0; 590 scsiDevice.bus = bus; 591 scsiDevice.targetID = id; 592 scsiDevice.LUN = 0; 593 594 CLEAR(capacityData); 595 596 status = DoSCSICommand( 597 scsiDevice, 598 "\pRead Capacity", 599 (SCSI_CommandPtr) &gCapacityCommand, 600 (Ptr) &capacityData, 601 sizeof (SCSI_Capacity_Data), 602 scsiDirectionIn, 603 NULL, 604 &senseData, 605 errorText 606 ); 607 608 if (status == noErr) { 609 temp = capacityData.lbn4; 610 temp = (temp << 8) | capacityData.lbn3; 611 temp = (temp << 8) | capacityData.lbn2; 612 temp = (temp << 8) | capacityData.lbn1; 613 *blockCount = temp; 614 615 temp = capacityData.len4; 616 temp = (temp << 8) | capacityData.len3; 617 temp = (temp << 8) | capacityData.len2; 618 temp = (temp << 8) | capacityData.len1; 619 *blockSize = temp; 620 621 rtn_value = 1; 622 } else { 623 rtn_value = 0; 624 } 625 return rtn_value; 626} 627 628 629int 630DoInquiry(UInt32 id, UInt32 bus, UInt32 *devType) 631{ 632 OSErr status; 633 Str255 errorText; 634 static const SCSI_6_Byte_Command gInquiryCommand = { 635 kScsiCmdInquiry, 0, 0, 0, kRequiredSCSIinquiryLength, 0 636 }; 637 SCSI_Sense_Data senseData; 638 DeviceIdent scsiDevice; 639 SCSI_Inquiry_Data inquiryData; 640 UInt32 temp; 641 int rtn_value; 642 643 scsiDevice.diReserved = 0; 644 scsiDevice.bus = bus; 645 scsiDevice.targetID = id; 646 scsiDevice.LUN = 0; 647 648 CLEAR(inquiryData); 649 650 status = DoSCSICommand( 651 scsiDevice, 652 "\pInquiry", 653 (SCSI_CommandPtr) &gInquiryCommand, 654 (Ptr) &inquiryData, 655 kRequiredSCSIinquiryLength, 656 scsiDirectionIn, 657 NULL, 658 &senseData, 659 errorText 660 ); 661 662 if (status == noErr) { 663 *devType = inquiryData.devType & kScsiDevTypeMask; 664 rtn_value = 1; 665 } else { 666 rtn_value = 0; 667 } 668 return rtn_value; 669} 670 671 672MEDIA 673SCSI_FindDevice(long dRefNum) 674{ 675 SCSIDriverPB pb; 676 OSErr status; 677 short targetID; 678 679 status = nsvErr; 680 if (AsyncSCSIPresent()) { 681 clear_memory((Ptr) &pb, sizeof pb); 682 683 pb.scsiPBLength = sizeof (SCSIDriverPB); 684 pb.scsiCompletion = NULL; 685 pb.scsiFlags = 0; 686 pb.scsiFunctionCode = SCSILookupRefNumXref; 687 pb.scsiDevice.bus = kNoDevice; /* was *((long *) &pb.scsiDevice) = 0xFFFFFFFFL; */ 688 689 do { 690 status = SCSIAction((SCSI_PB *) &pb); 691 692 if (status != noErr) { 693 break; 694 } else if (pb.scsiDriver == dRefNum 695 && pb.scsiDevice.bus != kNoDevice) { 696 return open_scsi_as_media(pb.scsiDevice.bus, pb.scsiDevice.targetID); 697 698 } else { 699 pb.scsiDevice = pb.scsiNextDevice; 700 } 701 } 702 while (pb.scsiDevice.bus != kNoDevice); 703 } 704 if (status == nsvErr) { 705 /* 706 * The asynchronous SCSI Manager is missing or the 707 * driver didn't register with the SCSI Manager.*/ 708 targetID = DriverRefNumToSCSI(dRefNum); 709 if (targetID >= 0 && targetID <= 6) { 710 return open_old_scsi_as_media(targetID); 711 } 712 } 713 return 0; 714} 715 716 717#pragma mark - 718 719 720SCSI_MEDIA_ITERATOR 721new_scsi_iterator(void) 722{ 723 return (SCSI_MEDIA_ITERATOR) new_media_iterator(sizeof(struct SCSI_media_iterator)); 724} 725 726 727MEDIA_ITERATOR 728create_scsi_iterator(void) 729{ 730 SCSI_MEDIA_ITERATOR a; 731 732 if (scsi_inited == 0) { 733 scsi_init(); 734 } 735 736 if (scsi_mgr.exists == 0) { 737 return 0; 738 } 739 740 a = new_scsi_iterator(); 741 if (a != 0) { 742 a->m.kind = scsi_mgr.kind; 743 a->m.state = kInit; 744 a->m.do_reset = reset_scsi_iterator; 745 a->m.do_step = step_scsi_iterator; 746 a->m.do_delete = delete_scsi_iterator; 747 a->bus_index = 0; 748 a->bus = 0; 749 a->id = 0; 750 } 751 752 return (MEDIA_ITERATOR) a; 753} 754 755 756void 757reset_scsi_iterator(MEDIA_ITERATOR m) 758{ 759 SCSI_MEDIA_ITERATOR a; 760 761 a = (SCSI_MEDIA_ITERATOR) m; 762 if (a == 0) { 763 /* no media */ 764 } else if (a->m.kind != scsi_mgr.kind) { 765 /* wrong kind - XXX need to error here - this is an internal problem */ 766 } else if (a->m.state != kInit) { 767 a->m.state = kReset; 768 } 769} 770 771 772char * 773step_scsi_iterator(MEDIA_ITERATOR m) 774{ 775 SCSI_MEDIA_ITERATOR a; 776 char *result; 777 778 a = (SCSI_MEDIA_ITERATOR) m; 779 if (a == 0) { 780 /* no media */ 781 } else if (a->m.kind != scsi_mgr.kind) { 782 /* wrong kind - XXX need to error here - this is an internal problem */ 783 } else { 784 switch (a->m.state) { 785 case kInit: 786 /* find # of buses - done in AllocatePB() out of scsi_init() */ 787 a->m.state = kReset; 788 /* fall through to reset */ 789 case kReset: 790 a->bus_index = 0 /* first bus id */; 791 a->bus = scsi_mgr.bus_list[a->bus_index].bus; 792 a->id = 0 /* first device id */; 793 a->m.state = kIterating; 794 clear_linux_cache(); 795 /* fall through to iterate */ 796 case kIterating: 797 while (1) { 798 if (a->bus_index >= scsi_mgr.bus_count /* max bus id */) { 799 break; 800 } 801 if (a->id == scsi_mgr.bus_list[a->bus_index].master_id) { 802 /* next id */ 803 a->id += 1; 804 } 805 if (a->id > scsi_mgr.bus_list[a->bus_index].max_id) { 806 a->bus_index += 1; 807 a->bus = scsi_mgr.bus_list[a->bus_index].bus; 808 a->id = 0 /* first device id */; 809 continue; /* try again */ 810 } 811 /* generate result */ 812 result = (char *) malloc(20); 813 if (result != NULL) { 814 if (a->bus == 0xFF) { 815 snprintf(result, 20, "/dev/scsi%c", '0'+a->id); 816 probe_scsi_device(a->bus, a->id, 1); 817 } else { 818 // insure bus number in range 819 if (a->bus > 9) { 820 free(result); 821 result = NULL; 822 break; 823 } 824 snprintf(result, 20, "/dev/scsi%c.%c", 825 '0'+a->bus, '0'+a->id); 826 /* only probe out of iterate; so always added in order. */ 827 probe_scsi_device(a->bus, a->id, 0); 828 } 829 } 830 831 a->id += 1; /* next id */ 832 return result; 833 } 834 a->m.state = kEnd; 835 /* fall through to end */ 836 case kEnd: 837 mark_linux_cache_loaded(); 838 default: 839 break; 840 } 841 } 842 return 0 /* no entry */; 843} 844 845 846void 847delete_scsi_iterator(MEDIA_ITERATOR m) 848{ 849 return; 850} 851 852 853#pragma mark - 854 855 856MEDIA 857open_linux_scsi_as_media(long index, int is_cdrom) 858{ 859 MEDIA m; 860 long bus; 861 long id; 862 863 if (lookup_scsi_index(index, is_cdrom, &bus, &id) > 0) { 864 m = open_scsi_as_media(bus, id); 865 } else { 866 m = 0; 867 } 868 869 return m; 870} 871 872 873char * 874linux_old_scsi_name(long id) 875{ 876 linux_scsi_name(kOriginalSCSIBusAdaptor, id); 877} 878 879 880char * 881linux_scsi_name(long bus, long id) 882{ 883 char *result = 0; 884 long value; 885 int is_cdrom; 886 int unsure; 887 char *suffix; 888 889 /* name is sda, sdb, sdc, ... 890 * in order by buses and ids, but only count responding devices ... 891 */ 892 if ((value = lookup_scsi_device(bus, id, &is_cdrom, &unsure)) >= 0) { 893 result = (char *) malloc(20); 894 if (result != NULL) { 895 if (unsure) { 896 suffix = " ?"; 897 } else { 898 suffix = ""; 899 } 900 if (is_cdrom) { 901 if (value > 9) { 902 // too many CD's, give up 903 free(result); result = NULL; 904 } else { 905 snprintf(result, 20, "/dev/scd%c%s", '0' + value, suffix); 906 } 907 } else { 908 if (value < 26) { 909 snprintf(result, 20, "/dev/sd%c%s", 'a' + value, suffix); 910 } else { 911 snprintf(result, 20, "/dev/sd%c%c%s", 912 'a' + value / 26, 'a' + value % 26, suffix); 913 } 914 } 915 } 916 } 917 return result; 918} 919 920 921void 922probe_all(void) 923{ 924 MEDIA_ITERATOR iter; 925 char *name; 926 927 iter = create_scsi_iterator(); 928 if (iter == 0) { 929 return; 930 } 931 932 printf("finding devices "); 933 fflush(stdout); 934 while ((name = step_media_iterator(iter)) != 0) { 935 /* step does the probe for us */ 936 printf("."); 937 fflush(stdout); 938 free(name); 939 } 940 delete_media_iterator(iter); 941 printf("\n"); 942 fflush(stdout); 943} 944 945 946void 947probe_scsi_device(long bus, long id, int unsure) 948{ 949 UInt32 devType; 950 951 if (DoInquiry(id, bus, &devType)) { 952 if (devType == kScsiDevTypeDirect 953 || devType == kScsiDevTypeOptical) { 954 add_to_cache(bus, id, 0, unsure); 955 } else if (devType == kScsiDevTypeCDROM 956 || devType == kScsiDevTypeWorm) { 957 add_to_cache(bus, id, 1, unsure); 958 } 959 } 960} 961 962 963long 964lookup_scsi_device(long bus, long id, int *is_cdrom, int *unsure) 965{ 966 /* walk down list looking for bus and id ? 967 * 968 * only probe out of iterate (so always add in order) 969 * reset list if we reset the iterate 970 */ 971 struct cache_item *item; 972 struct cache_item *next; 973 long result = -1; 974 int count = 0; 975 976 if (scsi_inited == 0) { 977 scsi_init(); 978 } 979 980 while (1) { 981 count++; 982 for (item = linux_order.first; item != NULL; item = item->next) { 983 if (item->bus == bus && item->id == id) { 984 result = item->value; 985 *is_cdrom = item->is_cdrom; 986 *unsure = item->unsure; 987 break; 988 } 989 } 990 if (count < 2 && result < 0) { 991 probe_all(); 992 } else { 993 break; 994 } 995 }; 996 997 return result; 998} 999 1000 1001/* 1002 * This has the same structure as lookup_scsi_device() except we are 1003 * matching on the value & type rather than the bus & id. 1004 */ 1005long 1006lookup_scsi_index(long index, int is_cdrom, long *bus, long *id) 1007{ 1008 struct cache_item *item; 1009 struct cache_item *next; 1010 long result = 0; 1011 int count = 0; 1012 1013 if (scsi_inited == 0) { 1014 scsi_init(); 1015 } 1016 1017 while (1) { 1018 count++; 1019 for (item = linux_order.first; item != NULL; item = item->next) { 1020 if (item->value == index && item->is_cdrom == is_cdrom 1021 && item->unsure == 0) { 1022 result = 1; 1023 *bus = item->bus; 1024 *id = item->id; 1025 break; 1026 } 1027 } 1028 if (count < 2 && result == 0 && !linux_cache_loaded()) { 1029 probe_all(); 1030 } else { 1031 break; 1032 } 1033 }; 1034 1035 return result; 1036} 1037 1038 1039void 1040add_to_cache(long bus, long id, int is_cdrom, int unsure) 1041{ 1042 struct cache_item *item; 1043 1044 item = malloc(sizeof(struct cache_item)); 1045 if (item == NULL) { 1046 return; 1047 } else { 1048 item->bus = bus; 1049 item->id = id; 1050 item->is_cdrom = is_cdrom; 1051 item->unsure = unsure; 1052 if (is_cdrom) { 1053 item->value = linux_order.next_cdrom; 1054 linux_order.next_cdrom++; 1055 } else { 1056 item->value = linux_order.next_disk; 1057 linux_order.next_disk++; 1058 } 1059 item->next = 0; 1060 } 1061 if (linux_order.first == NULL) { 1062 linux_order.first = item; 1063 linux_order.last = item; 1064 } else { 1065 linux_order.last->next = item; 1066 linux_order.last = item; 1067 } 1068} 1069 1070 1071void 1072init_linux_cache(void) 1073{ 1074 linux_order.first = NULL; 1075 clear_linux_cache(); 1076} 1077 1078 1079void 1080clear_linux_cache(void) 1081{ 1082 struct cache_item *item; 1083 struct cache_item *next; 1084 1085 for (item = linux_order.first; item != NULL; item = next) { 1086 next = item->next; 1087 free(item); 1088 } 1089 /* back to starting value */ 1090 linux_order.first = NULL; 1091 linux_order.last = NULL; 1092 linux_order.next_disk = 0; 1093 linux_order.next_cdrom = 0; 1094 linux_order.loaded = 0; 1095} 1096 1097 1098void 1099mark_linux_cache_loaded(void) 1100{ 1101 linux_order.loaded = 1; 1102} 1103 1104 1105int 1106linux_cache_loaded(void) 1107{ 1108 return linux_order.loaded; 1109} 1110