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) ((int16_t) (~(x) - 32))
42
43
44 /*
45 * Types
46 */
47 typedef struct SCSI_media *SCSI_MEDIA;
48
49 struct SCSI_media {
50 struct media m;
51 long bus;
52 long id;
53 };
54
55 struct bus_entry {
56 long bus;
57 long sort_value;
58 long max_id;
59 long master_id;
60 };
61
62 struct SCSI_manager {
63 long exists;
64 long kind;
65 long bus_count;
66 struct bus_entry *bus_list;
67 };
68
69 typedef struct SCSI_media_iterator *SCSI_MEDIA_ITERATOR;
70
71 struct SCSI_media_iterator {
72 struct media_iterator m;
73 long bus_index;
74 long bus;
75 long id;
76 };
77
78 struct 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
86 struct 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 */
99 enum {
100 kNoDevice = 0x00FF
101 };
102
103 enum {
104 kRequiredSCSIinquiryLength = 36
105 };
106
107
108 /*
109 * Global Variables
110 */
111 static long scsi_inited = 0;
112 static struct SCSI_manager scsi_mgr;
113 static struct linux_order_cache linux_order;
114
115
116 /*
117 * Forward declarations
118 */
119 int AsyncSCSIPresent(void);
120 void scsi_init(void);
121 SCSI_MEDIA new_scsi_media(void);
122 long read_scsi_media(MEDIA m, long long offset, uint32_t count, void *address);
123 long write_scsi_media(MEDIA m, long long offset, uint32_t count, void *address);
124 long close_scsi_media(MEDIA m);
125 long os_reload_scsi_media(MEDIA m);
126 long compute_id(long bus, long device);
127 int SCSI_ReadBlock(UInt32 id, UInt32 bus, UInt32 block_size, UInt32 block, UInt8 *address);
128 int SCSI_WriteBlock(UInt32 id, UInt32 bus, UInt32 block_size, UInt32 block, UInt8 *address);
129 int DoTestUnitReady(UInt8 targetID, int bus);
130 int DoReadCapacity(UInt32 id, UInt32 bus, UInt32 *blockCount, UInt32 *blockSize);
131 SCSI_MEDIA_ITERATOR new_scsi_iterator(void);
132 void reset_scsi_iterator(MEDIA_ITERATOR m);
133 char *step_scsi_iterator(MEDIA_ITERATOR m);
134 void delete_scsi_iterator(MEDIA_ITERATOR m);
135 void fill_bus_entry(struct bus_entry *entry, long bus);
136 /*long get_bus_sort_value(long bus);*/
137 int bus_entry_compare(const void* a, const void* b);
138 int DoInquiry(UInt32 id, UInt32 bus, UInt32 *devType);
139 void probe_all(void);
140 void probe_scsi_device(long bus, long id, int unsure);
141 long lookup_scsi_device(long bus, long id, int *is_cdrom, int *unsure);
142 long lookup_scsi_index(long index, int is_cdrom, long *bus, long *id);
143 void add_to_cache(long bus, long id, int is_cdrom, int unsure);
144 void init_linux_cache(void);
145 void clear_linux_cache(void);
146 void mark_linux_cache_loaded(void);
147 int linux_cache_loaded(void);
148
149
150 /*
151 * Routines
152 */
153 int
AsyncSCSIPresent(void)154 AsyncSCSIPresent(void)
155 {
156 return (TrapAvailable(_SCSIAtomic));
157 }
158
159
160 void
scsi_init(void)161 scsi_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
207 void
fill_bus_entry(struct bus_entry * entry,long bus)208 fill_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
256 int
bus_entry_compare(const void * a,const void * b)257 bus_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
272 SCSI_MEDIA
new_scsi_media(void)273 new_scsi_media(void)
274 {
275 return (SCSI_MEDIA) new_media(sizeof(struct SCSI_media));
276 }
277
278
279 MEDIA
open_old_scsi_as_media(long device)280 open_old_scsi_as_media(long device)
281 {
282 return open_scsi_as_media(kOriginalSCSIBusAdaptor, device);
283 }
284
285
286 MEDIA
open_scsi_as_media(long bus,long device)287 open_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
322 long
read_scsi_media(MEDIA m,long long offset,uint32_t count,void * address)323 read_scsi_media(MEDIA m, long long offset, uint32_t count, void *address)
324 {
325 SCSI_MEDIA a;
326 long rtn_value;
327 long block;
328 long block_count;
329 long block_size;
330 uint8_t *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
367 long
write_scsi_media(MEDIA m,long long offset,uint32_t count,void * address)368 write_scsi_media(MEDIA m, long long offset, uint32_t count, void *address)
369 {
370 SCSI_MEDIA a;
371 long rtn_value;
372 long block;
373 long block_count;
374 long block_size;
375 uint8_t *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
410 long
close_scsi_media(MEDIA m)411 close_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
427 long
os_reload_scsi_media(MEDIA m)428 os_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
438 int
DoTestUnitReady(UInt8 targetID,int bus)439 DoTestUnitReady(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
478 int
SCSI_ReadBlock(UInt32 id,UInt32 bus,UInt32 block_size,UInt32 block,UInt8 * address)479 SCSI_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
527 int
SCSI_WriteBlock(UInt32 id,UInt32 bus,UInt32 block_size,UInt32 block,UInt8 * address)528 SCSI_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
575 int
DoReadCapacity(UInt32 id,UInt32 bus,UInt32 * blockCount,UInt32 * blockSize)576 DoReadCapacity(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
629 int
DoInquiry(UInt32 id,UInt32 bus,UInt32 * devType)630 DoInquiry(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
672 MEDIA
SCSI_FindDevice(long dRefNum)673 SCSI_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
720 SCSI_MEDIA_ITERATOR
new_scsi_iterator(void)721 new_scsi_iterator(void)
722 {
723 return (SCSI_MEDIA_ITERATOR) new_media_iterator(sizeof(struct SCSI_media_iterator));
724 }
725
726
727 MEDIA_ITERATOR
create_scsi_iterator(void)728 create_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
756 void
reset_scsi_iterator(MEDIA_ITERATOR m)757 reset_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
772 char *
step_scsi_iterator(MEDIA_ITERATOR m)773 step_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
846 void
delete_scsi_iterator(MEDIA_ITERATOR m)847 delete_scsi_iterator(MEDIA_ITERATOR m)
848 {
849 return;
850 }
851
852
853 #pragma mark -
854
855
856 MEDIA
open_linux_scsi_as_media(long index,int is_cdrom)857 open_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
873 char *
linux_old_scsi_name(long id)874 linux_old_scsi_name(long id)
875 {
876 linux_scsi_name(kOriginalSCSIBusAdaptor, id);
877 }
878
879
880 char *
linux_scsi_name(long bus,long id)881 linux_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
921 void
probe_all(void)922 probe_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
946 void
probe_scsi_device(long bus,long id,int unsure)947 probe_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
963 long
lookup_scsi_device(long bus,long id,int * is_cdrom,int * unsure)964 lookup_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 */
1005 long
lookup_scsi_index(long index,int is_cdrom,long * bus,long * id)1006 lookup_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
1039 void
add_to_cache(long bus,long id,int is_cdrom,int unsure)1040 add_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
1071 void
init_linux_cache(void)1072 init_linux_cache(void)
1073 {
1074 linux_order.first = NULL;
1075 clear_linux_cache();
1076 }
1077
1078
1079 void
clear_linux_cache(void)1080 clear_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
1098 void
mark_linux_cache_loaded(void)1099 mark_linux_cache_loaded(void)
1100 {
1101 linux_order.loaded = 1;
1102 }
1103
1104
1105 int
linux_cache_loaded(void)1106 linux_cache_loaded(void)
1107 {
1108 return linux_order.loaded;
1109 }
1110