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

📄 scsi.c

📁 cy68013a USB2.0 highspeed mass storage source code
💻 C
📖 第 1 页 / 共 3 页
字号:
//-----------------------------------------------------------------------------
//   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/CY4611B/scsi.c $
// $Date: 5/27/05 4:11p $
// $Revision: 4 $
//
//-----------------------------------------------------------------------------
//  Copyright (c) 1999 Cypress Semiconductor, Inc. All rights reserved
//-----------------------------------------------------------------------------
#include "fx2.h"
#include "fx2regs.h"
#include "scsi.h"
#include "gpif.h"
#include "globals.h"

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

#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;

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

   result = sendSCSICommand();

   // 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 EP6 
      return(USBS_FAILED);
      }

   // no need to do the data xfer phase if the host isn't expecting any data.
   if (!dataTransferLen)
      {
      if (readATAPI_STATUS_REG() & ATAPI_STATUS_DRQ_BIT)
         {
         return(USBS_PHASE_ERROR);       // USBS_PHASE_ERROR -- Hn < Di (case 2) or Hn < Do (case 3)
         }
      else
         return(USBS_PASSED);
      }

   //////////////////////////////////////////////////////////////////
   // Start of data xfer phase
   //////////////////////////////////////////////////////////////////
   if (bUseUdma) 
   {
      result = scsiReadUdma();
   }
   else
   {
      result = scsiReadPio();
   }

   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 EP6, 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;

   bUseUdma = 0;

   // if the drive is configured for udma then use udma depending on the
   // scsi command
   if (ActiveLunConfigData.udmaMode)
   {
      bUseUdma = 1;   
   }

   result = sendSCSICommand();

   // If the command failed, stall the endpoint and get out
   if (result != USBS_PASSED)
   {
      stallEP2OUT();
      return(USBS_FAILED);
   }

   if (!dataTransferLen)
      return(result);

   if (bUseUdma)
   {
      return(scsiWriteUdma());
   }
   else
   {
      return(scsiWrite());
   }

#endif

#if DEVICE_TYPE_IS_IDE
   return(0);
#endif
}



#define SENSE_LEN 18
   
///////////////////////////////////////////////////////////////////////////////
#if DEVICE_TYPE_IS_SCSI
///////////////////////////////////////////////////////////////////////////////
WORD getDriveDataLen()
{
    WORD driveDataLen;

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

//-----------------------------------------------------------------------------
// 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.
//
//-----------------------------------------------------------------------------
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;
   
   while( (!bDone) && dataTransferLen)
      {
       // Make sure the data is already in the endpoint buffer
      if(!(EP2CS & (bmEPEMPTY | bmEPSTALL))) 
         {
         if (EP2BC & (wPacketSize - 1))
            bShortPacketReceived = 1;

         EP2BCL = 00;         // Release the endpoint buffer to FIFO.

         wAmountSent = 0; 
         while( (wPacketSize > wAmountSent) && (!bDone) && dataTransferLen)
            {
            // Make sure the write is successful, otherwise get out. -- First wait for the busy bit to clear.
            if (!wDriveDataLen)
               {
               driveStatus = waitForDRQBit(1);
               readATAPI_STATUS_REG();             // Clear interrupt for next round.
   
               if(driveStatus & ATAPI_STATUS_ERROR_BIT)
                  {
                  cReturnStatus = USBS_FAILED;  

⌨️ 快捷键说明

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