Files
test/middleware/usb/uC-USBD/Class/MSC/usbd_scsi.c
2025-11-07 20:19:23 +08:00

1860 lines
97 KiB
C

/*
*********************************************************************************************************
* uC/USB-Device
* The Embedded USB Device Stack
*
* Copyright 2004-2021 Silicon Laboratories Inc. www.silabs.com
*
* SPDX-License-Identifier: APACHE-2.0
*
* This software is subject to an open source license and is distributed by
* Silicon Laboratories Inc. pursuant to the terms of the Apache License,
* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0.
*
*********************************************************************************************************
*/
/*
*********************************************************************************************************
*
* USB DEVICE SCSI OPERATIONS
*
* Filename : usbd_scsi.c
* Version : V4.06.01
*********************************************************************************************************
*/
/*
**********************************************************************************************************
* INCLUDE FILES
**********************************************************************************************************
*/
#define MICRIUM_SOURCE
#define USBD_SCSI_MODULE
#include "usbd_scsi.h"
#if (USBD_MSC_CFG_MICRIUM_FS == DEF_ENABLED)
#include "Storage/uC-FS/V4/usbd_storage.h"
#else
#include "Storage/RAMDisk/usbd_storage.h"
#endif
/*
**********************************************************************************************************
* LOCAL DEFINES
**********************************************************************************************************
*/
#define USBD_SCSI_LOCK_DLY_mS 4u
#define USBD_SCSI_BLOCK_DESC_LEN 0u
#define USBD_SCSI_INQUIRY_DATA_LEN 36u
#define USBD_SCSI_MODE_SENSE_DATA_LEN 256u
#define USBD_SCSI_RD_CAPACITY_10_PARAM_DATA_LEN 8u
#define USBD_SCSI_RD_CAPACITY_16_PARAM_DATA_LEN 16u
#define USBD_SCSI_REQ_SENSE_DATA_LEN 18u
/* ------------------ DATA XFER DIR ------------------- */
#define USBD_SCSI_CBW_HOST_TO_DEVICE 0x00
#define USBD_SCSI_CBW_DEVICE_TO_HOST 0x80
/* ------------- DIRECT ACCESS MEDIUM TYPE ------------ */
#define USBD_DISK_MEMORY_MEDIA 0x00
/* ------------------ INQUIRY DATA -------------------- */
#define USBD_SCSI_STD_INQUIRY_DATA 0x00
#define USBD_SCSI_INQUIRY_VERS_OBSOLETE 0x02
#define USBD_SCSI_INQUIRY_VERS_SPC_3 0x05
#define USBD_SCSI_INQUIRY_RESP_DATA_FMT_DEFAULT 0x02
/* ------------------ REQ SENSE DATA ------------------ */
#define USBD_SCSI_REQ_SENSE_RESP_CODE_CUR_ERR 0x70
/*
**********************************************************************************************************
* SCSI COMMANDS
*
* Note(s) : (1) The SCSI Operation Codes can be found in SCSI Primary Commands - 3 (SPC-3),
* section D.3 Operation Codes.
*
* (2) The SCSI Status Codes can be found in SCSI Architecture Model - 4 (SAM-3),
* section 5.3.1 Status Codes.
*
* (3) The SCSI Sense Keys can be found in SCSI Primary Commands - 3 (SPC-3),
* section 4.5.6 Status Key and Sense Code Definitions, Table 27.
*
* (4) The SCSI Additional Sense Codes can be found in SCSI Primary Commands - 3 (SPC-3),
* section D.2 Additional Sense Codes.
*
* (5) The SCSI Mode Page Codes can be found in SCSI Primary Commands - 3 (SPC-3),
* section D.6 Mode Page Codes.
**********************************************************************************************************
*/
/* ------------ SCSI OPCODES (See Notes #1) ------------ */
#define USBD_SCSI_CMD_TEST_UNIT_READY 0x00
#define USBD_SCSI_CMD_REWIND 0x01
#define USBD_SCSI_CMD_REZERO_UNIT 0x01
#define USBD_SCSI_CMD_REQUEST_SENSE 0x03
#define USBD_SCSI_CMD_FORMAT_UNIT 0x04
#define USBD_SCSI_CMD_FORMAT_MEDIUM 0x04
#define USBD_SCSI_CMD_FORMAT 0x04
#define USBD_SCSI_CMD_READ_BLOCK_LIMITS 0x05
#define USBD_SCSI_CMD_REASSIGN_BLOCKS 0x07
#define USBD_SCSI_CMD_INITIALIZE_ELEMENT_STATUS 0x07
#define USBD_SCSI_CMD_READ_06 0x08
#define USBD_SCSI_CMD_RECEIVE 0x08
#define USBD_SCSI_CMD_GET_MESSAGE_06 0x08
#define USBD_SCSI_CMD_WRITE_06 0x0A
#define USBD_SCSI_CMD_SEND_06 0x0A
#define USBD_SCSI_CMD_SEND_MESSAGE_06 0x0A
#define USBD_SCSI_CMD_PRINT 0x0A
#define USBD_SCSI_CMD_SEEK_06 0x0B
#define USBD_SCSI_CMD_SET_CAPACITY 0x0B
#define USBD_SCSI_CMD_SLEW_AND_PRINT 0x0B
#define USBD_SCSI_CMD_READ_REVERSE_06 0x0F
#define USBD_SCSI_CMD_WRITE_FILEMARKS_06 0x10
#define USBD_SCSI_CMD_SYNCHRONIZE_BUFFER 0x10
#define USBD_SCSI_CMD_SPACE_06 0x11
#define USBD_SCSI_CMD_INQUIRY 0x12
#define USBD_SCSI_CMD_VERIFY_06 0x13
#define USBD_SCSI_CMD_RECOVER_BUFFERED_DATA 0x14
#define USBD_SCSI_CMD_MODE_SELECT_06 0x15
#define USBD_SCSI_CMD_RESERVE_06 0x16
#define USBD_SCSI_CMD_RESERVE_ELEMENT_06 0x16
#define USBD_SCSI_CMD_RELEASE_06 0x17
#define USBD_SCSI_CMD_RELEASE_ELEMENT_06 0x17
#define USBD_SCSI_CMD_COPY 0x18
#define USBD_SCSI_CMD_ERASE_06 0x19
#define USBD_SCSI_CMD_MODE_SENSE_06 0x1A
#define USBD_SCSI_CMD_START_STOP_UNIT 0x1B
#define USBD_SCSI_CMD_LOAD_UNLOAD 0x1B
#define USBD_SCSI_CMD_SCAN_06 0x1B
#define USBD_SCSI_CMD_STOP_PRINT 0x1B
#define USBD_SCSI_CMD_OPEN_CLOSE_IMPORT_EXPORT_ELEMENT 0x1B
#define USBD_SCSI_CMD_RECEIVE_DIAGNOSTIC_RESULTS 0x1C
#define USBD_SCSI_CMD_SEND_DIAGNOSTIC 0x1D
#define USBD_SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E
#define USBD_SCSI_CMD_READ_FORMAT_CAPACITIES 0x23
#define USBD_SCSI_CMD_SET_WINDOW 0x24
#define USBD_SCSI_CMD_READ_CAPACITY_10 0x25
#define USBD_SCSI_CMD_READ_CAPACITY 0x25
#define USBD_SCSI_CMD_READ_CARD_CAPACITY 0x25
#define USBD_SCSI_CMD_GET_WINDOW 0x25
#define USBD_SCSI_CMD_READ_10 0x28
#define USBD_SCSI_CMD_GET_MESSAGE_10 0x28
#define USBD_SCSI_CMD_READ_GENERATION 0x29
#define USBD_SCSI_CMD_WRITE_10 0x2A
#define USBD_SCSI_CMD_SEND_10 0x2A
#define USBD_SCSI_CMD_SEND_MESSAGE_10 0x2A
#define USBD_SCSI_CMD_SEEK_10 0x2B
#define USBD_SCSI_CMD_LOCATE_10 0x2B
#define USBD_SCSI_CMD_POSITION_TO_ELEMENT 0x2B
#define USBD_SCSI_CMD_ERASE_10 0x2C
#define USBD_SCSI_CMD_READ_UPDATED_BLOCK 0x2D
#define USBD_SCSI_CMD_WRITE_AND_VERIFY_10 0x2E
#define USBD_SCSI_CMD_VERIFY_10 0x2F
#define USBD_SCSI_CMD_SEARCH_DATA_HIGH_10 0x30
#define USBD_SCSI_CMD_SEARCH_DATA_EQUAL_10 0x31
#define USBD_SCSI_CMD_OBJECT_POSITION 0x31
#define USBD_SCSI_CMD_SEARCH_DATA_LOW_10 0x32
#define USBD_SCSI_CMD_SET_LIMITS_10 0x33
#define USBD_SCSI_CMD_PRE_FETCH_10 0x34
#define USBD_SCSI_CMD_READ_POSITION 0x34
#define USBD_SCSI_CMD_GET_DATA_BUFFER_STATUS 0x34
#define USBD_SCSI_CMD_SYNCHRONIZE_CACHE_10 0x35
#define USBD_SCSI_CMD_LOCK_UNLOCK_CACHE_10 0x36
#define USBD_SCSI_CMD_READ_DEFECT_DATA_10 0x37
#define USBD_SCSI_CMD_INIT_ELEMENT_STATUS_WITH_RANGE 0x37
#define USBD_SCSI_CMD_MEDIUM_SCAN 0x38
#define USBD_SCSI_CMD_COMPARE 0x39
#define USBD_SCSI_CMD_COPY_AND_VERIFY 0x3A
#define USBD_SCSI_CMD_WRITE_BUFFER 0x3B
#define USBD_SCSI_CMD_READ_BUFFER 0x3C
#define USBD_SCSI_CMD_UPDATE_BLOCK 0x3D
#define USBD_SCSI_CMD_READ_LONG_10 0x3E
#define USBD_SCSI_CMD_WRITE_LONG_10 0x3F
#define USBD_SCSI_CMD_CHANGE_DEFINITION 0x40
#define USBD_SCSI_CMD_WRITE_SAME_10 0x41
#define USBD_SCSI_CMD_READ_SUBCHANNEL 0x42
#define USBD_SCSI_CMD_READ_TOC_PMA_ATIP 0x43
#define USBD_SCSI_CMD_REPORT_DENSITY_SUPPORT 0x44
#define USBD_SCSI_CMD_READ_HEADER 0x44
#define USBD_SCSI_CMD_PLAY_AUDIO_10 0x45
#define USBD_SCSI_CMD_GET_CONFIGURATION 0x46
#define USBD_SCSI_CMD_PLAY_AUDIO_MSF 0x47
#define USBD_SCSI_CMD_GET_EVENT_STATUS_NOTIFICATION 0x4A
#define USBD_SCSI_CMD_PAUSE_RESUME 0x4B
#define USBD_SCSI_CMD_LOG_SELECT 0x4C
#define USBD_SCSI_CMD_LOG_SENSE 0x4D
#define USBD_SCSI_CMD_STOP_PLAY_SCAN 0x4E
#define USBD_SCSI_CMD_XDWRITE_10 0x50
#define USBD_SCSI_CMD_XPWRITE_10 0x51
#define USBD_SCSI_CMD_READ_DISC_INFORMATION 0x51
#define USBD_SCSI_CMD_XDREAD_10 0x52
#define USBD_SCSI_CMD_READ_TRACK_INFORMATION 0x52
#define USBD_SCSI_CMD_RESERVE_TRACK 0x53
#define USBD_SCSI_CMD_SEND_OPC_INFORMATION 0x54
#define USBD_SCSI_CMD_MODE_SELECT_10 0x55
#define USBD_SCSI_CMD_RESERVE_10 0x56
#define USBD_SCSI_CMD_RESERVE_ELEMENT_10 0x56
#define USBD_SCSI_CMD_RELEASE_10 0x57
#define USBD_SCSI_CMD_RELEASE_ELEMENT_10 0x57
#define USBD_SCSI_CMD_REPAIR_TRACK 0x58
#define USBD_SCSI_CMD_MODE_SENSE_10 0x5A
#define USBD_SCSI_CMD_CLOSE_TRACK_SESSION 0x5B
#define USBD_SCSI_CMD_READ_BUFFER_CAPACITY 0x5C
#define USBD_SCSI_CMD_SEND_CUE_SHEET 0x5D
#define USBD_SCSI_CMD_PERSISTENT_RESERVE_IN 0x5E
#define USBD_SCSI_CMD_PERSISTENT_RESERVE_OUT 0x5F
#define USBD_SCSI_CMD_EXTENDED_CDB 0x7E
#define USBD_SCSI_CMD_VARIABLE_LENGTH_CDB 0x7F
#define USBD_SCSI_CMD_XDWRITE_EXTENDED_16 0x80
#define USBD_SCSI_CMD_WRITE_FILEMARKS_16 0x80
#define USBD_SCSI_CMD_REBUILD_16 0x81
#define USBD_SCSI_CMD_READ_REVERSE_16 0x81
#define USBD_SCSI_CMD_REGENERATE_16 0x82
#define USBD_SCSI_CMD_EXTENDED_COPY 0x83
#define USBD_SCSI_CMD_RECEIVE_COPY_RESULTS 0x84
#define USBD_SCSI_CMD_ATA_COMMAND_PASS_THROUGH_16 0x85
#define USBD_SCSI_CMD_ACCESS_CONTROL_IN 0x86
#define USBD_SCSI_CMD_ACCESS_CONTROL_OUT 0x87
#define USBD_SCSI_CMD_READ_16 0x88
#define USBD_SCSI_CMD_WRITE_16 0x8A
#define USBD_SCSI_CMD_ORWRITE 0x8B
#define USBD_SCSI_CMD_READ_ATTRIBUTE 0x8C
#define USBD_SCSI_CMD_WRITE_ATTRIBUTE 0x8D
#define USBD_SCSI_CMD_WRITE_AND_VERIFY_16 0x8E
#define USBD_SCSI_CMD_VERIFY_16 0x8F
#define USBD_SCSI_CMD_PREFETCH_16 0x90
#define USBD_SCSI_CMD_SYNCHRONIZE_CACHE_16 0x91
#define USBD_SCSI_CMD_SPACE_16 0x91
#define USBD_SCSI_CMD_LOCK_UNLOCK_CACHE_16 0x92
#define USBD_SCSI_CMD_LOCATE_16 0x92
#define USBD_SCSI_CMD_WRITE_SAME_16 0x93
#define USBD_SCSI_CMD_ERASE_16 0x93
#define USBD_SCSI_CMD_SERVICE_ACTION_IN_16 0x9E
#define USBD_SCSI_CMD_SERVICE_ACTION_OUT_16 0x9F
#define USBD_SCSI_CMD_REPORT_LUNS 0xA0
#define USBD_SCSI_CMD_BLANK 0xA1
#define USBD_SCSI_CMD_ATA_COMMAND_PASS_THROUGH_12 0xA1
#define USBD_SCSI_CMD_SECURITY_PROTOCOL_IN 0xA2
#define USBD_SCSI_CMD_MAINTENANCE_IN 0xA3
#define USBD_SCSI_CMD_SEND_KEY 0xA3
#define USBD_SCSI_CMD_MAINTENANCE_OUT 0xA4
#define USBD_SCSI_CMD_REPORT_KEY 0xA4
#define USBD_SCSI_CMD_MOVE_MEDIUM 0xA5
#define USBD_SCSI_CMD_PLAY_AUDIO_12 0xA5
#define USBD_SCSI_CMD_EXCHANGE_MEDIUM 0xA6
#define USBD_SCSI_CMD_LOAD_UNLOAD_CDVD 0xA6
#define USBD_SCSI_CMD_MOVE_MEDIUM_ATTACHED 0xA7
#define USBD_SCSI_CMD_SET_READ_AHEAD 0xA7
#define USBD_SCSI_CMD_READ_12 0xA8
#define USBD_SCSI_CMD_GET_MESSAGE_12 0xA8
#define USBD_SCSI_CMD_SERVICE_ACTION_OUT_12 0xA9
#define USBD_SCSI_CMD_WRITE_12 0xAA
#define USBD_SCSI_CMD_SEND_MESSAGE_12 0xAA
#define USBD_SCSI_CMD_SERVICE_ACTION_IN_12 0xAB
#define USBD_SCSI_CMD_ERASE_12 0xAC
#define USBD_SCSI_CMD_GET_PERFORMANCE 0xAC
#define USBD_SCSI_CMD_READ_DVD_STRUCTURE 0xAD
#define USBD_SCSI_CMD_WRITE_AND_VERIFY_12 0xAE
#define USBD_SCSI_CMD_VERIFY_12 0xAF
#define USBD_SCSI_CMD_SEARCH_DATA_HIGH_12 0xB0
#define USBD_SCSI_CMD_SEARCH_DATA_EQUAL_12 0xB1
#define USBD_SCSI_CMD_SEARCH_DATA_LOW_12 0xB2
#define USBD_SCSI_CMD_SET_LIMITS_12 0xB3
#define USBD_SCSI_CMD_READ_ELEMENT_STATUS_ATTACHED 0xB4
#define USBD_SCSI_CMD_SECURITY_PROTOCOL_OUT 0xB5
#define USBD_SCSI_CMD_REQUEST_VOLUME_ELEMENT_ADDRESS 0xB5
#define USBD_SCSI_CMD_SEND_VOLUME_TAG 0xB6
#define USBD_SCSI_CMD_SET_STREAMING 0xB6
#define USBD_SCSI_CMD_READ_DEFECT_DATA_12 0xB7
#define USBD_SCSI_CMD_READ_ELEMENT_STATUS 0xB8
#define USBD_SCSI_CMD_READ_CD_MSF 0xB9
#define USBD_SCSI_CMD_REDUNDANCY_GROUP_IN 0xBA
#define USBD_SCSI_CMD_SCAN 0xBA
#define USBD_SCSI_CMD_REDUNDANCY_GROUP_OUT 0xBB
#define USBD_SCSI_CMD_SET_CD_SPEED 0xBB
#define USBD_SCSI_CMD_SPARE_IN 0xBC
#define USBD_SCSI_CMD_SPARE_OUT 0xBD
#define USBD_SCSI_CMD_MECHANISM_STATUS 0xBD
#define USBD_SCSI_CMD_VOLUME_SET_IN 0xBE
#define USBD_SCSI_CMD_READ_CD 0xBE
#define USBD_SCSI_CMD_VOLUME_SET_OUT 0xBF
#define USBD_SCSI_CMD_SEND_DVD_STRUCTURE 0xBF
/* -------- SCSI STATUS CODES (See Notes #2) ---------- */
#define USBD_SCSI_STATUS_GOOD 0x00
#define USBD_SCSI_STATUS_CHECK_CONDITION 0x02
#define USBD_SCSI_STATUS_CONDITION_MET 0x04
#define USBD_SCSI_STATUS_BUSY 0x08
#define USBD_SCSI_STATUS_RESERVATION_CONFLICT 0x18
#define USBD_SCSI_STATUS_TASK_SET_FULL 0x28
#define USBD_SCSI_STATUS_ACA_ACTIVE 0x30
#define USBD_SCSI_STATUS_TASK_ABORTED 0x40
/* -------- SCSI SENSE KEYS (See Notes #3) ------------ */
#define USBD_SCSI_SENSE_KEY_NO_SENSE 0x00
#define USBD_SCSI_SENSE_KEY_RECOVERED_ERROR 0x01
#define USBD_SCSI_SENSE_KEY_NOT_RDY 0x02
#define USBD_SCSI_SENSE_KEY_MEDIUM_ERROR 0x03
#define USBD_SCSI_SENSE_KEY_HARDWARE_ERROR 0x04
#define USBD_SCSI_SENSE_KEY_ILLEGAL_REQUEST 0x05
#define USBD_SCSI_SENSE_KEY_UNIT_ATTENTION 0x06
#define USBD_SCSI_SENSE_KEY_DATA_PROTECT 0x07
#define USBD_SCSI_SENSE_KEY_BLANK_CHECK 0x08
#define USBD_SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x09
#define USBD_SCSI_SENSE_KEY_COPY_ABORTED 0x0A
#define USBD_SCSI_SENSE_KEY_ABORTED_COMMAND 0x0B
#define USBD_SCSI_SENSE_KEY_VOLUME_OVERFLOW 0x0D
#define USBD_SCSI_SENSE_KEY_MISCOMPARE 0x0E
/* ---- SCSI ADDITIONAL SENSE CODES (See Notes #4) ---- */
#define USBD_SCSI_ASC_NO_ADDITIONAL_SENSE_INFO 0x00
#define USBD_SCSI_ASC_NO_INDEX_SECTOR_SIGNAL 0x01
#define USBD_SCSI_ASC_NO_SEEK_COMPLETE 0x02
#define USBD_SCSI_ASC_PERIPHERAL_DEV_WR_FAULT 0x03
#define USBD_SCSI_ASC_LOG_UNIT_NOT_RDY 0x04
#define USBD_SCSI_ASC_LOG_UNIT_NOT_RESPOND_TO_SELECTION 0x05
#define USBD_SCSI_ASC_NO_REFERENCE_POSITION_FOUND 0x06
#define USBD_SCSI_ASC_MULTIPLE_PERIPHERAL_DEVS_SELECTED 0x07
#define USBD_SCSI_ASC_LOG_UNIT_COMMUNICATION_FAIL 0x08
#define USBD_SCSI_ASC_TRACK_FOLLOWING_ERR 0x09
#define USBD_SCSI_ASC_ERR_LOG_OVERFLOW 0x0A
#define USBD_SCSI_ASC_WARNING 0x0B
#define USBD_SCSI_ASC_WR_ERR 0x0C
#define USBD_SCSI_ASC_ERR_DETECTED_BY_THIRD_PARTY 0x0D
#define USBD_SCSI_ASC_INVALID_INFO_UNIT 0x0E
#define USBD_SCSI_ASC_ID_CRC_OR_ECC_ERR 0x10
#define USBD_SCSI_ASC_UNRECOVERED_RD_ERR 0x11
#define USBD_SCSI_ASC_ADDR_MARK_NOT_FOUND_FOR_ID 0x12
#define USBD_SCSI_ASC_ADDR_MARK_NOT_FOUND_FOR_DATA 0x13
#define USBD_SCSI_ASC_RECORDED_ENTITY_NOT_FOUND 0x14
#define USBD_SCSI_ASC_RANDOM_POSITIONING_ERR 0x15
#define USBD_SCSI_ASC_DATA_SYNCHRONIZATION_MARK_ERR 0x16
#define USBD_SCSI_ASC_RECOVERED_DATA_NO_ERR_CORRECT 0x17
#define USBD_SCSI_ASC_RECOVERED_DATA_ERR_CORRECT 0x18
#define USBD_SCSI_ASC_DEFECT_LIST_ERR 0x19
#define USBD_SCSI_ASC_PARAMETER_LIST_LENGTH_ERR 0x1A
#define USBD_SCSI_ASC_SYNCHRONOUS_DATA_TRANSFER_ERR 0x1B
#define USBD_SCSI_ASC_DEFECT_LIST_NOT_FOUND 0x1C
#define USBD_SCSI_ASC_MISCOMPARE_DURING_VERIFY_OP 0x1D
#define USBD_SCSI_ASC_RECOVERED_ID_WITH_ECC_CORRECTION 0x1E
#define USBD_SCSI_ASC_PARTIAL_DEFECT_LIST_TRANSFER 0x1F
#define USBD_SCSI_ASC_INVALID_CMD_OP_CODE 0x20
#define USBD_SCSI_ASC_LOG_BLOCK_ADDR_OUT_OF_RANGE 0x21
#define USBD_SCSI_ASC_ILLEGAL_FUNCTION 0x22
#define USBD_SCSI_ASC_INVALID_FIELD_IN_CDB 0x24
#define USBD_SCSI_ASC_LOG_UNIT_NOT_SUPPORTED 0x25
#define USBD_SCSI_ASC_INVALID_FIELD_IN_PARAMETER_LIST 0x26
#define USBD_SCSI_ASC_WR_PROTECTED 0x27
#define USBD_SCSI_ASC_NOT_RDY_TO_RDY_CHANGE 0x28
#define USBD_SCSI_ASC_POWER_ON_OR_BUS_DEV_RESET 0x29
#define USBD_SCSI_ASC_PARAMETERS_CHANGED 0x2A
#define USBD_SCSI_ASC_CANNOT_COPY_CANNOT_DISCONNECT 0x2B
#define USBD_SCSI_ASC_CMD_SEQUENCE_ERR 0x2C
#define USBD_SCSI_ASC_OVERWR_ERR_ON_UPDATE_IN_PLACE 0x2D
#define USBD_SCSI_ASC_INSUFFICIENT_TIME_FOR_OP 0x2E
#define USBD_SCSI_ASC_CMDS_CLEARED_BY_ANOTHER_INIT 0x2F
#define USBD_SCSI_ASC_INCOMPATIBLE_MEDIUM_INSTALLED 0x30
#define USBD_SCSI_ASC_MEDIUM_FORMAT_CORRUPTED 0x31
#define USBD_SCSI_ASC_NO_DEFECT_SPARE_LOCATION_AVAIL 0x32
#define USBD_SCSI_ASC_TAPE_LENGTH_ERR 0x33
#define USBD_SCSI_ASC_ENCLOSURE_FAIL 0x34
#define USBD_SCSI_ASC_ENCLOSURE_SERVICES_FAIL 0x35
#define USBD_SCSI_ASC_RIBBON_INK_OR_TONER_FAIL 0x36
#define USBD_SCSI_ASC_ROUNDED_PARAMETER 0x37
#define USBD_SCSI_ASC_EVENT_STATUS_NOTIFICATION 0x38
#define USBD_SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x39
#define USBD_SCSI_ASC_MEDIUM_NOT_PRESENT 0x3A
#define USBD_SCSI_ASC_SEQUENTIAL_POSITIONING_ERR 0x3B
#define USBD_SCSI_ASC_INVALID_BITS_IN_IDENTIFY_MSG 0x3D
#define USBD_SCSI_ASC_LOG_UNIT_HAS_NOT_SELF_CFG_YET 0x3E
#define USBD_SCSI_ASC_TARGET_OP_CONDITIONS_HAVE_CHANGED 0x3F
#define USBD_SCSI_ASC_RAM_FAIL 0x40
#define USBD_SCSI_ASC_DATA_PATH_FAIL 0x41
#define USBD_SCSI_ASC_POWER_ON_SELF_TEST_FAIL 0x42
#define USBD_SCSI_ASC_MSG_ERR 0x43
#define USBD_SCSI_ASC_INTERNAL_TARGET_FAIL 0x44
#define USBD_SCSI_ASC_SELECT_OR_RESELECT_FAIL 0x45
#define USBD_SCSI_ASC_UNSUCCESSFUL_SOFT_RESET 0x46
#define USBD_SCSI_ASC_SCSI_PARITY_ERR 0x47
#define USBD_SCSI_ASC_INIT_DETECTED_ERR_MSG_RECEIVED 0x48
#define USBD_SCSI_ASC_INVALID_MSG_ERR 0x49
#define USBD_SCSI_ASC_CMD_PHASE_ERR 0x4A
#define USBD_SCSI_ASC_DATA_PHASE_ERR 0x4B
#define USBD_SCSI_ASC_LOG_UNIT_FAILED_SELF_CFG 0x4C
#define USBD_SCSI_ASC_OVERLAPPED_CMDS_ATTEMPTED 0x4E
#define USBD_SCSI_ASC_WR_APPEND_ERR 0x50
#define USBD_SCSI_ASC_ERASE_FAIL 0x51
#define USBD_SCSI_ASC_CARTRIDGE_FAULT 0x52
#define USBD_SCSI_ASC_MEDIA_LOAD_OR_EJECT_FAILED 0x53
#define USBD_SCSI_ASC_SCSI_TO_HOST_SYSTEM_IF_FAIL 0x54
#define USBD_SCSI_ASC_SYSTEM_RESOURCE_FAIL 0x55
#define USBD_SCSI_ASC_UNABLE_TO_RECOVER_TOC 0x57
#define USBD_SCSI_ASC_GENERATION_DOES_NOT_EXIST 0x58
#define USBD_SCSI_ASC_UPDATED_BLOCK_RD 0x59
#define USBD_SCSI_ASC_OP_REQUEST_OR_STATE_CHANGE_INPUT 0x5A
#define USBD_SCSI_ASC_LOG_EXCEPT 0x5B
#define USBD_SCSI_ASC_RPL_STATUS_CHANGE 0x5C
#define USBD_SCSI_ASC_FAIL_PREDICTION_TH_EXCEEDED 0x5D
#define USBD_SCSI_ASC_LOW_POWER_CONDITION_ON 0x5E
#define USBD_SCSI_ASC_LAMP_FAIL 0x60
#define USBD_SCSI_ASC_VIDEO_ACQUISITION_ERR 0x61
#define USBD_SCSI_ASC_SCAN_HEAD_POSITIONING_ERR 0x62
#define USBD_SCSI_ASC_END_OF_USER_AREA_ENCOUNTERED 0x63
#define USBD_SCSI_ASC_ILLEGAL_MODE_FOR_THIS_TRACK 0x64
#define USBD_SCSI_ASC_VOLTAGE_FAULT 0x65
#define USBD_SCSI_ASC_AUTO_DOCUMENT_FEEDER_COVER_UP 0x66
#define USBD_SCSI_ASC_CONFIGURATION_FAIL 0x67
#define USBD_SCSI_ASC_LOG_UNIT_NOT_CONFIGURED 0x68
#define USBD_SCSI_ASC_DATA_LOSS_ON_LOG_UNIT 0x69
#define USBD_SCSI_ASC_INFORMATIONAL_REFER_TO_LOG 0x6A
#define USBD_SCSI_ASC_STATE_CHANGE_HAS_OCCURRED 0x6B
#define USBD_SCSI_ASC_REBUILD_FAIL_OCCURRED 0x6C
#define USBD_SCSI_ASC_RECALCULATE_FAIL_OCCURRED 0x6D
#define USBD_SCSI_ASC_CMD_TO_LOG_UNIT_FAILED 0x6E
#define USBD_SCSI_ASC_COPY_PROTECTION_KEY_EXCHANGE_FAIL 0x6F
#define USBD_SCSI_ASC_DECOMPRESSION_EXCEPT_LONG_ALGO_ID 0x71
#define USBD_SCSI_ASC_SESSION_FIXATION_ERR 0x72
#define USBD_SCSI_ASC_CD_CONTROL_ERR 0x73
#define USBD_SCSI_ASC_SECURITY_ERR 0x74
/* ------- SCSI MODE PAGE CODES (See Notes #5) -------- */
#define USBD_SCSI_PAGE_CODE_READ_WRITE_ERROR_RECOVERY 0x01
#define USBD_SCSI_PAGE_CODE_FORMAT_DEVICE 0x03
#define USBD_SCSI_PAGE_CODE_FLEXIBLE_DISK 0x05
#define USBD_SCSI_PAGE_CODE_INFORMATIONAL_EXCEPTIONS 0x1C
#define USBD_SCSI_PAGE_CODE_ALL 0x3F
#define USBD_SCSI_PAGE_LENGTH_INFORMATIONAL_EXCEPTIONS 0x0A
#define USBD_SCSI_PAGE_LENGTH_READ_WRITE_ERROR_RECOVERY 0x0A
#define USBD_SCSI_PAGE_LENGTH_FLEXIBLE_DISK 0x1E
#define USBD_SCSI_PAGE_LENGTH_FORMAT_DEVICE 0x16
/*
*********************************************************************************************************
* INQUIRY CMD
*
* Note(s) : (1) The peripheral qualifiers are specified in 'SCSI Primary Commands - 3' (SPC-3),
* Revision 23, Section 6.4.2, Table 82 - Peripheral Qualifer.
*
* (2) The peripheral device types are specified in 'SCSI Primary Commands - 3' (SPC-3),
* Revision 23, Section 6.4.2, Table 83 - Peripheral Device Type.
*********************************************************************************************************
*/
/* -------------- PERIPHERAL QUALIFIERS --------------- */
#define USBD_SCSI_PER_QUAL_CONN 0x00
#define USBD_SCSI_PER_QUAL_NOT_CONN 0x01
#define USBD_SCSI_PER_QUAL_NOT_SUPPORTED 0x03
/* ------------- PERIPHERAL DEVICE TYPES -------------- */
#define USBD_SCSI_PER_DEV_TYPE_DIRECT_ACCESS_BLOCK_DEV 0x00
#define USBD_SCSI_PER_DEV_TYPE_SEQ_ACCESS_DEV 0x01
#define USBD_SCSI_PER_DEV_TYPE_PRINTER_DEV 0x02
#define USBD_SCSI_PER_DEV_TYPE_PROCESSOR_DEV 0x03
#define USBD_SCSI_PER_DEV_TYPE_WR_ONCE_DEV 0x04
#define USBD_SCSI_PER_DEV_TYPE_CD_DVD_DEV 0x05
#define USBD_SCSI_PER_DEV_TYPE_OPTICAL_MEM_DEV 0x07
#define USBD_SCSI_PER_DEV_TYPE_MEDIUM_CHANGER_DEV 0x08
#define USBD_SCSI_PER_DEV_TYPE_STORAGE_ARRAY_CTRL_DEV 0x0C
#define USBD_SCSI_PER_DEV_TYPE_ENCLOSURE_SVC_DEV 0x0D
#define USBD_SCSI_PER_DEV_TYPE_SIMPL_DIRECT_ACCESS_DEV 0x0E
#define USBD_SCSI_PER_DEV_TYPE_OPTICAL_CARD_RD_WR_DEV 0x0F
#define USBD_SCSI_PER_DEV_TYPE_BRIDGE_CTRL_CMDS 0x10
#define USBD_SCSI_PER_DEV_TYPE_OBJ_BASED_STORAGE_DEV 0x11
#define USBD_SCSI_PER_DEV_TYPE_AUTOMATION_DRIVE_IF 0x12
#define USBD_SCSI_INQUIRY_RMB DEF_BIT_07
/*
**********************************************************************************************************
* START STOP UNIT CMD
**********************************************************************************************************
*/
#define USBD_SCSI_START_STOP_UNIT_START DEF_BIT_00
#define USBD_SCSI_START_STOP_UNIT_LOEJ DEF_BIT_01
/*
*********************************************************************************************************
* MODE SENSE CMD AND DATA
*********************************************************************************************************
*/
#define USBD_SCSI_MSK_PAGE_CODE 0x3F
/* ----------------- MODE SENSE DATA ------------------ */
#define USBD_SCSI_MODE_SENSE_DATA_SPEC_PARAM_WR_EN 0x00
#define USBD_SCSI_MODE_SENSE_DATA_SPEC_PARAM_WR_PROT 0x80
#define USBD_SCSI_MODE_SENSE_DATA_MODE_PARAM_HDR_6_LEN 3u
#define USBD_SCSI_MODE_SENSE_DATA_MODE_PARAM_HDR_10_LEN 6u
#define USBD_SCSI_MODE_SENSE_DATA_MODE_PAGE_HDR_LEN 2u
/* --------- INFO EXCEPTIONS CTRL PAGE PARAM ---------- */
#define USBD_SCSI_MODE_SENSE_DATA_MRIE_NO_SENSE 0x05
/* ---------- READ/WRITE ERR RECOVERY PARAM ----------- */
#define USBD_SCSI_MODE_SENSE_DATA_AWRE 0x80
#define USBD_SCSI_MODE_SENSE_DATA_RD_RETRY_CNT 3u
#define USBD_SCSI_MODE_SENSE_DATA_WR_RETRY_CNT 3u
#define USBD_SCSI_MODE_SENSE_DATA_CORRECTION_SPAN 0x00
#define USBD_SCSI_MODE_SENSE_DATA_HEAD_OFFSET_CNT 0x00
#define USBD_SCSI_MODE_SENSE_DATA_DATA_STROBE_OFFSET 0x00
#define USBD_SCSI_MODE_SENSE_DATA_RECOVERY_LIMIT 0x00
/*
**********************************************************************************************************
* TRACE MACROS
**********************************************************************************************************
*/
#define USBD_DBG_MSC_SCSI_MSG(msg) USBD_DBG_GENERIC ((msg), \
USBD_EP_ADDR_NONE, \
USBD_IF_NBR_NONE)
#define USBD_DBG_MSC_SCSI_ARG(msg, arg) USBD_DBG_GENERIC_ARG((msg), \
USBD_EP_ADDR_NONE, \
USBD_IF_NBR_NONE, \
(arg))
/*
**********************************************************************************************************
* LOCAL CONSTANTS
**********************************************************************************************************
*/
/*
**********************************************************************************************************
* LOCAL DATA TYPES
**********************************************************************************************************
*/
/*
**********************************************************************************************************
* LOCAL TABLES
**********************************************************************************************************
*/
static USBD_STORAGE_LUN USBD_SCSI_LunTbl[USBD_MSC_CFG_MAX_LUN];
static CPU_INT08U USBD_SCSI_InquiryData[USBD_SCSI_INQUIRY_DATA_LEN];
static CPU_INT08U USBD_SCSI_ModeSenseData[USBD_SCSI_MODE_SENSE_DATA_LEN];
static CPU_INT08U USBD_SCSI_ReadCapacityData[USBD_SCSI_RD_CAPACITY_16_PARAM_DATA_LEN];
static CPU_INT08U USBD_SCSI_ReqSenseData[USBD_SCSI_REQ_SENSE_DATA_LEN];
/*
**********************************************************************************************************
* LOCAL GLOBAL VARIABLES
**********************************************************************************************************
*/
static CPU_INT08U *USBD_SCSI_RespBufPtr; /* Ptr to data buf for Data IN phase. */
static CPU_INT32U USBD_SCSI_RespLen; /* Buf len. */
static CPU_INT64U USBD_SCSI_LBAddr; /* 64-bit Logical Blk Addr. */
static CPU_INT32U USBD_SCSI_LBCnt; /* Nbr of mem blks. */
static CPU_INT08U USBD_SCSI_SenseKey; /* Sense key describing an err or exception cond. */
static CPU_INT08U USBD_SCSI_ASC; /* Additional Sense Code describing sense key in detail.*/
static CPU_INT08U USBD_SCSI_ASCQ; /* Additional Sense Code Qualifier. */
/*
**********************************************************************************************************
* LOCAL FUNCTION PROTOTYPES
**********************************************************************************************************
*/
static void USBD_SCSI_ModeSenseDataPrepare(const USBD_MSC_LUN_CTRL *p_lun,
CPU_INT08U scsi_cmd,
CPU_INT08U page_code,
USBD_ERR *p_err);
static void USBD_SCSI_ReqSenseDataUpdate ( CPU_INT08U sense_key,
CPU_INT08U sense_code,
CPU_INT08U sense_code_qual);
static void USBD_SCSI_InquiryDataPrepare (const USBD_MSC_LUN_CTRL *p_lun,
CPU_INT08U cmdt_evpd,
CPU_INT08U page_code,
USBD_ERR *p_err);
static void USBD_SCSI_LunStatusAnalyze ( USBD_ERR err);
static void USBD_SCSI_PageRdWrErrRecovery ( void *p_buf_dest);
static void USBD_SCSI_PageInfoExcept ( void *p_buf_dest);
/*
**********************************************************************************************************
* LOCAL CONFIGURATION ERRORS
**********************************************************************************************************
*/
/*
*********************************************************************************************************
*********************************************************************************************************
* GLOBAL FUNCTIONS
*********************************************************************************************************
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* USBD_SCSI_Init()
*
* Description : Initialize internal tables, variables and the storage layer.
*
* Argument(s) : p_err Pointer to variable that will receive the return error code from this function :
*
* ---------- RETURNED BY USBD_StorageInit() : -------
* USBD_ERR_NONE Storage layer successfully initialized.
*
* Return(s) : None.
*
* Note(s) : (1) The format of standard INQUIRY data is specified in 'SCSI Primary Commands - 3' (SPC-3),
* Revision 23, Section 6.4.2.
*
* (a) Byte 2: VERSION field indicates the implemented version of this standard.
*
* (b) Byte 3: RESPONSE DATA FORMAT field value of two indicates that the data shall be
* in the format defined in this standard
*
* (c) Byte 4: ADDITIONAL LENGTH field indicates the length in bytes of the remaining
* standard INQUIRY data.
*
* (2) The format of MODE SENSE data is specified in 'SCSI Primary Commands - 3' (SPC-3),
* Revision 23, Section 7.4.1.
*
* (3) The format of READ CAPACITY(10) parameter data is specified in 'SCSI Block Commands - 3'
* (SPC-3), Section 5.12.2.
* The format of READ CAPACITY(16) parameter data is specified in 'SCSI Block Commands - 3'
* (SPC-3), Section 5.12.3.
*
* (4) The format of standard fixed-format sense data is specified in 'SCSI Primary Commands - 3'
* (SPC-3), Revision 23, Section 4.5.3.
*
* (a) Byte 0: RESPONSE CODE field indicates the error type and format of the sense data.
*
* (b) Byte 7: ADDITIONAL SENSE LENGTH field indicates the number of additional sense
* bytes that follow.
*********************************************************************************************************
*/
void USBD_SCSI_Init (USBD_ERR *p_err)
{
CPU_INT08U ix;
for (ix = 0; ix < USBD_MSC_CFG_MAX_LUN; ix++) {
Mem_Clr((void *)&USBD_SCSI_LunTbl[ix],
(CPU_SIZE_T) sizeof(USBD_STORAGE_LUN));
}
/* See Note #1. */
Mem_Clr((void *)USBD_SCSI_InquiryData,
(CPU_SIZE_T)USBD_SCSI_INQUIRY_DATA_LEN);
/* See Note #2. */
Mem_Clr((void *)USBD_SCSI_ModeSenseData,
(CPU_SIZE_T)USBD_SCSI_MODE_SENSE_DATA_LEN);
/* See Note #3. */
Mem_Clr((void *)USBD_SCSI_ReadCapacityData,
(CPU_SIZE_T)USBD_SCSI_RD_CAPACITY_16_PARAM_DATA_LEN);
/* See Note #4. */
Mem_Clr((void *)USBD_SCSI_ReqSenseData,
(CPU_SIZE_T)USBD_SCSI_REQ_SENSE_DATA_LEN);
/* See Note #1a to 1c. */
USBD_SCSI_InquiryData[2] = USBD_SCSI_INQUIRY_VERS_SPC_3;
USBD_SCSI_InquiryData[3] = USBD_SCSI_INQUIRY_RESP_DATA_FMT_DEFAULT;
USBD_SCSI_InquiryData[4] = (USBD_SCSI_INQUIRY_DATA_LEN - 5);
/* See Note #4a to 4b. */
USBD_SCSI_ReqSenseData[0] = USBD_SCSI_REQ_SENSE_RESP_CODE_CUR_ERR;
USBD_SCSI_ReqSenseData[7] = (USBD_SCSI_REQ_SENSE_DATA_LEN - 8);
USBD_SCSI_RespBufPtr = (CPU_INT08U *)0u;
USBD_SCSI_RespLen = 0u;
USBD_SCSI_LBAddr = 0u;
USBD_SCSI_LBCnt = 0u;
USBD_SCSI_SenseKey = 0u;
USBD_SCSI_ASC = 0u;
USBD_SCSI_ASCQ = 0u;
USBD_StorageInit(p_err); /* Init storage layer. */
}
/*
*********************************************************************************************************
* USBD_SCSI_LunAdd()
*
* Description : Initialize the specified logical unit.
*
* Argument(s) : lun_nbr Logical unit number.
*
* p_vol_str Pointer to string uniquely identifying the logical unit.
*
* p_err Pointer to variable that will receive the return error code from this function :
*
* ---------- RETURNED BY USBD_StorageAdd() : -------
* USBD_ERR_NONE Logical unit successfully initialized.
*
* Return(s) : None.
*
* Note(s) : None.
*********************************************************************************************************
*/
void USBD_SCSI_LunAdd (CPU_INT08U lun_nbr,
CPU_CHAR *p_vol_str,
USBD_ERR *p_err)
{
USBD_SCSI_LunTbl[lun_nbr].LunNbr = lun_nbr;
USBD_SCSI_LunTbl[lun_nbr].VolStrPtr = p_vol_str;
USBD_StorageAdd(&USBD_SCSI_LunTbl[lun_nbr], p_err); /* Init logical unit. */
}
/*
**********************************************************************************************************
* USBD_SCSI_CmdProcess()
*
* Description : Process operation(s) associated with the SCSI command.
*
* Argument(s) : p_lun Pointer to Logical Unit information.
*
* p_cbwcb Pointer to the Command Block Wrapper that contains the SCSI command.
*
* p_resp_len Pointer to variable that will receive the length of the SCSI response
* that needs to be transfered in the data stage.
*
* p_data_dir Pointer to variable that will receive the data transfer direction
* indicator:
*
* USBD_SCSI_CBW_DEVICE_TO_HOST Data stage response from device to host.
* USBD_SCSI_CBW_HOST_TO_DEVICE Data stage response from host to device.
*
* p_err Pointer to variable that will receive the return error code from this function :
*
* USBD_ERR_NONE SCSI command successfully processed.
* USBD_ERR_SCSI_MEDIUM_NOTPRESENT Logical unit lock failed or logical
* already ejected by host.
* USBD_ERR_SCSI_UNSUPPORTED_CMD SCSI command not supported.
* USBD_ERR_SCSI_LOG_BLOCK_ADDR Logical block address out of range.
*
* --- RETURNED BY USBD_StorageLock() : ---
* USBD_ERR_SCSI_LOCK Logical unit lock failed.
* USBD_ERR_SCSI_LOCK_TIMEOUT Logical unit lock timed out.
*
* --- RETURNED BY USBD_SCSI_InquiryDataPrepare() : ---
* USBD_ERR_SCSI_UNSUPPORTED_CMD SCSI command not supported.
*
* --- RETURNED BY USBD_StorageStatusGet() : ---
* USBD_ERR_SCSI_MEDIUM_NOTPRESENT Medium not present.
* USBD_ERR_SCSI_MEDIUM_NOT_RDY_TO_RDY Medium from not ready to ready state.
* USBD_ERR_SCSI_MEDIUM_RDY_TO_NOT_RDY Medium from ready to not ready state.
*
* --- RETURNED BY USBD_StorageCapacityGet() : ---
* USBD_ERR_SCSI_MEDIUM_NOTPRESENT Medium not present.
*
* --- RETURNED BY USBD_SCSI_ModeSenseDataPrepare() : ---
* USBD_ERR_SCSI_UNSUPPORTED_CMD Page code not supported.
*
* Return(s) : None.
*
* Note(s) : (1) The format of standard INQUIRY data is specified in 'SCSI Primary Commands - 3'
* (SPC-3), Revision 23, Section 6.4.
*
* (2) The format of TEST UNIT READY command is specified in 'SCSI Primary Commands - 3'
* (SPC-3), Revision 23, Section 6.33.
*
* (3) The format of READ CAPACITY (10) command is specified in 'SCSI Blocks Commands - 3'
* (SBC-3), Revision 16, Section 5.12.
*
* (4) The format of READ CAPACITY (16) command is specified in 'SCSI Blocks Commands - 3'
* (SBC-3), Revision 16, Section 5.13.
*
* (5) The format of READ(10) command is specified in 'SCSI Block Commands - 3'
* (SBC), Revision 16, Section 5.8.
*
* (6) The format of READ(12) command is specified in 'SCSI Block Commands - 3'
* (SBC), Revision 16, Section 5.9.
*
* (7) The format of READ(16) command is specified in 'SCSI Block Commands - 3'
* (SBC), Revision 16, Section 5.10.
*
* (8) The format of WRITE(10) command is specified in 'SCSI Block Commands - 3'
* (SBC), Revision 16, Section 5.27.
*
* (9) The format of WRITE(12) command is specified in 'SCSI Block Commands - 3'
* (SBC), Revision 16, Section 5.28.
*
* (10) The format of WRITE(16) command is specified in 'SCSI Block Commands - 3'
* (SBC), Revision 16, Section 5.29.
*
* (11) The format of VERIFY(10) command is specified in 'SCSI Block Commands - 3'
* (SBC), Revision 16, Section 5.22.
*
* (12) The format of VERIFY(12) command is specified in 'SCSI Block Commands - 3'
* (SBC), Revision 16, Section 5.23.
*
* (13) The format of VERIFY(16) command is specified in 'SCSI Block Commands - 3'
* (SBC), Revision 16, Section 5.24.
*
* (14) The format of MODE SENSE(6) command is specified in 'SCSI Primary Commands - 3'
* (SPC-3), Revision 23, Section 6.9.
*
* (15) The format of MODE SENSE(10) command is specified in 'SCSI Primary Commands - 3'
* (SPC-3), Revision 23, Section 6.10.
*
* (16) The format of REQUEST SENSE command is specified in 'SCSI Primary Commands - 3'
* (SPC-3), Revision 23, Section 6.25.
*
* (17) The format of PREVENT ALLOW MEDIUM REMOVAL command is specified in 'SCSI Primary
* Commands - 3' (SPC-3), Revision 23, Section 6.13.
*
* (18) The format of START STOP UNIT command is specified in 'SCSI Primary
* Commands - 3' (SPC-3), Revision 23, Section 5.19.
**********************************************************************************************************
*/
void USBD_SCSI_CmdProcess ( USBD_MSC_LUN_CTRL *p_lun,
const CPU_INT08U *p_cbwcb,
CPU_INT32U *p_resp_len,
CPU_INT08U *p_data_dir,
USBD_ERR *p_err)
{
CPU_INT08U scsi_cmd;
CPU_INT08U page_code;
CPU_INT08U cmdt_evpd;
CPU_INT08U loej;
CPU_INT08U start_flag;
CPU_INT32U len;
CPU_INT64U nbr_blks;
CPU_INT32U total_area_size_verifd;
CPU_INT32U total_lu_size;
USBD_STORAGE_LUN *p_storage_lun;
scsi_cmd = p_cbwcb[0]; /* Get the SCSI cmd blk opcode. */
*p_err = USBD_ERR_NONE;
*p_resp_len = 0;
p_storage_lun = &USBD_SCSI_LunTbl[p_lun->LunNbr];
switch (scsi_cmd) {
case USBD_SCSI_CMD_INQUIRY: /* -------------- INQUIRY(see Notes #1) -------------- */
USBD_DBG_MSC_SCSI_MSG("SCSI: INQUIRY Command");
cmdt_evpd = p_cbwcb[1] & 0x03; /* Get the enable vital prod data bit. */
page_code = p_cbwcb[2]; /* Page code for vital prod data info. */
USBD_SCSI_InquiryDataPrepare(p_lun, cmdt_evpd, page_code, p_err);
if (*p_err == USBD_ERR_NONE) {
len = DEF_MIN(USBD_SCSI_INQUIRY_DATA_LEN, p_cbwcb[4]);
/* Copy the Inquiry data. */
USBD_SCSI_RespBufPtr = &USBD_SCSI_InquiryData[0];
USBD_SCSI_RespLen = len;
*p_data_dir = USBD_SCSI_CBW_DEVICE_TO_HOST;
/* Build req sense data with no err cond. */
USBD_SCSI_ReqSenseDataUpdate(USBD_SCSI_SENSE_KEY_NO_SENSE,
USBD_SCSI_ASC_NO_ADDITIONAL_SENSE_INFO,
0x00);
} else {
USBD_SCSI_RespBufPtr = (CPU_INT08U *)0;
USBD_SCSI_RespLen = 0;
/* Build req sense data with an err cond. */
USBD_SCSI_ReqSenseDataUpdate(USBD_SCSI_SENSE_KEY_ILLEGAL_REQUEST,
USBD_SCSI_ASC_INVALID_FIELD_IN_CDB,
0x00);
}
break;
case USBD_SCSI_CMD_TEST_UNIT_READY: /* ----------- TEST UNIT READY(see Notes #2) ---------- */
USBD_DBG_MSC_SCSI_MSG("SCSI: TEST UNIT READY Command");
USBD_StorageStatusGet(p_storage_lun, p_err); /* Get logical unit status. */
if (*p_err == USBD_ERR_NONE) {
if (p_storage_lun->EjectFlag == DEF_TRUE) { /* Logical unit has been ejected by host... */
*p_err = USBD_ERR_SCSI_MEDIUM_NOTPRESENT; /* ...medium is considered not present. */
} else if (p_storage_lun->LockFlag == DEF_FALSE) {
/* Try locking logical unit. */
USBD_StorageLock(p_storage_lun, USBD_SCSI_LOCK_DLY_mS, p_err);
if (*p_err == USBD_ERR_NONE) {
p_storage_lun->LockFlag = DEF_TRUE;
} else { /* If lock failed or timed out, consider medium... */
/* ...as not present. */
*p_err = USBD_ERR_SCSI_MEDIUM_NOTPRESENT;
}
}
} else {
p_storage_lun->EjectFlag = DEF_FALSE;
}
USBD_SCSI_LunStatusAnalyze(*p_err); /* Check err code & build req sense data. */
USBD_SCSI_RespBufPtr = (CPU_INT08U *)0;
USBD_SCSI_RespLen = 0;
break;
case USBD_SCSI_CMD_READ_CAPACITY_10: /* --------- READ CAPACITY(10)(see Notes #3) ---------- */
case USBD_SCSI_CMD_SERVICE_ACTION_IN_16: /* --------- READ CAPACITY(16)(see Notes #4) ---------- */
USBD_DBG_MSC_SCSI_MSG("SCSI: READ CAPACITY 10 / 16 Command");
if ((p_storage_lun->LockFlag == DEF_FALSE) || /* Logical unit not locked... */
(p_storage_lun->EjectFlag == DEF_TRUE )) { /* Logical unit has been ejected by host... */
*p_err = USBD_ERR_SCSI_MEDIUM_NOTPRESENT; /* ...medium is considered not present. */
} else { /* Get logical unit status. */
USBD_StorageStatusGet(p_storage_lun, p_err);
}
USBD_SCSI_LunStatusAnalyze(*p_err); /* Check err code & build req sense data. */
if (*p_err == USBD_ERR_NONE){
/* Get the capacity, nbr of blks and blk size. */
USBD_StorageCapacityGet(p_storage_lun,
&p_lun->NbrBlocks,
&p_lun->BlockSize,
p_err);
USBD_SCSI_LunStatusAnalyze(*p_err); /* Check err code & build req sense data. */
if (*p_err != USBD_ERR_NONE ) {
break;
}
if (scsi_cmd == USBD_SCSI_CMD_READ_CAPACITY_10) {
MEM_VAL_SET_INT32U_BIG(&USBD_SCSI_ReadCapacityData[0], p_lun->NbrBlocks - 1);
MEM_VAL_SET_INT32U_BIG(&USBD_SCSI_ReadCapacityData[4], p_lun->BlockSize);
USBD_SCSI_RespBufPtr = &USBD_SCSI_ReadCapacityData[0];
USBD_SCSI_RespLen = USBD_SCSI_RD_CAPACITY_10_PARAM_DATA_LEN;
} else {
nbr_blks = p_lun->NbrBlocks - 1;
MEM_VAL_COPY_SET_INTU_BIG(&USBD_SCSI_ReadCapacityData[0], &nbr_blks, 8u);
MEM_VAL_SET_INT32U_BIG(&USBD_SCSI_ReadCapacityData[8], p_lun->BlockSize);
USBD_SCSI_RespBufPtr = &USBD_SCSI_ReadCapacityData[0];
USBD_SCSI_RespLen = USBD_SCSI_RD_CAPACITY_16_PARAM_DATA_LEN;
}
*p_data_dir = USBD_SCSI_CBW_DEVICE_TO_HOST;
}
break;
case USBD_SCSI_CMD_READ_10: /* -------------- READ(10)(see Notes #5) -------------- */
case USBD_SCSI_CMD_READ_12: /* -------------- READ(12)(see Notes #6) -------------- */
case USBD_SCSI_CMD_READ_16: /* -------------- READ(16)(see Notes #7) -------------- */
USBD_DBG_MSC_SCSI_MSG("SCSI: READ 10 / 12 / 16 Command");
if ((p_storage_lun->LockFlag == DEF_FALSE) || /* Logical unit not locked... */
(p_storage_lun->EjectFlag == DEF_TRUE )) { /* Logical unit has been ejected by host... */
*p_err = USBD_ERR_SCSI_MEDIUM_NOTPRESENT; /* ...medium is considered not present. */
} else { /* Get logical unit status. */
USBD_StorageStatusGet(p_storage_lun, p_err);
}
USBD_SCSI_LunStatusAnalyze(*p_err); /* Check err code & build req sense data. */
if (*p_err == USBD_ERR_NONE){
if (scsi_cmd == USBD_SCSI_CMD_READ_10){
/* Get the LBA from where data has to be rd. */
USBD_SCSI_LBAddr = MEM_VAL_GET_INT32U_BIG(&p_cbwcb[2]);
/* Nbr of log blks that shall be rd. */
USBD_SCSI_LBCnt = MEM_VAL_GET_INT16U_BIG(&p_cbwcb[7]);
} else if (scsi_cmd == USBD_SCSI_CMD_READ_12){
/* Get the LBA from where data has to be rd. */
USBD_SCSI_LBAddr = MEM_VAL_GET_INT32U_BIG(&p_cbwcb[2]);
/* Nbr of log blks that shall be rd. */
USBD_SCSI_LBCnt = MEM_VAL_GET_INT32U_BIG(&p_cbwcb[6]);
} else {
/* Get the LBA from where data has to be rd. */
MEM_VAL_COPY_GET_INTU_BIG(&USBD_SCSI_LBAddr, &p_cbwcb[2], 8u);
/* Nbr of log blks that shall be rd. */
USBD_SCSI_LBCnt = MEM_VAL_GET_INT32U_BIG(&p_cbwcb[10]);
}
USBD_SCSI_RespBufPtr = (CPU_INT08U *)0;
USBD_SCSI_RespLen = USBD_SCSI_LBCnt * (p_lun->BlockSize);
*p_data_dir = USBD_SCSI_CBW_DEVICE_TO_HOST;
/* Build req sense data with no err cond. */
USBD_SCSI_ReqSenseDataUpdate(USBD_SCSI_SENSE_KEY_NO_SENSE,
USBD_SCSI_ASC_NO_ADDITIONAL_SENSE_INFO,
0x00);
}
break;
case USBD_SCSI_CMD_WRITE_10: /* -------------- WRITE(10)(see Notes #8) ------------- */
case USBD_SCSI_CMD_WRITE_12: /* -------------- WRITE(12)(see Notes #9) ------------- */
case USBD_SCSI_CMD_WRITE_16: /* ------------- WRITE(16)(see Notes #10) ------------- */
USBD_DBG_MSC_SCSI_MSG("SCSI: WRITE 10 / 12 / 16 Command");
if ((p_storage_lun->LockFlag == DEF_FALSE) || /* Logical unit not locked... */
(p_storage_lun->EjectFlag == DEF_TRUE )) { /* Logical unit has been ejected by host... */
/* ...medium is considered not present. */
USBD_SCSI_RespBufPtr = (CPU_INT08U *)0;
USBD_SCSI_RespLen = 0;
USBD_SCSI_ReqSenseDataUpdate(USBD_SCSI_SENSE_KEY_NOT_RDY,
USBD_SCSI_ASC_MEDIUM_NOT_PRESENT,
0x00);
}
if (p_lun->LunInfo.ReadOnly == DEF_TRUE) { /* Check medium is wr protected or not. */
USBD_SCSI_ReqSenseDataUpdate(USBD_SCSI_SENSE_KEY_DATA_PROTECT,
USBD_SCSI_ASC_WR_PROTECTED,
0x00);
*p_err = USBD_ERR_SCSI_UNSUPPORTED_CMD;
break;
}
if (scsi_cmd == USBD_SCSI_CMD_WRITE_10) {
/* Get the LBA from where data has to be written. */
USBD_SCSI_LBAddr = MEM_VAL_GET_INT32U_BIG(&p_cbwcb[2]);
/* Nbr of log blks that shall be written. */
USBD_SCSI_LBCnt = MEM_VAL_GET_INT16U_BIG(&p_cbwcb[7]);
} else if (scsi_cmd == USBD_SCSI_CMD_WRITE_12) {
/* Get the LBA from where data has to be written. */
USBD_SCSI_LBAddr = MEM_VAL_GET_INT32U_BIG(&p_cbwcb[2]);
/* Nbr of log blks that shall be written. */
USBD_SCSI_LBCnt = MEM_VAL_GET_INT32U_BIG(&p_cbwcb[6]);
} else {
/* Get the LBA from where data has to be written. */
MEM_VAL_COPY_GET_INTU_BIG(&USBD_SCSI_LBAddr, &p_cbwcb[2], 8u);
/* Nbr of log blks that shall be written. */
USBD_SCSI_LBCnt = MEM_VAL_GET_INT32U_BIG(&p_cbwcb[10]);
}
USBD_SCSI_RespBufPtr = (CPU_INT08U *)0;
USBD_SCSI_RespLen = USBD_SCSI_LBCnt * (p_lun->BlockSize);
*p_data_dir = USBD_SCSI_CBW_HOST_TO_DEVICE;
/* Build req sense data with no err cond. */
USBD_SCSI_ReqSenseDataUpdate(USBD_SCSI_SENSE_KEY_NO_SENSE,
USBD_SCSI_ASC_NO_ADDITIONAL_SENSE_INFO,
0x00);
break;
case USBD_SCSI_CMD_VERIFY_10: /* ------------ VERIFY(10)(see Notes #11) ------------- */
case USBD_SCSI_CMD_VERIFY_12: /* ------------ VERIFY(12)(see Notes #12) ------------- */
case USBD_SCSI_CMD_VERIFY_16: /* ------------ VERIFY(16)(see Notes #13) ------------- */
USBD_DBG_MSC_SCSI_MSG("SCSI: VERIFY 10 / 12 / 16 Command");
if (scsi_cmd == USBD_SCSI_CMD_VERIFY_10){
/* Get the LBA of where data has to be verified. */
USBD_SCSI_LBAddr = MEM_VAL_GET_INT32U_BIG(&p_cbwcb[2]);
/* Nbr of log blks that shall be verified. */
USBD_SCSI_LBCnt = MEM_VAL_GET_INT16U_BIG(&p_cbwcb[7]);
} else if (scsi_cmd == USBD_SCSI_CMD_VERIFY_12) {
/* Get the LBA of where data has to be verified. */
USBD_SCSI_LBAddr = MEM_VAL_GET_INT32U_BIG(&p_cbwcb[2]);
/* Nbr of log blks that shall be verified. */
USBD_SCSI_LBCnt = MEM_VAL_GET_INT32U_BIG(&p_cbwcb[6]);
} else {
/* Get the LBA of where data has to be verified. */
MEM_VAL_COPY_GET_INTU_BIG(&USBD_SCSI_LBAddr, &p_cbwcb[2], 8u);
/* Nbr of log blks that shall be verified. */
USBD_SCSI_LBCnt = MEM_VAL_GET_INT32U_BIG(&p_cbwcb[10]);
}
total_area_size_verifd = USBD_SCSI_LBAddr * USBD_SCSI_LBCnt;
total_lu_size = p_lun->NbrBlocks * p_lun->BlockSize;
if (total_area_size_verifd > total_lu_size) {
*p_err = USBD_ERR_SCSI_LOG_BLOCK_ADDR;
}
USBD_SCSI_LunStatusAnalyze(*p_err); /* Check err code & build req sense data. */
USBD_SCSI_RespBufPtr = (CPU_INT08U *)0;
USBD_SCSI_RespLen = 0;
break;
case USBD_SCSI_CMD_MODE_SENSE_06: /* ---------- MODE SENSE(6) (see Notes #14) ----------- */
case USBD_SCSI_CMD_MODE_SENSE_10: /* ---------- MODE SENSE(10) (see Notes #15) ---------- */
USBD_DBG_MSC_SCSI_MSG("SCSI: MODE SENSE Command");
if ((p_storage_lun->LockFlag == DEF_FALSE) || /* Logical unit not locked... */
(p_storage_lun->EjectFlag == DEF_TRUE )) { /* Logical unit has been ejected by host... */
*p_err = USBD_ERR_SCSI_MEDIUM_NOTPRESENT; /* ...medium is considered not present. */
} else { /* Get logical unit status. */
USBD_StorageStatusGet(p_storage_lun, p_err);
}
USBD_SCSI_LunStatusAnalyze(*p_err); /* Check err code & build req sense data. */
if (*p_err == USBD_ERR_NONE){
/* Get page code. */
page_code = p_cbwcb[2] & USBD_SCSI_MSK_PAGE_CODE;
USBD_SCSI_ModeSenseDataPrepare(p_lun, scsi_cmd, page_code, p_err);
if (*p_err == USBD_ERR_NONE) {
if (scsi_cmd == USBD_SCSI_CMD_MODE_SENSE_06) {
len = DEF_MIN(USBD_SCSI_ModeSenseData[0] + 1, p_cbwcb[4]);
} else {
len = (p_cbwcb[7] << 8u) |
p_cbwcb[8];
len = DEF_MIN(((CPU_INT32U)USBD_SCSI_ModeSenseData[0] + 1), len);
}
USBD_SCSI_RespBufPtr = &USBD_SCSI_ModeSenseData[0];
USBD_SCSI_RespLen = len; /* Nbr of bytes of data that shall be xfered. */
*p_data_dir = USBD_SCSI_CBW_DEVICE_TO_HOST;
USBD_SCSI_ReqSenseDataUpdate(USBD_SCSI_SENSE_KEY_NO_SENSE,
USBD_SCSI_ASC_NO_ADDITIONAL_SENSE_INFO,
0x00);
} else {
USBD_SCSI_ReqSenseDataUpdate(USBD_SCSI_SENSE_KEY_ILLEGAL_REQUEST,
USBD_SCSI_ASC_INVALID_FIELD_IN_CDB,
0x00);
}
}
break;
case USBD_SCSI_CMD_REQUEST_SENSE: /* ----------- REQUEST SENSE(see Notes #16) ----------- */
USBD_DBG_MSC_SCSI_MSG("SCSI: REQUEST SENSE Command");
len = DEF_MIN(USBD_SCSI_REQ_SENSE_DATA_LEN, p_cbwcb[4]);
USBD_SCSI_ReqSenseData[2] = USBD_SCSI_SenseKey;
USBD_SCSI_ReqSenseData[12] = USBD_SCSI_ASC;
USBD_SCSI_ReqSenseData[13] = USBD_SCSI_ASCQ;
USBD_SCSI_RespBufPtr = &USBD_SCSI_ReqSenseData[0];
USBD_SCSI_RespLen = len; /* Nbr of bytes of data that shall be xferred. */
*p_data_dir = USBD_SCSI_CBW_DEVICE_TO_HOST;
USBD_SCSI_ReqSenseDataUpdate(USBD_SCSI_SENSE_KEY_NO_SENSE,
USBD_SCSI_ASC_NO_ADDITIONAL_SENSE_INFO,
0x00);
break;
case USBD_SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: /* --- PREVENT ALLOW MEDIUM REMOVAL (see Notes #17) --- */
USBD_DBG_MSC_SCSI_MSG("SCSI: PREVENT ALLOW MEDIUM REMOVAL Command");
USBD_SCSI_RespBufPtr = (CPU_INT08U *)0;
USBD_SCSI_RespLen = 0;
USBD_SCSI_ReqSenseDataUpdate(USBD_SCSI_SENSE_KEY_NO_SENSE,
USBD_SCSI_ASC_NO_ADDITIONAL_SENSE_INFO,
0x00);
break;
case USBD_SCSI_CMD_START_STOP_UNIT: /* ---------- START STOP UNIT (see Notes #18) --------- */
USBD_DBG_MSC_SCSI_MSG("SCSI: START STOP UNIT Command");
loej = p_cbwcb[4] & USBD_SCSI_START_STOP_UNIT_LOEJ;
start_flag = p_cbwcb[4] & USBD_SCSI_START_STOP_UNIT_START;
/* Eject the medium. */
if ((DEF_BIT_IS_SET(loej, USBD_SCSI_START_STOP_UNIT_LOEJ) == DEF_YES) &&
(DEF_BIT_IS_CLR(start_flag, USBD_SCSI_START_STOP_UNIT_START) == DEF_YES)) {
p_storage_lun->EjectFlag = DEF_TRUE; /* Flag logical unit as ejected. */
USBD_StorageUnlock(p_storage_lun, p_err);
p_storage_lun->LockFlag = DEF_FALSE;
USBD_SCSI_LunStatusAnalyze(*p_err); /* Check err code & build req sense data. */
if (*p_err != USBD_ERR_NONE ) {
break;
}
} else {
USBD_SCSI_RespBufPtr = (CPU_INT08U *)0;
USBD_SCSI_RespLen = 0;
*p_err = USBD_ERR_SCSI_UNSUPPORTED_CMD;
USBD_SCSI_ReqSenseDataUpdate(USBD_SCSI_SENSE_KEY_ILLEGAL_REQUEST,
USBD_SCSI_ASC_NO_ADDITIONAL_SENSE_INFO,
0x00);
}
break;
default : /* Cmd not supported. */
USBD_DBG_MSC_SCSI_MSG("SCSI: UNSUPPORTED Command");
USBD_SCSI_RespBufPtr = (CPU_INT08U *)0;
USBD_SCSI_RespLen = 0;
*p_err = USBD_ERR_SCSI_UNSUPPORTED_CMD;
USBD_SCSI_ReqSenseDataUpdate(USBD_SCSI_SENSE_KEY_ILLEGAL_REQUEST,
USBD_SCSI_ASC_NO_ADDITIONAL_SENSE_INFO,
0x00);
break;
}
if (*p_err == USBD_ERR_NONE) {
*p_resp_len = USBD_SCSI_RespLen; /* SCSI supported len. */
}
}
/*
**********************************************************************************************************
* USBD_SCSI_DataRd()
*
* Description : Read data from the SCSI device OR copy response data to buffer.
*
* Argument(s) : p_lun Pointer to Logical Unit information.
*
* scsi_cmd SCSI command operation code.
*
* p_data_buf Pointer to receive buffer.
*
* data_len Number of bytes to read.
*
* p_ret_len Pointer to variable that will receive the number of bytes read.
*
* p_err Pointer to variable that will receive the return error code from this function :
*
* USBD_ERR_NONE Read was successful & no more data to be read.
* USBD_ERR_SCSI_MORE_DATA Read was successful & more data to be read.
*
* --- RETURNED BY USBD_StorageRd() : ---
* USBD_ERR_SCSI_MEDIUM_NOTPRESENT Reading logical unit failed.
*
* Return(s) : None.
*
* Note(s) : (1) SCSI commands that require a Data IN phase are: INQUIRY, READ CAPACITY, MODE SENSE,
* REQUEST SENSE and READ. For all these SCSI commands except READ, the buffer containing
* data for the host is prepared upfront during the CBW processing done in
* USBD_SCSI_CmdProcess().
**********************************************************************************************************
*/
void USBD_SCSI_DataRd (const USBD_MSC_LUN_CTRL *p_lun,
CPU_INT08U scsi_cmd,
CPU_INT08U *p_data_buf,
CPU_INT32U data_len,
CPU_INT32U *p_ret_len,
USBD_ERR *p_err)
{
CPU_INT32U lb_cnt;
switch (scsi_cmd) {
case USBD_SCSI_CMD_READ_10:
case USBD_SCSI_CMD_READ_12:
case USBD_SCSI_CMD_READ_16:
USBD_DBG_MSC_SCSI_MSG("SCSI Read data from Disk.");
lb_cnt = data_len / p_lun->BlockSize; /* Nbr of blks that can fit in scsi_data_buf. */
USBD_StorageRd(&USBD_SCSI_LunTbl[p_lun->LunNbr],
USBD_SCSI_LBAddr,
lb_cnt,
p_data_buf,
p_err);
USBD_SCSI_LunStatusAnalyze(*p_err); /* Check err code & build req sense data. */
if (*p_err != USBD_ERR_NONE) {
return;
}
USBD_SCSI_LBAddr += lb_cnt;
USBD_SCSI_LBCnt -= lb_cnt;
if (USBD_SCSI_LBCnt > 0) { /* More data has to be transferred. */
*p_err = USBD_ERR_SCSI_MORE_DATA;
} else {
*p_err = USBD_ERR_NONE;
}
*p_ret_len = data_len; /* Send req'd len. */
break;
default: /* See Note #1. */
if (data_len < USBD_SCSI_RespLen) { /* More data than mass sto req'd. */
*p_ret_len = data_len;
*p_err = USBD_ERR_SCSI_MORE_DATA;
} else {
*p_ret_len = USBD_SCSI_RespLen;
*p_err = USBD_ERR_NONE;
}
Mem_Copy((void *)p_data_buf, /* Retrieve resp buf answering SCSI cmd. */
(void *)USBD_SCSI_RespBufPtr,
*p_ret_len);
break;
}
}
/*
**********************************************************************************************************
* USBD_SCSI_DataWr()
*
* Description : Write data to the SCSI device.
*
* Argument(s) : p_lun Pointer to Logical Unit information.
*
* scsi_cmd SCSI command operation code.
*
* p_data_buf Pointer to transmit buffer.
*
* data_len Number of bytes to write.
*
* p_err Pointer to variable that will receive the return error code from this function :
*
* USBD_ERR_NONE Write was successful & no more data
* to write.
* USBD_ERR_SCSI_MORE_DATA Write was successful & more data to write.
* USBD_ERR_SCSI_UNSUPPORTED_CMD Command not supported.
*
---- RETURNED BY USBD_StorageWr() : ---
* USBD_ERR_SCSI_MEDIUM_NOTPRESENT Writing to logical unit failed.
*
* Return(s) : None.
*
* Note(s) : None.
**********************************************************************************************************
*/
void USBD_SCSI_DataWr (const USBD_MSC_LUN_CTRL *p_lun,
CPU_INT08U scsi_cmd,
void *p_data_buf,
CPU_INT32U data_len,
USBD_ERR *p_err)
{
CPU_INT32U lb_cnt;
switch (scsi_cmd) {
case USBD_SCSI_CMD_WRITE_10:
case USBD_SCSI_CMD_WRITE_12:
case USBD_SCSI_CMD_WRITE_16:
USBD_DBG_MSC_SCSI_MSG("SCSI Write data to Disk.");
lb_cnt = data_len / (p_lun->BlockSize); /* Nbr of blks present in scsi_data_buf. */
USBD_StorageWr(&USBD_SCSI_LunTbl[p_lun->LunNbr],
USBD_SCSI_LBAddr,
lb_cnt,
p_data_buf,
p_err);
USBD_SCSI_LunStatusAnalyze(*p_err); /* Check err code & build req sense data. */
if (*p_err != USBD_ERR_NONE) {
return;
}
USBD_SCSI_LBAddr += lb_cnt;
USBD_SCSI_LBCnt -= lb_cnt;
if (USBD_SCSI_LBCnt > 0) { /* More data has to be xferred. */
*p_err = USBD_ERR_SCSI_MORE_DATA;
} else {
*p_err = USBD_ERR_NONE;
}
break;
default:
*p_err = USBD_ERR_SCSI_UNSUPPORTED_CMD;
USBD_SCSI_ReqSenseDataUpdate(USBD_SCSI_SENSE_KEY_ILLEGAL_REQUEST,
USBD_SCSI_ASC_NO_ADDITIONAL_SENSE_INFO,
0x00);
break;
}
}
/*
**********************************************************************************************************
* USBD_SCSI_Reset()
*
* Description : Reset the SCSI global variables when Bulk-Only Mass Storage Reset request is sent by the
* host.
*
* Argument(s) : None.
*
* Return(s) : None.
*
* Note(s) : None.
**********************************************************************************************************
*/
void USBD_SCSI_Reset (void)
{
USBD_SCSI_LBAddr = 0;
USBD_SCSI_LBCnt = 0;
USBD_SCSI_RespLen = 0;
USBD_SCSI_RespBufPtr = (CPU_INT08U *)0;
USBD_SCSI_SenseKey = 0;
USBD_SCSI_ASC = 0;
USBD_SCSI_ASCQ = 0;
USBD_DBG_MSC_SCSI_MSG("SCSI Reset");
}
/*
**********************************************************************************************************
* USBD_SCSI_Conn()
*
* Description : Reset eject flag upon new configuration activation.
*
* Argument(s) : p_lun Pointer to Logical Unit information.
*
* Return(s) : None.
*
* Note(s) : None.
**********************************************************************************************************
*/
void USBD_SCSI_Conn (const USBD_MSC_LUN_CTRL *p_lun)
{
USBD_SCSI_LunTbl[p_lun->LunNbr].LockFlag = DEF_FALSE;
USBD_SCSI_LunTbl[p_lun->LunNbr].EjectFlag = DEF_FALSE;
}
/*
**********************************************************************************************************
* USBD_SCSI_Unlock()
*
* Description : Unlock the SCSI Storage Medium.
*
* Argument(s) : p_lun Pointer to Logical Unit information.
*
* p_err Pointer to variable that will receive the return error code from this function :
*
* USBD_ERR_NONE Eject flag successfully reset.
*
* Return(s) : None.
*
* Note(s) : (1) Unlocking a logical unit can be done with a software eject (for instance Windows
* right's click eject). In that case, the unlock operation must not be executed another
* time. If a software eject has occurred, the unlock operation done upon physical
* disconnection of the device must be discarded.
**********************************************************************************************************
*/
void USBD_SCSI_Unlock (const USBD_MSC_LUN_CTRL *p_lun,
USBD_ERR *p_err)
{
USBD_STORAGE_LUN *p_storage_lun;
p_storage_lun = &USBD_SCSI_LunTbl[p_lun->LunNbr];
if (p_storage_lun->EjectFlag == DEF_FALSE) { /* See Note #1. */
USBD_StorageUnlock(p_storage_lun, p_err); /* Unlock logical unit upon physical disconnect. */
p_storage_lun->LockFlag = DEF_FALSE;
} else {
*p_err = USBD_ERR_NONE;
}
}
/*
*********************************************************************************************************
*********************************************************************************************************
* LOCAL FUNCTIONS
*********************************************************************************************************
*********************************************************************************************************
*/
/*
**********************************************************************************************************
* USBD_SCSI_ModeSenseDataPrepare()
*
* Description : Prepare response to be sent to host for the MODE SENSE SCSI command (see Note #1).
*
* Argument(s) : p_lun Pointer to Logical Unit information.
*
* scsi_cmd SCSI command operation code.
*
* page_code Page code.
*
* p_err Pointer to variable that will receive the return error code from this function :
*
* USBD_ERR_NONE, Mode sense data successfully prepared.
* USBD_ERR_SCSI_UNSUPPORTED_CMD Page code not supported.
*
* Return(s) : None.
*
* Note(s) : (1) MODE SENSE allows the host to request information related to the storage media, a
* logical unit or the device itself. The device reports the information through the
* mode parameter list whose general format is:
*
* +--------------------------------------+
* | bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
* | byte |
* ----------------------------------------
* | | Mode parameter header |
* ----------------------------------------
* | | Block descriptor(s) |
* ----------------------------------------
* | |Mode page(s) or vendor specific|
* +--------------------------------------+
*
* See 'SCSI Primary Commands - 3' (SPC), Revision 23, sections 6.11, 6.12 & 7.4 for more
* details.
*
* (2) The Informational Exceptions Control mode page defines the methods used by the device
* to control the reporting and the operations of specific informational exception
* conditions.
* The format of Informational Exceptions Control mode page is specified in
* 'SCSI Primary Commands - 3' (SPC), Revision 23, Section 7.4.11.
*
* (3) The Read-Write Error Recovery mode page specifies the error recovery parameters the
* device shall use during any command that performs a read or write operation to the
* medium.
* The format of Read/Write Error Recovery mode Page is specified in
* 'SCSI Blocks Commands - 3' (SBC-3), Revision 16, Section 6.3.5.
**********************************************************************************************************
*/
static void USBD_SCSI_ModeSenseDataPrepare (const USBD_MSC_LUN_CTRL *p_lun,
CPU_INT08U scsi_cmd,
CPU_INT08U page_code,
USBD_ERR *p_err)
{
CPU_INT08U ix_mode_data_len;
CPU_INT08U ix_medium_type;
CPU_INT08U ix_dev_spec_param;
CPU_INT08U ix_mode_page;
CPU_INT08U ix_nxt_page;
CPU_INT08U mode_param_hdr_len;
/* Index preparation according to MODE SENSE cmd type. */
if(scsi_cmd == USBD_SCSI_CMD_MODE_SENSE_06) {
ix_mode_data_len = 0;
ix_medium_type = 1;
ix_dev_spec_param = 2;
ix_mode_page = 4;
mode_param_hdr_len = USBD_SCSI_MODE_SENSE_DATA_MODE_PARAM_HDR_6_LEN;
} else { /* MODE SENSE(10). */
ix_mode_data_len = 1; /* Mode data len LSB. */
ix_medium_type = 2;
ix_dev_spec_param = 3;
ix_mode_page = 8;
mode_param_hdr_len = USBD_SCSI_MODE_SENSE_DATA_MODE_PARAM_HDR_10_LEN;
}
/* Ensure Mode Sense buf properly reset. */
Mem_Clr((void *)USBD_SCSI_ModeSenseData,
(CPU_SIZE_T)USBD_SCSI_MODE_SENSE_DATA_LEN);
/* ------------------ MODE PARAM HDR ------------------ */
/* Medium type supported by LUN. */
USBD_SCSI_ModeSenseData[ix_medium_type] = USBD_DISK_MEMORY_MEDIA;
/* Indicate if medium is write-protected. */
if (p_lun->LunInfo.ReadOnly) {
USBD_SCSI_ModeSenseData[ix_dev_spec_param] = USBD_SCSI_MODE_SENSE_DATA_SPEC_PARAM_WR_PROT;
} else {
USBD_SCSI_ModeSenseData[ix_dev_spec_param] = USBD_SCSI_MODE_SENSE_DATA_SPEC_PARAM_WR_EN;
}
switch (page_code) {
case USBD_SCSI_PAGE_CODE_INFORMATIONAL_EXCEPTIONS: /* See Note #1. */
/* Mode Data Len. */
USBD_SCSI_ModeSenseData[ix_mode_data_len] = mode_param_hdr_len +
USBD_SCSI_MODE_SENSE_DATA_MODE_PAGE_HDR_LEN +
USBD_SCSI_PAGE_LENGTH_INFORMATIONAL_EXCEPTIONS;
/* --------------- BLK DESC & MODE PAGE --------------- */
USBD_SCSI_PageInfoExcept((void *)&USBD_SCSI_ModeSenseData[ix_mode_page]);
*p_err = USBD_ERR_NONE;
break;
case USBD_SCSI_PAGE_CODE_READ_WRITE_ERROR_RECOVERY: /* See Note #2. */
/* Mode Data Len. */
USBD_SCSI_ModeSenseData[ix_mode_data_len] = mode_param_hdr_len +
USBD_SCSI_MODE_SENSE_DATA_MODE_PAGE_HDR_LEN +
USBD_SCSI_PAGE_LENGTH_READ_WRITE_ERROR_RECOVERY;
/* --------------- BLK DESC & MODE PAGE --------------- */
USBD_SCSI_PageRdWrErrRecovery((void *)&USBD_SCSI_ModeSenseData[ix_mode_page]);
*p_err = USBD_ERR_NONE;
break;
case USBD_SCSI_PAGE_CODE_ALL: /* Page Code: all pages supported by target. */
/* Mode Data Len. */
USBD_SCSI_ModeSenseData[ix_mode_data_len] = mode_param_hdr_len +
USBD_SCSI_MODE_SENSE_DATA_MODE_PAGE_HDR_LEN +
USBD_SCSI_PAGE_LENGTH_READ_WRITE_ERROR_RECOVERY +
USBD_SCSI_MODE_SENSE_DATA_MODE_PAGE_HDR_LEN +
USBD_SCSI_PAGE_LENGTH_INFORMATIONAL_EXCEPTIONS;
/* --------------- BLK DESC & MODE PAGE --------------- */
USBD_SCSI_PageRdWrErrRecovery((void *)&USBD_SCSI_ModeSenseData[ix_mode_page]);
ix_nxt_page = ix_mode_page +
USBD_SCSI_MODE_SENSE_DATA_MODE_PAGE_HDR_LEN +
USBD_SCSI_PAGE_LENGTH_READ_WRITE_ERROR_RECOVERY;
USBD_SCSI_PageInfoExcept((void *)&USBD_SCSI_ModeSenseData[ix_nxt_page]);
*p_err = USBD_ERR_NONE;
break;
default:
*p_err = USBD_ERR_SCSI_UNSUPPORTED_CMD;
break;
}
}
/*
**********************************************************************************************************
* USBD_SCSI_ReqSenseDataUpdate()
*
* Description : Update Request Sense data parameters.
*
* Argument(s) : sense_key Sense key describing an error or exception condition.
*
* sense_code Additional Sense Code describing sense key in detail.
*
* sense_code_qual Additional Sense Code Qualifier which in detail to the ASC.
*
* Return(s) : None.
*
* Note(s) : None.
**********************************************************************************************************
*/
static void USBD_SCSI_ReqSenseDataUpdate (CPU_INT08U sense_key,
CPU_INT08U sense_code,
CPU_INT08U sense_code_qual)
{
USBD_SCSI_SenseKey = sense_key;
USBD_SCSI_ASC = sense_code;
USBD_SCSI_ASCQ = sense_code_qual;
}
/*
**********************************************************************************************************
* USBD_SCSI_InquiryDataPrepare()
*
* Description : Prepare response for INQUIRY SCSI command.
*
* Argument(s) : p_lun Pointer to Logical Unit information.
*
* cmdt_evpd Inform about which type of data to prepare (Command support data or vital
* product data or both or standard inquiry data).
*
* page_code Page code which specifies which page of inquiry data.
*
* p_err Pointer to variable that will receive the return error code from this function :
*
* USBD_ERR_NONE Inquiry data successfully prepared.
* USBD_ERR_SCSI_UNSUPPORTED_CMD Page code not supported or wrong command.
*
* Return(s) : None.
*
* Note(s) : (1) The device reports the information through the inquiry data whose general format is:
*
* +------------------------------------------------------+
* | bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
* | byte | |
* --------------------------------------------------------
* | 0 | Peripheral Qual | Peripheral Device type |
* --------------------------------------------------------
* | 1-7 | Controls and Flags |
* --------------------------------------------------------
* | 8-15 | T10 VENDOR IDENTIFICATION |
* --------------------------------------------------------
* | 16-31| PRODUCT IDENTIFICATION |
* --------------------------------------------------------
* | 32-35| PRODUCT REVISION LEVEL |
* +------------------------------------------------------+
*
* See 'SCSI Primary Commands - 3' (SPC-3), Revision 23, Section 6.4.2, fore more
* details.
**********************************************************************************************************
*/
static void USBD_SCSI_InquiryDataPrepare (const USBD_MSC_LUN_CTRL *p_lun,
CPU_INT08U cmdt_evpd,
CPU_INT08U page_code,
USBD_ERR *p_err)
{
if (cmdt_evpd == USBD_SCSI_STD_INQUIRY_DATA) {
if (page_code == 0) { /* Get target info. */
USBD_SCSI_InquiryData[0] = USBD_SCSI_PER_DEV_TYPE_DIRECT_ACCESS_BLOCK_DEV |
(USBD_SCSI_PER_QUAL_CONN << 5);
/* Indicate medium as removable. */
DEF_BIT_SET(USBD_SCSI_InquiryData[1], USBD_SCSI_INQUIRY_RMB);
/* Vendor ID info. */
Mem_Copy((void *)&USBD_SCSI_InquiryData[8],
(void *)&p_lun->LunInfo.VendorId[0],
sizeof(p_lun->LunInfo.VendorId));
/* Product ID info. */
Mem_Copy((void *)&USBD_SCSI_InquiryData[16],
(void *)&p_lun->LunInfo.ProdId[0],
sizeof(p_lun->LunInfo.ProdId));
/* Product revision level. */
Mem_Copy((void *)&USBD_SCSI_InquiryData[32],
(void *)&p_lun->LunInfo.ProdRevisionLevel,
4u);
*p_err = USBD_ERR_NONE;
} else {
*p_err = USBD_ERR_SCSI_UNSUPPORTED_CMD; /* Page code is not supported. */
}
} else {
*p_err = USBD_ERR_SCSI_UNSUPPORTED_CMD;
}
}
/*
**********************************************************************************************************
* USBD_SCSI_LunStatusAnalyze()
*
* Description : Update Request Sense data parameters corresponding to the error code gotten from logical
* unit.
*
* Argument(s) : err Error code from logical unit.
*
* Return(s) : None.
*
* Note(s) : None.
**********************************************************************************************************
*/
static void USBD_SCSI_LunStatusAnalyze (USBD_ERR err)
{
switch (err) {
case USBD_ERR_NONE:
USBD_SCSI_ReqSenseDataUpdate(USBD_SCSI_SENSE_KEY_NO_SENSE,
USBD_SCSI_ASC_NO_ADDITIONAL_SENSE_INFO,
0x00);
break;
case USBD_ERR_SCSI_MEDIUM_NOTPRESENT: /* Target is not present. */
USBD_SCSI_ReqSenseDataUpdate(USBD_SCSI_SENSE_KEY_NOT_RDY,
USBD_SCSI_ASC_MEDIUM_NOT_PRESENT,
0x00);
break;
case USBD_ERR_SCSI_MEDIUM_NOT_RDY_TO_RDY: /* Target in not rdy to rdy transition. */
USBD_SCSI_ReqSenseDataUpdate(USBD_SCSI_SENSE_KEY_UNIT_ATTENTION,
USBD_SCSI_ASC_NOT_RDY_TO_RDY_CHANGE,
0x00);
break;
case USBD_ERR_SCSI_MEDIUM_RDY_TO_NOT_RDY: /* Target in rdy to not rdy transition. */
USBD_SCSI_ReqSenseDataUpdate(USBD_SCSI_SENSE_KEY_NOT_RDY,
USBD_SCSI_ASC_MEDIUM_NOT_PRESENT,
0x00);
break;
case USBD_ERR_SCSI_LU_NOTRDY: /* LUN is not rdy to perform any operation. */
USBD_SCSI_ReqSenseDataUpdate(USBD_SCSI_SENSE_KEY_NOT_RDY,
USBD_SCSI_ASC_LOG_UNIT_NOT_RDY,
0x00);
break;
case USBD_ERR_SCSI_LU_NOTSUPPORTED: /* LUN is not supported. */
USBD_SCSI_ReqSenseDataUpdate(USBD_SCSI_SENSE_KEY_ILLEGAL_REQUEST,
USBD_SCSI_ASC_LOG_UNIT_NOT_SUPPORTED,
0x00);
break;
case USBD_ERR_SCSI_LU_BUSY: /* LUN is busy. */
USBD_SCSI_ReqSenseDataUpdate(USBD_SCSI_SENSE_KEY_UNIT_ATTENTION,
USBD_SCSI_ASC_NOT_RDY_TO_RDY_CHANGE,
0x00);
break;
default: /* Err is not supported considered as hw err. */
USBD_SCSI_ReqSenseDataUpdate(USBD_SCSI_SENSE_KEY_HARDWARE_ERROR,
USBD_SCSI_ASC_NO_ADDITIONAL_SENSE_INFO,
0x00);
break;
}
}
/*
**********************************************************************************************************
* USBD_SCSI_PageRdWrErrRecovery()
*
* Description : Prepare Mode Sense Data with Read/Write Error Recovery page parameters.
*
* Argument(s) : p_buf_dest Pointer to buffer that will hold Mode sense data.
*
* Return(s) : None.
*
* Note(s) : (1) The format of Read/Write Error Recovery mode Page is specified in
* 'SCSI Blocks Commands - 3' (SBC-3), Revision 16, Section 6.3.5.
**********************************************************************************************************
*/
static void USBD_SCSI_PageRdWrErrRecovery (void *p_buf_dest)
{
CPU_INT08U *p_buf_dest_08;
p_buf_dest_08 = (CPU_INT08U *)p_buf_dest;
p_buf_dest_08[0] = USBD_SCSI_PAGE_CODE_READ_WRITE_ERROR_RECOVERY; /* Page Code: rd/wr err recovery page. */
p_buf_dest_08[1] = USBD_SCSI_PAGE_LENGTH_READ_WRITE_ERROR_RECOVERY; /* Page Length: rd/wr err recovery page. */
p_buf_dest_08[2] = USBD_SCSI_MODE_SENSE_DATA_AWRE; /* Enable AWRE. */
p_buf_dest_08[3] = USBD_SCSI_MODE_SENSE_DATA_RD_RETRY_CNT; /* Recovery algorithm attempts during rd ops. */
p_buf_dest_08[4] = USBD_SCSI_MODE_SENSE_DATA_CORRECTION_SPAN; /* Obsolete. */
p_buf_dest_08[5] = USBD_SCSI_MODE_SENSE_DATA_HEAD_OFFSET_CNT; /* Obsolete. */
p_buf_dest_08[6] = USBD_SCSI_MODE_SENSE_DATA_DATA_STROBE_OFFSET; /* Obsolete. */
p_buf_dest_08[7] = 0x00; /* Reserved. */
p_buf_dest_08[8] = USBD_SCSI_MODE_SENSE_DATA_WR_RETRY_CNT; /* Recovery algorithm attempts during wr ops. */
p_buf_dest_08[9] = 0x00; /* Reserved. */
/* Err recovery time. */
MEM_VAL_SET_INT16U_BIG(p_buf_dest_08 + 10, USBD_SCSI_MODE_SENSE_DATA_RECOVERY_LIMIT);
}
/*
**********************************************************************************************************
* USBD_SCSI_PageInfoExcept()
*
* Description : Prepare Mode Sense Data with Informational Exceptions Control Page parameters.
*
* Argument(s) : p_buf_dest Pointer to buffer that will hold Mode sense data.
*
* Return(s) : None.
*
* Note(s) : (1) The format of Informational Exceptions Control mode page is specified in
* 'SCSI Primary Commands - 3' (SPC), Revision 23, Section 7.4.11.
**********************************************************************************************************
*/
static void USBD_SCSI_PageInfoExcept (void *p_buf_dest)
{
CPU_INT08U *p_buf_dest_08;
p_buf_dest_08 = (CPU_INT08U *)p_buf_dest;
p_buf_dest_08[0] = USBD_SCSI_PAGE_CODE_INFORMATIONAL_EXCEPTIONS;
p_buf_dest_08[1] = USBD_SCSI_PAGE_LENGTH_INFORMATIONAL_EXCEPTIONS;
p_buf_dest_08[2] = 0u;
p_buf_dest_08[3] = USBD_SCSI_MODE_SENSE_DATA_MRIE_NO_SENSE;/* Method of reporting info exceptions field. */
MEM_VAL_SET_INT32U_BIG(p_buf_dest_08 + 4, 0u); /* Interval Timer. */
MEM_VAL_SET_INT32U_BIG(p_buf_dest_08 + 8, 1u); /* Report Count. */
}