| // Copyright 2019 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. |
| |
| #ifndef SRC_DEVICES_BLOCK_DRIVERS_VIRTIO_SCSI_H_ |
| #define SRC_DEVICES_BLOCK_DRIVERS_VIRTIO_SCSI_H_ |
| |
| #include <lib/fzl/vmo-mapper.h> |
| #include <lib/scsi/controller-dfv1.h> |
| #include <lib/scsi/disk-dfv1.h> |
| #include <lib/sync/completion.h> |
| #include <lib/virtio/backends/backend.h> |
| #include <lib/virtio/device.h> |
| #include <lib/virtio/ring.h> |
| #include <lib/zircon-internal/thread_annotations.h> |
| #include <stdlib.h> |
| #include <sys/uio.h> |
| #include <zircon/compiler.h> |
| |
| #include <atomic> |
| #include <memory> |
| #include <optional> |
| |
| #include <ddktl/device.h> |
| #include <fbl/auto_lock.h> |
| #include <fbl/condition_variable.h> |
| #include <virtio/scsi.h> |
| |
| namespace virtio { |
| |
| constexpr int MAX_IOS = 16; |
| |
| class ScsiDevice : public virtio::Device, public scsi::Controller, public ddk::Device<ScsiDevice> { |
| public: |
| enum Queue { |
| CONTROL = 0, |
| EVENT = 1, |
| REQUEST = 2, |
| }; |
| |
| ScsiDevice(zx_device_t* device, zx::bti bti, std::unique_ptr<Backend> backend) |
| : virtio::Device(std::move(bti), std::move(backend)), |
| ddk::Device<ScsiDevice>(device), |
| device_(device) {} |
| |
| // virtio::Device overrides |
| zx_status_t Init() override; |
| void DdkRelease(); |
| // Invoked for most device interrupts. |
| virtual void IrqRingUpdate() override; |
| // Invoked on config change interrupts. |
| void IrqConfigChange() override {} |
| |
| // scsi::Controller overrides |
| size_t BlockOpSize() override { |
| // No additional metadata required for each command transaction. |
| return sizeof(scsi::DiskOp); |
| } |
| zx_status_t ExecuteCommandSync(uint8_t target, uint16_t lun, iovec cdb, bool is_write, |
| iovec data) override; |
| void ExecuteCommandAsync(uint8_t target, uint16_t lun, iovec cdb, bool is_write, |
| uint32_t block_size_bytes, scsi::DiskOp* disk_op, iovec data) override; |
| |
| const char* tag() const override { return "virtio-scsi"; } |
| |
| static void FillLUNStructure(struct virtio_scsi_req_cmd* req, uint8_t target, uint16_t lun); |
| |
| private: |
| void QueueCommand(uint8_t target, uint16_t lun, iovec cdb, bool is_write, |
| zx::unowned_vmo data_vmo, zx_off_t vmo_offset_bytes, size_t transfer_bytes, |
| void (*cb)(void*, zx_status_t), void* cookie, void* data, bool vmar_mapped, |
| std::optional<zx::vmo> trim_data_vmo = std::nullopt); |
| |
| zx_status_t WorkerThread(); |
| |
| zx::result<> AllocatePages(zx::vmo& vmo, fzl::VmoMapper& mapper, size_t size); |
| |
| // Latched copy of virtio-scsi device configuration. |
| struct virtio_scsi_config config_ TA_GUARDED(lock_) = {}; |
| |
| struct scsi_io_slot { |
| zx::unowned_vmo data_vmo; |
| zx_off_t vmo_offset_bytes; |
| size_t transfer_bytes; |
| bool is_write; |
| void* data; |
| bool vmar_mapped; |
| io_buffer_t request_buffer; |
| bool avail; |
| vring_desc* tail_desc; |
| void* cookie; |
| void (*callback)(void* cookie, zx_status_t status); |
| void* data_in_region; |
| io_buffer_t* request_buffers; |
| struct virtio_scsi_resp_cmd* response; |
| // Sustains the lifetime of the trim data while it is being used. |
| std::optional<zx::vmo> trim_data_vmo; |
| }; |
| scsi_io_slot* GetIO() TA_REQ(lock_); |
| void FreeIO(scsi_io_slot* io_slot) TA_REQ(lock_); |
| size_t request_buffers_size_; |
| scsi_io_slot scsi_io_slot_table_[MAX_IOS] TA_GUARDED(lock_) = {}; |
| |
| zx_device_t* device_ = nullptr; |
| |
| Ring control_ring_ TA_GUARDED(lock_) = {this}; |
| Ring request_queue_ = {this}; |
| |
| thrd_t worker_thread_; |
| bool worker_thread_should_exit_ TA_GUARDED(lock_) = {}; |
| |
| // Synchronizes virtio rings and worker thread control. |
| fbl::Mutex lock_; |
| |
| // We use the condvar to control the number of IO's in flight |
| // as well as to wait for descs to become available. |
| fbl::ConditionVariable ioslot_cv_ __TA_GUARDED(lock_); |
| fbl::ConditionVariable desc_cv_ __TA_GUARDED(lock_); |
| uint32_t active_ios_ __TA_GUARDED(lock_); |
| uint64_t scsi_transport_tag_ __TA_GUARDED(lock_); |
| }; |
| |
| } // namespace virtio |
| |
| #endif // SRC_DEVICES_BLOCK_DRIVERS_VIRTIO_SCSI_H_ |