📄 scsicmd.c
字号:
/*
**********************************************************************************************
* Project: FS7805 SD CARD READER
* File: main.c
* Contents:
* The main function is SD and MMC card reader.
*
* $Date: 12/15/06 Derek V1.0
*
* Coments: This is the SD/MMC card reader firmware.
* When read sector,the 512 pingpong FIFO mechanism
* is used to improve performance.But when write sector,
* only single FIFO is used.
*
* Copyright (c) 2006 Fameg, Inc. All rights reserved
*
*
***********************************************************************************************
*/
#include "include\Include.h"
/*************************************************
Global Variables
*************************************************/
xdata BYTE SenseKey;
xdata BYTE AddSenseCode;
xdata BYTE AddSenseCodeQ;
xdata bool ScsiMediaChange[MAX_DEVICE_NUM];
/*************************************************
Local Variables
*************************************************/
static xdata BYTE ScsiWriteProtect[MAX_DEVICE_NUM];
static xdata bool ScsiWriteProtectChange[MAX_DEVICE_NUM];
//static xdata UINT32 CapacityInfo[2];
static xdata BYTE ScsiLoadStatus[MAX_DEVICE_NUM];
/*BYTE RequestSenseData[REQUEST_SENSE_DATA_LEN] =
{ 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00
};*/
code BYTE ModeParamHeader6[MODE_PARAM_HEADER_LEN] =
{ 0x00, 0x00, 0x00, 0x00 };
// Mode Page #1 Read-Write Error Recovery
code BYTE ModePage_1[] =
{ 0x01, 0x0A, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00
};
// Mode Page #5
/*code BYTE ModePage_5[] =
{ 0x05, 0x1e, 0x13, 0x88, 0x08, 0x20, 0x02, 0x00, 0x01, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x05, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x68,
0x00, 0x00, };
// Mode Page #1B
code BYTE ModePage_1B[] =
{ 0x1B, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
// Mode Page #1C
code BYTE ModePage_1C[] =
{ 0x1C, 0x06, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00 };
*/
xdata MODE_PAGE_TABLE ModePageArray[] =
{
{ ModePage_1, sizeof(ModePage_1) },
// Reduce XDATA Size so don't return more mode pages.
// { ModePage_5, sizeof(ModePage_5) },
// { ModePage_1B, sizeof(ModePage_1B) },
// { ModePage_1C, sizeof(ModePage_1C) },
{ NULL, 0 }
};
//----------------------------------------------------------------------------
// Detect the write protect on the storage media.(Shared)
//----------------------------------------------------------------------------
bool ScsiDetectWriteProtect(BYTE Lun)
{
if (ScsiWriteProtect[Lun])
{
SenseKey = DATA_PROTECT;
AddSenseCode = HW_WRITE_PROTECT;
return true;
}
return false;
}
//----------------------------------------------------------------------------
// Set Command Error.(INVALID_FIELD_IN_CDB)
//----------------------------------------------------------------------------
void ScsiInvalidFieldError(BYTE Lun) // To be replaced
{
Lun=Lun;
CmdStatus = PHASE_ERROR;
SenseKey = ILLEGAL_REQUEST;
AddSenseCode = INVALID_FIELD_IN_CDB;
AddSenseCodeQ = 0x00;
}
void SetSenseErrOpCode()
{
CmdStatus = PHASE_ERROR;
SenseKey = 0x05; // INVALID COMMAND OPERATION CODE
AddSenseCode = 0x20;
AddSenseCodeQ = 0x00;
}
void SetSenseErrCmdField()
{
CmdStatus = PHASE_ERROR;
SenseKey = 0x05; // INVALID FIELD IN COMMAND PACKET
AddSenseCode = 0x24;
AddSenseCodeQ = 0x00;
}
/*void SetSenseErrCmdPara()
{
CmdStatus = PHASE_ERROR;
SenseKey = 0x05; // PARAMETER VALUE INVALID
AddSenseCode = 0x26;
AddSenseCodeQ = 0x02;
}*/
void ScsiModifySenseWord(BYTE Lun, BYTE Status)
{
Lun=Lun;
switch (Status)
{
case STATUS_SUCCESS: // NO SENSE
SenseKey = 0x00;
AddSenseCode = 0x00;
AddSenseCodeQ = 0x00;
break;
case STATUS_NO_MEDIA: // MEDIUM NOT PRESENT
SenseKey = 0x02;
AddSenseCode = 0x3A;
AddSenseCodeQ = 0x00;
break;
case STATUS_MEDIA_CHANGE: // NOT READY TO READY TRANSITION
SenseKey = 0x06; // - MEDIA CHANGED
AddSenseCode = 0x28;
AddSenseCodeQ = 0x00;
break;
default: // UNKNOWN ERROR
SenseKey = 0x02;
AddSenseCode = 0xFF;
AddSenseCodeQ = 0xFF;
break;
}
}
void SetSenseDataWr(BYTE Status)
{
switch (Status)
{
case STATUS_SUCCESS: // NO SENSE
SenseKey = 0x00;
AddSenseCode = 0x00;
AddSenseCodeQ = 0x00;
break;
case STATUS_NO_MEDIA: // MEDIUM NOT PRESENT
SenseKey = 0x02;
AddSenseCode = 0x3A;
AddSenseCodeQ = 0x00;
break;
case STATUS_MEDIA_CHANGE: // NOT READY TO READY TRANSITION
SenseKey = 0x06; // - MEDIA CHANGED
AddSenseCode = 0x28;
AddSenseCodeQ = 0x00;
break;
case STATUS_WRITE_PROTECT:// WRITE PROTECTED MEDIA
SenseKey = 0x07;
AddSenseCode = 0x27;
AddSenseCodeQ = 0x00;
break;
case STATUS_FLASH_ERROR: // WRITE FAULT
case STATUS_NO_BLOCK: // WRITE FAULT
SenseKey = 0x03; //
AddSenseCode = 0x03;
AddSenseCodeQ = 0x00;
break;
default: // UNKNOWN ERROR
SenseKey = 0x02;
AddSenseCode = 0xFF;
AddSenseCodeQ = 0xFF;
break;
}
}
void SetSenseDataRd(BYTE Status)
{
switch (Status)
{
case STATUS_SUCCESS: // NO SENSE
SenseKey = 0x00;
AddSenseCode = 0x00;
AddSenseCodeQ = 0x00;
break;
case STATUS_NO_MEDIA: // MEDIUM NOT PRESENT
SenseKey = 0x02;
AddSenseCode = 0x3A;
AddSenseCodeQ = 0x00;
break;
case STATUS_MEDIA_CHANGE: // NOT READY TO READY TRANSITION
SenseKey = 0x06; // - MEDIUM CHANGED
AddSenseCode = 0x28;
AddSenseCodeQ = 0x00;
break;
case STATUS_FLASH_ERROR: // UNRECOVERED READ ERROR
case STATUS_ECC_2ERROR: // UNRECOVERED READ ERROR
SenseKey = 0x03;
AddSenseCode = 0x11;
AddSenseCodeQ = 0x00;
break;
default: // UNKNOWN ERROR
SenseKey = 0x02;
AddSenseCode = 0xFF;
AddSenseCodeQ = 0xFF;
break;
}
}
//----------------------------------------------------------------------------
// Get the LUN capcity
// Description: Write those capacity informations to the global variable
// CapacityInfo[].
//----------------------------------------------------------------------------
void ScsiGetLunCapacity()
{
BYTE Status;
Status = QueryDevice();
*(UINT32 xdata *)(FIFO_ADDRESS_IN + 0) = DeviceInfo.TotalBlocks;
*(UINT32 xdata *)(FIFO_ADDRESS_IN + 4) = (UINT32)DeviceInfo.BlockSize;
}
//----------------------------------------------------------------------------
// Check Vaild Logic Unit Number
// Description: If not valid, change Sense Parameters.
//----------------------------------------------------------------------------
void ScsiLunValidCheck()
{
BYTE Status;
if(ScsiLun > LastDevice)
{
CmdStatus = PHASE_ERROR;
return;
}
Status = QueryDevice();
if(ScsiWriteProtect[ScsiLun] != DeviceInfo.WriteProtect)
{
ScsiWriteProtectChange[ScsiLun] = true;
ScsiWriteProtect[ScsiLun] = DeviceInfo.WriteProtect;
}
if((Status == STATUS_SUCCESS) ||
(Status == STATUS_MEDIA_CHANGE))
{
if((ScsiLoadStatus[ScsiLun] & SCSI_LAST_QUERY_MASK) == 0)
ScsiLoadStatus[ScsiLun] |= SCSI_LOAD_STATUS_MASK;
ScsiLoadStatus[ScsiLun] |= SCSI_LAST_QUERY_MASK;
}
else
ScsiLoadStatus[ScsiLun] &= ~SCSI_LAST_QUERY_MASK;
if(Status == STATUS_SUCCESS)
return;
ScsiModifySenseWord(ScsiLun, Status);
CmdStatus = COMMAND_FAILED;
}
//----------------------------------------------------------------------------
// Make Mode Page Data Ready
//----------------------------------------------------------------------------
void ScsiPrepareModePage(BYTE PageCode, UINT16 XferLength)
{
UINT16 TotalPageLen = 0;
BYTE i = 0;
PBYTE Page;
BYTE PageLen;
while((Page = ModePageArray[i].PagePtr) != NULL)
{
PageLen = 0;
if ( (PageCode == 0x3f) || (PageCode == Page[0]) )
{
PageLen = ModePageArray[i].Size;
memcpy((BYTE xdata *)(FIFO_ADDRESS_IN + MODE_PARAM_HEADER_LEN \
+ TotalPageLen), (void *)Page, PageLen);
}
TotalPageLen += PageLen;
i++;
}
TotalPageLen += MODE_PARAM_HEADER_LEN;
memcpy((BYTE xdata *)(FIFO_ADDRESS_IN), (void *)ModeParamHeader6, \
MODE_PARAM_HEADER_LEN);
// Length field.(1 Byte)
*(BYTE xdata *)(FIFO_ADDRESS_IN + 0) = (BYTE)(TotalPageLen - 1);
// (Device-Specific-Parameter)It is write protect reference for WinXP & Win2K.
QueryDevice();
*(BYTE xdata *)(FIFO_ADDRESS_IN + 2) = DeviceInfo.WriteProtect ? 0x80: 0x00;
if (XferLength > TotalPageLen)
XferLength = TotalPageLen;
UsbDmaTotalLength = XferLength;
}
//--------------------------------------------------------------------
// Prepare Disk Info.
//--------------------------------------------------------------------
void ScsiPrepareDiskInfo()
{
memset((BYTE xdata *)(FIFO_ADDRESS_IN), 0, SCSI_INFO_START_OFFSET);
*(BYTE xdata *)(FIFO_ADDRESS_IN + 1) = 0x80;
*(BYTE xdata *)(FIFO_ADDRESS_IN + 3) = 0x01;
*(BYTE xdata *)(FIFO_ADDRESS_IN + 4) = 0x1F;
// Vendor Information
*(BYTE xdata *)(FIFO_ADDRESS_IN + 8) = 'F';
*(BYTE xdata *)(FIFO_ADDRESS_IN + 9) = 'a';
*(BYTE xdata *)(FIFO_ADDRESS_IN + 10) = 'm';
*(BYTE xdata *)(FIFO_ADDRESS_IN + 11) = 'e';
*(BYTE xdata *)(FIFO_ADDRESS_IN + 12) = 'G';
*(BYTE xdata *)(FIFO_ADDRESS_IN + 13) = ' ';
*(BYTE xdata *)(FIFO_ADDRESS_IN + 14) = ' ';
*(BYTE xdata *)(FIFO_ADDRESS_IN + 15) = ' ';
// Product Identification
*(BYTE xdata *)(FIFO_ADDRESS_IN + 16) = 'U';
*(BYTE xdata *)(FIFO_ADDRESS_IN + 17) = 'S';
*(BYTE xdata *)(FIFO_ADDRESS_IN + 18) = 'B';
*(BYTE xdata *)(FIFO_ADDRESS_IN + 19) = ' ';
*(BYTE xdata *)(FIFO_ADDRESS_IN + 20) = '2';
*(BYTE xdata *)(FIFO_ADDRESS_IN + 21) = '.';
*(BYTE xdata *)(FIFO_ADDRESS_IN + 22) = '0';
*(BYTE xdata *)(FIFO_ADDRESS_IN + 23) = ' ';
*(BYTE xdata *)(FIFO_ADDRESS_IN + 24) = 'D';
*(BYTE xdata *)(FIFO_ADDRESS_IN + 25) = 'i';
*(BYTE xdata *)(FIFO_ADDRESS_IN + 26) = 's';
*(BYTE xdata *)(FIFO_ADDRESS_IN + 27) = 'k';
*(BYTE xdata *)(FIFO_ADDRESS_IN + 28) = ' ';
*(BYTE xdata *)(FIFO_ADDRESS_IN + 29) = ' ';
*(BYTE xdata *)(FIFO_ADDRESS_IN + 30) = ' ';
*(BYTE xdata *)(FIFO_ADDRESS_IN + 31) = ' ';
// Revision Field.
*(BYTE xdata *)(FIFO_ADDRESS_IN + 32) = '1';
*(BYTE xdata *)(FIFO_ADDRESS_IN + 33) = '.';
*(BYTE xdata *)(FIFO_ADDRESS_IN + 34) = '0';
*(BYTE xdata *)(FIFO_ADDRESS_IN + 35) = '0';
}
/***************************************************************************
Notes of SCSI Command
1. Ignore Checking Valid CbwcbLen
***************************************************************************/
//----------------------------------------------------------------------------
// ScsiCmdTestUnitReady
//----------------------------------------------------------------------------
void ScsiCmdTestUnitReady()
{
if (ConvertEndian32(BlockWrapper->DataXsferLen) != 0)
ScsiInvalidFieldError(ScsiLun);
if (ScsiMediaChange[ScsiLun])
{
ScsiMediaChange[ScsiLun] = false;
ScsiModifySenseWord(ScsiLun, STATUS_MEDIA_CHANGE);
CmdStatus = COMMAND_FAILED;
}
else if (ScsiWriteProtectChange[ScsiLun])
{
ScsiWriteProtectChange[ScsiLun] = false;
ScsiModifySenseWord(ScsiLun, STATUS_MEDIA_CHANGE);
CmdStatus = COMMAND_FAILED;
}
else if(!(ScsiLoadStatus[ScsiLun] & SCSI_LOAD_STATUS_MASK))
{
ScsiModifySenseWord(ScsiLun, STATUS_NO_MEDIA);
CmdStatus = COMMAND_FAILED;
}
BulkFreeBuffer(); //.
if (CmdStatus == PHASE_ERROR)
{
BulkInStall();
BulkState = STALL_IN_COMPLETED;
}
else
BulkPrepareCSW(CmdStatus);
}
//----------------------------------------------------------------------------
// ScsiCmdInquiry
//----------------------------------------------------------------------------
void ScsiCmdInquiry()
{
BYTE i;
// Scsi command start.
for(i = 0; i < MAX_DEVICE_NUM; i++)
ScsiLoadStatus[i] = 0;
if (UsbDmaTotalLength > STANDARD_INQUIRY_DATA_LEN)
UsbDmaTotalLength = STANDARD_INQUIRY_DATA_LEN;
// Don't care LUN's value, we return the same Inquiry Data.
CmdStatus = COMMAND_PASSED; //
if (!(0x80 & BlockWrapper->Flags))
ScsiInvalidFieldError(ScsiLun);
BulkFreeBuffer(); //
// Prepare Data.
if (CmdStatus != PHASE_ERROR)
{
SetBulkInFull();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -