1// Copyright 2016 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4#pragma once 5 6#include "device.h" 7#include "ring.h" 8 9#include <stdlib.h> 10#include <zircon/compiler.h> 11 12#include "backends/backend.h" 13#include <virtio/block.h> 14#include <zircon/device/block.h> 15#include <ddk/protocol/block.h> 16 17#include <lib/sync/completion.h> 18 19namespace virtio { 20 21struct block_txn_t { 22 block_op_t op; 23 struct vring_desc* desc; 24 size_t index; 25 list_node_t node; 26 zx_handle_t pmt; 27}; 28 29class Ring; 30 31class BlockDevice : public Device { 32public: 33 BlockDevice(zx_device_t* device, zx::bti bti, fbl::unique_ptr<Backend> backend); 34 virtual ~BlockDevice(); 35 36 virtual zx_status_t Init() override; 37 38 virtual void IrqRingUpdate() override; 39 virtual void IrqConfigChange() override; 40 41 uint64_t GetSize() const { return config_.capacity * config_.blk_size; } 42 uint32_t GetBlockSize() const { return config_.blk_size; } 43 uint64_t GetBlockCount() const { return config_.capacity; } 44 const char* tag() const override { return "virtio-blk"; } 45 46private: 47 // DDK driver hooks 48 static zx_off_t virtio_block_get_size(void* ctx); 49 static zx_status_t virtio_block_ioctl(void* ctx, uint32_t op, const void* in_buf, size_t in_len, 50 void* out_buf, size_t out_len, size_t* out_actual); 51 52 static void virtio_block_query(void* ctx, block_info_t* bi, size_t* bopsz); 53 static void virtio_block_queue(void* ctx, block_op_t* bop); 54 55 void GetInfo(block_info_t* info); 56 57 zx_status_t QueueTxn(block_txn_t* txn, bool write, size_t bytes, 58 uint64_t* pages, size_t pagecount, uint16_t* idx); 59 void QueueReadWriteTxn(block_txn_t* txn, bool write); 60 61 void txn_complete(block_txn_t* txn, zx_status_t status); 62 63 // the main virtio ring 64 Ring vring_ = {this}; 65 66 // lock to be used around Ring::AllocDescChain and FreeDesc 67 // TODO: move this into Ring class once it's certain that other 68 // users of the class are okay with it. 69 fbl::Mutex ring_lock_; 70 71 static const uint16_t ring_size = 128; // 128 matches legacy pci 72 73 // saved block device configuration out of the pci config BAR 74 virtio_blk_config_t config_ = {}; 75 76 // a queue of block request/responses 77 static const size_t blk_req_count = 32; 78 79 io_buffer_t blk_req_buf_; 80 virtio_blk_req_t* blk_req_ = nullptr; 81 82 zx_paddr_t blk_res_pa_ = 0; 83 uint8_t* blk_res_ = nullptr; 84 85 uint32_t blk_req_bitmap_ = 0; 86 static_assert(blk_req_count <= sizeof(blk_req_bitmap_) * CHAR_BIT, ""); 87 88 size_t alloc_blk_req() { 89 size_t i = 0; 90 if (blk_req_bitmap_ != 0) 91 i = sizeof(blk_req_bitmap_) * CHAR_BIT - __builtin_clz(blk_req_bitmap_); 92 blk_req_bitmap_ |= (1 << i); 93 return i; 94 } 95 96 void free_blk_req(size_t i) { 97 blk_req_bitmap_ &= ~(1 << i); 98 } 99 100 // pending iotxns and waiter state 101 fbl::Mutex txn_lock_; 102 list_node txn_list_ = LIST_INITIAL_VALUE(txn_list_); 103 bool txn_wait_ = false; 104 sync_completion_t txn_signal_; 105 106 block_protocol_ops_t block_ops_ = {}; 107}; 108 109} // namespace virtio 110