📄 basedev.cpp
字号:
////////////////////////////////////////////////////////////
//
// Module BASEDEV.CPP
//
// ASPI class library
// SCSI device base class
//
// Project: A Programmer's Guide to SCSI
//
// Copyright (C) 1997, Brian Sawert
// Portions copyright (C) 1995, Larry Martin
// All rights reserved
//
////////////////////////////////////////////////////////////
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <time.h>
#include "basedev.hpp"
static char *MajorErrorString[NUM_MAJOR_ERRORS+1] = {
"No Sense",
"Recovered Error",
"Not Ready",
"Medium Error",
"Hardware Error",
"Illegal Request",
"Unit Attention",
"Data Protect",
"Blank Check",
"Vendor Specific",
"Copy Aborted",
"Aborted Command",
"Equal",
"Volume Overflow",
"Miscompare",
"Reserved",
// messages for made up errors
"Filemark Encountered",
"End of Medium",
"Incorrect Length",
"System Error",
"Driver Error",
"Unknown" };
char *ScsiBaseDevice::QueryMajorErrorString(ScsiError_t errcode)
{
if ( ((MajorError(errcode) >> 16) & 0xFFFF) < NUM_MAJOR_ERRORS )
return MajorErrorString[(MajorError(errcode) >> 16) & 0xFFFF];
else
return MajorErrorString[NUM_MAJOR_ERRORS];
}
void ScsiBaseDevice::QueryErrorString(ScsiError_t errcode, char *bufp, unsigned maxbytes)
{
if (bufp && maxbytes > 1)
{
char buf[256];
char *major = QueryMajorErrorString(errcode);
wsprintf(buf,"Error code: %04X\r\nDescription: %s\r\nASC: %02X ASQ: %02X",
errcode, major, AscError(errcode), AsqError(errcode));
strncpy(bufp,buf,maxbytes);
*(bufp+maxbytes-1) = 0;
}
}
ScsiBaseDevice::ScsiBaseDevice()
{
Device = NULL;
IsOpen = 0;
LastScsiError = Err_None;
LastError = MakeError(DEV_ERR_NO_SENSE, 0);
SystemError = 0;
Attributes.ShortTimeout = 1L*1000L;
Attributes.MediumTimeout = 120L*1000L;
Attributes.LongTimeout = 2L*60L*60L*1000L; // two hours
}
ScsiBaseDevice::~ScsiBaseDevice()
{
if (IsOpen)
Close();
}
int ScsiBaseDevice::ValidResidualCount()
{
return Sense.Valid;
}
long ScsiBaseDevice::GetResidualCount()
{
return ( ((long)Sense.InformationByte3 << 24)
| ((long)Sense.InformationByte2 << 16)
| ((long)Sense.InformationByte1 << 8)
| ((long)Sense.InformationByte0) );
}
unsigned ScsiBaseDevice::MapAscAsq()
{
return((Sense.Asc << 8) & Sense.Asq);
}
ScsiError_t ScsiBaseDevice::MapScsiError()
{
switch (LastScsiError)
{
case Err_None:
return MakeError(DEV_ERR_NO_SENSE, 0);
case Err_CheckCondition:
{
if ((Sense.ErrorCode != 0x70) && (Sense.ErrorCode != 0x71)) // recognized values?
return MakeError(DEV_ERR_DRIVER, 0);
// map sense keys to error codes
switch (Sense.SenseKey)
{
case SCSI_Skey_NoSense:
if (Sense.EndOfMedia)
return MakeError(DEV_ERR_END_OF_MEDIUM, 0);
if (Sense.FileMark)
return MakeError(DEV_ERR_FILEMARK, 0);
if (Sense.IllegalLength)
{
if (GetResidualCount() < 0)
return MakeError(DEV_ERR_INCORRECT_LENGTH, 0);
else
return MakeError(DEV_ERR_NO_SENSE, 0);
}
return MakeError(DEV_ERR_NO_SENSE, 0);
case SCSI_Skey_RecoveredError:
return MakeError(DEV_ERR_NO_SENSE, 0);
case SCSI_Skey_NotReady:
return MakeError(DEV_ERR_NOT_READY,MapAscAsq());
case SCSI_Skey_MediumError:
return MakeError(DEV_ERR_MEDIUM,MapAscAsq());
case SCSI_Skey_HardwareError:
return MakeError(DEV_ERR_HARDWARE,MapAscAsq());
case SCSI_Skey_IllegalRequest:
return MakeError(DEV_ERR_ILLEGAL_REQUEST,MapAscAsq());
case SCSI_Skey_UnitAttention:
return MakeError(DEV_ERR_UNIT_ATTENTION,MapAscAsq());
case SCSI_Skey_DataProtect:
return MakeError(DEV_ERR_DATA_PROTECT,MapAscAsq());
case SCSI_Skey_BlankCheck:
return MakeError(DEV_ERR_BLANK_CHECK,MapAscAsq());
case SCSI_Skey_VendorSpecific:
return MakeError(DEV_ERR_VENDOR,MapAscAsq());
case SCSI_Skey_CopyAborted:
return MakeError(DEV_ERR_COPY_ABORTED,MapAscAsq());
case SCSI_Skey_AbortedCommand:
return MakeError(DEV_ERR_CMD_ABORTED,MapAscAsq());
case SCSI_Skey_Equal:
return MakeError(DEV_ERR_EQUAL,MapAscAsq());
case SCSI_Skey_VolumeOverflow:
return MakeError(DEV_ERR_VOL_OVERFLOW,MapAscAsq());
case SCSI_Skey_Miscompare:
return MakeError(DEV_ERR_MISCOMPARE,MapAscAsq());
case SCSI_Skey_Reserved:
return MakeError(DEV_ERR_RESERVED,MapAscAsq());
}
return MakeError(DEV_ERR_UNKNOWN, 0);
}
// other errors mapped to driver error code
case Err_Aborted:
case Err_InvalidCommand:
case Err_InvalidHostAdapter:
case Err_NoDevice:
case Err_InvalidSrb:
case Err_FailedInit:
case Err_Busy:
case Err_BufferTooBig:
case Err_SelectionTimeout:
case Err_DataOverrun:
case Err_UnexpectedBusFree:
case Err_TargetPhase:
case Err_Timeout:
case Err_CommandTimeout:
case Err_MessageReject:
case Err_BusReset:
case Err_ParityError:
case Err_RequestSenseFailed:
case Err_TargetBusy:
case Err_TargetReservationConflict:
case Err_TargetQueueFull:
case Err_OutOfMemory:
case Err_Unknown:
case Err_AspiDriver:
return MakeError(DEV_ERR_DRIVER, 0);
default:
return MakeError(DEV_ERR_UNKNOWN, 0);
}
}
ScsiDevice *ScsiBaseDevice::GetScsiDevice()
{
return Device;
}
ScsiError_t ScsiBaseDevice::Open(ScsiDevice *dev, ScsiDeviceAttributes_t *attr)
{
if (IsOpen)
return MakeError(DEV_ERR_DRIVER, 0);
if (!dev)
return LastError = MakeError(DEV_ERR_DRIVER, 0);
Device = dev;
IsOpen = 1;
Adapter = dev->GetAdapter();
Unit = dev->GetUnit();
Lun = dev->GetLun();
LastError = Inquiry(&InquiryData,sizeof(InquiryData));
if (LastError)
{
IsOpen = 0;
Device = NULL;
return LastError;
}
return LastError;
}
ScsiError_t ScsiBaseDevice::Close(void)
{
if (IsOpen)
{
IsOpen = 0;
Device = NULL;
}
else
LastError = MakeError(DEV_ERR_DRIVER, 0);
return LastError;
}
ScsiError_t ScsiBaseDevice::DoCommand( void *cdb, unsigned cdblen,
void *dbuf, unsigned long dbuflen, int dir,
long timeout )
{
ScsiError_t err;
int x;
if (!Device)
return MakeError(DEV_ERR_DRIVER, 0);
x = ScbMutex.RequestMutex(-1L);
if (x != 0)
return MakeError(DEV_ERR_DRIVER, 0);
Scb.Init(SC_EXEC_SCSI_CMD,Adapter,Unit,Lun);
Scb.SetCdb(cdb,cdblen);
Scb.SetDataBuffer(dbuf,dbuflen);
Scb.srb.io.SRB_Flags = dir;
LastScsiError = Device->ExecuteScb(Scb,timeout);
if (LastScsiError == Err_CheckCondition)
Scb.GetSense(SenseBuffer,sizeof(SenseBuffer));
if (LastScsiError)
err = MapScsiError();
else
err = MakeError(DEV_ERR_NO_SENSE, 0);
ScbMutex.ReleaseMutex();
return err;
}
ScsiError_t ScsiBaseDevice::RequestSense(void *bufp, unsigned maxbytes)
{
SCSI_Cdb_RequestSense_t cdb;
memset(bufp,0,maxbytes);
memset(&cdb,0,sizeof(cdb));
cdb.CommandCode = SCSI_Cmd_RequestSense;
cdb.Lun = Lun;
cdb.AllocationLength = (sizeof(SenseBuffer) < 0xFF) ? sizeof(SenseBuffer) : 0xFF;
LastError = DoCommand(&cdb,6,SenseBuffer,sizeof(SenseBuffer),Scsi_Dir_In,Attributes.ShortTimeout);
memcpy(bufp,SenseBuffer,(maxbytes < sizeof(SenseBuffer)) ? maxbytes : sizeof(SenseBuffer) );
return LastError;
}
ScsiError_t ScsiBaseDevice::Inquiry( void *bufp, unsigned maxbytes, int evpd, int page_code )
{
SCSI_Cdb_Inquiry_t cdb;
char buf[260];
memset(bufp,0,maxbytes);
if (maxbytes > 255)
maxbytes = 255;
memset(&cdb,0,sizeof(cdb));
cdb.CommandCode = SCSI_Cmd_Inquiry;
cdb.Lun = Lun;
cdb.Evpd = evpd;
cdb.PageCode = page_code;
cdb.AllocationLength = 0xFF;
LastError = DoCommand(&cdb,6,buf,maxbytes,Scsi_Dir_In,Attributes.ShortTimeout);
memcpy(bufp,buf,maxbytes);
return LastError;
}
ScsiError_t ScsiBaseDevice::ModeSense( void *bufp, unsigned maxbytes, int page_code, int pc, int dbd )
{
SCSI_Cdb_ModeSense_t cdb;
memset(bufp,0,maxbytes);
memset(&cdb,0,sizeof(cdb));
cdb.CommandCode = SCSI_Cmd_ModeSense;
cdb.DisableBlockDescriptors = dbd;
cdb.Lun = Lun;
cdb.PageCode = page_code;
cdb.PageControl = pc;
cdb.AllocationLength = (maxbytes < 0xFF) ? maxbytes : 0xFF;
LastError = DoCommand(&cdb,6,bufp,maxbytes,Scsi_Dir_In,Attributes.ShortTimeout);
return LastError;
}
ScsiError_t ScsiBaseDevice::ModeSelect( void *bufp, unsigned nbytes, int pf, int sp )
{
SCSI_Cdb_ModeSelect_t cdb;
memset(&cdb,0,sizeof(cdb));
cdb.CommandCode = SCSI_Cmd_ModeSelect;
cdb.SavePages = sp;
cdb.PageFormat = pf;
cdb.Lun = Lun;
cdb.ParameterListLength = (nbytes < 0xFF) ? nbytes : 0xFF;
LastError = DoCommand(&cdb,6,bufp,nbytes,Scsi_Dir_Out,Attributes.ShortTimeout);
return LastError;
}
ScsiError_t ScsiBaseDevice::WaitTilReady(long timeout)
{
ScsiError_t err;
long elapsed_time;
long start_time = 0;
for (;;)
{
err = TestUnitReady();
if (LastScsiError != Err_CheckCondition)
break;
if (start_time == 0)
{
start_time = time(NULL);
elapsed_time = 0;
}
else
elapsed_time = time(NULL) - start_time;
if ( (timeout != -1L) && (elapsed_time > (timeout/1000 + 1)) )
return err;
Sleep((elapsed_time < 2) ? 100 : 1000L);
}
return err;
}
ScsiError_t ScsiBaseDevice::TestUnitReady(void)
{
SCSI_Cdb_TestUnitReady_t cdb;
long tmp1,tmp2,tmp3;
memset(&cdb,0,sizeof(cdb));
cdb.CommandCode = SCSI_Cmd_TestUnitReady;
cdb.Lun = Lun;
tmp1 = Device->RetryOnTargetBecomingReady;
tmp2 = Device->RetryOnTargetNotReady;
tmp3 = Device->RetryOnTargetBusy;
Device->RetryOnTargetBecomingReady = 0;
Device->RetryOnTargetNotReady = 0;
Device->RetryOnTargetBusy = 0;
LastError = DoCommand(&cdb,6,NULL,0,Scsi_Dir_None,Attributes.ShortTimeout);
Device->RetryOnTargetBecomingReady = tmp1;
Device->RetryOnTargetNotReady = tmp2;
Device->RetryOnTargetBusy = tmp3;
return LastError;
}
// Routines for AlignedBuffer class
AlignedBuffer::AlignedBuffer(WORD size)
{
AlignedPtr = NULL;
// allocate buffer
TruePtr = (char *) malloc(size + 4);
if (TruePtr)
// adjust aligned pointer
{
AlignedPtr = (void *) (TruePtr +
(4L - ((DWORD) AlignedPtr & 3L)));
}
}
AlignedBuffer::~AlignedBuffer()
{
free(TruePtr);
AlignedPtr = TruePtr = NULL;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -