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

📄 scsi.c

📁 对SCSI设备进行字节访问的操作,只要适合SCSI标准,均可
💻 C
📖 第 1 页 / 共 2 页
字号:
//-----------------------------------------------------------------------------
//   File:      scsi.c
//   Contents:   Functions to handle a scsi device.
//
// indent 3.  NO TABS!
//
// Description:
//    SCSI devices differ from IDE device as follows:
//    - SCSI devices may accept or return data according to the value of
//       its byte count registers which may differ from the host request
//       indicated in the CBW variable 'dataTransferlen'. 
//
//       If the host requests to write a greater amount than the byte count 
//       registers indicate, the extra data is processed by throwing it on 
//       the floor and reporting it as a residue.
//
//       If the host requests a read greater than what is indicated in the 
//       byte count registers, and the last packet is a full packet, a short 
//       packet is sent to terminate the transfer.
//
//    - generalSCSIInCommand() and generalSCSIOutCommand() are called from
//       periph.c.  Their conditional compile flags are kept inside the function
//       to maintain original code for periph.c.  All other functions in this
//       module are specific for SCSI and are static to this file.  They are
//       under one conditional compile flag.
//
//-----------------------------------------------------------------------------
// $Archive: /USB/atapifx2/software/scsi.c $
// $Date: 1/21/02 2:38p $
// $Revision: 41 $
//
//-----------------------------------------------------------------------------
//  Copyright (c) 1999 Cypress Semiconductor, Inc. All rights reserved
//-----------------------------------------------------------------------------
#include "fx2.h"
#include "fx2regs.h"
#include "scsi.h"
#include "gpif.h"

static BYTE scsiWrite(void);
static BYTE scsiWriteUdma();
static void prepareForATAPICommand();
static bit inDataFromDriveUdma();


// this bit determines if the current transfer is to be carried out using UDMA (1) or
// PIO (0)
bit useUdma;
bit bShortPacketSent;
BYTE udmaErrorCount;

#define SENSE_LEN 18

//-----------------------------------------------------------------------------
// Function:  generalSCSIInCommand()
//
// Input:   none
// Output:  bit flag
//          0 = success, 1 = failure
//
// Global data:
//    CBW from EP2FIFOBUF.
//
// Description:
//    Top level handler for scsi read.  The scsi command packet is 
//    a 12-byte packet extracted from the CBW contained in EP2FIFOBUF 
//    starting from byte 15.  If the command fails, the IN endpoint buffer
//    is stalled and the transaction is failed.
//
//    If the command was processed successfully, data is extracted from the 
//    drive till the byte count from the drive is exhausted.  If the byte count
//    indicated by the drive is less than what is requested by the host, the IN
//    endpoint is stalled, but the transaction is passed.  The remainder of bytes
//    the host still expects is reported as a residue.
//-----------------------------------------------------------------------------
BYTE generalSCSIInCommand()
{
#if DEVICE_TYPE_IS_SCSI

   BYTE result = 0;

   // Clear the bit telling us if we need a STALL to terminat the IRP on the host side   
   bShortPacketSent = 0;

   // if the drive is configured for udma then use udma depending on the
   // scsi command
   if (udmaMode)
   {
      switch(EP2FIFOBUF[0xf])
      {
         case 0x28:
         case 0xA8:
            useUdma = 1;     
            break;
         default:
            useUdma = 0;
            break;
      }
   }

   result = sendSCSICommand(EP2FIFOBUF + CBW_DATA_START);

   // relinquish control of the bulk buffer occupied by the CBW
   EP2BCL = 0x80; 
   
   // Need to modify this code so that we know if we sent a short packet to terminate the xfer.
   // Although the STALL is required, the ScanLogic driver and Mac driver will not properly handle it.
   
   if(result != USBS_PASSED)
      {
      failedIn();    // stalls EP8 
      return(USBS_FAILED);
      }

   // no need to do the data xfer phase if the host isn't expecting any data.
   if (!dataTransferLenLSW && !dataTransferLenMSW)
      {
      // Make sure the status is correct
      while (readATAPI_STATUS_REG() & ATAPI_STATUS_BUSY_BIT)
         ;

      if (readATAPI_STATUS_REG() & ATAPI_STATUS_DRQ_BIT)
         return(USBS_PHASE_ERROR);       // USBS_PHASE_ERROR -- Hn < Di (case 2)
      else
         return(USBS_PASSED);
      }

   //////////////////////////////////////////////////////////////////
   // Start of data xfer phase
   //////////////////////////////////////////////////////////////////
   if (useUdma) 
   {
      result = inDataFromDriveUdma();
   }
   else
   {
      result = inDataFromDrive();
   }

   if (dataTransferLen)    
      {
      // Case H(i) > D(i) or H(i) > D(n)
      // "terminate the transfer with a short packet, then STALL the IN endpoint"
      failedIn();       // only stalls EP8, does not return error
     
      // Pass the result to the next layer up.
      return(result);  
      }

   else
      return(result);       // No residue, just return status

#else
   return(0);
#endif
}   


