Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
Src/SCSISimpleSampleDisplay.c
/* SCSISimpleSampleDisplay.c */ |
/* |
* This module displays the results from all tests. Note that it is |
* intentionally pretty crude so the entire display is described in this file; |
* a "real" program would move strings to resources and, perhaps, more clearly |
* explain the results. |
*/ |
#include "SCSISimpleSample.h" |
typedef struct { |
unsigned char senseKey; |
StringPtr senseText; |
} SenseKeyText; |
/* |
* The sense keys. |
*/ |
static StringPtr gSenseKeyText[] = { |
"\pNo error", |
"\pRecovered error", |
"\pNot ready", |
"\pMedium error", |
"\pHardware error", |
"\pIllegal request", |
"\pUnit attention", |
"\pData protection", |
"\pBlank check", |
"\pVendor specific", |
"\pCopy aborted", |
"\pCommand aborted", |
"\pCompare equal", |
"\pVolume overflow", |
"\pMiscompare", |
"\pReserved" |
}; |
StringPtr gScsiDeviceType[] = { |
"\pDisk", |
"\pTape", |
"\pPrinter", |
"\pProc.", |
"\pWORM", |
"\pCD-ROM", |
"\pScanner", |
"\pOptical", |
"\pChanger", |
"\pCommunications", |
"\pGraphics Arts 0A", |
"\pGraphics Arts 0B", |
}; |
StringPtr gScsiState[] = { |
"\pNot Ready", |
"\pBecoming Ready", |
"\pUnit Attention", |
"\pBusy", |
"\pReady", |
"\pFailure" |
}; |
typedef struct CmdInfo { |
unsigned short cmdByte; |
StringPtr text; |
} CmdInfo, *CmdInfoPtr; |
static CmdInfo gCmdInfo[] = { |
{ kScsiCmdInquiry, "\pInquiry" }, |
{ kScsiCmdLogSelect, "\pLog Select" }, |
{ kScsiCmdLogSense, "\pLog Sense" }, |
{ kScsiCmdModeSelect12, "\pMode Select [12]" }, |
{ kScsiCmdModeSelect6, "\pMode Select [6]" }, |
{ kScsiCmdModeSense12, "\pMode Sense [6]" }, |
{ kScsiCmdRequestSense, "\pRequest Sense" }, |
{ kScsiCmdTestUnitReady, "\pTest Unit Ready" }, |
{ kScsiCmdPreventAllowRemoval, "\pPrevent or Allow Removal" }, |
{ kScsiCmdRead6, "\pRead [6]" }, |
{ kScsiCmdRead10, "\pRead [10]" }, |
{ kScsiCmdReadCapacity, "\pRead Device Capacity" }, |
{ kScsiCmdReadDefectData, "\pRead Defect Data" }, |
{ kScsiCmdReassignBlocks, "\pReassign Blocks" }, |
{ kScsiCmdStartStopUnit, "\pStart or Stop Unit" }, |
{ 0xFF, NULL } |
}; |
/* |
* ShowSCSIBusID is called before sending a command to the indicated device. |
*/ |
void |
ShowSCSIBusID( |
DeviceIdent scsiDevice, /* -> Bus/target/LUN */ |
ConstStr255Param commandText |
) |
{ |
Str255 work; |
pstrcpy(work, "\pBus ID: "); |
AppendDeviceID(work, scsiDevice); |
if (commandText != NULL) { |
pstrcat(work, "\p, "); |
pstrcat(work, commandText); |
} |
LOG(work); |
} |
/* |
* Display the results of an extended sense request. |
* Format the fields we understand. |
*/ |
void |
ShowRequestSense( |
register ScsiCmdBlockPtr scsiCmdBlockPtr |
) |
{ |
#define SCB (*scsiCmdBlockPtr) |
DoShowRequestSense( |
SCB.scsiDevice, /* For this device */ |
SCB.status, /* The original error from the SCSI Manager */ |
SCB.requestSenseStatus, /* The error, if any, from Request Sense */ |
&SCB.command, /* The command that failed */ |
&SCB.sense /* -> the sense buffer */ |
); |
#undef SCB |
} |
/* |
* Actually display the results of a request sense. This is independent of the SCB |
*/ |
void |
DoShowRequestSense( |
DeviceIdent scsiDevice, |
OSErr operationStatus, |
OSErr requestSenseStatus, |
const SCSI_CommandPtr scsiCommand, |
const SCSI_Sense_Data *sensePtr |
) |
{ |
register int i; |
Str255 work; |
Str255 senseMessage; |
#define SENSE (*sensePtr) |
if (operationStatus != noErr) { |
ShowSCSIBusID(scsiDevice, "\pOperation failed"); |
DoShowSCSICommand(scsiCommand, NULL); |
} |
if (operationStatus != noErr && operationStatus != statusErr) { |
/* |
* The operation failed, and the failure was severe enough that |
* the device didn't return Check Condition. Perhaps there is |
* no device at this bus/target. |
*/ |
ShowStatusError(scsiDevice, operationStatus, scsiCommand); |
} |
if (operationStatus == statusErr && requestSenseStatus == noErr) { |
/* |
* The operation failed, the device returned Check Condition, and |
* we were able to read the Request Sense information. |
*/ |
pstrcpy(work, "\pSense: "); |
if ((SENSE.errorCode & kScsiSenseInfoMask) != kScsiSenseInfoValid) { |
AppendPascalString(work, "\p(invalid sense code)"); |
AppendHexLeadingZeros(work, SENSE.errorCode, 2); |
LOG(work); |
} |
else { |
AppendPascalString( |
work, gSenseKeyText[SENSE.senseKey & kScsiSenseKeyMask]); |
if ((SENSE.senseKey & kScsiSenseILI) != 0) |
AppendPascalString(work, "\p, Illegal Logical Length"); |
if ((SENSE.senseKey & kScsiSenseEOM) != 0) |
AppendPascalString(work, "\p, End of Media"); |
if ((SENSE.senseKey & kScsiSenseFileMark) != 0) |
AppendPascalString(work, "\p, File Mark"); |
LOG(work); |
work[0] = 0; |
AppendPascalString(work, "\p ASC: "); |
AppendHexLeadingZeros(work, SENSE.additionalSenseCode, 2); |
AppendPascalString(work, "\p, ASQ: "); |
AppendHexLeadingZeros(work, SENSE.additionalSenseQualifier, 2); |
for (i = 1;; ++i) { |
GetIndString( |
senseMessage, SENSE.additionalSenseCode + STRS_SenseBase, i); |
if (senseMessage[0] == 0) { |
/* |
* We don't know the sense qualifier, use the default |
* additional sense code message, if any. |
*/ |
GetIndString( |
senseMessage, |
SENSE.additionalSenseCode + STRS_SenseBase, |
1 |
); |
if (senseMessage[0] != 0) |
goto displaySense; |
break; |
} |
if (senseMessage[1] == SENSE.additionalSenseQualifier) { |
displaySense: senseMessage[1] = senseMessage[0] - 1; |
AppendPascalString(work, "\p, "); |
AppendPascalString(work, (StringPtr) &senseMessage[1]); |
break; |
} |
} |
LOG(work); |
} |
} |
#undef SENSE |
} |
/* |
* This formats and displays the SCSI Manager OSErr code (with out extensions) |
*/ |
void |
ShowStatusError( |
DeviceIdent scsiDevice, |
OSErr errorStatus, |
const SCSI_CommandPtr scsiCommand |
) |
{ |
Str255 work; |
StringHandle errorHdl; |
if (errorStatus != noErr || gVerboseDisplay) { |
pstrcpy(work, "\pDevice: "); |
AppendDeviceID(work, scsiDevice); |
AppendPascalString(work, "\p, "); |
switch (errorStatus) { |
case noErr: AppendPascalString(work, "\pSuccessful"); break; |
case scsiNonZeroStatus: /* Continue */ |
case statusErr: AppendPascalString(work, "\pCheck Condition"); break; |
case controlErr: AppendPascalString(work, "\pBusy"); break; |
case scBadParmsErr: AppendPascalString(work, "\pParam Error"); break; |
case scCommErr: AppendPascalString(work, "\pNo Device"); break; |
case scPhaseErr: AppendPascalString(work, "\pPhase Error"); break; |
case scComplPhaseErr: AppendPascalString(work, "\pBad Phase"); break; |
default: |
AppendPascalString(work, "\pSystem Error "); |
AppendSigned(work, errorStatus); |
errorHdl = (StringHandle) GetResource('Estr', errorStatus); |
if (errorHdl != NULL) { |
AppendPascalString(work, "\p, \""); |
HLock((Handle) errorHdl); |
AppendPascalString(work, *errorHdl); |
HUnlock((Handle) errorHdl); |
ReleaseResource((Handle) errorHdl); |
AppendPascalString(work, "\p\""); |
} |
break; |
} |
LOG(work); |
DoShowSCSICommand(scsiCommand, NULL); |
} |
} |
void |
DoShowInquiry( |
DeviceIdent scsiDevice, /* -> Bus/target/LUN */ |
const SCSI_Inquiry_Data *inquiry |
) |
{ |
unsigned short i; |
Str255 work; |
#define INQUIRY (*inquiry) |
work[0] = 0; |
AppendDeviceID(work, scsiDevice); |
i = INQUIRY.devType; |
if (i == kScsiDevTypeMissing) |
AppendPascalString(work, "\p: Missing device or logical unit"); |
else { |
if (i >= kScsiDevTypeFirstReserved) { |
AppendPascalString(work, "\p: Reserved or unknown device type ("); |
AppendHexLeadingZeros(work, i, 2); |
AppendPascalString(work, "\p)"); |
} |
else { |
AppendPascalString(work, "\p: \""); |
AppendPascalString(work, gScsiDeviceType[i]); |
AppendPascalString(work, "\p\""); |
} |
AppendPascalString(work, "\p, \""); |
AppendBytes(work, (const Ptr) INQUIRY.vendor, sizeof INQUIRY.vendor); |
AppendPascalString(work, "\p\", \""); |
AppendBytes(work, (const Ptr) INQUIRY.product, sizeof INQUIRY.product); |
AppendPascalString(work, "\p\", \""); |
AppendBytes(work, (const Ptr) INQUIRY.revision, sizeof INQUIRY.revision); |
AppendPascalString(work, "\p\""); |
} |
LOG(work); |
#undef INQUIRY |
} |
void |
DisplaySCSIErrorMessage( |
OSErr errorStatus, |
ConstStr255Param errorText |
) |
{ |
Str255 work; |
Handle errorMsgHdl; |
if (errorStatus != noErr) { |
pstrcpy(work, "\pSCSI Error ("); |
AppendSigned(work, errorStatus); |
AppendPascalString(work, "\p) at "); |
AppendPascalString(work, (const StringPtr) errorText); |
AppendChar(work, '.'); |
errorMsgHdl = GetResource('Estr', errorStatus); |
if (errorMsgHdl != NULL) { |
AppendPascalString(work, "\p \""); |
AppendPascalString(work, (StringPtr) *errorMsgHdl); |
AppendPascalString(work, "\p\""); |
ReleaseResource(errorMsgHdl); |
} |
LOG(work); |
} |
} |
void |
DoShowSCSICommand( |
const SCSI_CommandPtr scsiCommand, |
ConstStr255Param message |
) |
{ |
register CmdInfoPtr cmdInfoPtr; |
register unsigned short i; |
unsigned short cmdBlockLength; /* -> Length of CDB */ |
Str255 work; |
work[0] = 0; |
if (message != NULL && message[0] != 0) { |
AppendPascalString(work, (StringPtr) message); |
AppendPascalString(work, "\p, "); |
} |
pstrcpy(work, "\pCommand "); |
for (cmdInfoPtr = gCmdInfo; cmdInfoPtr->text != NULL; cmdInfoPtr++) { |
if (cmdInfoPtr->cmdByte == scsiCommand->scsi[0]) { |
AppendPascalString(work, "\p ("); |
AppendPascalString(work, cmdInfoPtr->text); |
AppendPascalString(work, "\p)"); |
break; |
} |
} |
AppendPascalString(work, "\p ="); |
cmdBlockLength = SCSIGetCommandLength((Ptr) scsiCommand); |
if (cmdBlockLength == 0) |
cmdBlockLength = sizeof (SCSI_Command); |
for (i = 0; i < cmdBlockLength; i++) { |
AppendChar(work, ' '); |
AppendHexLeadingZeros(work, (unsigned long) scsiCommand->scsi[i], 2); |
} |
LOG(work); |
} |
void |
AppendDeviceID( |
StringPtr result, |
DeviceIdent scsiDevice |
) |
{ |
AppendUnsigned(result, scsiDevice.bus); |
AppendChar(result, '.'); |
AppendUnsigned(result, scsiDevice.targetID); |
AppendChar(result, '.'); |
AppendUnsigned(result, scsiDevice.LUN); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14