diff --git a/examples/device/cdc_msc/src/msc_disk.c b/examples/device/cdc_msc/src/msc_disk.c index 3076192a..e67e381c 100644 --- a/examples/device/cdc_msc/src/msc_disk.c +++ b/examples/device/cdc_msc/src/msc_disk.c @@ -243,11 +243,6 @@ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, switch (scsi_cmd[0]) { - case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: - // Host is about to read/write etc ... better not to disconnect disk - resplen = 0; - break; - default: // Set Sense = Invalid Command Operation tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); diff --git a/examples/device/cdc_msc_freertos/src/msc_disk.c b/examples/device/cdc_msc_freertos/src/msc_disk.c index b9205f0c..a895f473 100644 --- a/examples/device/cdc_msc_freertos/src/msc_disk.c +++ b/examples/device/cdc_msc_freertos/src/msc_disk.c @@ -221,11 +221,6 @@ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, switch (scsi_cmd[0]) { - case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: - // Host is about to read/write etc ... better not to disconnect disk - resplen = 0; - break; - default: // Set Sense = Invalid Command Operation tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); diff --git a/examples/device/dynamic_configuration/src/msc_disk.c b/examples/device/dynamic_configuration/src/msc_disk.c index b9205f0c..a895f473 100644 --- a/examples/device/dynamic_configuration/src/msc_disk.c +++ b/examples/device/dynamic_configuration/src/msc_disk.c @@ -221,11 +221,6 @@ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, switch (scsi_cmd[0]) { - case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: - // Host is about to read/write etc ... better not to disconnect disk - resplen = 0; - break; - default: // Set Sense = Invalid Command Operation tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); diff --git a/examples/device/msc_dual_lun/src/msc_disk_dual.c b/examples/device/msc_dual_lun/src/msc_disk_dual.c index 18d3ca0d..37446ebc 100644 --- a/examples/device/msc_dual_lun/src/msc_disk_dual.c +++ b/examples/device/msc_dual_lun/src/msc_disk_dual.c @@ -28,6 +28,9 @@ #if CFG_TUD_MSC +// When button is pressed, LUN1 will be set to not ready to simulate +// medium not present (e.g SD card removed) + // Some MCU doesn't have enough 8KB SRAM to store the whole disk // We will use Flash as read-only disk with board that has // CFG_EXAMPLE_MSC_READONLY defined @@ -227,7 +230,7 @@ void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16 // return true allowing host to read/write this LUN e.g SD card inserted bool tud_msc_test_unit_ready_cb(uint8_t lun) { - (void) lun; + if ( lun == 1 && board_button_read() ) return false; return true; // RAM disk is always ready } @@ -320,23 +323,6 @@ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, switch (scsi_cmd[0]) { - case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: - // Host is about to read/write etc ... better not to disconnect disk - resplen = 0; - break; - - case SCSI_CMD_START_STOP_UNIT: - // Host try to eject/safe remove/poweroff us. We could safely disconnect with disk storage, or go into lower power - /* scsi_start_stop_unit_t const * start_stop = (scsi_start_stop_unit_t const *) scsi_cmd; - // Start bit = 0 : low power mode, if load_eject = 1 : unmount disk storage as well - // Start bit = 1 : Ready mode, if load_eject = 1 : mount disk storage - start_stop->start; - start_stop->load_eject; - */ - resplen = 0; - break; - - default: // Set Sense = Invalid Command Operation tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c index 97837b11..e09a2b11 100644 --- a/src/class/msc/msc_device.c +++ b/src/class/msc/msc_device.c @@ -209,7 +209,7 @@ TU_ATTR_UNUSED static tu_lookup_entry_t const _msc_scsi_cmd_lookup[] = { .key = SCSI_CMD_MODE_SELECT_6 , .data = "Mode_Select 6" }, { .key = SCSI_CMD_MODE_SENSE_6 , .data = "Mode_Sense 6" }, { .key = SCSI_CMD_START_STOP_UNIT , .data = "Start Stop Unit" }, - { .key = SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL , .data = "Prevent Allow Medium Removal" }, + { .key = SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL , .data = "Prevent/Allow Medium Removal" }, { .key = SCSI_CMD_READ_CAPACITY_10 , .data = "Read Capacity10" }, { .key = SCSI_CMD_REQUEST_SENSE , .data = "Request Sense" }, { .key = SCSI_CMD_READ_FORMAT_CAPACITY , .data = "Read Format Capacity" }, @@ -239,6 +239,12 @@ bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, u return true; } +static inline void set_sense_medium_not_present(uint8_t lun) +{ + // default sense is NOT READY, MEDIUM NOT PRESENT + tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3A, 0x00); +} + //--------------------------------------------------------------------+ // USBD Driver API //--------------------------------------------------------------------+ @@ -406,7 +412,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t return false; } - TU_LOG(MSC_DEBUG, " SCSI Command: %s\r\n", tu_lookup_find(&_msc_scsi_cmd_table, p_cbw->command[0])); + TU_LOG(MSC_DEBUG, " SCSI Command [Lun%u]: %s\r\n", p_cbw->lun, tu_lookup_find(&_msc_scsi_cmd_table, p_cbw->command[0])); //TU_LOG_MEM(MSC_DEBUG, p_cbw, xferred_bytes, 2); p_csw->signature = MSC_CSW_SIGNATURE; @@ -473,7 +479,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t if ( resplen < 0 ) { // unsupported command - TU_LOG(MSC_DEBUG, " SCSI unsupported command\r\n"); + TU_LOG(MSC_DEBUG, " SCSI unsupported or failed command\r\n"); fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); } else if (resplen == 0) @@ -508,7 +514,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t break; case MSC_STAGE_DATA: - TU_LOG(MSC_DEBUG, " SCSI Data\r\n"); + TU_LOG(MSC_DEBUG, " SCSI Data [Lun%u]\r\n", p_cbw->lun); //TU_LOG_MEM(MSC_DEBUG, _mscd_buf, xferred_bytes, 2); if (SCSI_CMD_READ_10 == p_cbw->command[0]) @@ -569,7 +575,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t // Wait for the Status phase to complete if( (ep_addr == p_msc->ep_in) && (xferred_bytes == sizeof(msc_csw_t)) ) { - TU_LOG(MSC_DEBUG, " SCSI Status = %u\r\n", p_csw->status); + TU_LOG(MSC_DEBUG, " SCSI Status [Lun%u] = %u\r\n", p_cbw->lun, p_csw->status); // TU_LOG_MEM(MSC_DEBUG, p_csw, xferred_bytes, 2); // Invoke complete callback if defined @@ -654,8 +660,8 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ // Failed status response resplen = - 1; - // If sense key is not set by callback, default to Logical Unit Not Ready, Cause Not Reportable - if ( p_msc->sense_key == 0 ) tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x04, 0x00); + // set default sense if not set by callback + if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun); } break; @@ -670,8 +676,8 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ // Failed status response resplen = - 1; - // If sense key is not set by callback, default to Logical Unit Not Ready, Cause Not Reportable - if ( p_msc->sense_key == 0 ) tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x04, 0x00); + // set default sense if not set by callback + if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun); } } break; @@ -691,13 +697,13 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ { resplen = -1; - // If sense key is not set by callback, default to Logical Unit Not Ready, Cause Not Reportable - if ( p_msc->sense_key == 0 ) tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x04, 0x00); + // set default sense if not set by callback + if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun); }else { scsi_read_capacity10_resp_t read_capa10; - read_capa10.last_lba = tu_htonl(block_count-1); + read_capa10.last_lba = tu_htonl(block_count-1); read_capa10.block_size = tu_htonl(block_size); resplen = sizeof(read_capa10); @@ -727,8 +733,8 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ { resplen = -1; - // If sense key is not set by callback, default to Logical Unit Not Ready, Cause Not Reportable - if ( p_msc->sense_key == 0 ) tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x04, 0x00); + // set default sense if not set by callback + if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun); }else { read_fmt_capa.block_num = tu_htonl(block_count); @@ -765,10 +771,10 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ { scsi_mode_sense6_resp_t mode_resp = { - .data_len = 3, - .medium_type = 0, - .write_protected = false, - .reserved = 0, + .data_len = 3, + .medium_type = 0, + .write_protected = false, + .reserved = 0, .block_descriptor_len = 0 // no block descriptor are included }; @@ -789,12 +795,11 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ { scsi_sense_fixed_resp_t sense_rsp = { - .response_code = 0x70, + .response_code = 0x70, // current, fixed format .valid = 1 }; - sense_rsp.add_sense_len = sizeof(scsi_sense_fixed_resp_t) - 8; - + sense_rsp.add_sense_len = sizeof(scsi_sense_fixed_resp_t) - 8; sense_rsp.sense_key = p_msc->sense_key; sense_rsp.add_sense_code = p_msc->add_sense_code; sense_rsp.add_sense_qualifier = p_msc->add_sense_qualifier; @@ -802,6 +807,12 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ resplen = sizeof(sense_rsp); memcpy(buffer, &sense_rsp, resplen); + // request sense callback could overwrite the sense data + if (tud_msc_request_sense_cb) + { + resplen = tud_msc_request_sense_cb(lun, buffer, bufsize); + } + // Clear sense data after copy tud_msc_set_sense(lun, 0, 0, 0); } @@ -835,8 +846,8 @@ static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc) // negative means error -> endpoint is stalled & status in CSW set to failed TU_LOG(MSC_DEBUG, " tud_msc_read10_cb() return -1\r\n"); - // Sense = Flash not ready for access - tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_MEDIUM_ERROR, 0x33, 0x00); + // set sense + set_sense_medium_not_present(p_cbw->lun); fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); } @@ -900,8 +911,8 @@ static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint3 // update actual byte before failed p_msc->xferred_len += xferred_bytes; - // Sense = Flash not ready for access - tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_MEDIUM_ERROR, 0x33, 0x00); + // Set sense + set_sense_medium_not_present(p_cbw->lun); fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); }else diff --git a/src/class/msc/msc_device.h b/src/class/msc/msc_device.h index d3269434..5839b168 100644 --- a/src/class/msc/msc_device.h +++ b/src/class/msc/msc_device.h @@ -131,6 +131,9 @@ TU_ATTR_WEAK uint8_t tud_msc_get_maxlun_cb(void); // - Start = 1 : active mode, if load_eject = 1 : load disk storage TU_ATTR_WEAK bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject); +// Invoked when received REQUEST_SENSE +TU_ATTR_WEAK int32_t tud_msc_request_sense_cb(uint8_t lun, void* buffer, uint16_t bufsize); + // Invoked when Read10 command is complete TU_ATTR_WEAK void tud_msc_read10_complete_cb(uint8_t lun);