source: mainline/uspace/srv/bd/gxe_bd/gxe_bd.c@ c91f2d1b

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c91f2d1b was 95bc57c, checked in by Jiri Svoboda <jirik.svoboda@…>, 16 years ago

Servers can return value as soon as they are up. Use this with block-device drivers to start them synchronously. Eliminate ad-hoc sleeping.

  • Property mode set to 100644
File size: 6.7 KB
Line 
1/*
2 * Copyright (c) 2009 Jiri Svoboda
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 bd
30 * @{
31 */
32
33/**
34 * @file
35 * @brief GXemul disk driver
36 */
37
38#include <stdio.h>
39#include <libarch/ddi.h>
40#include <ddi.h>
41#include <ipc/ipc.h>
42#include <ipc/bd.h>
43#include <async.h>
44#include <as.h>
45#include <fibril_sync.h>
46#include <devmap.h>
47#include <sys/types.h>
48#include <errno.h>
49#include <task.h>
50
51#define NAME "gxe_bd"
52
53enum {
54 CTL_READ_START = 0,
55 CTL_WRITE_START = 1,
56};
57
58enum {
59 STATUS_FAILURE = 0
60};
61
62enum {
63 MAX_DISKS = 2
64};
65
66typedef struct {
67 uint32_t offset_lo;
68 uint32_t pad0;
69 uint32_t offset_hi;
70 uint32_t pad1;
71
72 uint32_t disk_id;
73 uint32_t pad2[3];
74
75 uint32_t control;
76 uint32_t pad3[3];
77
78 uint32_t status;
79
80 uint32_t pad4[3];
81 uint8_t pad5[0x3fc0];
82
83 uint8_t buffer[512];
84} gxe_bd_t;
85
86
87static const size_t block_size = 512;
88static size_t comm_size;
89
90static uintptr_t dev_physical = 0x13000000;
91static gxe_bd_t *dev;
92
93static dev_handle_t dev_handle[MAX_DISKS];
94
95static fibril_mutex_t dev_lock[MAX_DISKS];
96
97static int gxe_bd_init(void);
98static void gxe_bd_connection(ipc_callid_t iid, ipc_call_t *icall);
99static int gx_bd_rdwr(int disk_id, ipcarg_t method, off_t offset, size_t size,
100 void *buf);
101static int gxe_bd_read_block(int disk_id, uint64_t offset, size_t size,
102 void *buf);
103static int gxe_bd_write_block(int disk_id, uint64_t offset, size_t size,
104 const void *buf);
105
106int main(int argc, char **argv)
107{
108 printf(NAME ": GXemul disk driver\n");
109
110 if (gxe_bd_init() != EOK)
111 return -1;
112
113 printf(NAME ": Accepting connections\n");
114 task_retval(0);
115 async_manager();
116
117 /* Not reached */
118 return 0;
119}
120
121static int gxe_bd_init(void)
122{
123 void *vaddr;
124 int rc, i;
125 char name[16];
126
127 rc = devmap_driver_register(NAME, gxe_bd_connection);
128 if (rc < 0) {
129 printf(NAME ": Unable to register driver.\n");
130 return rc;
131 }
132
133 rc = pio_enable((void *) dev_physical, sizeof(gxe_bd_t), &vaddr);
134 if (rc != EOK) {
135 printf(NAME ": Could not initialize device I/O space.\n");
136 return rc;
137 }
138
139 dev = vaddr;
140
141 for (i = 0; i < MAX_DISKS; i++) {
142 snprintf(name, 16, "disk%d", i);
143 rc = devmap_device_register(name, &dev_handle[i]);
144 if (rc != EOK) {
145 devmap_hangup_phone(DEVMAP_DRIVER);
146 printf(NAME ": Unable to register device %s.\n",
147 name);
148 return rc;
149 }
150 fibril_mutex_initialize(&dev_lock[i]);
151 }
152
153 return EOK;
154}
155
156static void gxe_bd_connection(ipc_callid_t iid, ipc_call_t *icall)
157{
158 void *fs_va = NULL;
159 ipc_callid_t callid;
160 ipc_call_t call;
161 ipcarg_t method;
162 dev_handle_t dh;
163 int flags;
164 int retval;
165 off_t idx;
166 size_t size;
167 int disk_id, i;
168
169 /* Get the device handle. */
170 dh = IPC_GET_ARG1(*icall);
171
172 /* Determine which disk device is the client connecting to. */
173 disk_id = -1;
174 for (i = 0; i < MAX_DISKS; i++)
175 if (dev_handle[i] == dh)
176 disk_id = i;
177
178 if (disk_id < 0) {
179 ipc_answer_0(iid, EINVAL);
180 return;
181 }
182
183 /* Answer the IPC_M_CONNECT_ME_TO call. */
184 ipc_answer_0(iid, EOK);
185
186 if (!ipc_share_out_receive(&callid, &comm_size, &flags)) {
187 ipc_answer_0(callid, EHANGUP);
188 return;
189 }
190
191 fs_va = as_get_mappable_page(comm_size);
192 if (fs_va == NULL) {
193 ipc_answer_0(callid, EHANGUP);
194 return;
195 }
196
197 (void) ipc_share_out_finalize(callid, fs_va);
198
199 while (1) {
200 callid = async_get_call(&call);
201 method = IPC_GET_METHOD(call);
202 switch (method) {
203 case IPC_M_PHONE_HUNGUP:
204 /* The other side has hung up. */
205 ipc_answer_0(callid, EOK);
206 return;
207 case BD_READ_BLOCK:
208 case BD_WRITE_BLOCK:
209 idx = IPC_GET_ARG1(call);
210 size = IPC_GET_ARG2(call);
211 if (size > comm_size) {
212 retval = EINVAL;
213 break;
214 }
215 retval = gx_bd_rdwr(disk_id, method, idx * size,
216 size, fs_va);
217 break;
218 default:
219 retval = EINVAL;
220 break;
221 }
222 ipc_answer_0(callid, retval);
223 }
224}
225
226static int gx_bd_rdwr(int disk_id, ipcarg_t method, off_t offset, size_t size,
227 void *buf)
228{
229 int rc;
230 size_t now;
231
232 while (size > 0) {
233 now = size < block_size ? size : block_size;
234
235 if (method == BD_READ_BLOCK)
236 rc = gxe_bd_read_block(disk_id, offset, now, buf);
237 else
238 rc = gxe_bd_write_block(disk_id, offset, now, buf);
239
240 if (rc != EOK)
241 return rc;
242
243 buf += block_size;
244 offset += block_size;
245
246 if (size > block_size)
247 size -= block_size;
248 else
249 size = 0;
250 }
251
252 return EOK;
253}
254
255static int gxe_bd_read_block(int disk_id, uint64_t offset, size_t size,
256 void *buf)
257{
258 uint32_t status;
259 size_t i;
260 uint32_t w;
261
262 fibril_mutex_lock(&dev_lock[disk_id]);
263 pio_write_32(&dev->offset_lo, (uint32_t) offset);
264 pio_write_32(&dev->offset_hi, offset >> 32);
265 pio_write_32(&dev->disk_id, disk_id);
266 pio_write_32(&dev->control, CTL_READ_START);
267
268 status = pio_read_32(&dev->status);
269 if (status == STATUS_FAILURE) {
270 fibril_mutex_unlock(&dev_lock[disk_id]);
271 return EIO;
272 }
273
274 for (i = 0; i < size; i++) {
275 ((uint8_t *) buf)[i] = w = pio_read_8(&dev->buffer[i]);
276 }
277
278 fibril_mutex_unlock(&dev_lock[disk_id]);
279 return EOK;
280}
281
282static int gxe_bd_write_block(int disk_id, uint64_t offset, size_t size,
283 const void *buf)
284{
285 uint32_t status;
286 size_t i;
287
288 for (i = 0; i < size; i++) {
289 pio_write_8(&dev->buffer[i], ((const uint8_t *) buf)[i]);
290 }
291
292 fibril_mutex_lock(&dev_lock[disk_id]);
293 pio_write_32(&dev->offset_lo, (uint32_t) offset);
294 pio_write_32(&dev->offset_hi, offset >> 32);
295 pio_write_32(&dev->disk_id, disk_id);
296 pio_write_32(&dev->control, CTL_WRITE_START);
297
298 status = pio_read_32(&dev->status);
299 if (status == STATUS_FAILURE) {
300 fibril_mutex_unlock(&dev_lock[disk_id]);
301 return EIO;
302 }
303
304 fibril_mutex_unlock(&dev_lock[disk_id]);
305 return EOK;
306}
307
308/**
309 * @}
310 */
Note: See TracBrowser for help on using the repository browser.