📄 scsi_decoder.c
字号:
/**
* @file scsi_decoder.c,v
*
* Copyright (c) 2004 Atmel.
*
* Please read file license.txt for copyright notice.
*
* @brief This file is the SCSI decoder module
*
* This file contains the routines to decode and to manage the SCSI commands
*
* @version 1.14 c5131-mass-storage-virtual-1_0_6 $Id: scsi_decoder.c,v 1.14 2005/03/25 09:53:51 lguilhau Exp $
*
* @todo
* @bug
*/
//_____ I N C L U D E S ___________________________________________________
#include "config.h"
#include "scsi_decoder.h"
#include "conf\conf_usb.h"
#include "modules\control_access\ctrl_status.h"
#include "modules\control_access\ctrl_access.h"
//_____ M A C R O S ________________________________________________________
//_____ D E F I N I T I O N S ______________________________________________
_MEM_TYPE_SLOW_ U8 g_scsi_command[16];
_MEM_TYPE_SLOW_ U8 g_scsi_status;
_MEM_TYPE_FAST_ U32 g_scsi_data_remaining;
code Byte g_sbc_vendor_id[8] = SBC_VENDOR_ID;
code Byte g_sbc_product_id[16] = SBC_PRODUCT_ID;
code Byte g_sbc_revision_id[4] = SBC_REVISION_ID;
extern _MEM_TYPE_SLOW_ U8 usb_LUN;
_MEM_TYPE_SLOW_ s_scsi_sense g_scsi_sense;
code struct sbc_st_std_inquiry_data sbc_std_inquiry_data =
{
/* Byte 0 : 0x00 */
0x00, /* DeviceType: Direct-access device */
0, /* PeripheralQualifier : Currently connected */
/* Byte 1 : 0x80 */
0, /* Reserved1 */
1, /* RMB : Medium is removable */
// /* Byte 2 : 0x02 */
// 0x02, /* Version: Device compliant to ANSI X3.131:1994 */
/* Byte 2 : 0x00 */
0x00, /* Version: Device not compliant to any standard */
/* Byte 3 : 0x02 */
2, /* Response data format */
0, /* NormACA */
0, /* Obsolete0 */
0, /* AERC */
/* Byte 4 : 0x1F */
/* Byte 5 : 0x00 */
/* Byte 6 : 0x00 */
/* Reserved4[3] */
{
0x1F, /* Additional Length (n-4) */
0, /* SCCS : SCC supported */
0
},
/* Byte 7 : 0x00 */
0, /* SoftReset */
0, /* CommandQueue */
0, /* Reserved5 */
0, /* LinkedCommands */
0, /* Synchronous */
0, /* Wide16Bit */
0, /* Wide32Bit */
0, /* RelativeAddressing */
/* Byte 8 - 15 : "ATMEL " */
/* VendorId[8] */
SBC_VENDOR_ID,
/* Byte 16-31 : "AT89C5131 M.S. " */
/* ProductId[16] */
SBC_PRODUCT_ID,
/* Byte 32-35 : "0.00" */
/* ProductRevisionLevel[4] */
SBC_REVISION_ID,
/* Byte 36-55 : */
/* VendorSpecific[20]; out[64 bytes] within one packet only. */
{
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0
},
0, /* InfoUnitSupport */
0, /* QuickArbitSupport */
0, /* Clocking */
0, /* Reserved1 */
0, /* Reserved2 */
/* VersionDescriptor[8] */
{
0, 0, 0, 0,
0, 0, 0, 0
},
/* Reserved3[22] */
{
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0
}
};
static void send_informational_exceptions_page (void);
static void send_read_write_error_recovery_page (Byte);
//_____ D E C L A R A T I O N S ____________________________________________
/**
* @brief SCSI decoder function
*
* This function read the SCSI command and launches the appropriate function
*
* @warning Code:.. bytes (function code length)
*
* @param nonr
*
* @return FALSE: result KO,
* TRUE: result OK
*
*/
Bool scsi_decode_command(void)
{
if (g_scsi_command[0] == SBC_CMD_WRITE_10)
{
Scsi_start_write_action();
sbc_write_10();
Scsi_stop_write_action();
return TRUE;
}
if (g_scsi_command[0] == SBC_CMD_READ_10 )
{
Scsi_start_read_action();
sbc_read_10();
Scsi_stop_read_action();
return TRUE;
}
switch (g_scsi_command[0]) /* check other command received */
{
case SBC_CMD_REQUEST_SENSE: /* 0x03 - Mandatory */
return sbc_request_sense();
break;
case SBC_CMD_INQUIRY: /* 0x12 - Mandatory */
return sbc_inquiry();
break;
case SBC_CMD_TEST_UNIT_READY: /* 0x00 - Mandatory */
return sbc_test_unit_ready();
break;
case SBC_CMD_READ_CAPACITY: /* 0x25 - Mandatory */
return sbc_read_capacity();
break;
case SBC_CMD_MODE_SENSE_6: /* 0x1A - Optional */
return sbc_mode_sense_6();
break;
case SBC_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:/* 0x1E */
return sbc_prevent_allow_medium_removal();
break;
case SBC_CMD_VERIFY_10: /* 0x2F - Optional */
sbc_lun_status_is_good();
break;
case SBC_CMD_START_STOP_UNIT: /* 0x1B - Optional */
Sbc_send_good();
Sbc_build_sense(SBC_SENSE_KEY_NO_SENSE, SBC_ASC_NO_ADDITIONAL_SENSE_INFORMATION, 0x00);
break;
case SBC_CMD_FORMAT_UNIT: /* 0x04 - Mandatory */
case SBC_CMD_MODE_SELECT_6: /* 0x15 - Optional */
case SBC_CMD_MODE_SENSE_10: /* 0x5A - Optional */
case SBC_CMD_SEND_DIAGNOSTIC: /* 0x1D - */
case SBC_CMD_READ_LONG: /* 0x23 - Optional */
case SBC_CMD_SYNCHRONIZE_CACHE: /* 0x35 - Optional */
case SBC_CMD_WRITE_BUFFER: /* 0x3B - Optional */
case SBC_CMD_RESERVE_10: /* 0x56 - Mandatory */
case SBC_CMD_RELEASE_10: /* 0x57 - Mandatory - see chapter 7.16 - SPC 2 */
default:
{ /* Command not supported */
Sbc_send_failed();
Sbc_build_sense(SBC_SENSE_KEY_ILLEGAL_REQUEST, SBC_ASC_INVALID_COMMAND_OPERATION_CODE, 0x00);
return FALSE;
break;
}
}
return TRUE;
}
/**
* @brief This function manages the SCSI REQUEST SENSE command (0x03)
*
* The SCSI Sense contains the status of the last command
* This status is composed of 3 Bytes :
* - sense key (g_scsi_sense.key)
* - additional sense code (g_scsi_sense.asc)
* - additional sense code qualifier (g_scsi_sense.ascq)
*
* @warning Code:.. bytes (function code length)
*
* @param none
*
* @return FALSE: result KO,
* TRUE: result OK
*
*/
Bool sbc_request_sense (void)
{
U8 allocation_length, i;
U8 request_sens_output[17]; /* the maximum size of request is 17 */
allocation_length = g_scsi_command[4]; /* Allocation length */
/* Initialize the request sense data */
request_sens_output[0] = SBC_RESPONSE_CODE_SENSE; /* 70h */
request_sens_output[1] = 0x00; /* Obsolete */
request_sens_output[2] = g_scsi_sense.key;
request_sens_output[3] = 0x00; /* For direct access media, Information field */
request_sens_output[4] = 0x00; /* give the unsigned logical block */
request_sens_output[5] = 0x00; /* address associated with the sense key */
request_sens_output[6] = 0x00;
request_sens_output[7] = SBC_ADDITIONAL_SENSE_LENGTH; /* !! UFI device shall not adjust the Additional sense length to reflect truncation */
request_sens_output[8] = SBC_COMMAND_SPECIFIC_INFORMATION_3;
request_sens_output[9] = SBC_COMMAND_SPECIFIC_INFORMATION_2;
request_sens_output[10] = SBC_COMMAND_SPECIFIC_INFORMATION_1;
request_sens_output[11] = SBC_COMMAND_SPECIFIC_INFORMATION_0;
request_sens_output[12] = g_scsi_sense.asc;
request_sens_output[13] = g_scsi_sense.ascq;
request_sens_output[14] = SBC_FIELD_REPLACEABLE_UNIT_CODE;
request_sens_output[15] = SBC_SENSE_KEY_SPECIFIC_2;
request_sens_output[16] = SBC_SENSE_KEY_SPECIFIC_1;
request_sens_output[17] = SBC_SENSE_KEY_SPECIFIC_0;
/* Send the request data */
for( i=0 ; i<allocation_length ; i++ )
{
Usb_write_byte( request_sens_output[i] );
}
Sbc_valid_write_usb( allocation_length );
sbc_lun_status_is_good();
return TRUE;
}
/**
* @brief This function manages the SCSI INQUIRY command (0x12)
*
* The SCSI Inquiry field contains information regarding parameters
* of the target. For example:
* - vendor identification
* - product identification
* - peripheral qualifier
* - peripheral device type
* - etc
*
* @warning Code:.. bytes (function code length)
*
* @param none
*
* @return FALSE: result KO,
* TRUE: result OK
*
*/
Bool sbc_inquiry (void)
{
U8 CMDT_EVPD;
U8 page_code;
U8 allocation_length;
U8 i;
U8 code *ptr;
U8 status;
CMDT_EVPD = g_scsi_command[1] & 0x03;
page_code = g_scsi_command[2];
allocation_length = g_scsi_command[4];
status = TRUE;
// Usb_select_endpoint(EP_MS_IN);
switch (CMDT_EVPD) /* CMDT and EPVD bits */
{
case 0x00: /* CMDT and EPVD bits are 0 */
if (page_code == 0x00) /* PAGE or OPERATION CODE fields = 0x00? */
{ /* then send standard inquiry data */
ptr = (Byte *) &sbc_std_inquiry_data;
if (allocation_length > sizeof (sbc_std_inquiry_data))
{
allocation_length = sizeof (sbc_std_inquiry_data);
}
/* send data */
for (i = 0; ((i != 8) && (allocation_length != i)); i++)
{
Usb_write_byte((Byte)(*ptr)); /* write 8 first bytes of struct */
ptr++;
}
ptr = (Byte *) &g_sbc_vendor_id;
for (i = 8; ((i != 16) && (allocation_length > i)); i++)
{
Usb_write_byte((Byte)(*ptr)); /* write 8 bytes of vendor id */
ptr++;
}
ptr = (Byte *) &g_sbc_product_id;
for (i = 16; ((i != 32) && (allocation_length > i)); i++)
{
Usb_write_byte((Byte)(*ptr)); /* write 16 bytes of product id */
ptr++;
}
ptr = (Byte *) &g_sbc_revision_id;
for (i = 32; ((i != 36) && (allocation_length > i)); i++)
{
Usb_write_byte((Byte)(*ptr)); /* write 4 bytes of revision id */
ptr++;
}
ptr = ((Byte *) &sbc_std_inquiry_data) + 36;
for (i = 36; ((i != 64) && (allocation_length > i)); i++)
{
Usb_write_byte((Byte)(*ptr)); /* write last 64 bytes of struct */
ptr++;
}
if (allocation_length > 64)
{
Sbc_valid_write_usb(64);
allocation_length -= 64;
for (i = allocation_length; i != 0 ; i--)
{
Usb_write_byte((Byte)(*ptr)); /* write last bytes of struct */
ptr++;
}
Sbc_valid_write_usb(allocation_length);
}
else
{
Sbc_valid_write_usb(allocation_length);
}
sbc_lun_status_is_good();
}
else
{ /* CMDT=EVPD=0 and PAGE CODE <> 0x00 */
// Usb_enable_stall_handshake();
status = FALSE;
Sbc_send_failed();
Sbc_build_sense(SBC_SENSE_KEY_ILLEGAL_REQUEST, SBC_ASC_INVALID_FIELD_IN_CDB, 0x00);
}
break;
case 0x01: /* EVPD bit = 0 */
switch (page_code) /* Vital Product Data (VPD) Page code */
{
// case SBC_VPD_DEVICE_IDENTIFICATION_PAGE:
// sbc_send_vpd (SBC_VPD_DEVICE_IDENTIFICATION_PAGE);
//
// Sbc_build_sense(SBC_SENSE_KEY_NO_SENSE, 0x00, 0x00);
// break;
// case SBC_VPD_DEVICE_SUPPORTED_VITAL_PRODUCT_DATA_PAGE:
// sbc_send_vpd (SBC_VPD_DEVICE_SUPPORTED_VITAL_PRODUCT_DATA_PAGE);
// Sbc_build_sense(SBC_SENSE_KEY_NO_SENSE, 0x00, 0x00);
// break;
default:
// Usb_enable_stall_handshake();
status = FALSE;
Sbc_send_failed();
Sbc_build_sense(SBC_SENSE_KEY_ILLEGAL_REQUEST, SBC_ASC_INVALID_FIELD_IN_CDB, 0x00);
break;
}
break;
default:
// Usb_enable_stall_handshake();
status = FALSE;
Sbc_send_failed();
Sbc_build_sense(SBC_SENSE_KEY_ILLEGAL_REQUEST, SBC_ASC_INVALID_FIELD_IN_CDB, 0x00);
break;
}
return status;
}
Bool sbc_test_unit_ready(void)
{
switch ( mem_test_unit_ready(usb_LUN) )
{
case CTRL_GOOD :
sbc_lun_status_is_good();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -