⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 basedev.cpp

📁 使用ASPI包装成的一些通用类
💻 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 + -