source: mainline/uspace/lib/device/src/hr.c@ ca7fa5b

Last change on this file since ca7fa5b was ca7fa5b, checked in by Miroslav Cimerman <mc@…>, 4 months ago

hr: use <inttypes.h> macro specifiers

  • Property mode set to 100644
File size: 10.0 KB
Line 
1/*
2 * Copyright (c) 2025 Miroslav Cimerman
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libdevice
30 * @{
31 */
32/**
33 * @file
34 */
35
36#include <abi/ipc/interfaces.h>
37#include <async.h>
38#include <hr.h>
39#include <ipc/hr.h>
40#include <ipc/services.h>
41#include <loc.h>
42#include <stdlib.h>
43#include <stdio.h>
44#include <str.h>
45
46errno_t hr_sess_init(hr_t **rhr)
47{
48 errno_t rc;
49 hr_t *hr = NULL;
50
51 if (rhr == NULL)
52 return EINVAL;
53
54 hr = calloc(1, sizeof(hr_t));
55 if (hr == NULL) {
56 rc = ENOMEM;
57 goto error;
58 }
59
60 service_id_t hr_svcid;
61
62 rc = loc_service_get_id(SERVICE_NAME_HR, &hr_svcid, 0);
63 if (rc != EOK)
64 goto error;
65
66 hr->sess = loc_service_connect(hr_svcid, INTERFACE_HR, 0);
67 if (hr->sess == NULL) {
68 rc = EIO;
69 goto error;
70 }
71
72 *rhr = hr;
73 return EOK;
74error:
75 if (hr != NULL)
76 free(hr);
77
78 return rc;
79}
80
81void hr_sess_destroy(hr_t *hr)
82{
83 if (hr == NULL)
84 return;
85
86 async_hangup(hr->sess);
87 free(hr);
88}
89
90errno_t hr_create(hr_t *hr, hr_config_t *hr_config)
91{
92 errno_t rc, retval;
93 async_exch_t *exch;
94 aid_t req;
95
96 exch = async_exchange_begin(hr->sess);
97 if (exch == NULL)
98 return EINVAL;
99
100 req = async_send_0(exch, HR_CREATE, NULL);
101
102 rc = async_data_write_start(exch, hr_config, sizeof(hr_config_t));
103 if (rc != EOK) {
104 async_exchange_end(exch);
105 async_forget(req);
106 return rc;
107 }
108
109 async_exchange_end(exch);
110 async_wait_for(req, &retval);
111 if (retval != EOK)
112 return retval;
113
114 return EOK;
115}
116
117errno_t hr_assemble(hr_t *hr, hr_config_t *hr_config, size_t *rassembled_cnt)
118{
119 errno_t rc;
120 async_exch_t *exch;
121 aid_t req;
122 size_t assembled_cnt;
123
124 exch = async_exchange_begin(hr->sess);
125 if (exch == NULL)
126 return EINVAL;
127
128 req = async_send_0(exch, HR_ASSEMBLE, NULL);
129
130 rc = async_data_write_start(exch, hr_config, sizeof(hr_config_t));
131 if (rc != EOK) {
132 async_exchange_end(exch);
133 async_forget(req);
134 return rc;
135 }
136
137 rc = async_data_read_start(exch, &assembled_cnt, sizeof(size_t));
138 if (rc != EOK) {
139 async_exchange_end(exch);
140 async_forget(req);
141 return rc;
142 }
143
144 async_exchange_end(exch);
145 async_wait_for(req, &rc);
146
147 if (rassembled_cnt != NULL)
148 *rassembled_cnt = assembled_cnt;
149
150 return rc;
151}
152
153errno_t hr_auto_assemble(size_t *rassembled_cnt)
154{
155 hr_t *hr;
156 errno_t rc;
157 size_t assembled_cnt;
158
159 rc = hr_sess_init(&hr);
160 if (rc != EOK)
161 return rc;
162
163 async_exch_t *exch = async_exchange_begin(hr->sess);
164 if (exch == NULL) {
165 rc = EINVAL;
166 goto error;
167 }
168
169 aid_t req = async_send_0(exch, HR_AUTO_ASSEMBLE, NULL);
170
171 rc = async_data_read_start(exch, &assembled_cnt, sizeof(size_t));
172 if (rc != EOK) {
173 async_exchange_end(exch);
174 async_forget(req);
175 return rc;
176 }
177
178 async_exchange_end(exch);
179 async_wait_for(req, &rc);
180
181 if (rassembled_cnt != NULL)
182 *rassembled_cnt = assembled_cnt;
183error:
184 hr_sess_destroy(hr);
185 return rc;
186}
187
188static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info)
189{
190 errno_t rc;
191 size_t i;
192 char *devname;
193 hr_extent_t *ext;
194
195 printf("--- vol %zu ---\n", index);
196
197 printf("svc_id: %" PRIun "\n", vol_info->svc_id);
198
199 rc = loc_service_get_name(vol_info->svc_id, &devname);
200 if (rc != EOK)
201 return rc;
202 printf("devname: %s\n", devname);
203
204 printf("status: %s\n", hr_get_vol_status_msg(vol_info->status));
205
206 printf("level: %d\n", vol_info->level);
207 if (vol_info->level == HR_LVL_4 || vol_info->level == HR_LVL_5) {
208 printf("layout: %s\n",
209 hr_get_layout_str(vol_info->level, vol_info->layout));
210 }
211 if (vol_info->level == HR_LVL_0 || vol_info->level == HR_LVL_4) {
212 if (vol_info->strip_size / 1024 < 1)
213 printf("strip size in bytes: %" PRIu32 "\n",
214 vol_info->strip_size);
215 else
216 printf("strip size: %" PRIu32 "K\n",
217 vol_info->strip_size / 1024);
218 }
219 printf("size in bytes: %" PRIu64 "MiB\n",
220 vol_info->nblocks * vol_info->bsize / 1024 / 1024);
221 printf("size in blocks: %" PRIu64 "\n", vol_info->nblocks);
222 printf("block size: %zu\n", vol_info->bsize);
223
224 if (vol_info->level == HR_LVL_4)
225 printf("extents: [P] [status] [index] [devname]\n");
226 else
227 printf("extents: [status] [index] [devname]\n");
228 for (i = 0; i < vol_info->extent_no; i++) {
229 ext = &vol_info->extents[i];
230 if (ext->status == HR_EXT_MISSING || ext->status == HR_EXT_NONE) {
231 devname = (char *) "MISSING-devname";
232 } else {
233 rc = loc_service_get_name(ext->svc_id, &devname);
234 if (rc != EOK) {
235 printf("loc_service_get_name() failed, skipping...\n");
236 continue;
237 }
238 }
239 if (vol_info->level == HR_LVL_4) {
240 if ((i == 0 && vol_info->layout == HR_RLQ_RAID4_0) ||
241 (i == vol_info->extent_no - 1 &&
242 vol_info->layout == HR_RLQ_RAID4_N))
243 printf(" P %s %zu %s\n", hr_get_ext_status_msg(ext->status), i, devname);
244 else
245 printf(" %s %zu %s\n", hr_get_ext_status_msg(ext->status), i, devname);
246 } else {
247 printf(" %s %zu %s\n", hr_get_ext_status_msg(ext->status), i, devname);
248 }
249 }
250
251 if (vol_info->hotspare_no == 0)
252 return EOK;
253
254 printf("hotspares: [status] [index] [devname]\n");
255 for (i = 0; i < vol_info->hotspare_no; i++) {
256 ext = &vol_info->hotspares[i];
257 if (ext->status == HR_EXT_MISSING) {
258 devname = (char *) "MISSING-devname";
259 } else {
260 rc = loc_service_get_name(ext->svc_id, &devname);
261 if (rc != EOK)
262 return rc;
263 }
264 printf(" %s %zu %s\n",
265 hr_get_ext_status_msg(ext->status), i, devname);
266 }
267
268 return EOK;
269}
270
271errno_t hr_stop(const char *devname, long extent)
272{
273 hr_t *hr;
274 errno_t rc;
275 async_exch_t *exch;
276 service_id_t svc_id;
277
278 rc = loc_service_get_id(devname, &svc_id, 0);
279 if (rc != EOK)
280 return rc;
281
282 rc = hr_sess_init(&hr);
283 if (rc != EOK)
284 return rc;
285
286 exch = async_exchange_begin(hr->sess);
287 if (exch == NULL) {
288 rc = EINVAL;
289 goto error;
290 }
291 rc = async_req_2_0(exch, HR_STOP, svc_id, extent);
292 async_exchange_end(exch);
293error:
294 hr_sess_destroy(hr);
295 return rc;
296}
297
298errno_t hr_add_hotspare(service_id_t vol_svc_id, service_id_t hs_svc_id)
299{
300 hr_t *hr;
301 errno_t rc;
302 async_exch_t *exch;
303
304 rc = hr_sess_init(&hr);
305 if (rc != EOK)
306 return rc;
307
308 exch = async_exchange_begin(hr->sess);
309 if (exch == NULL) {
310 rc = EINVAL;
311 goto error;
312 }
313
314 rc = async_req_2_0(exch, HR_ADD_HOTSPARE, vol_svc_id, hs_svc_id);
315 async_exchange_end(exch);
316error:
317 hr_sess_destroy(hr);
318 return rc;
319}
320
321errno_t hr_print_status(void)
322{
323 hr_t *hr;
324 errno_t rc, retval;
325 async_exch_t *exch;
326 aid_t req;
327 size_t size, i;
328 hr_vol_info_t *vols = NULL;
329
330 rc = hr_sess_init(&hr);
331 if (rc != EOK)
332 return rc;
333
334 exch = async_exchange_begin(hr->sess);
335 if (exch == NULL) {
336 rc = EINVAL;
337 goto error;
338 }
339
340 req = async_send_0(exch, HR_STATUS, NULL);
341 rc = async_data_read_start(exch, &size, sizeof(size_t));
342 if (rc != EOK) {
343 async_exchange_end(exch);
344 async_forget(req);
345 return rc;
346 }
347
348 vols = calloc(size, sizeof(hr_vol_info_t));
349 if (vols == NULL) {
350 async_exchange_end(exch);
351 async_forget(req);
352 return ENOMEM;
353 }
354
355 for (i = 0; i < size; i++) {
356 rc = async_data_read_start(exch, &vols[i],
357 sizeof(hr_vol_info_t));
358 if (rc != EOK) {
359 async_exchange_end(exch);
360 async_forget(req);
361 goto error;
362 }
363 }
364
365 async_exchange_end(exch);
366 async_wait_for(req, &retval);
367 if (retval != EOK) {
368 rc = retval;
369 goto error;
370 }
371
372 if (size == 0) {
373 printf("no active arrays\n");
374 goto error;
375 }
376
377 for (i = 0; i < size; i++) {
378 rc = print_vol_info(i, &vols[i]);
379 if (rc != EOK)
380 goto error;
381 }
382
383error:
384 hr_sess_destroy(hr);
385 if (vols != NULL)
386 free(vols);
387 return rc;
388}
389
390const char *hr_get_vol_status_msg(hr_vol_status_t status)
391{
392 switch (status) {
393 case HR_VOL_NONE:
394 return "NONE/UNKNOWN";
395 case HR_VOL_ONLINE:
396 return "ONLINE";
397 case HR_VOL_FAULTY:
398 return "FAULTY";
399 case HR_VOL_DEGRADED:
400 return "DEGRADED";
401 case HR_VOL_REBUILD:
402 return "REBUILD";
403 default:
404 return "Invalid state value";
405 }
406}
407
408const char *hr_get_ext_status_msg(hr_ext_status_t status)
409{
410 switch (status) {
411 case HR_EXT_NONE:
412 return "NONE/UNKNOWN";
413 case HR_EXT_INVALID:
414 return "INVALID";
415 case HR_EXT_ONLINE:
416 return "ONLINE";
417 case HR_EXT_MISSING:
418 return "MISSING";
419 case HR_EXT_FAILED:
420 return "FAILED";
421 case HR_EXT_REBUILD:
422 return "REBUILD";
423 case HR_EXT_HOTSPARE:
424 return "HOTSPARE";
425 default:
426 return "Invalid state value";
427 }
428}
429
430const char *hr_get_layout_str(hr_level_t level, uint8_t layout)
431{
432 switch (level) {
433 case HR_LVL_4:
434 switch (layout) {
435 case HR_RLQ_RAID4_0:
436 return "RAID-4 Non-Rotating Parity 0";
437 case HR_RLQ_RAID4_N:
438 return "RAID-4 Non-Rotating Parity N";
439 default:
440 return "Invalid RAID 4 layout";
441 }
442 case HR_LVL_5:
443 switch (layout) {
444 case HR_RLQ_RAID5_0R:
445 return "RAID-5 Rotating Parity 0 with Data Restart";
446 case HR_RLQ_RAID5_NR:
447 return "RAID-5 Rotating Parity N with Data Restart";
448 case HR_RLQ_RAID5_NC:
449 return "RAID-5 Rotating Parity N with Data Continuation";
450 default:
451 return "Invalid RAID 5 layout";
452 }
453 default:
454 return "Invalid RAID level";
455 }
456}
457
458/** @}
459 */
Note: See TracBrowser for help on using the repository browser.