| 1 |
/* DoListSCSIDevices.c */ |
| 2 |
/* |
| 3 |
* DoListSCSIDevices.c |
| 4 |
* Copyright © 1992-94 Apple Computer Inc. All Rights Reserved. |
| 5 |
* |
| 6 |
* Find all SCSI devices. The alogrithm first asks the SCSI Manager for the |
| 7 |
* number of busses, then loops through each bus for each device and LUN. |
| 8 |
* old SCSI Manager. This is made complex by the flexible SCSI Manager 4.3 |
| 9 |
* architecture: it is possible for the asynchronous SCSI Manager to only |
| 10 |
* be available on a third-party bus interface, for example. Because of this, |
| 11 |
* we must always scan the bus using the original SCSI Manager even if the |
| 12 |
* asynchronous manager is present. |
| 13 |
*/ |
| 14 |
//#include "SCSISimpleSample.h" |
| 15 |
|
| 16 |
|
| 17 |
|
| 18 |
|
| 19 |
/* |
| 20 |
* These definitions are only for the code files. |
| 21 |
*/ |
| 22 |
#ifndef THINK_C /* MPW includes */ |
| 23 |
#include <Errors.h> |
| 24 |
#include <Script.h> |
| 25 |
#include <Types.h> |
| 26 |
#include <Resources.h> |
| 27 |
#include <QuickDraw.h> |
| 28 |
#include <Fonts.h> |
| 29 |
#include <Events.h> |
| 30 |
#include <Windows.h> |
| 31 |
#include <ToolUtils.h> |
| 32 |
#include <Memory.h> |
| 33 |
#include <Menus.h> |
| 34 |
#include <Lists.h> |
| 35 |
#include <Printing.h> |
| 36 |
#include <Dialogs.h> |
| 37 |
#include <Packages.h> |
| 38 |
#endif |
| 39 |
|
| 40 |
|
| 41 |
|
| 42 |
#include "scsi_test.h" |
| 43 |
#include "MacSCSICommand.h" |
| 44 |
//#include "LogManager.h" |
| 45 |
|
| 46 |
void |
| 47 |
DoListSCSIDevices(void) |
| 48 |
{ |
| 49 |
OSErr status; |
| 50 |
unsigned short lastHostBus; |
| 51 |
unsigned short initiatorID; |
| 52 |
unsigned short bus; |
| 53 |
unsigned short targetID; |
| 54 |
unsigned short LUN; |
| 55 |
DeviceIdent scsiDevice; |
| 56 |
SCSIGetVirtualIDInfoPB scsiGetVirtualIDInfo; |
| 57 |
short deviceCount; |
| 58 |
unsigned short maxTarget; |
| 59 |
Boolean useAsynchManager; |
| 60 |
Str255 work; |
| 61 |
|
| 62 |
LOG("\pList all SCSI Devices"); |
| 63 |
deviceCount = 0; |
| 64 |
/* |
| 65 |
* If we have the asynchronous SCSI Manager, find out how many busses |
| 66 |
* are present on this system. If not, force a "single bus" scan, since |
| 67 |
* DoSCSICommandWithSense ignores the hostBus information if it is |
| 68 |
* forced into "old-style" calls. |
| 69 |
*/ |
| 70 |
if (gEnableNewSCSIManager) |
| 71 |
status = SCSIGetHighHostBusAdaptor(&lastHostBus); |
| 72 |
else { |
| 73 |
status = noErr; |
| 74 |
lastHostBus = 0; /* Force one bus only */ |
| 75 |
} |
| 76 |
if (status == noErr) { |
| 77 |
for (bus = 0; bus <= lastHostBus; bus++) { |
| 78 |
/* |
| 79 |
* Look at this SCSI bus. This would be a good place to allocate |
| 80 |
* the SCSIExecIO command block. In this sample, however, it's |
| 81 |
* allocated on each call to AsyncSCSI, though this is inefficient. |
| 82 |
* Note that it is possible to have busses with no devices. This |
| 83 |
* is true for Apple Macintosh models with two busses (such as |
| 84 |
* the Quadra 950 and PowerMac 8100). Also, if you install a |
| 85 |
* third-party bus adaptor that supports the asynchronous SCSI |
| 86 |
* Manager on a machine with two busses, it would be assigned |
| 87 |
* bus 2 (with busses 0 and 1 referencing the internal system |
| 88 |
* busses). In this case, a system could have no devices on bus |
| 89 |
* 0 or 1. |
| 90 |
*/ |
| 91 |
*((long *) &scsiDevice) = 0; |
| 92 |
scsiDevice.bus = bus; |
| 93 |
/* |
| 94 |
* Check whether we can access this scsi device. SCSIBusAPI will |
| 95 |
* return an error status if this bus is inaccessable (i.e. no bus |
| 96 |
* or other trouble). If it returns noErr, useAsyncManager will |
| 97 |
* be TRUE if the asynchronous SCSI Manager is supported for this |
| 98 |
* bus, and FALSE if it can only be accessed through the original |
| 99 |
* SCSI Manager. This would indicate that a third-party bus |
| 100 |
* interface patched the original SCSI Manager traps (i.e., |
| 101 |
* patched SCSIGet, SCSISelect, etc). |
| 102 |
*/ |
| 103 |
status = SCSIBusAPI(scsiDevice, &useAsynchManager); |
| 104 |
if (status == noErr) { |
| 105 |
if (useAsynchManager) |
| 106 |
status = SCSIGetInitiatorID(scsiDevice, &initiatorID); |
| 107 |
else { |
| 108 |
initiatorID = 7; /* Asynch manager is disabled */ |
| 109 |
} |
| 110 |
} |
| 111 |
if (status != noErr) |
| 112 |
continue; |
| 113 |
/* |
| 114 |
* SCSIGetInitiatorID returned the bus ID of the Macintosh. This |
| 115 |
* is almost always seven, but only the SCSI Manager knows for |
| 116 |
* sure. Note that, by getting the Macintosh bus ID dynamically, |
| 117 |
* we prepare the code for a future system that permitted more |
| 118 |
* than one Macintosh on the same SCSI bus. |
| 119 |
*/ |
| 120 |
status = SCSIGetMaxTargetID(scsiDevice, &maxTarget); |
| 121 |
for (targetID = 0; targetID <= maxTarget; targetID++) { |
| 122 |
if (targetID != initiatorID) { |
| 123 |
scsiDevice.targetID = targetID; |
| 124 |
for (LUN = 0; LUN <= gMaxLogicalUnit; LUN++) { |
| 125 |
/* |
| 126 |
* Try to send a command to this LUN. If it fails, |
| 127 |
* don't try for higher-valued LUNs. |
| 128 |
* SCSICheckForDevicePresent looks, carefully, at the |
| 129 |
* returned error to distinguish between missing |
| 130 |
* devices and devices that are present, but unable to |
| 131 |
* respond, such as CD-ROM players with no disk |
| 132 |
* inserted. This call to SCSICheckForDevicePresent |
| 133 |
* will use the asynchronous SCSI Manager if it can. |
| 134 |
* |
| 135 |
* Note that, if the asynchronous manager is not |
| 136 |
* available, we can still check for non-zero LUNs by |
| 137 |
* using the old method of stuffing the LUN into the |
| 138 |
* command block, however this is not supported in |
| 139 |
* this example. |
| 140 |
*/ |
| 141 |
scsiDevice.LUN = LUN; |
| 142 |
if (SCSICheckForDevicePresent( |
| 143 |
scsiDevice, useAsynchManager) == FALSE) |
| 144 |
break; /* Don't look for LUNs */ |
| 145 |
else { |
| 146 |
++deviceCount; /* Found a device */ |
| 147 |
DoGetDriveInfo(scsiDevice, TRUE, useAsynchManager); |
| 148 |
} /* Check status */ |
| 149 |
} /* LUN loop */ |
| 150 |
} /* Not the initiator id */ |
| 151 |
} /* Target loop */ |
| 152 |
} /* Bus loop */ |
| 153 |
/* |
| 154 |
* Now, we need to look at the hard-wired SCSI drive addresses and |
| 155 |
* check whether a third-party hardware interface that does not use |
| 156 |
* the asynchronous SCSI Manager recognizes this address. If |
| 157 |
* gEnableNewSCSIManager is FALSE, the above loop called the original |
| 158 |
* SCSI Manager, so we don't have to try it again. In this sequence, |
| 159 |
* we hard-wire the initiator ID to seven, as there is no supported |
| 160 |
* way to determine it from the SCSI Manager or operating system. |
| 161 |
*/ |
| 162 |
if (gEnableNewSCSIManager) { |
| 163 |
scsiDevice.bus = 0; |
| 164 |
for (targetID = 0; targetID <= 6; targetID++) { |
| 165 |
CLEAR(scsiGetVirtualIDInfo); |
| 166 |
scsiGetVirtualIDInfo.scsiPBLength = sizeof scsiGetVirtualIDInfo; |
| 167 |
scsiGetVirtualIDInfo.scsiOldCallID = targetID; |
| 168 |
status = SCSIAction((SCSI_PB *) &scsiGetVirtualIDInfo); |
| 169 |
if (status != noErr) { |
| 170 |
/* |
| 171 |
* The asynchronous SCSI Manager does not know about this |
| 172 |
* target ID. Check whether it exists (forcing the request |
| 173 |
* to use the original SCSI Manager). |
| 174 |
*/ |
| 175 |
scsiDevice.targetID = targetID; |
| 176 |
for (LUN = 0; LUN <= gMaxLogicalUnit; LUN++) { |
| 177 |
scsiDevice.LUN = LUN; |
| 178 |
if (SCSICheckForDevicePresent(scsiDevice, FALSE) == FALSE) |
| 179 |
break; /* Don't look for LUNs */ |
| 180 |
else { |
| 181 |
++deviceCount; /* Found a device */ |
| 182 |
DoGetDriveInfo(scsiDevice, TRUE, FALSE); |
| 183 |
} /* Check status */ |
| 184 |
} |
| 185 |
} |
| 186 |
} |
| 187 |
} |
| 188 |
} /* Found a host adaptor */ |
| 189 |
NumToString(deviceCount, work); |
| 190 |
AppendPascalString(work, "\p SCSI Devices"); |
| 191 |
LOG(work); |
| 192 |
} |