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

📄 scsi.c

📁 cy68013a USB2.0 highspeed mass storage source code
💻 C
📖 第 1 页 / 共 3 页
字号:

      // Make sure we actually have the data before we send it!  (readPIO16 doesn't wait for done)
      while (!gpifIdle())
         ;

      // Replace device string with our own if we have a replacement string.
      if (cmd == INQUIRY && bFirstPacket)
         {
         if (currentLunNum == 0 && mx2_config_data.Lun0String)
            mymemmovexx(EP6FIFOBUF+SCSI_INQUIRY_MANUFACTURER, (BYTE xdata *)pDeviceDscr + (mx2_config_data.Lun0String) - 16, SCSI_IDENTIFY_LEN); 
         else if (currentLunNum == 1 && mx2_config_data.Lun1String)
            mymemmovexx(EP6FIFOBUF+SCSI_INQUIRY_MANUFACTURER, (BYTE xdata *)pDeviceDscr + (mx2_config_data.Lun1String) - 16, SCSI_IDENTIFY_LEN); 
         }

      // We either have a full packet or we're at the last packet.
      // Release the buffer to the SIE and re-init packet byte count.
      if (wInSize || (SHORT_PACKET_BEFORE_STALL))
         {
         if (bOddTransfer && wInSize && wInSize < wPacketSize)
            wInSize--;
         EP6BCH = MSB(wInSize);
         EP6BCL = LSB(wInSize);
         }
      if (wInSize < wPacketSize)
         bShortPacketSent = 1;
      wInSize = 0;
      bFirstPacket = 0;
      }

   // If we were doing an odd transfer, must adjust the residue.
   if (bOddTransfer && dataTransferLen)
      dataTransferLen--;
      
   // If the device hasn't yet told us that the command is done, make sure that the device says "done"
   if (!bDone)
      WAIT_FOR_INTRQ();
   // If the device still says it has data ready for us, we're either in case
   // 7 (Hi<Di) or 8 (Hi <> Do).  Both are phase error cases.
   if (waitForBusyBit() == USBS_FAILED)
      return (USBS_FAILED);
   else if ((readATAPI_ALT_STATUS_REG() & ATAPI_STATUS_DRQ_BIT) || wDriveDataLen)
      {
      return (USBS_PHASE_ERROR);
      }
 
   return(cReturnStatus);
}   
#endif   // DEVICE_TYPE_IS_SCSI

