xref: /netbsd-src/external/bsd/pdisk/dist/SCSI_media.c (revision 48a628ae0434c4247b560ad8f2eb1dc06d0dd070)
19428323dSchristos /*
29428323dSchristos  * SCSI_media.c -
39428323dSchristos  *
49428323dSchristos  * Written by Eryk Vershen
59428323dSchristos  */
69428323dSchristos 
79428323dSchristos /*
89428323dSchristos  * Copyright 1997,1998 by Apple Computer, Inc.
99428323dSchristos  *              All Rights Reserved
109428323dSchristos  *
119428323dSchristos  * Permission to use, copy, modify, and distribute this software and
129428323dSchristos  * its documentation for any purpose and without fee is hereby granted,
139428323dSchristos  * provided that the above copyright notice appears in all copies and
149428323dSchristos  * that both the copyright notice and this permission notice appear in
159428323dSchristos  * supporting documentation.
169428323dSchristos  *
179428323dSchristos  * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
189428323dSchristos  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
199428323dSchristos  * FOR A PARTICULAR PURPOSE.
209428323dSchristos  *
219428323dSchristos  * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
229428323dSchristos  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
239428323dSchristos  * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
249428323dSchristos  * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
259428323dSchristos  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
269428323dSchristos  */
279428323dSchristos 
289428323dSchristos 
299428323dSchristos // for printf() & sprintf()
309428323dSchristos #include <stdio.h>
319428323dSchristos // for malloc() & free()
329428323dSchristos #include <stdlib.h>
339428323dSchristos #include "DoSCSICommand.h"
349428323dSchristos #include "SCSI_media.h"
359428323dSchristos #include "util.h"
369428323dSchristos 
379428323dSchristos 
389428323dSchristos /*
399428323dSchristos  * Defines
409428323dSchristos  */
41*48a628aeSchristos #define DriverRefNumToSCSI(x)  ((int16_t) (~(x) - 32))
429428323dSchristos 
439428323dSchristos 
449428323dSchristos /*
459428323dSchristos  * Types
469428323dSchristos  */
479428323dSchristos typedef struct SCSI_media *SCSI_MEDIA;
489428323dSchristos 
499428323dSchristos struct SCSI_media {
509428323dSchristos     struct media    m;
519428323dSchristos     long            bus;
529428323dSchristos     long            id;
539428323dSchristos };
549428323dSchristos 
559428323dSchristos struct bus_entry {
569428323dSchristos     long    bus;
579428323dSchristos     long    sort_value;
589428323dSchristos     long    max_id;
599428323dSchristos     long    master_id;
609428323dSchristos };
619428323dSchristos 
629428323dSchristos struct SCSI_manager {
639428323dSchristos     long        exists;
649428323dSchristos     long        kind;
659428323dSchristos     long        bus_count;
669428323dSchristos     struct bus_entry *bus_list;
679428323dSchristos };
689428323dSchristos 
699428323dSchristos typedef struct SCSI_media_iterator *SCSI_MEDIA_ITERATOR;
709428323dSchristos 
719428323dSchristos struct SCSI_media_iterator {
729428323dSchristos     struct media_iterator   m;
739428323dSchristos     long                    bus_index;
749428323dSchristos     long                    bus;
759428323dSchristos     long                    id;
769428323dSchristos };
779428323dSchristos 
789428323dSchristos struct linux_order_cache {
799428323dSchristos     struct cache_item *first;
809428323dSchristos     struct cache_item *last;
819428323dSchristos     long next_disk;
829428323dSchristos     long next_cdrom;
839428323dSchristos     long loaded;
849428323dSchristos };
859428323dSchristos 
869428323dSchristos struct cache_item {
879428323dSchristos     struct cache_item *next;
889428323dSchristos     long bus;
899428323dSchristos     long id;
909428323dSchristos     long value;
919428323dSchristos     long is_cdrom;
929428323dSchristos     long unsure;
939428323dSchristos };
949428323dSchristos 
959428323dSchristos 
969428323dSchristos /*
979428323dSchristos  * Global Constants
989428323dSchristos  */
999428323dSchristos enum {
1009428323dSchristos     kNoDevice = 0x00FF
1019428323dSchristos };
1029428323dSchristos 
1039428323dSchristos enum {
1049428323dSchristos     kRequiredSCSIinquiryLength = 36
1059428323dSchristos };
1069428323dSchristos 
1079428323dSchristos 
1089428323dSchristos /*
1099428323dSchristos  * Global Variables
1109428323dSchristos  */
1119428323dSchristos static long scsi_inited = 0;
1129428323dSchristos static struct SCSI_manager scsi_mgr;
1139428323dSchristos static struct linux_order_cache linux_order;
1149428323dSchristos 
1159428323dSchristos 
1169428323dSchristos /*
1179428323dSchristos  * Forward declarations
1189428323dSchristos  */
1199428323dSchristos int AsyncSCSIPresent(void);
1209428323dSchristos void scsi_init(void);
1219428323dSchristos SCSI_MEDIA new_scsi_media(void);
122*48a628aeSchristos long read_scsi_media(MEDIA m, long long offset, uint32_t count, void *address);
123*48a628aeSchristos long write_scsi_media(MEDIA m, long long offset, uint32_t count, void *address);
1249428323dSchristos long close_scsi_media(MEDIA m);
1259428323dSchristos long os_reload_scsi_media(MEDIA m);
1269428323dSchristos long compute_id(long bus, long device);
1279428323dSchristos int SCSI_ReadBlock(UInt32 id, UInt32 bus, UInt32 block_size, UInt32 block, UInt8 *address);
1289428323dSchristos int SCSI_WriteBlock(UInt32 id, UInt32 bus, UInt32 block_size, UInt32 block, UInt8 *address);
1299428323dSchristos int DoTestUnitReady(UInt8 targetID, int bus);
1309428323dSchristos int DoReadCapacity(UInt32 id, UInt32 bus, UInt32 *blockCount, UInt32 *blockSize);
1319428323dSchristos SCSI_MEDIA_ITERATOR new_scsi_iterator(void);
1329428323dSchristos void reset_scsi_iterator(MEDIA_ITERATOR m);
1339428323dSchristos char *step_scsi_iterator(MEDIA_ITERATOR m);
1349428323dSchristos void delete_scsi_iterator(MEDIA_ITERATOR m);
1359428323dSchristos void fill_bus_entry(struct bus_entry *entry, long bus);
1369428323dSchristos /*long get_bus_sort_value(long bus);*/
1379428323dSchristos int bus_entry_compare(const void* a, const void* b);
1389428323dSchristos int DoInquiry(UInt32 id, UInt32 bus, UInt32 *devType);
1399428323dSchristos void probe_all(void);
1409428323dSchristos void probe_scsi_device(long bus, long id, int unsure);
1419428323dSchristos long lookup_scsi_device(long bus, long id, int *is_cdrom, int *unsure);
1429428323dSchristos long lookup_scsi_index(long index, int is_cdrom, long *bus, long *id);
1439428323dSchristos void add_to_cache(long bus, long id, int is_cdrom, int unsure);
1449428323dSchristos void init_linux_cache(void);
1459428323dSchristos void clear_linux_cache(void);
1469428323dSchristos void mark_linux_cache_loaded(void);
1479428323dSchristos int linux_cache_loaded(void);
1489428323dSchristos 
1499428323dSchristos 
1509428323dSchristos /*
1519428323dSchristos  * Routines
1529428323dSchristos  */
1539428323dSchristos int
AsyncSCSIPresent(void)1549428323dSchristos AsyncSCSIPresent(void)
1559428323dSchristos {
1569428323dSchristos     return (TrapAvailable(_SCSIAtomic));
1579428323dSchristos }
1589428323dSchristos 
1599428323dSchristos 
1609428323dSchristos void
scsi_init(void)1619428323dSchristos scsi_init(void)
1629428323dSchristos {
1639428323dSchristos     int i;
1649428323dSchristos     int old_scsi;
1659428323dSchristos 
1669428323dSchristos     if (scsi_inited != 0) {
1679428323dSchristos 	return;
1689428323dSchristos     }
1699428323dSchristos     scsi_inited = 1;
1709428323dSchristos 
1719428323dSchristos     scsi_mgr.exists = 1;
1729428323dSchristos     scsi_mgr.kind = allocate_media_kind();
1739428323dSchristos 
1749428323dSchristos     if (AsyncSCSIPresent()) {
1759428323dSchristos 	AllocatePB();
1769428323dSchristos 
1779428323dSchristos 	scsi_mgr.bus_count = gSCSIHiBusID + 1;
1789428323dSchristos 	old_scsi = 0;
1799428323dSchristos     } else {
1809428323dSchristos 	scsi_mgr.bus_count = 1;
1819428323dSchristos 	old_scsi = 1;
1829428323dSchristos     }
1839428323dSchristos 
1849428323dSchristos     scsi_mgr.bus_list = (struct bus_entry *)
1859428323dSchristos 	    calloc(scsi_mgr.bus_count, sizeof(struct bus_entry));
1869428323dSchristos 
1879428323dSchristos     if (scsi_mgr.bus_list == 0) {
1889428323dSchristos 	scsi_mgr.bus_count = 0;
1899428323dSchristos     } else {
1909428323dSchristos 	for (i = 0; i < scsi_mgr.bus_count; i++) {
1919428323dSchristos 	    if (old_scsi) {
1929428323dSchristos 		scsi_mgr.bus_list[i].bus = 0xFF;
1939428323dSchristos 	    } else {
1949428323dSchristos 		scsi_mgr.bus_list[i].bus = i;
1959428323dSchristos 	    }
1969428323dSchristos 	    fill_bus_entry(&scsi_mgr.bus_list[i], i);
1979428323dSchristos 	}
1989428323dSchristos 	qsort((void *)scsi_mgr.bus_list,    /* address of array */
1999428323dSchristos 		scsi_mgr.bus_count,         /* number of elements */
2009428323dSchristos 		sizeof(struct bus_entry),   /* size of element */
2019428323dSchristos 		bus_entry_compare);         /* element comparison routine */
2029428323dSchristos     }
2039428323dSchristos 
2049428323dSchristos     init_linux_cache();
2059428323dSchristos }
2069428323dSchristos 
2079428323dSchristos void
fill_bus_entry(struct bus_entry * entry,long bus)2089428323dSchristos fill_bus_entry(struct bus_entry *entry, long bus)
2099428323dSchristos {
2109428323dSchristos     OSErr           status;
2119428323dSchristos     SCSIBusInquiryPB    pb;
2129428323dSchristos     long len;
2139428323dSchristos     long result;
2149428323dSchristos     long x, y;
2159428323dSchristos 
2169428323dSchristos     if (!AsyncSCSIPresent()) {
2179428323dSchristos     	entry->sort_value = 0;
2189428323dSchristos 	entry->max_id = 7;
2199428323dSchristos 	entry->master_id = 7;
2209428323dSchristos 	return;
2219428323dSchristos     }
2229428323dSchristos     len = sizeof(SCSIBusInquiryPB);
2239428323dSchristos     clear_memory((Ptr) &pb, len);
2249428323dSchristos     pb.scsiPBLength = len;
2259428323dSchristos     pb.scsiFunctionCode = SCSIBusInquiry;
2269428323dSchristos     pb.scsiDevice.bus = bus;
2279428323dSchristos     status = SCSIAction((SCSI_PB *) &pb);
2289428323dSchristos     if (status != noErr) {
2299428323dSchristos 	result = 6;
2309428323dSchristos     } else {
2319428323dSchristos 	switch (pb.scsiHBAslotType) {
2329428323dSchristos 	case scsiMotherboardBus:    x = 0; break;
2339428323dSchristos 	case scsiPDSBus:            x = 1; break;
2349428323dSchristos 	case scsiNuBus:             x = 2; break;
2359428323dSchristos 	case scsiPCIBus:            x = 3; break;
2369428323dSchristos 	case scsiFireWireBridgeBus: x = 4; break;
2379428323dSchristos 	case scsiPCMCIABus:         x = 5; break;
2389428323dSchristos 	default:                    x = 7 + pb.scsiHBAslotType; break;
2399428323dSchristos 	};
2409428323dSchristos 
2419428323dSchristos 	switch (pb.scsiFeatureFlags & scsiBusInternalExternalMask) {
2429428323dSchristos 	case scsiBusInternal:                   y = 0; break;
2439428323dSchristos 	case scsiBusInternalExternal:           y = 1; break;
2449428323dSchristos 	case scsiBusExternal:                   y = 2; break;
2459428323dSchristos 	default:
2469428323dSchristos 	case scsiBusInternalExternalUnknown:    y = 3; break;
2479428323dSchristos 	};
2489428323dSchristos 	result = x * 4 + y;
2499428323dSchristos     }
2509428323dSchristos     entry->sort_value = result;
2519428323dSchristos     entry->max_id = pb.scsiMaxLUN;
2529428323dSchristos     entry->master_id = pb.scsiInitiatorID;
2539428323dSchristos }
2549428323dSchristos 
2559428323dSchristos 
2569428323dSchristos int
bus_entry_compare(const void * a,const void * b)2579428323dSchristos bus_entry_compare(const void* a, const void* b)
2589428323dSchristos {
2599428323dSchristos     long result;
2609428323dSchristos 
2619428323dSchristos     const struct bus_entry *x = (const struct bus_entry *) a;
2629428323dSchristos     const struct bus_entry *y = (const struct bus_entry *) b;
2639428323dSchristos 
2649428323dSchristos     result = x->sort_value - y->sort_value;
2659428323dSchristos     if (result == 0) {
2669428323dSchristos 	result = x->bus - y->bus;
2679428323dSchristos     }
2689428323dSchristos     return result;
2699428323dSchristos }
2709428323dSchristos 
2719428323dSchristos 
2729428323dSchristos SCSI_MEDIA
new_scsi_media(void)2739428323dSchristos new_scsi_media(void)
2749428323dSchristos {
2759428323dSchristos     return (SCSI_MEDIA) new_media(sizeof(struct SCSI_media));
2769428323dSchristos }
2779428323dSchristos 
2789428323dSchristos 
2799428323dSchristos MEDIA
open_old_scsi_as_media(long device)2809428323dSchristos open_old_scsi_as_media(long device)
2819428323dSchristos {
2829428323dSchristos     return open_scsi_as_media(kOriginalSCSIBusAdaptor, device);
2839428323dSchristos }
2849428323dSchristos 
2859428323dSchristos 
2869428323dSchristos MEDIA
open_scsi_as_media(long bus,long device)2879428323dSchristos open_scsi_as_media(long bus, long device)
2889428323dSchristos {
2899428323dSchristos     SCSI_MEDIA  a;
2909428323dSchristos     UInt32 blockCount;
2919428323dSchristos     UInt32 blockSize;
2929428323dSchristos 
2939428323dSchristos     if (scsi_inited == 0) {
2949428323dSchristos 	scsi_init();
2959428323dSchristos     }
2969428323dSchristos 
2979428323dSchristos     if (scsi_mgr.exists == 0) {
2989428323dSchristos 	return 0;
2999428323dSchristos     }
3009428323dSchristos 
3019428323dSchristos     a = 0;
3029428323dSchristos     if (DoTestUnitReady(device, bus) > 0) {
3039428323dSchristos 	if (DoReadCapacity(device, bus, &blockCount, &blockSize) != 0) {
3049428323dSchristos 	    a = new_scsi_media();
3059428323dSchristos 	    if (a != 0) {
3069428323dSchristos 		a->m.kind = scsi_mgr.kind;
3079428323dSchristos 		a->m.grain = blockSize;
3089428323dSchristos 		a->m.size_in_bytes = ((long long)blockCount) * blockSize;
3099428323dSchristos 		a->m.do_read = read_scsi_media;
3109428323dSchristos 		a->m.do_write = write_scsi_media;
3119428323dSchristos 		a->m.do_close = close_scsi_media;
3129428323dSchristos 		a->m.do_os_reload = os_reload_scsi_media;
3139428323dSchristos 		a->bus = bus;
3149428323dSchristos 		a->id = device;
3159428323dSchristos 	    }
3169428323dSchristos 	}
3179428323dSchristos     }
3189428323dSchristos     return (MEDIA) a;
3199428323dSchristos }
3209428323dSchristos 
3219428323dSchristos 
3229428323dSchristos long
read_scsi_media(MEDIA m,long long offset,uint32_t count,void * address)323*48a628aeSchristos read_scsi_media(MEDIA m, long long offset, uint32_t count, void *address)
3249428323dSchristos {
3259428323dSchristos     SCSI_MEDIA a;
3269428323dSchristos     long rtn_value;
3279428323dSchristos     long block;
3289428323dSchristos     long block_count;
3299428323dSchristos     long block_size;
330*48a628aeSchristos     uint8_t *buffer;
3319428323dSchristos     int i;
3329428323dSchristos 
3339428323dSchristos     block = (long) offset;
3349428323dSchristos //printf("scsi %d count %d\n", block, count);
3359428323dSchristos     a = (SCSI_MEDIA) m;
3369428323dSchristos     rtn_value = 0;
3379428323dSchristos     if (a == 0) {
3389428323dSchristos 	/* no media */
3399428323dSchristos     } else if (a->m.kind != scsi_mgr.kind) {
3409428323dSchristos 	/* wrong kind - XXX need to error here - this is an internal problem */
3419428323dSchristos     } else if (count <= 0 || count % a->m.grain != 0) {
3429428323dSchristos 	/* can't handle size */
3439428323dSchristos     } else if (offset < 0 || offset % a->m.grain != 0) {
3449428323dSchristos 	/* can't handle offset */
3459428323dSchristos     } else if (offset + count > a->m.size_in_bytes) {
3469428323dSchristos 	/* check for offset (and offset+count) too large */
3479428323dSchristos     } else {
3489428323dSchristos 	/* XXX do a read on the physical device */
3499428323dSchristos 	block_size = a->m.grain;
3509428323dSchristos 	block = offset / block_size;
3519428323dSchristos 	block_count = count / block_size;
3529428323dSchristos 	buffer = address;
3539428323dSchristos 	rtn_value = 1;
3549428323dSchristos 	for (i = 0; i < block_count; i++) {
3559428323dSchristos 	    if (SCSI_ReadBlock(a->id, a->bus, block_size, block, buffer) == 0) {
3569428323dSchristos 		rtn_value = 0;
3579428323dSchristos 		break;
3589428323dSchristos 	    }
3599428323dSchristos 	    buffer += block_size;
3609428323dSchristos 	    block += 1;
3619428323dSchristos 	}
3629428323dSchristos     }
3639428323dSchristos     return rtn_value;
3649428323dSchristos }
3659428323dSchristos 
3669428323dSchristos 
3679428323dSchristos long
write_scsi_media(MEDIA m,long long offset,uint32_t count,void * address)368*48a628aeSchristos write_scsi_media(MEDIA m, long long offset, uint32_t count, void *address)
3699428323dSchristos {
3709428323dSchristos     SCSI_MEDIA a;
3719428323dSchristos     long rtn_value;
3729428323dSchristos     long block;
3739428323dSchristos     long block_count;
3749428323dSchristos     long block_size;
375*48a628aeSchristos     uint8_t *buffer;
3769428323dSchristos     int i;
3779428323dSchristos 
3789428323dSchristos     a = (SCSI_MEDIA) m;
3799428323dSchristos     rtn_value = 0;
3809428323dSchristos     if (a == 0) {
3819428323dSchristos 	/* no media */
3829428323dSchristos     } else if (a->m.kind != scsi_mgr.kind) {
3839428323dSchristos 	/* XXX need to error here - this is an internal problem */
3849428323dSchristos     } else if (count <= 0 || count % a->m.grain != 0) {
3859428323dSchristos 	/* can't handle size */
3869428323dSchristos     } else if (offset < 0 || offset % a->m.grain != 0) {
3879428323dSchristos 	/* can't handle offset */
3889428323dSchristos     } else if (offset + count > a->m.size_in_bytes) {
3899428323dSchristos 	/* check for offset (and offset+count) too large */
3909428323dSchristos     } else {
3919428323dSchristos 	/* XXX do a write on the physical device */
3929428323dSchristos 	block_size = a->m.grain;
3939428323dSchristos 	block = offset / block_size;
3949428323dSchristos 	block_count = count / block_size;
3959428323dSchristos 	buffer = address;
3969428323dSchristos 	rtn_value = 1;
3979428323dSchristos 	for (i = 0; i < block_count; i++) {
3989428323dSchristos 	    if (SCSI_WriteBlock(a->id, a->bus, block_size, block, buffer) == 0) {
3999428323dSchristos 		rtn_value = 0;
4009428323dSchristos 		break;
4019428323dSchristos 	    }
4029428323dSchristos 	    buffer += block_size;
4039428323dSchristos 	    block += 1;
4049428323dSchristos 	}
4059428323dSchristos     }
4069428323dSchristos     return rtn_value;
4079428323dSchristos }
4089428323dSchristos 
4099428323dSchristos 
4109428323dSchristos long
close_scsi_media(MEDIA m)4119428323dSchristos close_scsi_media(MEDIA m)
4129428323dSchristos {
4139428323dSchristos     SCSI_MEDIA a;
4149428323dSchristos 
4159428323dSchristos     a = (SCSI_MEDIA) m;
4169428323dSchristos     if (a == 0) {
4179428323dSchristos 	return 0;
4189428323dSchristos     } else if (a->m.kind != scsi_mgr.kind) {
4199428323dSchristos 	/* XXX need to error here - this is an internal problem */
4209428323dSchristos 	return 0;
4219428323dSchristos     }
4229428323dSchristos     /* XXX nothing to do - I think? */
4239428323dSchristos     return 1;
4249428323dSchristos }
4259428323dSchristos 
4269428323dSchristos 
4279428323dSchristos long
os_reload_scsi_media(MEDIA m)4289428323dSchristos os_reload_scsi_media(MEDIA m)
4299428323dSchristos {
4309428323dSchristos     printf("Reboot your system so the partition table will be reread.\n");
4319428323dSchristos     return 1;
4329428323dSchristos }
4339428323dSchristos 
4349428323dSchristos 
4359428323dSchristos #pragma mark -
4369428323dSchristos 
4379428323dSchristos 
4389428323dSchristos int
DoTestUnitReady(UInt8 targetID,int bus)4399428323dSchristos DoTestUnitReady(UInt8 targetID, int bus)
4409428323dSchristos {
4419428323dSchristos     OSErr                   status;
4429428323dSchristos     Str255                  errorText;
4439428323dSchristos     char*       msg;
4449428323dSchristos     static const SCSI_6_Byte_Command gTestUnitReadyCommand = {
4459428323dSchristos 	kScsiCmdTestUnitReady, 0, 0, 0, 0, 0
4469428323dSchristos     };
4479428323dSchristos     SCSI_Sense_Data         senseData;
4489428323dSchristos     DeviceIdent scsiDevice;
4499428323dSchristos     int rtn_value;
4509428323dSchristos 
4519428323dSchristos     scsiDevice.diReserved = 0;
4529428323dSchristos     scsiDevice.bus = bus;
4539428323dSchristos     scsiDevice.targetID = targetID;
4549428323dSchristos     scsiDevice.LUN = 0;
4559428323dSchristos 
4569428323dSchristos     status = DoSCSICommand(
4579428323dSchristos 		scsiDevice,
4589428323dSchristos 		"\pTest Unit Ready",
4599428323dSchristos 		(SCSI_CommandPtr) &gTestUnitReadyCommand,
4609428323dSchristos 		NULL,
4619428323dSchristos 		0,
4629428323dSchristos 		scsiDirectionNone,
4639428323dSchristos 		NULL,
4649428323dSchristos 		&senseData,
4659428323dSchristos 		errorText
4669428323dSchristos 		);
4679428323dSchristos     if (status == scsiNonZeroStatus) {
4689428323dSchristos 	rtn_value = -1;
4699428323dSchristos     } else if (status != noErr) {
4709428323dSchristos 	rtn_value = 0;
4719428323dSchristos     } else {
4729428323dSchristos 	rtn_value = 1;
4739428323dSchristos     }
4749428323dSchristos     return rtn_value;
4759428323dSchristos }
4769428323dSchristos 
4779428323dSchristos 
4789428323dSchristos int
SCSI_ReadBlock(UInt32 id,UInt32 bus,UInt32 block_size,UInt32 block,UInt8 * address)4799428323dSchristos SCSI_ReadBlock(UInt32 id, UInt32 bus, UInt32 block_size, UInt32 block, UInt8 *address)
4809428323dSchristos {
4819428323dSchristos     OSErr                   status;
4829428323dSchristos     Str255                  errorText;
4839428323dSchristos     char*       msg;
4849428323dSchristos     static SCSI_10_Byte_Command gReadCommand = {
4859428323dSchristos 	kScsiCmdRead10, 0, 0, 0, 0, 0, 0, 0, 0, 0
4869428323dSchristos     };
4879428323dSchristos     SCSI_Sense_Data         senseData;
4889428323dSchristos     DeviceIdent scsiDevice;
4899428323dSchristos     int rtn_value;
4909428323dSchristos     long count;
4919428323dSchristos 
4929428323dSchristos //printf("scsi read %d:%d block %d size %d\n", bus, id, block, block_size);
4939428323dSchristos     scsiDevice.diReserved = 0;
4949428323dSchristos     scsiDevice.bus = bus;
4959428323dSchristos     scsiDevice.targetID = id;
4969428323dSchristos     scsiDevice.LUN = 0;
4979428323dSchristos 
4989428323dSchristos     gReadCommand.lbn4 = (block >> 24) & 0xFF;
4999428323dSchristos     gReadCommand.lbn3 = (block >> 16) & 0xFF;
5009428323dSchristos     gReadCommand.lbn2 = (block >> 8) & 0xFF;
5019428323dSchristos     gReadCommand.lbn1 = block & 0xFF;
5029428323dSchristos 
5039428323dSchristos     count = 1;
5049428323dSchristos     gReadCommand.len2 = (count >> 8) & 0xFF;
5059428323dSchristos     gReadCommand.len1 = count & 0xFF;
5069428323dSchristos 
5079428323dSchristos     status = DoSCSICommand(
5089428323dSchristos 		scsiDevice,
5099428323dSchristos 		"\pRead",
5109428323dSchristos 		(SCSI_CommandPtr) &gReadCommand,
5119428323dSchristos 		(Ptr) address,
5129428323dSchristos 		count * block_size,
5139428323dSchristos 		scsiDirectionIn,
5149428323dSchristos 		NULL,
5159428323dSchristos 		&senseData,
5169428323dSchristos 		errorText
5179428323dSchristos 	);
5189428323dSchristos     if (status == noErr) {
5199428323dSchristos 	rtn_value = 1;
5209428323dSchristos     } else {
5219428323dSchristos 	rtn_value = 0;
5229428323dSchristos     }
5239428323dSchristos     return rtn_value;
5249428323dSchristos }
5259428323dSchristos 
5269428323dSchristos 
5279428323dSchristos int
SCSI_WriteBlock(UInt32 id,UInt32 bus,UInt32 block_size,UInt32 block,UInt8 * address)5289428323dSchristos SCSI_WriteBlock(UInt32 id, UInt32 bus, UInt32 block_size, UInt32 block, UInt8 *address)
5299428323dSchristos {
5309428323dSchristos     OSErr                   status;
5319428323dSchristos     Str255                  errorText;
5329428323dSchristos     char*       msg;
5339428323dSchristos     static SCSI_10_Byte_Command gWriteCommand = {
5349428323dSchristos 	kScsiCmdWrite10, 0, 0, 0, 0, 0, 0, 0, 0, 0
5359428323dSchristos     };
5369428323dSchristos     SCSI_Sense_Data         senseData;
5379428323dSchristos     DeviceIdent scsiDevice;
5389428323dSchristos     int rtn_value;
5399428323dSchristos     long count;
5409428323dSchristos 
5419428323dSchristos     scsiDevice.diReserved = 0;
5429428323dSchristos     scsiDevice.bus = bus;
5439428323dSchristos     scsiDevice.targetID = id;
5449428323dSchristos     scsiDevice.LUN = 0;
5459428323dSchristos 
5469428323dSchristos     gWriteCommand.lbn4 = (block >> 24) & 0xFF;
5479428323dSchristos     gWriteCommand.lbn3 = (block >> 16) & 0xFF;
5489428323dSchristos     gWriteCommand.lbn2 = (block >> 8) & 0xFF;
5499428323dSchristos     gWriteCommand.lbn1 = block & 0xFF;
5509428323dSchristos 
5519428323dSchristos     count = 1;
5529428323dSchristos     gWriteCommand.len2 = (count >> 8) & 0xFF;
5539428323dSchristos     gWriteCommand.len1 = count & 0xFF;
5549428323dSchristos 
5559428323dSchristos     status = DoSCSICommand(
5569428323dSchristos 		scsiDevice,
5579428323dSchristos 		"\pWrite",
5589428323dSchristos 		(SCSI_CommandPtr) &gWriteCommand,
5599428323dSchristos 		(Ptr) address,
5609428323dSchristos 		count * block_size,
5619428323dSchristos 		scsiDirectionOut,
5629428323dSchristos 		NULL,
5639428323dSchristos 		&senseData,
5649428323dSchristos 		errorText
5659428323dSchristos 	);
5669428323dSchristos     if (status == noErr) {
5679428323dSchristos 	rtn_value = 1;
5689428323dSchristos     } else {
5699428323dSchristos 	rtn_value = 0;
5709428323dSchristos     }
5719428323dSchristos     return rtn_value;
5729428323dSchristos }
5739428323dSchristos 
5749428323dSchristos 
5759428323dSchristos int
DoReadCapacity(UInt32 id,UInt32 bus,UInt32 * blockCount,UInt32 * blockSize)5769428323dSchristos DoReadCapacity(UInt32 id, UInt32 bus, UInt32 *blockCount, UInt32 *blockSize)
5779428323dSchristos {
5789428323dSchristos     OSErr       status;
5799428323dSchristos     Str255      errorText;
5809428323dSchristos     static const SCSI_10_Byte_Command gCapacityCommand = {
5819428323dSchristos 	kScsiCmdReadCapacity, 0, 0, 0, 0, 0, 0, 0, 0, 0
5829428323dSchristos     };
5839428323dSchristos     SCSI_Sense_Data senseData;
5849428323dSchristos     DeviceIdent     scsiDevice;
5859428323dSchristos     SCSI_Capacity_Data  capacityData;
5869428323dSchristos     UInt32      temp;
5879428323dSchristos     int rtn_value;
5889428323dSchristos 
5899428323dSchristos     scsiDevice.diReserved = 0;
5909428323dSchristos     scsiDevice.bus = bus;
5919428323dSchristos     scsiDevice.targetID = id;
5929428323dSchristos     scsiDevice.LUN = 0;
5939428323dSchristos 
5949428323dSchristos     CLEAR(capacityData);
5959428323dSchristos 
5969428323dSchristos     status = DoSCSICommand(
5979428323dSchristos 		scsiDevice,
5989428323dSchristos 		"\pRead Capacity",
5999428323dSchristos 		(SCSI_CommandPtr) &gCapacityCommand,
6009428323dSchristos 		(Ptr) &capacityData,
6019428323dSchristos 		sizeof (SCSI_Capacity_Data),
6029428323dSchristos 		scsiDirectionIn,
6039428323dSchristos 		NULL,
6049428323dSchristos 		&senseData,
6059428323dSchristos 		errorText
6069428323dSchristos 		);
6079428323dSchristos 
6089428323dSchristos     if (status == noErr) {
6099428323dSchristos 	temp = capacityData.lbn4;
6109428323dSchristos 	temp = (temp << 8) | capacityData.lbn3;
6119428323dSchristos 	temp = (temp << 8) | capacityData.lbn2;
6129428323dSchristos 	temp = (temp << 8) | capacityData.lbn1;
6139428323dSchristos 	*blockCount = temp;
6149428323dSchristos 
6159428323dSchristos 	temp = capacityData.len4;
6169428323dSchristos 	temp = (temp << 8) | capacityData.len3;
6179428323dSchristos 	temp = (temp << 8) | capacityData.len2;
6189428323dSchristos 	temp = (temp << 8) | capacityData.len1;
6199428323dSchristos 	*blockSize = temp;
6209428323dSchristos 
6219428323dSchristos 	rtn_value = 1;
6229428323dSchristos     } else {
6239428323dSchristos 	rtn_value = 0;
6249428323dSchristos     }
6259428323dSchristos     return rtn_value;
6269428323dSchristos }
6279428323dSchristos 
6289428323dSchristos 
6299428323dSchristos int
DoInquiry(UInt32 id,UInt32 bus,UInt32 * devType)6309428323dSchristos DoInquiry(UInt32 id, UInt32 bus, UInt32 *devType)
6319428323dSchristos {
6329428323dSchristos     OSErr       status;
6339428323dSchristos     Str255      errorText;
6349428323dSchristos     static const SCSI_6_Byte_Command gInquiryCommand = {
6359428323dSchristos 	kScsiCmdInquiry, 0, 0, 0, kRequiredSCSIinquiryLength, 0
6369428323dSchristos     };
6379428323dSchristos     SCSI_Sense_Data senseData;
6389428323dSchristos     DeviceIdent     scsiDevice;
6399428323dSchristos     SCSI_Inquiry_Data  inquiryData;
6409428323dSchristos     UInt32      temp;
6419428323dSchristos     int rtn_value;
6429428323dSchristos 
6439428323dSchristos     scsiDevice.diReserved = 0;
6449428323dSchristos     scsiDevice.bus = bus;
6459428323dSchristos     scsiDevice.targetID = id;
6469428323dSchristos     scsiDevice.LUN = 0;
6479428323dSchristos 
6489428323dSchristos     CLEAR(inquiryData);
6499428323dSchristos 
6509428323dSchristos     status = DoSCSICommand(
6519428323dSchristos 		scsiDevice,
6529428323dSchristos 		"\pInquiry",
6539428323dSchristos 		(SCSI_CommandPtr) &gInquiryCommand,
6549428323dSchristos 		(Ptr) &inquiryData,
6559428323dSchristos 		kRequiredSCSIinquiryLength,
6569428323dSchristos 		scsiDirectionIn,
6579428323dSchristos 		NULL,
6589428323dSchristos 		&senseData,
6599428323dSchristos 		errorText
6609428323dSchristos 		);
6619428323dSchristos 
6629428323dSchristos     if (status == noErr) {
6639428323dSchristos 	*devType = inquiryData.devType & kScsiDevTypeMask;
6649428323dSchristos 	rtn_value = 1;
6659428323dSchristos     } else {
6669428323dSchristos 	rtn_value = 0;
6679428323dSchristos     }
6689428323dSchristos     return rtn_value;
6699428323dSchristos }
6709428323dSchristos 
6719428323dSchristos 
6729428323dSchristos MEDIA
SCSI_FindDevice(long dRefNum)6739428323dSchristos SCSI_FindDevice(long dRefNum)
6749428323dSchristos {
6759428323dSchristos     SCSIDriverPB            pb;
6769428323dSchristos     OSErr                   status;
6779428323dSchristos     short                   targetID;
6789428323dSchristos 
6799428323dSchristos     status = nsvErr;
6809428323dSchristos     if (AsyncSCSIPresent()) {
6819428323dSchristos 	clear_memory((Ptr) &pb, sizeof pb);
6829428323dSchristos 
6839428323dSchristos 	pb.scsiPBLength = sizeof (SCSIDriverPB);
6849428323dSchristos 	pb.scsiCompletion = NULL;
6859428323dSchristos 	pb.scsiFlags = 0;
6869428323dSchristos 	pb.scsiFunctionCode = SCSILookupRefNumXref;
6879428323dSchristos 	pb.scsiDevice.bus = kNoDevice;  /* was *((long *) &pb.scsiDevice) = 0xFFFFFFFFL; */
6889428323dSchristos 
6899428323dSchristos 	do {
6909428323dSchristos 	    status = SCSIAction((SCSI_PB *) &pb);
6919428323dSchristos 
6929428323dSchristos 	    if (status != noErr) {
6939428323dSchristos 		break;
6949428323dSchristos 	    } else if (pb.scsiDriver == dRefNum
6959428323dSchristos 		    && pb.scsiDevice.bus != kNoDevice) {
6969428323dSchristos 		return open_scsi_as_media(pb.scsiDevice.bus, pb.scsiDevice.targetID);
6979428323dSchristos 
6989428323dSchristos 	    } else {
6999428323dSchristos 		pb.scsiDevice = pb.scsiNextDevice;
7009428323dSchristos 	    }
7019428323dSchristos 	}
7029428323dSchristos 	while (pb.scsiDevice.bus != kNoDevice);
7039428323dSchristos     }
7049428323dSchristos     if (status == nsvErr) {
7059428323dSchristos 	/*
7069428323dSchristos 	 * The asynchronous SCSI Manager is missing or the
7079428323dSchristos 	 * driver didn't register with the SCSI Manager.*/
7089428323dSchristos 	targetID = DriverRefNumToSCSI(dRefNum);
7099428323dSchristos 	if (targetID >= 0 && targetID <= 6) {
7109428323dSchristos 	    return open_old_scsi_as_media(targetID);
7119428323dSchristos 	}
7129428323dSchristos     }
7139428323dSchristos      return 0;
7149428323dSchristos }
7159428323dSchristos 
7169428323dSchristos 
7179428323dSchristos #pragma mark -
7189428323dSchristos 
7199428323dSchristos 
7209428323dSchristos SCSI_MEDIA_ITERATOR
new_scsi_iterator(void)7219428323dSchristos new_scsi_iterator(void)
7229428323dSchristos {
7239428323dSchristos     return (SCSI_MEDIA_ITERATOR) new_media_iterator(sizeof(struct SCSI_media_iterator));
7249428323dSchristos }
7259428323dSchristos 
7269428323dSchristos 
7279428323dSchristos MEDIA_ITERATOR
create_scsi_iterator(void)7289428323dSchristos create_scsi_iterator(void)
7299428323dSchristos {
7309428323dSchristos     SCSI_MEDIA_ITERATOR a;
7319428323dSchristos 
7329428323dSchristos     if (scsi_inited == 0) {
7339428323dSchristos 	scsi_init();
7349428323dSchristos     }
7359428323dSchristos 
7369428323dSchristos     if (scsi_mgr.exists == 0) {
7379428323dSchristos 	return 0;
7389428323dSchristos     }
7399428323dSchristos 
7409428323dSchristos     a = new_scsi_iterator();
7419428323dSchristos     if (a != 0) {
7429428323dSchristos 	a->m.kind = scsi_mgr.kind;
7439428323dSchristos 	a->m.state = kInit;
7449428323dSchristos 	a->m.do_reset = reset_scsi_iterator;
7459428323dSchristos 	a->m.do_step = step_scsi_iterator;
7469428323dSchristos 	a->m.do_delete = delete_scsi_iterator;
7479428323dSchristos 	a->bus_index = 0;
7489428323dSchristos 	a->bus = 0;
7499428323dSchristos 	a->id = 0;
7509428323dSchristos     }
7519428323dSchristos 
7529428323dSchristos     return (MEDIA_ITERATOR) a;
7539428323dSchristos }
7549428323dSchristos 
7559428323dSchristos 
7569428323dSchristos void
reset_scsi_iterator(MEDIA_ITERATOR m)7579428323dSchristos reset_scsi_iterator(MEDIA_ITERATOR m)
7589428323dSchristos {
7599428323dSchristos     SCSI_MEDIA_ITERATOR a;
7609428323dSchristos 
7619428323dSchristos     a = (SCSI_MEDIA_ITERATOR) m;
7629428323dSchristos     if (a == 0) {
7639428323dSchristos 	/* no media */
7649428323dSchristos     } else if (a->m.kind != scsi_mgr.kind) {
7659428323dSchristos 	/* wrong kind - XXX need to error here - this is an internal problem */
7669428323dSchristos     } else if (a->m.state != kInit) {
7679428323dSchristos 	a->m.state = kReset;
7689428323dSchristos     }
7699428323dSchristos }
7709428323dSchristos 
7719428323dSchristos 
7729428323dSchristos char *
step_scsi_iterator(MEDIA_ITERATOR m)7739428323dSchristos step_scsi_iterator(MEDIA_ITERATOR m)
7749428323dSchristos {
7759428323dSchristos     SCSI_MEDIA_ITERATOR a;
7769428323dSchristos     char *result;
7779428323dSchristos 
7789428323dSchristos     a = (SCSI_MEDIA_ITERATOR) m;
7799428323dSchristos     if (a == 0) {
7809428323dSchristos 	/* no media */
7819428323dSchristos     } else if (a->m.kind != scsi_mgr.kind) {
7829428323dSchristos 	/* wrong kind - XXX need to error here - this is an internal problem */
7839428323dSchristos     } else {
7849428323dSchristos 	switch (a->m.state) {
7859428323dSchristos 	case kInit:
7869428323dSchristos 	    /* find # of buses - done in AllocatePB() out of scsi_init() */
7879428323dSchristos 	    a->m.state = kReset;
7889428323dSchristos 	    /* fall through to reset */
7899428323dSchristos 	case kReset:
7909428323dSchristos 	    a->bus_index = 0 /* first bus id */;
7919428323dSchristos 	    a->bus = scsi_mgr.bus_list[a->bus_index].bus;
7929428323dSchristos 	    a->id = 0 /* first device id */;
7939428323dSchristos 	    a->m.state = kIterating;
7949428323dSchristos 	    clear_linux_cache();
7959428323dSchristos 	    /* fall through to iterate */
7969428323dSchristos 	case kIterating:
7979428323dSchristos 	    while (1) {
7989428323dSchristos 		if (a->bus_index >= scsi_mgr.bus_count /* max bus id */) {
7999428323dSchristos 		    break;
8009428323dSchristos 		}
8019428323dSchristos 		if (a->id == scsi_mgr.bus_list[a->bus_index].master_id) {
8029428323dSchristos 		    /* next id */
8039428323dSchristos 		    a->id += 1;
8049428323dSchristos 		}
8059428323dSchristos 		if (a->id > scsi_mgr.bus_list[a->bus_index].max_id) {
8069428323dSchristos 		    a->bus_index += 1;
8079428323dSchristos 		    a->bus = scsi_mgr.bus_list[a->bus_index].bus;
8089428323dSchristos 		    a->id = 0 /* first device id */;
8099428323dSchristos 		    continue;   /* try again */
8109428323dSchristos 		}
8119428323dSchristos 		/* generate result */
8129428323dSchristos 		result = (char *) malloc(20);
8139428323dSchristos 		if (result != NULL) {
8149428323dSchristos 		    if (a->bus == 0xFF) {
815*48a628aeSchristos 			snprintf(result, 20, "/dev/scsi%c", '0'+a->id);
8169428323dSchristos 			probe_scsi_device(a->bus, a->id, 1);
8179428323dSchristos 		    } else {
8189428323dSchristos 			// insure bus number in range
8199428323dSchristos 			if (a->bus > 9) {
8209428323dSchristos 			    free(result);
8219428323dSchristos 			    result = NULL;
8229428323dSchristos 			    break;
8239428323dSchristos 			}
824*48a628aeSchristos 			snprintf(result, 20, "/dev/scsi%c.%c",
825*48a628aeSchristos 			    '0'+a->bus, '0'+a->id);
8269428323dSchristos 			/* only probe out of iterate; so always added in order. */
8279428323dSchristos 			probe_scsi_device(a->bus, a->id, 0);
8289428323dSchristos 		    }
8299428323dSchristos 		}
8309428323dSchristos 
8319428323dSchristos 		a->id += 1; /* next id */
8329428323dSchristos 		return result;
8339428323dSchristos 	    }
8349428323dSchristos 	    a->m.state = kEnd;
8359428323dSchristos 	    /* fall through to end */
8369428323dSchristos 	case kEnd:
8379428323dSchristos 	    mark_linux_cache_loaded();
8389428323dSchristos 	default:
8399428323dSchristos 	    break;
8409428323dSchristos 	}
8419428323dSchristos     }
8429428323dSchristos     return 0 /* no entry */;
8439428323dSchristos }
8449428323dSchristos 
8459428323dSchristos 
8469428323dSchristos void
delete_scsi_iterator(MEDIA_ITERATOR m)8479428323dSchristos delete_scsi_iterator(MEDIA_ITERATOR m)
8489428323dSchristos {
8499428323dSchristos     return;
8509428323dSchristos }
8519428323dSchristos 
8529428323dSchristos 
8539428323dSchristos #pragma mark -
8549428323dSchristos 
8559428323dSchristos 
8569428323dSchristos MEDIA
open_linux_scsi_as_media(long index,int is_cdrom)8579428323dSchristos open_linux_scsi_as_media(long index, int is_cdrom)
8589428323dSchristos {
8599428323dSchristos     MEDIA m;
8609428323dSchristos     long bus;
8619428323dSchristos     long id;
8629428323dSchristos 
8639428323dSchristos     if (lookup_scsi_index(index, is_cdrom, &bus, &id) > 0) {
8649428323dSchristos 	m = open_scsi_as_media(bus, id);
8659428323dSchristos     } else {
8669428323dSchristos 	m = 0;
8679428323dSchristos     }
8689428323dSchristos 
8699428323dSchristos     return m;
8709428323dSchristos }
8719428323dSchristos 
8729428323dSchristos 
8739428323dSchristos char *
linux_old_scsi_name(long id)8749428323dSchristos linux_old_scsi_name(long id)
8759428323dSchristos {
8769428323dSchristos     linux_scsi_name(kOriginalSCSIBusAdaptor, id);
8779428323dSchristos }
8789428323dSchristos 
8799428323dSchristos 
8809428323dSchristos char *
linux_scsi_name(long bus,long id)8819428323dSchristos linux_scsi_name(long bus, long id)
8829428323dSchristos {
8839428323dSchristos     char *result = 0;
8849428323dSchristos     long value;
8859428323dSchristos     int is_cdrom;
8869428323dSchristos     int unsure;
8879428323dSchristos     char *suffix;
8889428323dSchristos 
8899428323dSchristos     /* name is sda, sdb, sdc, ...
8909428323dSchristos      * in order by buses and ids, but only count responding devices ...
8919428323dSchristos      */
8929428323dSchristos     if ((value = lookup_scsi_device(bus, id, &is_cdrom, &unsure)) >= 0) {
8939428323dSchristos 	result = (char *) malloc(20);
8949428323dSchristos 	if (result != NULL) {
8959428323dSchristos 	    if (unsure) {
8969428323dSchristos 		suffix = " ?";
8979428323dSchristos 	    } else {
8989428323dSchristos 		suffix = "";
8999428323dSchristos 	    }
9009428323dSchristos 	    if (is_cdrom) {
9019428323dSchristos 		if (value > 9) {
9029428323dSchristos 		    // too many CD's, give up
9039428323dSchristos 		    free(result); result = NULL;
9049428323dSchristos 		} else {
905*48a628aeSchristos 		    snprintf(result, 20, "/dev/scd%c%s", '0' + value, suffix);
9069428323dSchristos 		}
9079428323dSchristos 	    } else {
9089428323dSchristos 		if (value < 26) {
909*48a628aeSchristos 		    snprintf(result, 20, "/dev/sd%c%s", 'a' + value, suffix);
9109428323dSchristos 		} else {
911*48a628aeSchristos 		    snprintf(result, 20, "/dev/sd%c%c%s",
9129428323dSchristos 			    'a' + value / 26, 'a' + value % 26, suffix);
9139428323dSchristos 		}
9149428323dSchristos 	    }
9159428323dSchristos 	}
9169428323dSchristos     }
9179428323dSchristos     return result;
9189428323dSchristos }
9199428323dSchristos 
9209428323dSchristos 
9219428323dSchristos void
probe_all(void)9229428323dSchristos probe_all(void)
9239428323dSchristos {
9249428323dSchristos     MEDIA_ITERATOR iter;
9259428323dSchristos     char *name;
9269428323dSchristos 
9279428323dSchristos     iter = create_scsi_iterator();
9289428323dSchristos     if (iter == 0) {
9299428323dSchristos 	return;
9309428323dSchristos     }
9319428323dSchristos 
9329428323dSchristos     printf("finding devices ");
9339428323dSchristos     fflush(stdout);
9349428323dSchristos     while ((name = step_media_iterator(iter)) != 0) {
9359428323dSchristos     	/* step does the probe for us */
9369428323dSchristos 	printf(".");
9379428323dSchristos 	fflush(stdout);
9389428323dSchristos 	free(name);
9399428323dSchristos     }
9409428323dSchristos     delete_media_iterator(iter);
9419428323dSchristos     printf("\n");
9429428323dSchristos     fflush(stdout);
9439428323dSchristos }
9449428323dSchristos 
9459428323dSchristos 
9469428323dSchristos void
probe_scsi_device(long bus,long id,int unsure)9479428323dSchristos probe_scsi_device(long bus, long id, int unsure)
9489428323dSchristos {
9499428323dSchristos     UInt32 devType;
9509428323dSchristos 
9519428323dSchristos     if (DoInquiry(id, bus, &devType)) {
9529428323dSchristos     	if (devType == kScsiDevTypeDirect
9539428323dSchristos     		|| devType == kScsiDevTypeOptical) {
9549428323dSchristos     	    add_to_cache(bus, id, 0, unsure);
9559428323dSchristos     	} else if (devType == kScsiDevTypeCDROM
9569428323dSchristos 		|| devType == kScsiDevTypeWorm) {
9579428323dSchristos     	    add_to_cache(bus, id, 1, unsure);
9589428323dSchristos     	}
9599428323dSchristos     }
9609428323dSchristos }
9619428323dSchristos 
9629428323dSchristos 
9639428323dSchristos long
lookup_scsi_device(long bus,long id,int * is_cdrom,int * unsure)9649428323dSchristos lookup_scsi_device(long bus, long id, int *is_cdrom, int *unsure)
9659428323dSchristos {
9669428323dSchristos     /* walk down list looking for bus and id ?
9679428323dSchristos      *
9689428323dSchristos      * only probe out of iterate (so always add in order)
9699428323dSchristos      * reset list if we reset the iterate
9709428323dSchristos      */
9719428323dSchristos     struct cache_item *item;
9729428323dSchristos     struct cache_item *next;
9739428323dSchristos     long result = -1;
9749428323dSchristos     int count = 0;
9759428323dSchristos 
9769428323dSchristos     if (scsi_inited == 0) {
9779428323dSchristos 	scsi_init();
9789428323dSchristos     }
9799428323dSchristos 
9809428323dSchristos     while (1) {
9819428323dSchristos     	count++;
9829428323dSchristos 	for (item = linux_order.first; item != NULL; item = item->next) {
9839428323dSchristos 	    if (item->bus == bus && item->id == id) {
9849428323dSchristos 		result = item->value;
9859428323dSchristos 		*is_cdrom = item->is_cdrom;
9869428323dSchristos 		*unsure = item->unsure;
9879428323dSchristos 		break;
9889428323dSchristos 	    }
9899428323dSchristos 	}
9909428323dSchristos 	if (count < 2 && result < 0) {
9919428323dSchristos 	    probe_all();
9929428323dSchristos 	} else {
9939428323dSchristos 	    break;
9949428323dSchristos 	}
9959428323dSchristos     };
9969428323dSchristos 
9979428323dSchristos     return result;
9989428323dSchristos }
9999428323dSchristos 
10009428323dSchristos 
10019428323dSchristos /*
10029428323dSchristos  * This has the same structure as lookup_scsi_device() except we are
10039428323dSchristos  * matching on the value & type rather than the bus & id.
10049428323dSchristos  */
10059428323dSchristos long
lookup_scsi_index(long index,int is_cdrom,long * bus,long * id)10069428323dSchristos lookup_scsi_index(long index, int is_cdrom, long *bus, long *id)
10079428323dSchristos {
10089428323dSchristos     struct cache_item *item;
10099428323dSchristos     struct cache_item *next;
10109428323dSchristos     long result = 0;
10119428323dSchristos     int count = 0;
10129428323dSchristos 
10139428323dSchristos     if (scsi_inited == 0) {
10149428323dSchristos 	scsi_init();
10159428323dSchristos     }
10169428323dSchristos 
10179428323dSchristos     while (1) {
10189428323dSchristos     	count++;
10199428323dSchristos 	for (item = linux_order.first; item != NULL; item = item->next) {
10209428323dSchristos 	    if (item->value == index && item->is_cdrom == is_cdrom
10219428323dSchristos 		    && item->unsure == 0) {
10229428323dSchristos 		result = 1;
10239428323dSchristos 		*bus = item->bus;
10249428323dSchristos 		*id = item->id;
10259428323dSchristos 		break;
10269428323dSchristos 	    }
10279428323dSchristos 	}
10289428323dSchristos 	if (count < 2 && result == 0 && !linux_cache_loaded()) {
10299428323dSchristos 	    probe_all();
10309428323dSchristos 	} else {
10319428323dSchristos 	    break;
10329428323dSchristos 	}
10339428323dSchristos     };
10349428323dSchristos 
10359428323dSchristos     return result;
10369428323dSchristos }
10379428323dSchristos 
10389428323dSchristos 
10399428323dSchristos void
add_to_cache(long bus,long id,int is_cdrom,int unsure)10409428323dSchristos add_to_cache(long bus, long id, int is_cdrom, int unsure)
10419428323dSchristos {
10429428323dSchristos     struct cache_item *item;
10439428323dSchristos 
10449428323dSchristos     item = malloc(sizeof(struct cache_item));
10459428323dSchristos     if (item == NULL) {
10469428323dSchristos 	return;
10479428323dSchristos     } else {
10489428323dSchristos 	item->bus = bus;
10499428323dSchristos 	item->id = id;
10509428323dSchristos 	item->is_cdrom = is_cdrom;
10519428323dSchristos 	item->unsure = unsure;
10529428323dSchristos 	if (is_cdrom) {
10539428323dSchristos 	    item->value = linux_order.next_cdrom;
10549428323dSchristos 	    linux_order.next_cdrom++;
10559428323dSchristos 	} else {
10569428323dSchristos 	    item->value = linux_order.next_disk;
10579428323dSchristos 	    linux_order.next_disk++;
10589428323dSchristos 	}
10599428323dSchristos 	item->next = 0;
10609428323dSchristos     }
10619428323dSchristos     if (linux_order.first == NULL) {
10629428323dSchristos 	linux_order.first = item;
10639428323dSchristos 	linux_order.last = item;
10649428323dSchristos     } else {
10659428323dSchristos 	linux_order.last->next = item;
10669428323dSchristos 	linux_order.last = item;
10679428323dSchristos     }
10689428323dSchristos }
10699428323dSchristos 
10709428323dSchristos 
10719428323dSchristos void
init_linux_cache(void)10729428323dSchristos init_linux_cache(void)
10739428323dSchristos {
10749428323dSchristos     linux_order.first = NULL;
10759428323dSchristos     clear_linux_cache();
10769428323dSchristos }
10779428323dSchristos 
10789428323dSchristos 
10799428323dSchristos void
clear_linux_cache(void)10809428323dSchristos clear_linux_cache(void)
10819428323dSchristos {
10829428323dSchristos     struct cache_item *item;
10839428323dSchristos     struct cache_item *next;
10849428323dSchristos 
10859428323dSchristos     for (item = linux_order.first; item != NULL; item = next) {
10869428323dSchristos 	next = item->next;
10879428323dSchristos 	free(item);
10889428323dSchristos     }
10899428323dSchristos     /* back to starting value */
10909428323dSchristos     linux_order.first = NULL;
10919428323dSchristos     linux_order.last = NULL;
10929428323dSchristos     linux_order.next_disk = 0;
10939428323dSchristos     linux_order.next_cdrom = 0;
10949428323dSchristos     linux_order.loaded = 0;
10959428323dSchristos }
10969428323dSchristos 
10979428323dSchristos 
10989428323dSchristos void
mark_linux_cache_loaded(void)10999428323dSchristos mark_linux_cache_loaded(void)
11009428323dSchristos {
11019428323dSchristos     linux_order.loaded = 1;
11029428323dSchristos }
11039428323dSchristos 
11049428323dSchristos 
11059428323dSchristos int
linux_cache_loaded(void)11069428323dSchristos linux_cache_loaded(void)
11079428323dSchristos {
11089428323dSchristos     return linux_order.loaded;
11099428323dSchristos }
1110