//-----------------------------------------------------------------------------
// Function:  generalSCSIOutCommand()
//
// Input:   none
// Output:  bit flag
//          0 = success, 1 = failure
//
// Global data:
//    CBW from EP2FIFOBUF.
//
// Local data:
//    cmd      - command op code from CBW
//    result   - return status
//
// Description:
//    The scsi command packet is a 12-byte packet extracted from the CBW 
//    contained in EP2FIFOBUF starting from byte 15.  If the command fails, 
//    the OUT endpoint buffer is stalled and the transaction is failed.
//
//    If the command is successful, data is sent to the drive.
//    When the write encounters an error, the endpoint is stalled and the
//    transaction is failed.
//
//-----------------------------------------------------------------------------
BYTE generalSCSIOutCommand()
{
#if DEVICE_TYPE_IS_SCSI
   // Init local vars.

   BYTE result = USBS_FAILED;

   useUdma = 0;

   // if the drive is configured for udma then use udma depending on the
   // scsi command
   if (udmaMode)
   {
      switch(EP2FIFOBUF[0xf])
      {
         case 0x2A:
         case 0xAA:
            useUdma = 1;   //syk
            break;
         default:
            useUdma = 0;
            break;
      }
   }

   result = sendSCSICommand(EP2FIFOBUF + CBW_DATA_START);

   // relinquish control of the bulk buffer occupied by the CBW
   EP2BCL = 0x80;     

   // If the command failed, stall the endpoint and get out
   if (result != USBS_PASSED)
   {
      // If the transfer still contains data, and the xfer has not been terminated by a short packet
      // then we must stop the transfer with a STALL.
      if (dataTransferLen > 0)
      {
         // We may want to stall the endpoint here, but we must be careful to make sure that 
         // we don't set the stall bit when the xfer has completed!
          stallEP2OUT();
      }
      return(USBS_FAILED);
   }

   if (!dataTransferLen)
      return(result);

   if (useUdma)
   {
      result = scsiWriteUdma();
   }
   else
   {
      result = scsiWrite();
   }

   return(result);
#endif

#if DEVICE_TYPE_IS_IDE
   return(0);
#endif
}



