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 5 #pragma once 6 7 #include <assert.h> 8 #include <limits.h> 9 #include <zircon/device/ioctl-wrapper.h> 10 #include <zircon/device/ioctl.h> 11 #include <zircon/types.h> 12 13 // Get information about the underlying block device. 14 #define IOCTL_BLOCK_GET_INFO \ 15 IOCTL(IOCTL_KIND_DEFAULT, IOCTL_FAMILY_BLOCK, 1) 16 // Get the type GUID of the partition (if one exists) 17 #define IOCTL_BLOCK_GET_TYPE_GUID \ 18 IOCTL(IOCTL_KIND_DEFAULT, IOCTL_FAMILY_BLOCK, 2) 19 // Get the GUID of the partition (if one exists) 20 #define IOCTL_BLOCK_GET_PARTITION_GUID \ 21 IOCTL(IOCTL_KIND_DEFAULT, IOCTL_FAMILY_BLOCK, 3) 22 // Get the name of the partition (if one exists) 23 #define IOCTL_BLOCK_GET_NAME \ 24 IOCTL(IOCTL_KIND_DEFAULT, IOCTL_FAMILY_BLOCK, 4) 25 // Rebind the block device (if supported) 26 #define IOCTL_BLOCK_RR_PART \ 27 IOCTL(IOCTL_KIND_DEFAULT, IOCTL_FAMILY_BLOCK, 5) 28 // Set up a FIFO-based server on the block device; acquire the handle to it 29 #define IOCTL_BLOCK_GET_FIFOS \ 30 IOCTL(IOCTL_KIND_GET_HANDLE, IOCTL_FAMILY_BLOCK, 6) 31 // Attach a VMO to the currently running FIFO server 32 #define IOCTL_BLOCK_ATTACH_VMO \ 33 IOCTL(IOCTL_KIND_SET_HANDLE, IOCTL_FAMILY_BLOCK, 7) 34 // Shut down the fifo server, waiting for it to be ready to be started again. 35 // Only necessary to guarantee availability to the next fifo server client; 36 // otherwise, closing the client fifo is sufficient to shut down the server. 37 #define IOCTL_BLOCK_FIFO_CLOSE \ 38 IOCTL(IOCTL_KIND_DEFAULT, IOCTL_FAMILY_BLOCK, 10) 39 // Allocate a virtual partition with the requested length. 40 #define IOCTL_BLOCK_FVM_ALLOC_PARTITION \ 41 IOCTL(IOCTL_KIND_DEFAULT, IOCTL_FAMILY_BLOCK, 11) 42 // Extend a virtual partition. 43 #define IOCTL_BLOCK_FVM_EXTEND \ 44 IOCTL(IOCTL_KIND_DEFAULT, IOCTL_FAMILY_BLOCK, 12) 45 // Shink a virtual partition. Returns "success" if ANY slices are 46 // freed, even if part of the requested range contains unallocated slices. 47 #define IOCTL_BLOCK_FVM_SHRINK \ 48 IOCTL(IOCTL_KIND_DEFAULT, IOCTL_FAMILY_BLOCK, 13) 49 // Given a handle to a partition, destroy it. 50 #define IOCTL_BLOCK_FVM_DESTROY_PARTITION \ 51 IOCTL(IOCTL_KIND_DEFAULT, IOCTL_FAMILY_BLOCK, 14) 52 // Returns the total number of vslices and slice size for an FVM partition 53 #define IOCTL_BLOCK_FVM_QUERY \ 54 IOCTL(IOCTL_KIND_DEFAULT, IOCTL_FAMILY_BLOCK, 15) 55 // Given a number of initial vslices, returns the number of contiguous allocated 56 // (or unallocated) vslices starting from each vslice. 57 #define IOCTL_BLOCK_FVM_VSLICE_QUERY \ 58 IOCTL(IOCTL_KIND_DEFAULT, IOCTL_FAMILY_BLOCK, 16) 59 // Atomically marks a vpartition (by instance GUID) as inactive, while finding 60 // another partition (by instance GUID) and marking it as active. 61 // 62 // If the "old" partition does not exist, the GUID is ignored. 63 // If the "old" partition is the same as the "new" partition, the "old" 64 // GUID is ignored (as in, "Upgrade" only activates). 65 // If the "new" partition does not exist, |ZX_ERR_NOT_FOUND| is returned. 66 // 67 // This function does not destroy the "old" partition, it just marks it as 68 // inactive -- to reclaim that space, the "old" partition must be explicitly 69 // destroyed. This destruction can also occur automatically when the FVM driver 70 // is rebound (i.e., on reboot). 71 // 72 // This function may be useful for A/B updates within the FVM, 73 // since it will allow "activating" updated partitions. 74 #define IOCTL_BLOCK_FVM_UPGRADE \ 75 IOCTL(IOCTL_KIND_DEFAULT, IOCTL_FAMILY_BLOCK, 17) 76 // Prints stats about the block device to the provided buffer and optionally 77 // clears the counters 78 #define IOCTL_BLOCK_GET_STATS \ 79 IOCTL(IOCTL_KIND_DEFAULT, IOCTL_FAMILY_BLOCK, 18) 80 81 // Block Impl ioctls (specific to each block device): 82 83 #define BLOCK_FLAG_READONLY 0x00000001 84 #define BLOCK_FLAG_REMOVABLE 0x00000002 85 #define BLOCK_FLAG_BOOTPART 0x00000004 // block device has bootdata partition map 86 // provided by device metadata 87 88 #define BLOCK_MAX_TRANSFER_UNBOUNDED 0xFFFFFFFF 89 90 typedef struct { 91 uint64_t block_count; // The number of blocks in this block device 92 uint32_t block_size; // The size of a single block 93 uint32_t max_transfer_size; // Max size in bytes per transfer. 94 // May be BLOCK_MAX_TRANSFER_UNBOUNDED if there 95 // is no restriction. 96 uint32_t flags; 97 uint32_t reserved; 98 } block_info_t; 99 100 typedef struct { 101 size_t total_ops; // Total number of block ops processed 102 size_t total_blocks; // Total number of blocks processed 103 size_t total_reads; 104 size_t total_blocks_read; 105 size_t total_writes; 106 size_t total_blocks_written; 107 } block_stats_t; 108 109 // ssize_t ioctl_block_get_info(int fd, block_info_t* out); 110 IOCTL_WRAPPER_OUT(ioctl_block_get_info, IOCTL_BLOCK_GET_INFO, block_info_t); 111 112 // ssize_t ioctl_block_get_type_guid(int fd, void* out, size_t out_len); 113 IOCTL_WRAPPER_VAROUT(ioctl_block_get_type_guid, IOCTL_BLOCK_GET_TYPE_GUID, void); 114 115 // ssize_t ioctl_block_get_partition_guid(int fd, void* out, size_t out_len); 116 IOCTL_WRAPPER_VAROUT(ioctl_block_get_partition_guid, IOCTL_BLOCK_GET_PARTITION_GUID, void); 117 118 // ssize_t ioctl_block_get_name(int fd, char* out, size_t out_len); 119 IOCTL_WRAPPER_VAROUT(ioctl_block_get_name, IOCTL_BLOCK_GET_NAME, char); 120 121 // ssize_t ioctl_block_rr_part(int fd); 122 IOCTL_WRAPPER(ioctl_block_rr_part, IOCTL_BLOCK_RR_PART); 123 124 // TODO(smklein): Move these to a separate file 125 // Block Device ioctls (shared between all block devices): 126 127 // ssize_t ioctl_block_get_fifos(int fd, zx_handle_t* fifo_out); 128 IOCTL_WRAPPER_OUT(ioctl_block_get_fifos, IOCTL_BLOCK_GET_FIFOS, zx_handle_t); 129 130 typedef uint16_t vmoid_t; 131 132 // Dummy vmoid value reserved for "invalid". Will never be allocated; can be 133 // used as a local value for unallocated / freed ID. 134 #define VMOID_INVALID 0 135 136 // ssize_t ioctl_block_attach_vmo(int fd, zx_handle_t* in, vmoid_t* out_vmoid); 137 IOCTL_WRAPPER_INOUT(ioctl_block_attach_vmo, IOCTL_BLOCK_ATTACH_VMO, zx_handle_t, vmoid_t); 138 139 // ssize_t ioctl_block_fifo_close(int fd); 140 IOCTL_WRAPPER(ioctl_block_fifo_close, IOCTL_BLOCK_FIFO_CLOSE); 141 142 #define GUID_LEN 16 143 #define NAME_LEN 24 144 #define MAX_FVM_VSLICE_REQUESTS 16 145 146 typedef struct { 147 size_t slice_count; 148 uint8_t type[GUID_LEN]; 149 uint8_t guid[GUID_LEN]; 150 char name[NAME_LEN]; 151 uint32_t flags; // Refer to fvm.h for options here; default is zero. 152 } alloc_req_t; 153 154 // ssize_t ioctl_block_fvm_alloc_partition(int fd, const alloc_req_t* req); 155 IOCTL_WRAPPER_IN(ioctl_block_fvm_alloc_partition, IOCTL_BLOCK_FVM_ALLOC_PARTITION, alloc_req_t); 156 157 typedef struct { 158 size_t offset; // Both in units of "slice". "0" = slice 0, "1" = slice 1, etc... 159 size_t length; 160 } extend_request_t; 161 162 // ssize_t ioctl_block_fvm_extend(int fd, const extend_request_t* request); 163 IOCTL_WRAPPER_IN(ioctl_block_fvm_extend, IOCTL_BLOCK_FVM_EXTEND, extend_request_t); 164 165 // ssize_t ioctl_block_fvm_shrink(int fd, const extend_request_t* request); 166 IOCTL_WRAPPER_IN(ioctl_block_fvm_shrink, IOCTL_BLOCK_FVM_SHRINK, extend_request_t); 167 168 // ssize_t ioctl_block_fvm_destroy_partition(int fd); 169 IOCTL_WRAPPER(ioctl_block_fvm_destroy_partition, IOCTL_BLOCK_FVM_DESTROY_PARTITION); 170 171 typedef struct { 172 bool allocated; // true if vslices are allocated, false otherwise 173 size_t count; // number of contiguous vslices 174 } vslice_range_t; 175 176 typedef struct { 177 size_t count; // number of elements in vslice_start 178 size_t vslice_start[MAX_FVM_VSLICE_REQUESTS]; // vslices to query from 179 } query_request_t; 180 181 typedef struct { 182 size_t count; // number of elements in vslice_range 183 vslice_range_t vslice_range[MAX_FVM_VSLICE_REQUESTS]; // number of contiguous vslices 184 // that are allocated (or unallocated) 185 } query_response_t; 186 187 typedef struct { 188 size_t slice_size; // Size of a single slice, in bytes. 189 size_t vslice_count; // Number of addressable slices. 190 size_t pslice_total_count; // Total number of allocatable slices. 191 size_t pslice_allocated_count; // Total number of currently allocated slices. 192 } fvm_info_t; 193 194 // ssize_t ioctl_block_fvm_query(int fd, fvm_info_t* info); 195 IOCTL_WRAPPER_OUT(ioctl_block_fvm_query, IOCTL_BLOCK_FVM_QUERY, fvm_info_t); 196 197 // ssize_t ioctl_block_fvm_vslice_query(int fd, query_request_t* request, 198 // query_response_t* response); 199 IOCTL_WRAPPER_INOUT(ioctl_block_fvm_vslice_query, IOCTL_BLOCK_FVM_VSLICE_QUERY, 200 query_request_t, query_response_t); 201 202 typedef struct { 203 uint8_t old_guid[GUID_LEN]; 204 uint8_t new_guid[GUID_LEN]; 205 } upgrade_req_t; 206 207 // ssize_t ioctl_block_fvm_upgrade(int fd, const upgrade_req_t* req); 208 IOCTL_WRAPPER_IN(ioctl_block_fvm_upgrade, IOCTL_BLOCK_FVM_UPGRADE, upgrade_req_t); 209 210 // ssize_t ioctl_block_get_stats(int fd, bool clear, block_stats_t* out) 211 IOCTL_WRAPPER_INOUT(ioctl_block_get_stats, IOCTL_BLOCK_GET_STATS, bool, block_stats_t); 212 213 // Multiple Block IO operations may be sent at once before a response is actually sent back. 214 // Block IO ops may be sent concurrently to different vmoids, and they also may be sent 215 // to different groups at any point in time. 216 // 217 // MAX_TXN_GROUP_COUNT "groups" are pre-allocated lanes separated on the block 218 // server. Using a group allows multiple message to be buffered at once 219 // on a single communication channel before receiving a response. 220 // 221 // Usage of groups is identified by BLOCKIO_GROUP_ITEM, and is optional. 222 // 223 // These groups may be referred to with a "groupid", in the range [0, 224 // MAX_TXN_GROUP_COUNT). 225 // 226 // The protocol to communicate with a single group is as follows: 227 // 1) SEND [N - 1] messages with an allocated groupid for any value of 1 <= N. 228 // The BLOCKIO_GROUP_ITEM flag is set for these messages. 229 // 2) SEND a final Nth message with the same groupid. 230 // The BLOCKIO_GROUP_ITEM | BLOCKIO_GROUP_LAST flags are set for this 231 // message. 232 // 3) RECEIVE a single response from the Block IO server after all N requests have completed. 233 // This response is sent once all operations either complete or a single operation fails. 234 // At this point, step (1) may begin again for the same groupid. 235 // 236 // For BLOCKIO_READ and BLOCKIO_WRITE, N may be greater than 1. 237 // Otherwise, N == 1 (skipping step (1) in the protocol above). 238 // 239 // Notes: 240 // - groupids may operate on any number of vmoids at once. 241 // - If additional requests are sent on the same groupid before step (3) has completed, then 242 // the additional request will not be processed. If BLOCKIO_GROUP_LAST is set, an error will 243 // be returned. Otherwise, the request will be silently dropped. 244 // - Messages within a group are not guaranteed to be processed in any order 245 // relative to each other. 246 // - All requests receive responses, except for ones with BLOCKIO_GROUP_ITEM 247 // that do not have BLOCKIO_GROUP_LAST set. 248 // 249 // For example, the following is a valid sequence of transactions: 250 // -> (groupid = 1, vmoid = 1, OP = Write | GroupItem, reqid = 1) 251 // -> (groupid = 1, vmoid = 2, OP = Write | GroupItem, reqid = 2) 252 // -> (groupid = 2, vmoid = 3, OP = Write | GroupItem | GroupLast, reqid = 0) 253 // <- Response sent to groupid = 2, reqid = 0 254 // -> (groupid = 1, vmoid = 1, OP = Read | GroupItem | GroupLast, reqid = 3) 255 // <- Response sent to groupid = 1, reqid = 3 256 // -> (groupid = 3, vmoid = 1, OP = Write | GroupItem, reqid = 4) 257 // -> (groupid = don't care, vmoid = 1, OP = Read, reqid = 5) 258 // <- Response sent to reqid = 5 259 // -> (groupid = 3, vmoid = 1, OP = Read | GroupItem | GroupLast, reqid = 6) 260 // <- Response sent to groupid = 3, reqid = 6 261 // 262 // Each transaction reads or writes up to 'length' blocks from the device, starting at 'dev_offset' 263 // blocks, into the VMO associated with 'vmoid', starting at 'vmo_offset' blocks. If the 264 // transaction is out of range, for example if 'length' is too large or if 'dev_offset' is beyond 265 // the end of the device, ZX_ERR_OUT_OF_RANGE is returned. 266 267 #define MAX_TXN_GROUP_COUNT 8 268 269 // The Request ID allowing callers to correspond requests with responses. 270 // This field is entirely for client-side bookkeeping; there is no obligation 271 // to make request IDs unique. 272 typedef uint32_t reqid_t; 273 typedef uint16_t groupid_t; 274 275 // Reads from the Block device into the VMO 276 #define BLOCKIO_READ 0x00000001 277 // Writes to the Block device from the VMO 278 #define BLOCKIO_WRITE 0x00000002 279 // Write any cached data to nonvolatile storage. 280 // Implies BARRIER_BEFORE and BARRIER_AFTER. 281 #define BLOCKIO_FLUSH 0x00000003 282 // Detaches the VMO from the block device. 283 #define BLOCKIO_CLOSE_VMO 0x00000004 284 #define BLOCKIO_OP_MASK 0x000000FF 285 286 // Require that this operation will not begin until all prior operations 287 // have completed. 288 #define BLOCKIO_BARRIER_BEFORE 0x00000100 289 // Require that this operation must complete before additional operations begin. 290 #define BLOCKIO_BARRIER_AFTER 0x00000200 291 // Associate the following request with |group|. 292 #define BLOCKIO_GROUP_ITEM 0x00000400 293 // Only respond after this request (and all previous within group) have completed. 294 // Only valid with BLOCKIO_GROUP_ITEM. 295 #define BLOCKIO_GROUP_LAST 0x00000800 296 #define BLOCKIO_FLAG_MASK 0x0000FF00 297 298 typedef struct { 299 uint32_t opcode; 300 reqid_t reqid; // Transmitted in the block_fifo_response_t. 301 groupid_t group; // Only used if opcode & BLOCKIO_GROUP_ITEM. 302 vmoid_t vmoid; 303 uint32_t length; 304 uint64_t vmo_offset; 305 uint64_t dev_offset; 306 } block_fifo_request_t; 307 308 typedef struct { 309 zx_status_t status; 310 reqid_t reqid; 311 groupid_t group; // Only valid if transmitted in request. 312 vmoid_t reserved0; 313 uint32_t count; // The number of messages in the transaction completed by the block server. 314 uint64_t reserved1; 315 uint64_t reserved2; 316 } block_fifo_response_t; 317 318 static_assert(sizeof(block_fifo_request_t) == sizeof(block_fifo_response_t), 319 "FIFO messages are the same size in both directions"); 320 321 #define BLOCK_FIFO_ESIZE (sizeof(block_fifo_request_t)) 322 #define BLOCK_FIFO_MAX_DEPTH (4096 / BLOCK_FIFO_ESIZE) 323