2020-01-18 09:38:21 +01:00
|
|
|
/*
|
2020-12-19 12:50:57 +02:00
|
|
|
* Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il>
|
2020-01-18 09:38:21 +01:00
|
|
|
*
|
2021-04-22 01:24:48 -07:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
2020-01-18 09:38:21 +01:00
|
|
|
*/
|
|
|
|
|
2020-03-08 12:33:14 +01:00
|
|
|
#include <AK/Memory.h>
|
2020-03-23 13:45:10 +01:00
|
|
|
#include <AK/StringView.h>
|
2021-01-25 16:07:10 +01:00
|
|
|
#include <Kernel/Debug.h>
|
2022-04-23 11:48:40 +03:00
|
|
|
#include <Kernel/Devices/DeviceManagement.h>
|
2021-09-07 13:39:11 +02:00
|
|
|
#include <Kernel/FileSystem/OpenFileDescription.h>
|
2022-04-23 11:48:40 +03:00
|
|
|
#include <Kernel/FileSystem/SysFS/Subsystems/DeviceIdentifiers/BlockDevicesDirectory.h>
|
|
|
|
#include <Kernel/FileSystem/SysFS/Subsystems/DeviceIdentifiers/SymbolicLinkDeviceComponent.h>
|
|
|
|
#include <Kernel/FileSystem/SysFS/Subsystems/Devices/Storage/DeviceDirectory.h>
|
|
|
|
#include <Kernel/FileSystem/SysFS/Subsystems/Devices/Storage/Directory.h>
|
2020-12-19 12:50:57 +02:00
|
|
|
#include <Kernel/Storage/StorageDevice.h>
|
2021-02-25 19:36:49 +02:00
|
|
|
#include <Kernel/Storage/StorageManagement.h>
|
2021-10-08 22:20:26 +02:00
|
|
|
#include <LibC/sys/ioctl_numbers.h>
|
2019-07-28 23:44:01 +10:00
|
|
|
|
2020-02-16 01:27:42 +01:00
|
|
|
namespace Kernel {
|
|
|
|
|
Kernel/Storage: Add LUN address to each StorageDevice
LUN address is essentially how people used to address SCSI devices back
in the day we had these devices more in use. However, SCSI was taken as
an abstraction layer for many Unix and Unix-like systems, so it still
common to see LUN addresses in use. In Serenity, we don't really provide
such abstraction layer, and therefore until now, we didn't use LUNs too.
However (again), this changes, as we want to let users to address their
devices under SysFS easily. LUNs make sense in that regard, because they
can be easily adapted to different interfaces besides SCSI.
For example, for legacy ATA hard drive being connected to the first IDE
controller which was enumerated on the PCI bus, and then to the primary
channel as slave device, the LUN address would be 0:0:1.
To make this happen, we add unique ID number to each StorageController,
which increments by 1 for each new instance of StorageController. Then,
we adapt the ATA and NVMe devices to use these numbers and generate LUN
in the construction time.
2022-04-22 18:52:20 +03:00
|
|
|
StorageDevice::StorageDevice(LUNAddress logical_unit_number_address, MajorNumber major, MinorNumber minor, size_t sector_size, u64 max_addressable_block, NonnullOwnPtr<KString> device_name)
|
2020-12-19 12:50:57 +02:00
|
|
|
: BlockDevice(major, minor, sector_size)
|
2021-08-27 17:13:03 +03:00
|
|
|
, m_early_storage_device_name(move(device_name))
|
Kernel/Storage: Add LUN address to each StorageDevice
LUN address is essentially how people used to address SCSI devices back
in the day we had these devices more in use. However, SCSI was taken as
an abstraction layer for many Unix and Unix-like systems, so it still
common to see LUN addresses in use. In Serenity, we don't really provide
such abstraction layer, and therefore until now, we didn't use LUNs too.
However (again), this changes, as we want to let users to address their
devices under SysFS easily. LUNs make sense in that regard, because they
can be easily adapted to different interfaces besides SCSI.
For example, for legacy ATA hard drive being connected to the first IDE
controller which was enumerated on the PCI bus, and then to the primary
channel as slave device, the LUN address would be 0:0:1.
To make this happen, we add unique ID number to each StorageController,
which increments by 1 for each new instance of StorageController. Then,
we adapt the ATA and NVMe devices to use these numbers and generate LUN
in the construction time.
2022-04-22 18:52:20 +03:00
|
|
|
, m_logical_unit_number_address(logical_unit_number_address)
|
2020-12-19 12:50:57 +02:00
|
|
|
, m_max_addressable_block(max_addressable_block)
|
2022-01-29 11:51:21 +05:30
|
|
|
, m_blocks_per_page(PAGE_SIZE / block_size())
|
2019-07-28 23:44:01 +10:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2022-04-23 11:48:40 +03:00
|
|
|
void StorageDevice::after_inserting()
|
|
|
|
{
|
|
|
|
after_inserting_add_to_device_management();
|
|
|
|
auto sysfs_storage_device_directory = StorageDeviceSysFSDirectory::create(SysFSStorageDirectory::the(), *this);
|
|
|
|
m_sysfs_device_directory = sysfs_storage_device_directory;
|
|
|
|
SysFSStorageDirectory::the().plug({}, *sysfs_storage_device_directory);
|
|
|
|
VERIFY(!m_symlink_sysfs_component);
|
|
|
|
auto sys_fs_component = MUST(SysFSSymbolicLinkDeviceComponent::try_create(SysFSDeviceIdentifiersDirectory::the(), *this, *m_sysfs_device_directory));
|
|
|
|
m_symlink_sysfs_component = sys_fs_component;
|
2022-07-16 10:39:57 +03:00
|
|
|
after_inserting_add_symlink_to_device_identifier_directory();
|
2022-04-23 11:48:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void StorageDevice::will_be_destroyed()
|
|
|
|
{
|
|
|
|
VERIFY(m_symlink_sysfs_component);
|
2022-07-16 10:39:57 +03:00
|
|
|
before_will_be_destroyed_remove_symlink_from_device_identifier_directory();
|
2022-04-23 11:48:40 +03:00
|
|
|
m_symlink_sysfs_component.clear();
|
|
|
|
SysFSStorageDirectory::the().unplug({}, *m_sysfs_device_directory);
|
|
|
|
before_will_be_destroyed_remove_from_device_management();
|
|
|
|
}
|
|
|
|
|
2021-07-11 01:46:09 +02:00
|
|
|
StringView StorageDevice::class_name() const
|
2019-07-28 23:44:01 +10:00
|
|
|
{
|
2021-10-02 15:24:00 -07:00
|
|
|
return "StorageDevice"sv;
|
2019-07-28 23:44:01 +10:00
|
|
|
}
|
|
|
|
|
2022-04-22 16:15:41 +03:00
|
|
|
StringView StorageDevice::command_set_to_string_view() const
|
|
|
|
{
|
|
|
|
switch (command_set()) {
|
|
|
|
case CommandSet::PlainMemory:
|
|
|
|
return "memory"sv;
|
|
|
|
case CommandSet::SCSI:
|
|
|
|
return "scsi"sv;
|
|
|
|
case CommandSet::ATA:
|
|
|
|
return "ata"sv;
|
|
|
|
case CommandSet::NVMe:
|
|
|
|
return "nvme"sv;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
VERIFY_NOT_REACHED();
|
|
|
|
}
|
|
|
|
|
|
|
|
StringView StorageDevice::interface_type_to_string_view() const
|
|
|
|
{
|
|
|
|
switch (interface_type()) {
|
|
|
|
case InterfaceType::PlainMemory:
|
|
|
|
return "memory"sv;
|
|
|
|
case InterfaceType::SCSI:
|
|
|
|
return "scsi"sv;
|
|
|
|
case InterfaceType::ATA:
|
|
|
|
return "ata"sv;
|
|
|
|
case InterfaceType::NVMe:
|
|
|
|
return "nvme"sv;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
VERIFY_NOT_REACHED();
|
|
|
|
}
|
|
|
|
|
2021-11-08 00:51:39 +01:00
|
|
|
ErrorOr<size_t> StorageDevice::read(OpenFileDescription&, u64 offset, UserOrKernelBuffer& outbuf, size_t len)
|
2020-02-09 21:43:22 +11:00
|
|
|
{
|
2022-01-29 15:28:06 +05:30
|
|
|
u64 index = offset >> block_size_log();
|
2022-03-28 21:01:46 +02:00
|
|
|
off_t offset_within_block = 0;
|
2022-01-29 15:28:06 +05:30
|
|
|
size_t whole_blocks = len >> block_size_log();
|
|
|
|
size_t remaining = len - (whole_blocks << block_size_log());
|
2020-02-09 21:43:22 +11:00
|
|
|
|
|
|
|
// PATAChannel will chuck a wobbly if we try to read more than PAGE_SIZE
|
|
|
|
// at a time, because it uses a single page for its DMA buffer.
|
2022-01-29 11:51:21 +05:30
|
|
|
if (whole_blocks >= m_blocks_per_page) {
|
|
|
|
whole_blocks = m_blocks_per_page;
|
2020-02-09 21:43:22 +11:00
|
|
|
remaining = 0;
|
|
|
|
}
|
|
|
|
|
2022-03-28 21:01:46 +02:00
|
|
|
if (len < block_size())
|
|
|
|
offset_within_block = offset - (index << block_size_log());
|
|
|
|
|
2021-03-12 14:02:17 +01:00
|
|
|
dbgln_if(STORAGE_DEVICE_DEBUG, "StorageDevice::read() index={}, whole_blocks={}, remaining={}", index, whole_blocks, remaining);
|
2020-02-09 21:43:22 +11:00
|
|
|
|
|
|
|
if (whole_blocks > 0) {
|
2021-09-07 16:40:54 +02:00
|
|
|
auto read_request = TRY(try_make_request<AsyncBlockDeviceRequest>(AsyncBlockDeviceRequest::Read, index, whole_blocks, outbuf, whole_blocks * block_size()));
|
2020-11-02 11:16:01 -07:00
|
|
|
auto result = read_request->wait();
|
|
|
|
if (result.wait_result().was_interrupted())
|
2021-01-20 23:11:17 +01:00
|
|
|
return EINTR;
|
2020-11-02 11:16:01 -07:00
|
|
|
switch (result.request_result()) {
|
|
|
|
case AsyncDeviceRequest::Failure:
|
|
|
|
case AsyncDeviceRequest::Cancelled:
|
2021-01-20 23:11:17 +01:00
|
|
|
return EIO;
|
2020-11-02 11:16:01 -07:00
|
|
|
case AsyncDeviceRequest::MemoryFault:
|
2021-01-20 23:11:17 +01:00
|
|
|
return EFAULT;
|
2020-11-02 11:16:01 -07:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2020-02-09 21:43:22 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
off_t pos = whole_blocks * block_size();
|
|
|
|
|
|
|
|
if (remaining > 0) {
|
2022-01-20 17:47:39 +00:00
|
|
|
auto data = TRY(ByteBuffer::create_uninitialized(block_size()));
|
2020-09-11 21:11:07 -06:00
|
|
|
auto data_buffer = UserOrKernelBuffer::for_kernel_buffer(data.data());
|
2021-09-07 16:40:54 +02:00
|
|
|
auto read_request = TRY(try_make_request<AsyncBlockDeviceRequest>(AsyncBlockDeviceRequest::Read, index + whole_blocks, 1, data_buffer, block_size()));
|
2020-11-02 11:16:01 -07:00
|
|
|
auto result = read_request->wait();
|
|
|
|
if (result.wait_result().was_interrupted())
|
2021-01-20 23:11:17 +01:00
|
|
|
return EINTR;
|
2020-11-02 11:16:01 -07:00
|
|
|
switch (result.request_result()) {
|
|
|
|
case AsyncDeviceRequest::Failure:
|
2020-02-09 21:43:22 +11:00
|
|
|
return pos;
|
2020-11-02 11:16:01 -07:00
|
|
|
case AsyncDeviceRequest::Cancelled:
|
2021-01-20 23:11:17 +01:00
|
|
|
return EIO;
|
2020-11-02 11:16:01 -07:00
|
|
|
case AsyncDeviceRequest::MemoryFault:
|
|
|
|
// This should never happen, we're writing to a kernel buffer!
|
2021-02-23 20:42:32 +01:00
|
|
|
VERIFY_NOT_REACHED();
|
2020-11-02 11:16:01 -07:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2022-03-28 21:01:46 +02:00
|
|
|
TRY(outbuf.write(data.offset_pointer(offset_within_block), pos, remaining));
|
2020-02-09 21:43:22 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
return pos + remaining;
|
|
|
|
}
|
|
|
|
|
2022-04-01 20:58:27 +03:00
|
|
|
bool StorageDevice::can_read(OpenFileDescription const&, u64 offset) const
|
2020-02-09 21:43:22 +11:00
|
|
|
{
|
2020-12-19 12:50:57 +02:00
|
|
|
return offset < (max_addressable_block() * block_size());
|
2020-02-09 21:43:22 +11:00
|
|
|
}
|
|
|
|
|
2022-04-01 20:58:27 +03:00
|
|
|
ErrorOr<size_t> StorageDevice::write(OpenFileDescription&, u64 offset, UserOrKernelBuffer const& inbuf, size_t len)
|
2020-02-09 21:43:22 +11:00
|
|
|
{
|
2022-01-29 15:28:06 +05:30
|
|
|
u64 index = offset >> block_size_log();
|
2022-03-28 21:01:46 +02:00
|
|
|
off_t offset_within_block = 0;
|
2022-01-29 15:28:06 +05:30
|
|
|
size_t whole_blocks = len >> block_size_log();
|
|
|
|
size_t remaining = len - (whole_blocks << block_size_log());
|
2020-02-09 21:43:22 +11:00
|
|
|
|
|
|
|
// PATAChannel will chuck a wobbly if we try to write more than PAGE_SIZE
|
|
|
|
// at a time, because it uses a single page for its DMA buffer.
|
2022-01-29 11:51:21 +05:30
|
|
|
if (whole_blocks >= m_blocks_per_page) {
|
|
|
|
whole_blocks = m_blocks_per_page;
|
2020-02-09 21:43:22 +11:00
|
|
|
remaining = 0;
|
|
|
|
}
|
|
|
|
|
2022-03-28 21:01:46 +02:00
|
|
|
if (len < block_size())
|
|
|
|
offset_within_block = offset - (index << block_size_log());
|
|
|
|
|
2022-01-25 14:58:47 +02:00
|
|
|
// We try to allocate the temporary block buffer for partial writes *before* we start any full block writes,
|
|
|
|
// to try and prevent partial writes
|
|
|
|
Optional<ByteBuffer> partial_write_block;
|
|
|
|
if (remaining > 0)
|
|
|
|
partial_write_block = TRY(ByteBuffer::create_zeroed(block_size()));
|
|
|
|
|
2021-03-12 14:02:17 +01:00
|
|
|
dbgln_if(STORAGE_DEVICE_DEBUG, "StorageDevice::write() index={}, whole_blocks={}, remaining={}", index, whole_blocks, remaining);
|
2020-02-09 21:43:22 +11:00
|
|
|
|
|
|
|
if (whole_blocks > 0) {
|
2021-09-07 16:40:54 +02:00
|
|
|
auto write_request = TRY(try_make_request<AsyncBlockDeviceRequest>(AsyncBlockDeviceRequest::Write, index, whole_blocks, inbuf, whole_blocks * block_size()));
|
2020-11-02 11:16:01 -07:00
|
|
|
auto result = write_request->wait();
|
|
|
|
if (result.wait_result().was_interrupted())
|
2021-01-20 23:11:17 +01:00
|
|
|
return EINTR;
|
2020-11-02 11:16:01 -07:00
|
|
|
switch (result.request_result()) {
|
|
|
|
case AsyncDeviceRequest::Failure:
|
|
|
|
case AsyncDeviceRequest::Cancelled:
|
2021-01-20 23:11:17 +01:00
|
|
|
return EIO;
|
2020-11-02 11:16:01 -07:00
|
|
|
case AsyncDeviceRequest::MemoryFault:
|
2021-01-20 23:11:17 +01:00
|
|
|
return EFAULT;
|
2020-11-02 11:16:01 -07:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2020-02-09 21:43:22 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
off_t pos = whole_blocks * block_size();
|
|
|
|
|
|
|
|
// since we can only write in block_size() increments, if we want to do a
|
|
|
|
// partial write, we have to read the block's content first, modify it,
|
|
|
|
// then write the whole block back to the disk.
|
|
|
|
if (remaining > 0) {
|
2022-01-25 14:58:47 +02:00
|
|
|
auto data_buffer = UserOrKernelBuffer::for_kernel_buffer(partial_write_block->data());
|
2020-11-02 11:16:01 -07:00
|
|
|
{
|
2021-09-07 16:40:54 +02:00
|
|
|
auto read_request = TRY(try_make_request<AsyncBlockDeviceRequest>(AsyncBlockDeviceRequest::Read, index + whole_blocks, 1, data_buffer, block_size()));
|
2020-11-02 11:16:01 -07:00
|
|
|
auto result = read_request->wait();
|
|
|
|
if (result.wait_result().was_interrupted())
|
2021-01-20 23:11:17 +01:00
|
|
|
return EINTR;
|
2020-11-02 11:16:01 -07:00
|
|
|
switch (result.request_result()) {
|
|
|
|
case AsyncDeviceRequest::Failure:
|
|
|
|
return pos;
|
|
|
|
case AsyncDeviceRequest::Cancelled:
|
2021-01-20 23:11:17 +01:00
|
|
|
return EIO;
|
2020-11-02 11:16:01 -07:00
|
|
|
case AsyncDeviceRequest::MemoryFault:
|
|
|
|
// This should never happen, we're writing to a kernel buffer!
|
2021-02-23 20:42:32 +01:00
|
|
|
VERIFY_NOT_REACHED();
|
2020-11-02 11:16:01 -07:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-28 21:01:46 +02:00
|
|
|
TRY(inbuf.read(partial_write_block->offset_pointer(offset_within_block), pos, remaining));
|
2020-11-02 11:16:01 -07:00
|
|
|
|
|
|
|
{
|
2021-09-07 16:40:54 +02:00
|
|
|
auto write_request = TRY(try_make_request<AsyncBlockDeviceRequest>(AsyncBlockDeviceRequest::Write, index + whole_blocks, 1, data_buffer, block_size()));
|
2020-11-02 11:16:01 -07:00
|
|
|
auto result = write_request->wait();
|
|
|
|
if (result.wait_result().was_interrupted())
|
2021-01-20 23:11:17 +01:00
|
|
|
return EINTR;
|
2020-11-02 11:16:01 -07:00
|
|
|
switch (result.request_result()) {
|
|
|
|
case AsyncDeviceRequest::Failure:
|
|
|
|
return pos;
|
|
|
|
case AsyncDeviceRequest::Cancelled:
|
2021-01-20 23:11:17 +01:00
|
|
|
return EIO;
|
2020-11-02 11:16:01 -07:00
|
|
|
case AsyncDeviceRequest::MemoryFault:
|
|
|
|
// This should never happen, we're writing to a kernel buffer!
|
2021-02-23 20:42:32 +01:00
|
|
|
VERIFY_NOT_REACHED();
|
2020-11-02 11:16:01 -07:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-02-09 21:43:22 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
return pos + remaining;
|
|
|
|
}
|
|
|
|
|
2021-08-27 17:13:03 +03:00
|
|
|
StringView StorageDevice::early_storage_name() const
|
2021-10-02 16:22:16 -07:00
|
|
|
{
|
2021-08-27 17:13:03 +03:00
|
|
|
return m_early_storage_device_name->view();
|
2021-10-02 16:22:16 -07:00
|
|
|
}
|
|
|
|
|
2022-04-01 20:58:27 +03:00
|
|
|
bool StorageDevice::can_write(OpenFileDescription const&, u64 offset) const
|
2019-07-28 23:44:01 +10:00
|
|
|
{
|
2020-12-19 12:50:57 +02:00
|
|
|
return offset < (max_addressable_block() * block_size());
|
2019-07-28 23:44:01 +10:00
|
|
|
}
|
2020-02-16 01:27:42 +01:00
|
|
|
|
2021-11-08 00:51:39 +01:00
|
|
|
ErrorOr<void> StorageDevice::ioctl(OpenFileDescription&, unsigned request, Userspace<void*> arg)
|
2021-10-08 22:20:26 +02:00
|
|
|
{
|
|
|
|
switch (request) {
|
|
|
|
case STORAGE_DEVICE_GET_SIZE: {
|
2022-01-25 20:29:02 +02:00
|
|
|
u64 disk_size = m_max_addressable_block * block_size();
|
|
|
|
return copy_to_user(static_ptr_cast<u64*>(arg), &disk_size);
|
2021-10-08 22:20:26 +02:00
|
|
|
break;
|
|
|
|
}
|
2021-10-09 11:19:51 +02:00
|
|
|
case STORAGE_DEVICE_GET_BLOCK_SIZE: {
|
|
|
|
size_t size = block_size();
|
2021-11-14 15:43:43 -07:00
|
|
|
return copy_to_user(static_ptr_cast<size_t*>(arg), &size);
|
2021-10-09 11:19:51 +02:00
|
|
|
break;
|
|
|
|
}
|
2021-10-08 22:20:26 +02:00
|
|
|
default:
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-16 01:27:42 +01:00
|
|
|
}
|