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