source: mainline/uspace/lib/drv/generic/remote_ahci.c@ 132ab5d1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 132ab5d1 was 25a179e, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 8 years ago

IPC return values are always errno constants. Adjust types to reflect that.

In principle, IPC server is not allowed to return non-errno values via
the "main" return value, because kernel interprets it (e.g. EHANGUP).
It's still possible to return arbitrary additional return values alongside EOK,
which are not interpreted in normal communication.

  • Property mode set to 100644
File size: 8.8 KB
Line 
1/*
2 * Copyright (c) 2012 Petr Jerman
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 libdrv
30 * @{
31 */
32/** @file
33 */
34
35#include <as.h>
36#include <async.h>
37#include <devman.h>
38#include <errno.h>
39#include <stdio.h>
40#include <macros.h>
41#include "ahci_iface.h"
42#include "ddf/driver.h"
43
44typedef enum {
45 IPC_M_AHCI_GET_SATA_DEVICE_NAME,
46 IPC_M_AHCI_GET_NUM_BLOCKS,
47 IPC_M_AHCI_GET_BLOCK_SIZE,
48 IPC_M_AHCI_READ_BLOCKS,
49 IPC_M_AHCI_WRITE_BLOCKS
50} ahci_iface_funcs_t;
51
52#define MAX_NAME_LENGTH 1024
53
54#define LO(ptr) \
55 ((uint32_t) (((uint64_t) ((uintptr_t) (ptr))) & 0xffffffff))
56
57#define HI(ptr) \
58 ((uint32_t) (((uint64_t) ((uintptr_t) (ptr))) >> 32))
59
60async_sess_t* ahci_get_sess(devman_handle_t funh, char **name)
61{
62 // FIXME: Use a better way than substring match
63
64 *name = NULL;
65
66 char devn[MAX_NAME_LENGTH];
67 int rc = devman_fun_get_name(funh, devn, MAX_NAME_LENGTH);
68 if (rc != EOK)
69 return NULL;
70
71 size_t devn_size = str_size(devn);
72
73 if ((devn_size > 5) && (str_lcmp(devn, "ahci_", 5) == 0)) {
74 async_sess_t *sess = devman_device_connect(funh, IPC_FLAG_BLOCKING);
75
76 if (sess) {
77 *name = str_dup(devn);
78 return sess;
79 }
80 }
81
82 return NULL;
83}
84
85int ahci_get_sata_device_name(async_sess_t *sess, size_t sata_dev_name_length,
86 char *sata_dev_name)
87{
88 async_exch_t *exch = async_exchange_begin(sess);
89 if (!exch)
90 return EINVAL;
91
92 aid_t req = async_send_2(exch, DEV_IFACE_ID(AHCI_DEV_IFACE),
93 IPC_M_AHCI_GET_SATA_DEVICE_NAME, sata_dev_name_length, NULL);
94
95 async_data_read_start(exch, sata_dev_name, sata_dev_name_length);
96
97 int rc;
98 async_wait_for(req, &rc);
99
100 return rc;
101}
102
103int ahci_get_num_blocks(async_sess_t *sess, uint64_t *blocks)
104{
105 async_exch_t *exch = async_exchange_begin(sess);
106 if (!exch)
107 return EINVAL;
108
109 sysarg_t blocks_hi;
110 sysarg_t blocks_lo;
111 int rc = async_req_1_2(exch, DEV_IFACE_ID(AHCI_DEV_IFACE),
112 IPC_M_AHCI_GET_NUM_BLOCKS, &blocks_hi, &blocks_lo);
113
114 async_exchange_end(exch);
115
116 if (rc == EOK) {
117 *blocks = (((uint64_t) blocks_hi) << 32)
118 | (((uint64_t) blocks_lo) & 0xffffffff);
119 }
120
121 return rc;
122}
123
124int ahci_get_block_size(async_sess_t *sess, size_t *blocks_size)
125{
126 async_exch_t *exch = async_exchange_begin(sess);
127 if (!exch)
128 return EINVAL;
129
130 sysarg_t bs;
131 int rc = async_req_1_1(exch, DEV_IFACE_ID(AHCI_DEV_IFACE),
132 IPC_M_AHCI_GET_BLOCK_SIZE, &bs);
133
134 async_exchange_end(exch);
135
136 if (rc == EOK)
137 *blocks_size = (size_t) bs;
138
139 return rc;
140}
141
142int ahci_read_blocks(async_sess_t *sess, uint64_t blocknum, size_t count,
143 void *buf)
144{
145 async_exch_t *exch = async_exchange_begin(sess);
146 if (!exch)
147 return EINVAL;
148
149 aid_t req;
150 req = async_send_4(exch, DEV_IFACE_ID(AHCI_DEV_IFACE),
151 IPC_M_AHCI_READ_BLOCKS, HI(blocknum), LO(blocknum), count, NULL);
152
153 async_share_out_start(exch, buf, AS_AREA_READ | AS_AREA_WRITE);
154
155 async_exchange_end(exch);
156
157 int rc;
158 async_wait_for(req, &rc);
159
160 return rc;
161}
162
163int ahci_write_blocks(async_sess_t *sess, uint64_t blocknum, size_t count,
164 void* buf)
165{
166 async_exch_t *exch = async_exchange_begin(sess);
167 if (!exch)
168 return EINVAL;
169
170 aid_t req = async_send_4(exch, DEV_IFACE_ID(AHCI_DEV_IFACE),
171 IPC_M_AHCI_WRITE_BLOCKS, HI(blocknum), LO(blocknum), count, NULL);
172
173 async_share_out_start(exch, buf, AS_AREA_READ | AS_AREA_WRITE);
174
175 async_exchange_end(exch);
176
177 int rc;
178 async_wait_for(req, &rc);
179
180 return rc;
181}
182
183static void remote_ahci_get_sata_device_name(ddf_fun_t *, void *, ipc_callid_t,
184 ipc_call_t *);
185static void remote_ahci_get_num_blocks(ddf_fun_t *, void *, ipc_callid_t,
186 ipc_call_t *);
187static void remote_ahci_get_block_size(ddf_fun_t *, void *, ipc_callid_t,
188 ipc_call_t *);
189static void remote_ahci_read_blocks(ddf_fun_t *, void *, ipc_callid_t,
190 ipc_call_t *);
191static void remote_ahci_write_blocks(ddf_fun_t *, void *, ipc_callid_t,
192 ipc_call_t *);
193
194/** Remote AHCI interface operations. */
195static const remote_iface_func_ptr_t remote_ahci_iface_ops [] = {
196 [IPC_M_AHCI_GET_SATA_DEVICE_NAME] = remote_ahci_get_sata_device_name,
197 [IPC_M_AHCI_GET_NUM_BLOCKS] = remote_ahci_get_num_blocks,
198 [IPC_M_AHCI_GET_BLOCK_SIZE] = remote_ahci_get_block_size,
199 [IPC_M_AHCI_READ_BLOCKS] = remote_ahci_read_blocks,
200 [IPC_M_AHCI_WRITE_BLOCKS] = remote_ahci_write_blocks
201};
202
203/** Remote AHCI interface structure.
204 */
205const remote_iface_t remote_ahci_iface = {
206 .method_count = ARRAY_SIZE(remote_ahci_iface_ops),
207 .methods = remote_ahci_iface_ops
208};
209
210void remote_ahci_get_sata_device_name(ddf_fun_t *fun, void *iface,
211 ipc_callid_t callid, ipc_call_t *call)
212{
213 const ahci_iface_t *ahci_iface = (ahci_iface_t *) iface;
214
215 if (ahci_iface->get_sata_device_name == NULL) {
216 async_answer_0(callid, ENOTSUP);
217 return;
218 }
219
220 const size_t sata_dev_name_length =
221 (size_t) DEV_IPC_GET_ARG1(*call);
222
223 char* sata_dev_name = malloc(sata_dev_name_length);
224 if (sata_dev_name == NULL) {
225 async_answer_0(callid, ENOMEM);
226 return;
227 }
228
229 const int ret = ahci_iface->get_sata_device_name(fun,
230 sata_dev_name_length, sata_dev_name);
231
232 size_t real_size;
233 ipc_callid_t cid;
234 if ((async_data_read_receive(&cid, &real_size)) &&
235 (real_size == sata_dev_name_length))
236 async_data_read_finalize(cid, sata_dev_name, sata_dev_name_length);
237
238 free(sata_dev_name);
239 async_answer_0(callid, ret);
240}
241
242static void remote_ahci_get_num_blocks(ddf_fun_t *fun, void *iface,
243 ipc_callid_t callid, ipc_call_t *call)
244{
245 const ahci_iface_t *ahci_iface = (ahci_iface_t *) iface;
246
247 if (ahci_iface->get_num_blocks == NULL) {
248 async_answer_0(callid, ENOTSUP);
249 return;
250 }
251
252 uint64_t blocks;
253 const int ret = ahci_iface->get_num_blocks(fun, &blocks);
254
255 if (ret != EOK)
256 async_answer_0(callid, ret);
257 else
258 async_answer_2(callid, EOK, HI(blocks), LO(blocks));
259}
260
261static void remote_ahci_get_block_size(ddf_fun_t *fun, void *iface,
262 ipc_callid_t callid, ipc_call_t *call)
263{
264 const ahci_iface_t *ahci_iface = (ahci_iface_t *) iface;
265
266 if (ahci_iface->get_block_size == NULL) {
267 async_answer_0(callid, ENOTSUP);
268 return;
269 }
270
271 size_t blocks;
272 const int ret = ahci_iface->get_block_size(fun, &blocks);
273
274 if (ret != EOK)
275 async_answer_0(callid, ret);
276 else
277 async_answer_1(callid, EOK, blocks);
278}
279
280void remote_ahci_read_blocks(ddf_fun_t *fun, void *iface,
281 ipc_callid_t callid, ipc_call_t *call)
282{
283 const ahci_iface_t *ahci_iface = (ahci_iface_t *) iface;
284
285 if (ahci_iface->read_blocks == NULL) {
286 async_answer_0(callid, ENOTSUP);
287 return;
288 }
289
290 size_t maxblock_size;
291 unsigned int flags;
292
293 ipc_callid_t cid;
294 async_share_out_receive(&cid, &maxblock_size, &flags);
295
296 void *buf;
297 async_share_out_finalize(cid, &buf);
298
299 const uint64_t blocknum =
300 (((uint64_t) (DEV_IPC_GET_ARG1(*call))) << 32) |
301 (((uint64_t) (DEV_IPC_GET_ARG2(*call))) & 0xffffffff);
302 const size_t cnt = (size_t) DEV_IPC_GET_ARG3(*call);
303
304 const int ret = ahci_iface->read_blocks(fun, blocknum, cnt, buf);
305
306 async_answer_0(callid, ret);
307}
308
309void remote_ahci_write_blocks(ddf_fun_t *fun, void *iface, ipc_callid_t callid,
310 ipc_call_t *call)
311{
312 const ahci_iface_t *ahci_iface = (ahci_iface_t *) iface;
313
314 if (ahci_iface->read_blocks == NULL) {
315 async_answer_0(callid, ENOTSUP);
316 return;
317 }
318
319 size_t maxblock_size;
320 unsigned int flags;
321
322 ipc_callid_t cid;
323 async_share_out_receive(&cid, &maxblock_size, &flags);
324
325 void *buf;
326 async_share_out_finalize(cid, &buf);
327
328 const uint64_t blocknum =
329 (((uint64_t)(DEV_IPC_GET_ARG1(*call))) << 32) |
330 (((uint64_t)(DEV_IPC_GET_ARG2(*call))) & 0xffffffff);
331 const size_t cnt = (size_t) DEV_IPC_GET_ARG3(*call);
332
333 const int ret = ahci_iface->write_blocks(fun, blocknum, cnt, buf);
334
335 async_answer_0(callid, ret);
336}
337
338/**
339 * @}
340 */
Note: See TracBrowser for help on using the repository browser.