///////////////////////////////////////////////////////////////////////////////////////
// This code must consider a few of the 13 cases:
// Hi <> Do -- Not much we can do about this one.
// Hi == Di -- Thin diagonal
// Hi > Dn  -- The usual error case.  No data.  UDMA will terminate normally by device.  We will get an interrupt.
// Hi > Di  -- Another normal error.  Less data than expected. UDMA will terminate normally by device.  We will get an interrupt.
// Hi < Di  -- $#&* compliance only case.  More data returned than expected.  Device will NOT terminate UDMA, but we should.  We will not get an interrupt.
///////////////////////////////////////////////////////////////////////////////////////
BYTE scsiReadUdma()
{
   #if DEVICE_TYPE_IS_SCSI
   BYTE error = 0;
   
   initUdmaRead();
   
   {
      DWORD dmaLen = dataTransferLen >> 1;

      prepUDMA(((BYTE *) &dmaLen)[1],
               ((BYTE *) &dmaLen)[2],
               ((BYTE *) &dmaLen)[3]);
      readUDMA();

      // Check for partial data buffer.  There are two cases here:
      // -- Host asked for less than a full buffer and he got it.
      if (dataTransferLenLSW & (wPacketSize - 1))
         {
         bShortPacketSent = 1;
         INPKTEND = 0x6;            // EP6 In Packet End
         WRITEDELAY();    
         }
      // -- Host asked for an even number of buffers, but he got a partial buffer.
      // dmalen - GPIFTCLSW = number of xfers done
      else if ((((WORD *) &dmaLen)[1] - GPIFTCLSW) & ((wPacketSize/2)-1))
         {
         bShortPacketSent = 1;
         INPKTEND = 0x6;            // EP6 In Packet End
         WRITEDELAY();
         }
      // Check if 0 length packet is needed (no data transferred at all)
      else if (GPIFTCMSW == ((BYTE *) &dmaLen)[1]
               && GPIFTCLSW == ((WORD *) &dmaLen)[1])
         {
         bShortPacketSent = 1;
         INPKTEND = 0x6;            // EP6 In Packet End
         WRITEDELAY();
         }
   }

   
   // switch the EP back to manual mode
   // EP6FIFOCFG = 0x05;

   // Figure out the residue.  
   // We don't have enough code space to do the math on the upper portion of GPIFTC.  
   // If there is residue in the upper half of GPIFTC, tell the host that the whole thing failed.
   // If there is residue in the lower half, properly tell the host.
   if (!GPIFTCMSW)
   {
      // It may seem wierd to do this in three lines when one will do.
      // If you put all of this code in one line, the compiler translates the single bit (i) into a DWORD before calling
      // a library routine to do the OR.
      BYTE i = (dataTransferLen & 1); 
      dataTransferLen = ((DWORD) GPIFTCLSW << 1);  // Keep the LSBit -- No odd xfers allowed in UDMA mode, extra byte is residue
      dataTransferLenLSW |= i;
   }
    
   // Check for Hi < Di.  We will xfer data until Hi is decremented to 0 but the UDMA i/f will 
   // not have signalled an interupt.
   if (GPIFREADYSTAT & 2)    // Look for DMARQ still active on the drive
      return(USBS_PHASE_ERROR);

   if (waitForBusyBit() == USBS_FAILED) 
   {
      error = readPIO8(ATAPI_ERROR_REG);

      // Upper 4 bits of error contain sense key.  4 is the sense key for parity error
      if ((error & 0xf0) == 0x40)
      {
         slowDownOnUDMAErrors();
      }
      return(USBS_FAILED);
   }
   else
      {
      // successful xfer.  If we're tracking errors, take one away from the error count.
      if (udmaErrorCount)
         udmaErrorCount--;

      attemptFastScsi = 1;
      return(USBS_PASSED);
      }
   #else
      return(USBS_FAILED);
   #endif   // DEVICE_TYPE_IS_SCSI
}
   

// Note:  This routine will never STALL the out pipe.
//        If dataTransferLen remains above 0, it will get stuck rather than stall.
BYTE scsiWriteUdma()
{
   #if DEVICE_TYPE_IS_SCSI
   {
      DWORD dmaLen = (dataTransferLen+1) >> 1;
      initUdmaWrite();
      prepUDMA(((BYTE *) &dmaLen)[1],
               ((BYTE *) &dmaLen)[2],
               ((BYTE *) &dmaLen)[3]);
      writeUDMA();
   }

   // cancel AUTO OUT mode
   EP2FIFOCFG = bmWORDWIDE;
   WRITEDELAY();
   IFCONFIG = IFCONFIG_DEFAULT;

   // If there's anything in the transfer count it's an error
   // This code doesn't handle partial transfers.  Any failure kills the entire xfer.
   if (! (GPIFTCMSW || GPIFTCLSW))
   {
      dataTransferLen = 0;
   }
   else 
   {
      stallEP2OUT();     // If there is still data to be transferred from the host, send them a STALL.
         
   
      // We don't have enough code space to do the math on the upper portion of GPIFTC.  
      // If there is residue in the upper half of GPIFTC, tell the host that the whole thing failed.
      // If there is residue in the lower half, properly tell the host.
      if (!GPIFTCMSW)
      {
        dataTransferLen &= 1;         // Keep the LSBit -- No odd xfers allowed in UDMA mode, extra byte is residue
        dataTransferLen |= GPIFTCLSW << 1;
      }
   }

   if (GPIFREADYSTAT & 2)    // Look for DMARQ still active on the drive
      return(USBS_PHASE_ERROR);

   // Check status to clear interrupt.
   if (waitForBusyBit() == USBS_FAILED) 
      return(USBS_FAILED);
   else
      {
      attemptFastScsi = 1;
      return(USBS_PASSED);
      }
   #else
      return(USBS_FAILED);
   #endif   // DEVICE_TYPE_IS_SCSI
}