#define SENSE_LEN 18
const char code testUnitReady[12] = { 0x00, 0x00, 0x00, 0x00, 00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const char code requestSense[12] = {  0x03, 0x00, 0x00, 0x00, SENSE_LEN, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
// Send a TestUnitReady command to the device.
// If the device fails the testUnitReady command, return the sense code, else return 0
BYTE SCSITestUnitReady()
{

   bit result = 0;
   //char count;
    
   if (!scsi)
      return(result);

#if DEVICE_TYPE_IS_SCSI
   useUdma = 0;
   result = sendSCSICommand((char xdata *) testUnitReady);
   if (result != USBS_PASSED)
   {
      result = sendSCSICommand((char xdata *) requestSense);
      if (result != USBS_PASSED)
         {
         }

      //result = waitForIntrq();

      readPIO16toXdata(ATAPI_DATA_REG, halfKBuffer, SENSE_LEN, LISTEN_TO_DRIVE_LEN);
      return(halfKBuffer[12]);
    }
#endif
}   


// Read the Inquiry info into our internal data structures.
// NOT prompted by the host.
#define INQUIRY_LEN 0x2c
const char code inquiryCommand[12] = { 0x12, 0x00, 0x00, 0x00, INQUIRY_LEN, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
void SCSIInquiryToATAPI()
{
#if DEVICE_TYPE_IS_SCSI

    bit result;

    useUdma = 0;
    result = sendSCSICommand((char xdata *) inquiryCommand);
    if (result != USBS_PASSED)
    {
        failedIn();    //This is an internal command, just leave if it fails.
        return;
    }

     result = waitForIntrq();

     readPIO16toXdata(ATAPI_DATA_REG, halfKBuffer, INQUIRY_LEN, LISTEN_TO_DRIVE_LEN);
  

   if (halfKBuffer[SCSI_INQUIRY_DEVICE_CLASS] == 5)
   {
      intrfcSubClass = USB_MS_CD_ROM_SUBCLASS;  
   }
#endif
}   


WORD getDriveDataLen()
{
    WORD driveDataLen;


    driveDataLen = readPIO8(ATAPI_BYTE_COUNT_MSB) << 8;
    driveDataLen += readPIO8(ATAPI_BYTE_COUNT_LSB);
    return(driveDataLen);
}
 


///////////////////////////////////////////////////////////////////////////////
#if DEVICE_TYPE_IS_SCSI
///////////////////////////////////////////////////////////////////////////////

//-----------------------------------------------------------------------------
// Function:  scsiWrite()
//
// Input:   none
// Output:  bit flag
//          0 = success, 1 = failure
//
// Global data:
//    dataTransferLen   - Amount of data requested by the host.  Counts down.
//    EP2CS             - Endpoint buffer status byte.
//    EP2BCL            - Endpoint LSB byte count register.
//
// Local data:
//    wDriveDataLen     - Amount of data drive will accept.
//    wAmountToWrite    - Amount of data to write to the drive.  This is typically
//                         a portion wDriveDataLen, and is qualified by the packet lenght.
//    wAmountSent       - Amount of data sent to the drive.  Counts up to ensure we don't
//                         exceed the packet size.
//    driveStatus       - Drive status from last action.  
//    bDone             - loop control flag     
//
// Description:
//    This function handles the special case of scsi MODE PAGE write (MODE SELECT command).
//    The drive byte count and the DRQ bit are used to determine how much data to send.
//    Typically, the host requests to send data that is much larger than what the
//    drive wants to accept.  
//
//    The drive may want to receive data in chunks less than a packet size, and the 
//    total number of bytes to satisfy the command may be less or greater than
//    a packet length.  Drive data request is processed as follows:
//    
//    (1) Total number of bytes is less than a packet, and drive wants to receive it in
//    increments.  The rest of the packet must be processed out of the buffer in
//    the size requested by the drive.  This transaction is governed by the
//    DRQ bit in the status register.
//
//    (2) Total number of bytes is greater than a packet, but drive wants it
//    in increments less than a packet lenght.  Full packet(s) are processed out
//    of the buffer using logic from (1) until the drive is satisfied.  This 
//    transaction is governed by the DRQ bit in the status register as well as the
//    byte count from the drive.  Any data residue in the endpoint buffer is sent 
//    to ATAPI_NULL_REGISTER.
//
//    If the host is determined to queue up packets to the buffer after the drive 
//    byte count has been satisfied (DRQ=0), the data is processed out of the endpoint 
//    buffer and discarded by setting the skip bit in the endpoint's byte count
//    register.
//
//    The DRQ bit is valid.
//
//    If a write encounters an error, we return an error and let caller 
//    stall the endpoint.
//
//-----------------------------------------------------------------------------
static BYTE scsiWrite(void)
{

   WORD wDriveDataLen = 0;
   BYTE driveStatus = 0;
   WORD wAmountToWrite = 0;
   WORD wAmountSent = 0;  
   bit bDone = 0;
   bit bShortPacketReceived = 0;
   BYTE cReturnStatus = USBS_PASSED;
   

   // See if drive is finished processing command and
   // is ready for data.
   while(readATAPI_STATUS_REG() & ATAPI_STATUS_BUSY_BIT)
      ;

   driveStatus = readATAPI_STATUS_REG();

   if (driveStatus & ATAPI_STATUS_DRQ_BIT)
   {
      while( (!(driveStatus & ATAPI_STATUS_ERROR_BIT)) && (!bDone) && dataTransferLen)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -