blob: ca3a37538dc91126c0f135185b7a53058cc85682 [file] [log] [blame]
// Copyright 2025 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fidl/fuchsia.hardware.ufs/cpp/common_types.h>
#include <fidl/fuchsia.hardware.ufs/cpp/markers.h>
#include <fidl/fuchsia.hardware.ufs/cpp/natural_types.h>
#include <fidl/fuchsia.hardware.ufs/cpp/wire_types.h>
#include <lib/fidl/cpp/wire/channel.h>
#include <lib/fidl/cpp/wire/vector_view.h>
#include <lib/fidl/cpp/wire/wire_types.h>
#include <lib/fzl/owned-vmo-mapper.h>
#include <zircon/errors.h>
#include <cstdint>
#include <gtest/gtest.h>
#include "src/devices/block/drivers/ufs/device_manager.h"
#include "src/devices/block/drivers/ufs/upiu/attributes.h"
#include "src/devices/block/drivers/ufs/upiu/descriptors.h"
#include "src/devices/block/drivers/ufs/upiu/upiu_transactions.h"
#include "unit-lib.h"
namespace ufs {
using namespace ufs_mock_device;
class ServerTest : public UfsTest {
public:
fidl::ClientEnd<fuchsia_hardware_ufs::Ufs> GetClient() {
zx::result device = driver_test().Connect<fuchsia_hardware_ufs::Service::Device>();
EXPECT_EQ(ZX_OK, device.status_value());
return std::move(device.value());
}
fdf::Arena arena_{'test'};
};
TEST_F(ServerTest, ReadDescriptor) {
zx::result result = driver_test().RunOnBackgroundDispatcherSync(
[client_end = GetClient(), &mock_device = mock_device_]() {
fidl::Arena arena;
auto desc = fuchsia_hardware_ufs::wire::Descriptor::Builder(arena)
.type(fuchsia_hardware_ufs::DescriptorType::kDevice)
.Build();
const fidl::WireResult result = fidl::WireCall(client_end)->ReadDescriptor(desc);
ASSERT_TRUE(result.ok());
const fit::result response = result.value();
ASSERT_TRUE(response.is_ok());
DeviceDescriptor descriptor;
std::memset(&descriptor, 0, sizeof(DeviceDescriptor));
auto response_data = response->data;
std::memcpy(&descriptor, response_data.data(), sizeof(DeviceDescriptor));
auto mock_desc = mock_device.GetDeviceDesc();
ASSERT_EQ(descriptor.bLength, mock_desc.bLength);
ASSERT_EQ(descriptor.bDescriptorIDN, mock_desc.bDescriptorIDN);
ASSERT_EQ(descriptor.bDeviceSubClass, mock_desc.bDeviceSubClass);
ASSERT_EQ(descriptor.bNumberWLU, mock_desc.bNumberWLU);
ASSERT_EQ(descriptor.bInitPowerMode, mock_desc.bInitPowerMode);
ASSERT_EQ(descriptor.bHighPriorityLUN, mock_desc.bHighPriorityLUN);
ASSERT_EQ(descriptor.wSpecVersion, mock_desc.wSpecVersion);
ASSERT_EQ(descriptor.bUD0BaseOffset, mock_desc.bUD0BaseOffset);
ASSERT_EQ(descriptor.bUDConfigPLength, mock_desc.bUDConfigPLength);
});
ASSERT_OK(result.status_value());
}
TEST_F(ServerTest, WriteDescriptor) {
zx::result result = driver_test().RunOnBackgroundDispatcherSync(
[client_end = GetClient(), &mock_device = mock_device_]() {
// 0x7F: Same priority for all LUNs
// If all LUNs already have the same priority, change the priority of LUN0 higher
// If specific LUN has higher priority, change to the same priority for all LUNs
const uint8_t kLunPrioritySameForAll = 0x7F;
uint8_t high_priority_lun =
mock_device.GetDeviceDesc().bHighPriorityLUN == kLunPrioritySameForAll
? 0
: kLunPrioritySameForAll;
ConfigurationDescriptor descriptor;
std::memset(&descriptor, 0, sizeof(ConfigurationDescriptor));
descriptor.bLength = 0xE6;
descriptor.bDescriptorIDN = 0x01;
descriptor.bConfDescContinue = 0x00;
descriptor.bHighPriorityLUN = high_priority_lun;
fidl::Arena arena;
auto desc = fuchsia_hardware_ufs::wire::Descriptor::Builder(arena)
.type(fuchsia_hardware_ufs::DescriptorType::kConfiguration)
.Build();
std::vector<uint8_t> data_segment(sizeof(ConfigurationDescriptor));
std::memcpy(data_segment.data(), &descriptor, sizeof(ConfigurationDescriptor));
const fidl::WireResult result =
fidl::WireCall(client_end)
->WriteDescriptor(desc, fidl::VectorView<uint8_t>(arena, data_segment));
ASSERT_TRUE(result.ok());
const fit::result response = result.value();
ASSERT_TRUE(response.is_ok());
ASSERT_EQ(high_priority_lun, mock_device.GetDeviceDesc().bHighPriorityLUN);
});
ASSERT_OK(result.status_value());
}
TEST_F(ServerTest, ReadFlag) {
bool device_init = false;
mock_device_.SetFlag(Flags::fDeviceInit, device_init);
auto result = driver_test().RunOnBackgroundDispatcherSync(
[client_end = GetClient(), &mock_device = mock_device_]() {
fidl::Arena arena;
auto flag = fuchsia_hardware_ufs::wire::Flag::Builder(arena)
.type(fuchsia_hardware_ufs::FlagType::kDeviceInit)
.Build();
const fidl::WireResult result = fidl::WireCall(client_end)->ReadFlag(flag);
ASSERT_TRUE(result.ok());
const fit::result response = result.value();
ASSERT_TRUE(response.is_ok());
ASSERT_EQ(response->value, mock_device.GetFlag(Flags::fDeviceInit));
});
ASSERT_OK(result.status_value());
}
TEST_F(ServerTest, SetFlag) {
bool refresh_enable = false;
mock_device_.SetFlag(Flags::fRefreshEnable, refresh_enable);
zx::result result = driver_test().RunOnBackgroundDispatcherSync(
[client_end = GetClient(), &mock_device = mock_device_]() {
fidl::Arena arena;
auto flag = fuchsia_hardware_ufs::wire::Flag::Builder(arena)
.type(fuchsia_hardware_ufs::FlagType::kRefreshEnable)
.Build();
const fidl::WireResult result = fidl::WireCall(client_end)->SetFlag(flag);
ASSERT_TRUE(result.ok());
const fit::result response = result.value();
ASSERT_TRUE(response.is_ok());
ASSERT_TRUE(response->value);
ASSERT_EQ(response->value, mock_device.GetFlag(Flags::fRefreshEnable));
});
ASSERT_OK(result.status_value());
}
TEST_F(ServerTest, ToggleFlag) {
bool refresh_enable = true;
mock_device_.SetFlag(Flags::fRefreshEnable, refresh_enable);
zx::result result = driver_test().RunOnBackgroundDispatcherSync(
[client_end = GetClient(), &mock_device = mock_device_]() {
fidl::Arena arena;
auto flag = fuchsia_hardware_ufs::wire::Flag::Builder(arena)
.type(fuchsia_hardware_ufs::FlagType::kRefreshEnable)
.Build();
const fidl::WireResult result = fidl::WireCall(client_end)->ToggleFlag(flag);
ASSERT_TRUE(result.ok());
const fit::result response = result.value();
ASSERT_TRUE(response.is_ok());
ASSERT_FALSE(response->value);
ASSERT_EQ(response->value, mock_device.GetFlag(Flags::fRefreshEnable));
});
ASSERT_OK(result.status_value());
}
TEST_F(ServerTest, ClearFlag) {
bool refresh_enable = true;
mock_device_.SetFlag(Flags::fRefreshEnable, refresh_enable);
zx::result result = driver_test().RunOnBackgroundDispatcherSync(
[client_end = GetClient(), &mock_device = mock_device_]() {
fidl::Arena arena;
auto flag = fuchsia_hardware_ufs::wire::Flag::Builder(arena)
.type(fuchsia_hardware_ufs::FlagType::kRefreshEnable)
.Build();
const fidl::WireResult result = fidl::WireCall(client_end)->ClearFlag(flag);
ASSERT_TRUE(result.ok());
const fit::result response = result.value();
ASSERT_TRUE(response.is_ok());
ASSERT_FALSE(response->value);
ASSERT_EQ(response->value, mock_device.GetFlag(Flags::fRefreshEnable));
});
ASSERT_OK(result.status_value());
}
TEST_F(ServerTest, ReadAttribute) {
mock_device_.SetAttribute(Attributes::bCurrentPowerMode,
static_cast<uint32_t>(UfsPowerMode::kActive));
zx::result result = driver_test().RunOnBackgroundDispatcherSync(
[client_end = GetClient(), &mock_device = mock_device_]() {
fidl::Arena arena;
auto attr = fuchsia_hardware_ufs::wire::Attribute::Builder(arena)
.type(fuchsia_hardware_ufs::AttributeType::kCurrentPowerMode)
.Build();
const fidl::WireResult result = fidl::WireCall(client_end)->ReadAttribute(attr);
ASSERT_TRUE(result.ok());
const fit::result response = result.value();
ASSERT_TRUE(response.is_ok());
ASSERT_EQ(response->value, mock_device.GetAttribute(Attributes::bCurrentPowerMode));
});
ASSERT_OK(result.status_value());
}
TEST_F(ServerTest, WriteAttribute) {
zx::result result = driver_test().RunOnBackgroundDispatcherSync([client_end = GetClient(),
&mock_device = mock_device_]() {
fidl::Arena arena;
auto attr = fuchsia_hardware_ufs::wire::Attribute::Builder(arena)
.type(fuchsia_hardware_ufs::AttributeType::kConfigDescrLock)
.Build();
uint32_t changed_value = 0x01;
const fidl::WireResult result = fidl::WireCall(client_end)->WriteAttribute(attr, changed_value);
ASSERT_TRUE(result.ok());
const fit::result response = result.value();
ASSERT_TRUE(response.is_ok());
ASSERT_EQ(changed_value, mock_device.GetAttribute(Attributes::bConfigDescrLock));
});
ASSERT_OK(result.status_value());
}
TEST_F(ServerTest, UicCommandDmeGet) {
zx::result result = driver_test().RunOnBackgroundDispatcherSync([client_end = GetClient()]() {
auto uic_arg_mib_sel = [](uint16_t attr, uint16_t sel) {
return (((attr) & 0xFFFF) << 16) | ((sel) & 0xFFFF);
};
fidl::Array<uint32_t, fuchsia_hardware_ufs::kUicCommandArgumentCount> args;
args[0] = uic_arg_mib_sel(PA_MaxRxHSGear, 0);
const fidl::WireResult result =
fidl::WireCall(client_end)
->SendUicCommand(fuchsia_hardware_ufs::UicCommandOpcode::kDmeGet, args);
ASSERT_TRUE(result.ok());
const fit::result response = result.value();
ASSERT_TRUE(response.is_ok());
ASSERT_EQ(response->result, ufs_mock_device::kMaxGear);
});
ASSERT_OK(result.status_value());
}
TEST_F(ServerTest, UicCommandDmeSet) {
zx::result result = driver_test().RunOnBackgroundDispatcherSync([client_end = GetClient()]() {
auto uic_arg_mib_sel = [](uint16_t attr, uint16_t sel) {
return (((attr) & 0xFFFF) << 16) | ((sel) & 0xFFFF);
};
fidl::Array<uint32_t, fuchsia_hardware_ufs::kUicCommandArgumentCount> args;
args[0] = uic_arg_mib_sel(PA_MaxRxHSGear, 0);
const fidl::WireResult result =
fidl::WireCall(client_end)
->SendUicCommand(fuchsia_hardware_ufs::UicCommandOpcode::kDmeSet, args);
ASSERT_TRUE(result.ok());
const fit::result response = result.value();
ASSERT_TRUE(response.is_ok());
ASSERT_EQ(response->result, 0U);
});
ASSERT_OK(result.status_value());
}
TEST_F(ServerTest, UicCommandDmePeerGet) {
zx::result result = driver_test().RunOnBackgroundDispatcherSync([client_end = GetClient()]() {
auto uic_arg_mib_sel = [](uint16_t attr, uint16_t sel) {
return (((attr) & 0xFFFF) << 16) | ((sel) & 0xFFFF);
};
fidl::Array<uint32_t, fuchsia_hardware_ufs::kUicCommandArgumentCount> args;
args[0] = uic_arg_mib_sel(PA_TActivate, 0);
const fidl::WireResult result =
fidl::WireCall(client_end)
->SendUicCommand(fuchsia_hardware_ufs::UicCommandOpcode::kDmePeerGet, args);
ASSERT_TRUE(result.ok());
const fit::result response = result.value();
ASSERT_TRUE(response.is_ok());
ASSERT_EQ(response->result, ufs_mock_device::kTActivate);
});
ASSERT_OK(result.status_value());
}
TEST_F(ServerTest, UicCommandDmePeerSet) {
zx::result result = driver_test().RunOnBackgroundDispatcherSync([client_end = GetClient()]() {
auto uic_arg_mib_sel = [](uint16_t attr, uint16_t sel) {
return (((attr) & 0xFFFF) << 16) | ((sel) & 0xFFFF);
};
fidl::Array<uint32_t, fuchsia_hardware_ufs::kUicCommandArgumentCount> args;
args[0] = uic_arg_mib_sel(PA_TActivate, 0);
const fidl::WireResult result =
fidl::WireCall(client_end)
->SendUicCommand(fuchsia_hardware_ufs::UicCommandOpcode::kDmePeerSet, args);
ASSERT_TRUE(result.ok());
const fit::result response = result.value();
ASSERT_TRUE(response.is_ok());
ASSERT_EQ(response->result, 0U);
});
ASSERT_OK(result.status_value());
}
TEST_F(ServerTest, RequestQueryUpiu) {
uint8_t power_mode = static_cast<uint8_t>(UfsPowerMode::kActive);
mock_device_.SetAttribute(Attributes::bCurrentPowerMode, power_mode);
zx::result result = driver_test().RunOnBackgroundDispatcherSync(
[client_end = GetClient(), &mock_device = mock_device_, &arena = arena_]() {
// Prepare the request upiu
QueryRequestUpiuData request_upiu;
request_upiu.header.trans_type = UpiuTransactionCodes::kQueryRequest;
request_upiu.header.function = static_cast<uint8_t>(QueryFunction::kStandardReadRequest);
request_upiu.opcode = static_cast<uint8_t>(QueryOpcode::kReadAttribute);
request_upiu.idn = 0x2;
// Copy the data into a vector for FIDL transmission
std::vector<uint8_t> upiu_vector(sizeof(QueryRequestUpiuData));
std::memcpy(upiu_vector.data(), &request_upiu, sizeof(QueryRequestUpiuData));
fidl::VectorView<uint8_t> upiu{arena, upiu_vector};
// Send the request
auto response = fidl::WireCall(client_end)->Request(upiu);
ASSERT_TRUE(response.ok());
ASSERT_TRUE(response->is_ok());
// Check response data
auto response_data = response.value()->response;
QueryResponseUpiuData response_upiu;
std::memcpy(&response_upiu, response_data.data(), sizeof(QueryResponseUpiuData));
// Validate the response
ASSERT_EQ(response_upiu.header.trans_type, UpiuTransactionCodes::kQueryResponse);
ASSERT_EQ(response_upiu.header.function,
static_cast<uint8_t>(QueryFunction::kStandardReadRequest));
ASSERT_EQ(response_upiu.header.response, UpiuHeaderResponseCode::kTargetSuccess);
ASSERT_EQ(response_upiu.opcode, static_cast<uint8_t>(QueryOpcode::kReadAttribute));
ASSERT_EQ(response_upiu.idn, static_cast<uint8_t>(Attributes::bCurrentPowerMode));
ASSERT_EQ(betoh32(response_upiu.value),
mock_device.GetAttribute(Attributes::bCurrentPowerMode));
});
ASSERT_OK(result.status_value());
}
TEST_F(ServerTest, ReadDescriptorWithInvalidIdn) {
zx::result result = driver_test().RunOnBackgroundDispatcherSync([client_end = GetClient()]() {
// Checks if an error occurs when the request type is missing.
fidl::Arena arena;
auto desc = fuchsia_hardware_ufs::wire::Descriptor::Builder(arena).Build();
const fidl::WireResult result = fidl::WireCall(client_end)->ReadDescriptor(desc);
ASSERT_TRUE(result.ok());
const fit::result response = result.value();
ASSERT_TRUE(response.is_error());
ASSERT_EQ(response.error_value(), fuchsia_hardware_ufs::QueryErrorCode::kInvalidIdn);
});
ASSERT_OK(result.status_value());
}
TEST_F(ServerTest, RequestInternalFail) {
// Reserve admin slot.
ASSERT_OK(ReserveAdminSlot());
zx::result result = driver_test().RunOnBackgroundDispatcherSync([client_end = GetClient()]() {
fidl::Arena arena;
auto attr = fuchsia_hardware_ufs::wire::Attribute::Builder(arena)
.type(fuchsia_hardware_ufs::AttributeType::kCurrentPowerMode)
.Build();
const fidl::WireResult result = fidl::WireCall(client_end)->ReadAttribute(attr);
ASSERT_TRUE(result.ok());
const fit::result response = result.value();
ASSERT_TRUE(response.is_error());
ASSERT_EQ(response.error_value(), fuchsia_hardware_ufs::QueryErrorCode::kGeneralFailure);
});
ASSERT_OK(result.status_value());
}
TEST_F(ServerTest, RequestNotSupportedTransaction) {
zx::result result =
driver_test().RunOnBackgroundDispatcherSync([client_end = GetClient(), &arena = arena_]() {
// Prepare the request upiu
QueryRequestUpiuData request_upiu;
request_upiu.header.trans_type = UpiuTransactionCodes::kRejectUpiu;
// Copy the data into a vector for FIDL transmission
std::vector<uint8_t> upiu_vector(sizeof(QueryRequestUpiuData));
std::memcpy(upiu_vector.data(), &request_upiu, sizeof(QueryRequestUpiuData));
fidl::VectorView<uint8_t> upiu{arena, upiu_vector};
// Send the request
const fidl::WireResult result = fidl::WireCall(client_end)->Request(upiu);
ASSERT_TRUE(result.ok());
const fit::result response = result.value();
ASSERT_TRUE(response.is_error());
ASSERT_EQ(response.error_value(), ZX_ERR_NOT_SUPPORTED);
});
ASSERT_OK(result.status_value());
}
TEST_F(ServerTest, RequestWrongUpiuData) {
zx::result result =
driver_test().RunOnBackgroundDispatcherSync([client_end = GetClient(), &arena = arena_]() {
// Prepare the request upiu
CommandUpiuData request_upiu;
request_upiu.header.trans_type = UpiuTransactionCodes::kQueryRequest;
request_upiu.header.function = static_cast<uint8_t>(QueryFunction::kStandardReadRequest);
// Copy the data into a vector for FIDL transmission
std::vector<uint8_t> upiu_vector(sizeof(CommandUpiuData));
std::memcpy(upiu_vector.data(), &request_upiu, sizeof(CommandUpiuData));
fidl::VectorView<uint8_t> upiu{arena, upiu_vector};
// Send the request
const fidl::WireResult result = fidl::WireCall(client_end)->Request(upiu);
ASSERT_TRUE(result.ok());
const fit::result response = result.value();
ASSERT_TRUE(response.is_error());
ASSERT_EQ(response.error_value(), ZX_ERR_INVALID_ARGS);
});
ASSERT_OK(result.status_value());
}
TEST_F(ServerTest, SendUicCommandWithUnsupportedOpcode) {
zx::result result = driver_test().RunOnBackgroundDispatcherSync([client_end = GetClient()]() {
fidl::Array<uint32_t, fuchsia_hardware_ufs::kUicCommandArgumentCount> args{0};
const fidl::WireResult result =
fidl::WireCall(client_end)
->SendUicCommand(fuchsia_hardware_ufs::UicCommandOpcode::kDmeHiberEnter, args);
ASSERT_TRUE(result.ok());
const fit::result response = result.value();
ASSERT_TRUE(response.is_error());
ASSERT_EQ(response.error_value(), ZX_ERR_NOT_SUPPORTED);
});
ASSERT_OK(result.status_value());
}
TEST_F(ServerTest, ReadBuffer) {
const uint8_t kTestLun = 0;
uint32_t offset = 0;
// Write test data to the mock device buffer
char buf[kMockBlockSize];
std::memset(buf, 0xf0, sizeof(buf));
mock_device_.WriteToDeviceBuffer(kTestLun, buf, offset, sizeof(buf));
zx::result result = driver_test().RunOnBackgroundDispatcherSync(
[client_end = GetClient(), &mock_device = mock_device_]() {
uint32_t buffer_offset = 1024;
uint32_t length = 256;
fzl::OwnedVmoMapper mapper;
ASSERT_OK(mapper.CreateAndMap(zx_system_get_page_size(), "read-buffer-test-vmo"));
zx::vmo dup;
ASSERT_OK(mapper.vmo().duplicate(ZX_RIGHT_SAME_RIGHTS, &dup));
const fidl::WireResult result =
fidl::WireCall(client_end)
->ReadBuffer(0, fuchsia_hardware_scsi::wire::ReadBufferMode::kData, 0,
buffer_offset, length, std::move(dup));
ASSERT_TRUE(result.ok());
const fit::result response = result.value();
ASSERT_TRUE(response.is_ok());
// Reads data from mock_device and compares it to the mapper.
char buf[kMockBlockSize];
mock_device.ReadFromDeviceBuffer(0, buf, buffer_offset, length);
ASSERT_EQ(memcmp(mapper.start(), buf, length), 0);
});
ASSERT_OK(result.status_value());
}
TEST_F(ServerTest, WriteBuffer) {
zx::result result = driver_test().RunOnBackgroundDispatcherSync(
[client_end = GetClient(), &mock_device = mock_device_]() {
uint32_t buffer_offset = 0;
uint32_t length = 1024;
zx::vmo vmo;
ASSERT_OK(zx::vmo::create(zx_system_get_page_size(), 0, &vmo));
char write_buf[kMockBlockSize];
std::memset(write_buf, 0xf0, sizeof(write_buf));
vmo.write(&write_buf, 0, length);
const fidl::WireResult result =
fidl::WireCall(client_end)
->WriteBuffer(0, fuchsia_hardware_scsi::wire::WriteBufferMode::kData, 0,
buffer_offset, length, std::move(vmo));
ASSERT_TRUE(result.ok());
const fit::result response = result.value();
ASSERT_TRUE(response.is_ok());
char buf[kMockBlockSize];
mock_device.ReadFromDeviceBuffer(0, buf, buffer_offset, length);
ASSERT_EQ(memcmp(&write_buf, buf, length), 0);
});
ASSERT_OK(result.status_value());
}
TEST_F(ServerTest, ReadWirteBufferOutOfRange) {
const uint8_t kTestLun = 0;
uint32_t offset = 0;
// Write test data to the mock device buffer
char buf[kMockBlockSize];
std::memset(buf, 0xf0, sizeof(buf));
mock_device_.WriteToDeviceBuffer(kTestLun, buf, offset, sizeof(buf));
zx::result result = driver_test().RunOnBackgroundDispatcherSync([client_end = GetClient()]() {
uint32_t buffer_offset = kMaxDeviceBufferSize;
uint32_t length = 256;
// Read buffer
{
fzl::OwnedVmoMapper mapper;
ASSERT_OK(mapper.CreateAndMap(zx_system_get_page_size(), "read-buffer-test-vmo"));
zx::vmo dup;
ASSERT_OK(mapper.vmo().duplicate(ZX_RIGHT_SAME_RIGHTS, &dup));
const fidl::WireResult result =
fidl::WireCall(client_end)
->ReadBuffer(0, fuchsia_hardware_scsi::wire::ReadBufferMode::kData, 0, buffer_offset,
length, std::move(dup));
ASSERT_TRUE(result.ok());
const fit::result response = result.value();
ASSERT_EQ(response.error_value(), ZX_ERR_BAD_STATE);
}
// Write buffer
{
zx::vmo vmo;
ASSERT_OK(zx::vmo::create(zx_system_get_page_size(), 0, &vmo));
char write_buf[kMockBlockSize];
std::memset(write_buf, 0xf0, sizeof(write_buf));
vmo.write(&write_buf, 0, length);
const fidl::WireResult result =
fidl::WireCall(client_end)
->WriteBuffer(0, fuchsia_hardware_scsi::wire::WriteBufferMode::kData, 0,
buffer_offset, length, std::move(vmo));
ASSERT_TRUE(result.ok());
const fit::result response = result.value();
ASSERT_EQ(response.error_value(), ZX_ERR_BAD_STATE);
}
});
ASSERT_OK(result.status_value());
}
TEST_F(ServerTest, ReadWriteBufferInvalidVmoSize) {
zx::result result = driver_test().RunOnBackgroundDispatcherSync([client_end = GetClient()]() {
uint32_t buffer_offset = 0;
uint32_t length = kMockBlockSize * 2;
// Read buffer with invalid vmo size
{
fzl::OwnedVmoMapper mapper;
ASSERT_OK(mapper.CreateAndMap(kMockBlockSize, "read-buffer-test-vmo"));
zx::vmo dup;
ASSERT_OK(mapper.vmo().duplicate(ZX_RIGHT_SAME_RIGHTS, &dup));
const fidl::WireResult result =
fidl::WireCall(client_end)
->ReadBuffer(0, fuchsia_hardware_scsi::wire::ReadBufferMode::kData, 0, buffer_offset,
length, std::move(dup));
ASSERT_TRUE(result.ok());
const fit::result response = result.value();
ASSERT_EQ(response.error_value(), ZX_ERR_OUT_OF_RANGE);
}
// Write buffer with invalid vmo size
{
zx::vmo vmo;
ASSERT_OK(zx::vmo::create(kMockBlockSize, 0, &vmo));
char write_buf[kMockBlockSize * 2];
std::memset(write_buf, 0xf0, sizeof(write_buf));
vmo.write(&write_buf, 0, length);
const fidl::WireResult result =
fidl::WireCall(client_end)
->WriteBuffer(0, fuchsia_hardware_scsi::wire::WriteBufferMode::kData, 0,
buffer_offset, length, std::move(vmo));
ASSERT_TRUE(result.ok());
const fit::result response = result.value();
ASSERT_EQ(response.error_value(), ZX_ERR_OUT_OF_RANGE);
}
});
ASSERT_OK(result.status_value());
}
TEST_F(ServerTest, ReadWriteBufferWithInvalidLun) {
zx::result result = driver_test().RunOnBackgroundDispatcherSync([client_end = GetClient()]() {
uint32_t buffer_offset = 0;
uint32_t length = kMockBlockSize;
zx::vmo vmo;
ASSERT_OK(zx::vmo::create(kMockBlockSize, 0, &vmo));
const uint8_t kTestLun = 1;
// Request to write buffer with invalid lun
{
char write_buf[kMockBlockSize];
std::memset(write_buf, 0xf0, sizeof(write_buf));
vmo.write(&write_buf, 0, length);
const fidl::WireResult result =
fidl::WireCall(client_end)
->WriteBuffer(kTestLun, fuchsia_hardware_scsi::wire::WriteBufferMode::kData, 0,
buffer_offset, length, std::move(vmo));
ASSERT_TRUE(result.ok());
const fit::result response = result.value();
ASSERT_EQ(response.error_value(), ZX_ERR_BAD_STATE);
}
// Request to read buffer with invalid lun
{
fzl::OwnedVmoMapper mapper;
ASSERT_OK(mapper.CreateAndMap(zx_system_get_page_size(), "read-buffer-test-vmo"));
zx::vmo dup;
ASSERT_OK(mapper.vmo().duplicate(ZX_RIGHT_SAME_RIGHTS, &dup));
const fidl::WireResult result =
fidl::WireCall(client_end)
->ReadBuffer(kTestLun, fuchsia_hardware_scsi::wire::ReadBufferMode::kData, 0,
buffer_offset, length, std::move(dup));
ASSERT_TRUE(result.ok());
const fit::result response = result.value();
ASSERT_EQ(response.error_value(), ZX_ERR_BAD_STATE);
}
});
ASSERT_OK(result.status_value());
}
} // namespace ufs