#if DEVICE_TYPE_IS_SCSI
// Wait for busy, then wait for DRQ bit.  Return status register contents.
BYTE waitForDRQBit(bit expectedValue)
{
   BYTE driveStatus;
   BYTE i;

   // Wait for the drive interrupt.
   WAIT_FOR_INTRQ();
   waitForBusyBit();

   // Don't trust the first result after the busy bit goes away.  Read it again.
   // The DELL-07 CDRW has occasional problems if this is not done.
   // The Imation 1208A drive may take >60ms to report proper status.
   // This is solved by looking at the INTRQ bit above!
   for (i = 0; i < 120; i++)
      {
      driveStatus = readATAPI_ALT_STATUS_REG();
      if (driveStatus & ATAPI_STATUS_ERROR_BIT) 
         return(driveStatus);
      if (expectedValue)
         {
         if (driveStatus & ATAPI_STATUS_DRQ_BIT)
            return(driveStatus);
         }
      else if (!(driveStatus & ATAPI_STATUS_DRQ_BIT))
         return(driveStatus);

      if (WAIT_FOR_BUSY_BIT)
         EZUSB_Delay(1);
      else
         return(driveStatus);
      }
   return(driveStatus);
}


////////////////////////////////////////////////////////////////////////////////////////
#endif      // DEVICE_TYPE_IS_SCSI
////////////////////////////////////////////////////////////////////////////////////////

// If UDMA errors are found, slow down.  UDMA errors are commonly found in test setups
// where several adapters are lashed together to attach a 1.8" hard drive or a laptop
// CD-ROM to the tailgate board.
void slowDownOnUDMAErrors()
{
   // Allow up to a 10/1 error ratio.  If it gets above that, slow down or stop using UDMA.
   // The UDMA success code should decrement the udmaErrorCount.
   udmaErrorCount += 10;
   if (udmaErrorCount >= 20)
      {
//      if (ActiveLunConfigData.udmaMode == TRANSFER_MODE_UDMA5)
//         {
//         ActiveLunConfigData.udmaMode = TRANSFER_MODE_UDMA4;
//         configureATATransferMode(ActiveLunConfigData.udmaMode);
//         }
//       else
      if (ActiveLunConfigData.udmaMode == TRANSFER_MODE_UDMA4)
         {
         ActiveLunConfigData.udmaMode = TRANSFER_MODE_UDMA2;
         configureATATransferMode(ActiveLunConfigData.udmaMode);
         }
      else
         {
         ActiveLunConfigData.udmaMode = 0;
         configureATATransferMode(PIO_MODE4);
         }
      udmaErrorCount = 0;
      }
}
   
  

void preloadSCSIRegs()
{
   // Select ATAPI device
   writeATA_DRIVESEL_REG();

   // Make sure the device is ready for the packet
   while(readATAPI_STATUS_REG() & ATAPI_STATUS_BUSY_BIT)
      ;

   // Set "max byte count"
   writePIO8(ATAPI_BYTE_COUNT_LSB, 0xfe);
   writePIO8(ATAPI_BYTE_COUNT_MSB, 0xff);

   // set to 1 here, cleared to 0 in sendScsiCommand() if we're wrong.
   if (ActiveLunConfigData.udmaMode)
      writePIO8(ATAPI_FEATURE_REG, 0x01);
   else
      writePIO8(ATAPI_FEATURE_REG, 0x00);
}

⌨️ 快捷键说明

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