1 | /* |
2 | * Common code for block device models |
3 | * |
4 | * Copyright (C) 2012 Red Hat, Inc. |
5 | * |
6 | * This work is licensed under the terms of the GNU GPL, version 2 or |
7 | * later. See the COPYING file in the top-level directory. |
8 | */ |
9 | |
10 | #include "qemu/osdep.h" |
11 | #include "sysemu/blockdev.h" |
12 | #include "sysemu/block-backend.h" |
13 | #include "hw/block/block.h" |
14 | #include "qapi/error.h" |
15 | #include "qapi/qapi-types-block.h" |
16 | |
17 | /* |
18 | * Read the entire contents of @blk into @buf. |
19 | * @blk's contents must be @size bytes, and @size must be at most |
20 | * BDRV_REQUEST_MAX_BYTES. |
21 | * On success, return true. |
22 | * On failure, store an error through @errp and return false. |
23 | * Note that the error messages do not identify the block backend. |
24 | * TODO Since callers don't either, this can result in confusing |
25 | * errors. |
26 | * This function not intended for actual block devices, which read on |
27 | * demand. It's for things like memory devices that (ab)use a block |
28 | * backend to provide persistence. |
29 | */ |
30 | bool blk_check_size_and_read_all(BlockBackend *blk, void *buf, hwaddr size, |
31 | Error **errp) |
32 | { |
33 | int64_t blk_len; |
34 | int ret; |
35 | |
36 | blk_len = blk_getlength(blk); |
37 | if (blk_len < 0) { |
38 | error_setg_errno(errp, -blk_len, |
39 | "can't get size of block backend" ); |
40 | return false; |
41 | } |
42 | if (blk_len != size) { |
43 | error_setg(errp, "device requires %" HWADDR_PRIu " bytes, " |
44 | "block backend provides %" PRIu64 " bytes" , |
45 | size, blk_len); |
46 | return false; |
47 | } |
48 | |
49 | /* |
50 | * We could loop for @size > BDRV_REQUEST_MAX_BYTES, but if we |
51 | * ever get to the point we want to read *gigabytes* here, we |
52 | * should probably rework the device to be more like an actual |
53 | * block device and read only on demand. |
54 | */ |
55 | assert(size <= BDRV_REQUEST_MAX_BYTES); |
56 | ret = blk_pread(blk, 0, buf, size); |
57 | if (ret < 0) { |
58 | error_setg_errno(errp, -ret, "can't read block backend" ); |
59 | return false; |
60 | } |
61 | return true; |
62 | } |
63 | |
64 | void blkconf_blocksizes(BlockConf *conf) |
65 | { |
66 | BlockBackend *blk = conf->blk; |
67 | BlockSizes blocksizes; |
68 | int backend_ret; |
69 | |
70 | backend_ret = blk_probe_blocksizes(blk, &blocksizes); |
71 | /* fill in detected values if they are not defined via qemu command line */ |
72 | if (!conf->physical_block_size) { |
73 | if (!backend_ret) { |
74 | conf->physical_block_size = blocksizes.phys; |
75 | } else { |
76 | conf->physical_block_size = BDRV_SECTOR_SIZE; |
77 | } |
78 | } |
79 | if (!conf->logical_block_size) { |
80 | if (!backend_ret) { |
81 | conf->logical_block_size = blocksizes.log; |
82 | } else { |
83 | conf->logical_block_size = BDRV_SECTOR_SIZE; |
84 | } |
85 | } |
86 | } |
87 | |
88 | bool blkconf_apply_backend_options(BlockConf *conf, bool readonly, |
89 | bool resizable, Error **errp) |
90 | { |
91 | BlockBackend *blk = conf->blk; |
92 | BlockdevOnError rerror, werror; |
93 | uint64_t perm, shared_perm; |
94 | bool wce; |
95 | int ret; |
96 | |
97 | perm = BLK_PERM_CONSISTENT_READ; |
98 | if (!readonly) { |
99 | perm |= BLK_PERM_WRITE; |
100 | } |
101 | |
102 | shared_perm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED | |
103 | BLK_PERM_GRAPH_MOD; |
104 | if (resizable) { |
105 | shared_perm |= BLK_PERM_RESIZE; |
106 | } |
107 | if (conf->share_rw) { |
108 | shared_perm |= BLK_PERM_WRITE; |
109 | } |
110 | |
111 | ret = blk_set_perm(blk, perm, shared_perm, errp); |
112 | if (ret < 0) { |
113 | return false; |
114 | } |
115 | |
116 | switch (conf->wce) { |
117 | case ON_OFF_AUTO_ON: wce = true; break; |
118 | case ON_OFF_AUTO_OFF: wce = false; break; |
119 | case ON_OFF_AUTO_AUTO: wce = blk_enable_write_cache(blk); break; |
120 | default: |
121 | abort(); |
122 | } |
123 | |
124 | rerror = conf->rerror; |
125 | if (rerror == BLOCKDEV_ON_ERROR_AUTO) { |
126 | rerror = blk_get_on_error(blk, true); |
127 | } |
128 | |
129 | werror = conf->werror; |
130 | if (werror == BLOCKDEV_ON_ERROR_AUTO) { |
131 | werror = blk_get_on_error(blk, false); |
132 | } |
133 | |
134 | blk_set_enable_write_cache(blk, wce); |
135 | blk_set_on_error(blk, rerror, werror); |
136 | |
137 | return true; |
138 | } |
139 | |
140 | bool blkconf_geometry(BlockConf *conf, int *ptrans, |
141 | unsigned cyls_max, unsigned heads_max, unsigned secs_max, |
142 | Error **errp) |
143 | { |
144 | if (!conf->cyls && !conf->heads && !conf->secs) { |
145 | hd_geometry_guess(conf->blk, |
146 | &conf->cyls, &conf->heads, &conf->secs, |
147 | ptrans); |
148 | } else if (ptrans && *ptrans == BIOS_ATA_TRANSLATION_AUTO) { |
149 | *ptrans = hd_bios_chs_auto_trans(conf->cyls, conf->heads, conf->secs); |
150 | } |
151 | if (conf->cyls || conf->heads || conf->secs) { |
152 | if (conf->cyls < 1 || conf->cyls > cyls_max) { |
153 | error_setg(errp, "cyls must be between 1 and %u" , cyls_max); |
154 | return false; |
155 | } |
156 | if (conf->heads < 1 || conf->heads > heads_max) { |
157 | error_setg(errp, "heads must be between 1 and %u" , heads_max); |
158 | return false; |
159 | } |
160 | if (conf->secs < 1 || conf->secs > secs_max) { |
161 | error_setg(errp, "secs must be between 1 and %u" , secs_max); |
162 | return false; |
163 | } |
164 | } |
165 | return true; |
166 | } |
167 | |