source: mainline/uspace/srv/bd/gxe_bd/gxe_bd.c@ 8559fa0

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 8559fa0 was f73b291, checked in by Martin Decky <martin@…>, 13 years ago

libblock.{c|h} → block.{c|h}

  • Property mode set to 100644
File size: 7.6 KB
RevLine 
[44a53fd]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 <async.h>
42#include <as.h>
[4802dd7]43#include <bd_srv.h>
[1e4cada]44#include <fibril_synch.h>
[15f3c3f]45#include <loc.h>
[44a53fd]46#include <sys/types.h>
47#include <errno.h>
[1ee00b7]48#include <macros.h>
[95bc57c]49#include <task.h>
[44a53fd]50
[1313ee9]51#define NAME "gxe_bd"
52#define NAMESPACE "bd"
[44a53fd]53
54enum {
55 CTL_READ_START = 0,
56 CTL_WRITE_START = 1,
57};
58
59enum {
60 STATUS_FAILURE = 0
61};
62
[84adbf0]63enum {
64 MAX_DISKS = 2
65};
66
[4802dd7]67/** GXE disk hardware registers */
[44a53fd]68typedef struct {
69 uint32_t offset_lo;
70 uint32_t pad0;
71 uint32_t offset_hi;
72 uint32_t pad1;
73
74 uint32_t disk_id;
75 uint32_t pad2[3];
76
77 uint32_t control;
78 uint32_t pad3[3];
79
80 uint32_t status;
81
82 uint32_t pad4[3];
[39580667]83 uint8_t pad5[0x3fc0];
[44a53fd]84
[39580667]85 uint8_t buffer[512];
[4802dd7]86} gxe_bd_hw_t;
[44a53fd]87
[4802dd7]88/** GXE block device soft state */
89typedef struct {
[135486d]90 /** Block device service structure */
91 bd_srvs_t bds;
[4802dd7]92 int disk_id;
93} gxe_bd_t;
[44a53fd]94
[3ecc02e]95static const size_t block_size = 512;
96
[44a53fd]97static uintptr_t dev_physical = 0x13000000;
[4802dd7]98static gxe_bd_hw_t *dev;
[44a53fd]99
[15f3c3f]100static service_id_t service_id[MAX_DISKS];
[44a53fd]101
[12956e57]102static fibril_mutex_t dev_lock[MAX_DISKS];
[44a53fd]103
[4802dd7]104static gxe_bd_t gxe_bd[MAX_DISKS];
105
[44a53fd]106static int gxe_bd_init(void);
[9934f7d]107static void gxe_bd_connection(ipc_callid_t iid, ipc_call_t *icall, void *);
[1ee00b7]108static int gxe_bd_read_block(int disk_id, uint64_t ba, void *buf);
109static int gxe_bd_write_block(int disk_id, uint64_t ba, const void *buf);
[44a53fd]110
[135486d]111static int gxe_bd_open(bd_srvs_t *, bd_srv_t *);
[4802dd7]112static int gxe_bd_close(bd_srv_t *);
113static int gxe_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, size_t);
114static int gxe_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, const void *, size_t);
115static int gxe_bd_get_block_size(bd_srv_t *, size_t *);
116static int gxe_bd_get_num_blocks(bd_srv_t *, aoff64_t *);
117
118static bd_ops_t gxe_bd_ops = {
119 .open = gxe_bd_open,
120 .close = gxe_bd_close,
121 .read_blocks = gxe_bd_read_blocks,
122 .write_blocks = gxe_bd_write_blocks,
123 .get_block_size = gxe_bd_get_block_size,
124 .get_num_blocks = gxe_bd_get_num_blocks
125};
126
127static gxe_bd_t *bd_srv_gxe(bd_srv_t *bd)
128{
[f73b291]129 return (gxe_bd_t *) bd->srvs->sarg;
[4802dd7]130}
131
[44a53fd]132int main(int argc, char **argv)
133{
134 printf(NAME ": GXemul disk driver\n");
135
136 if (gxe_bd_init() != EOK)
137 return -1;
138
139 printf(NAME ": Accepting connections\n");
[95bc57c]140 task_retval(0);
[44a53fd]141 async_manager();
142
143 /* Not reached */
144 return 0;
145}
146
147static int gxe_bd_init(void)
148{
[f302586]149 async_set_client_connection(gxe_bd_connection);
[b16e77d]150 int rc = loc_server_register(NAME);
151 if (rc != EOK) {
152 printf("%s: Unable to register driver.\n", NAME);
[44a53fd]153 return rc;
154 }
[b16e77d]155
156 void *vaddr;
[4802dd7]157 rc = pio_enable((void *) dev_physical, sizeof(gxe_bd_hw_t), &vaddr);
[44a53fd]158 if (rc != EOK) {
[b16e77d]159 printf("%s: Could not initialize device I/O space.\n", NAME);
[44a53fd]160 return rc;
161 }
[b16e77d]162
[44a53fd]163 dev = vaddr;
[b16e77d]164
165 for (unsigned int i = 0; i < MAX_DISKS; i++) {
166 char name[16];
167
[135486d]168 bd_srvs_init(&gxe_bd[i].bds);
169 gxe_bd[i].bds.ops = &gxe_bd_ops;
170 gxe_bd[i].bds.sarg = (void *)&gxe_bd[i];
[4802dd7]171
[b16e77d]172 snprintf(name, 16, "%s/disk%u", NAMESPACE, i);
[15f3c3f]173 rc = loc_service_register(name, &service_id[i]);
[84adbf0]174 if (rc != EOK) {
[b16e77d]175 printf("%s: Unable to register device %s.\n", NAME,
176 name);
[84adbf0]177 return rc;
178 }
[b16e77d]179
[12956e57]180 fibril_mutex_initialize(&dev_lock[i]);
[44a53fd]181 }
[b16e77d]182
[44a53fd]183 return EOK;
184}
185
[9934f7d]186static void gxe_bd_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
[44a53fd]187{
[15f3c3f]188 service_id_t dsid;
[84adbf0]189 int disk_id, i;
190
191 /* Get the device handle. */
[15f3c3f]192 dsid = IPC_GET_ARG1(*icall);
[84adbf0]193
194 /* Determine which disk device is the client connecting to. */
195 disk_id = -1;
196 for (i = 0; i < MAX_DISKS; i++)
[15f3c3f]197 if (service_id[i] == dsid)
[84adbf0]198 disk_id = i;
199
200 if (disk_id < 0) {
[ffa2c8ef]201 async_answer_0(iid, EINVAL);
[84adbf0]202 return;
203 }
[44a53fd]204
[135486d]205 bd_conn(iid, icall, &gxe_bd[disk_id].bds);
[4802dd7]206}
[1ee00b7]207
[4802dd7]208/** Open device. */
[135486d]209static int gxe_bd_open(bd_srvs_t *bds, bd_srv_t *bd)
[4802dd7]210{
211 return EOK;
212}
[44a53fd]213
[4802dd7]214/** Close device. */
215static int gxe_bd_close(bd_srv_t *bd)
216{
217 return EOK;
[44a53fd]218}
219
[1ee00b7]220/** Read multiple blocks from the device. */
[4802dd7]221static int gxe_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt,
222 void *buf, size_t size)
223{
224 int disk_id = bd_srv_gxe(bd)->disk_id;
[3ecc02e]225 int rc;
226
[4802dd7]227 if (size < cnt * block_size)
228 return EINVAL;
229
[1ee00b7]230 while (cnt > 0) {
231 rc = gxe_bd_read_block(disk_id, ba, buf);
232 if (rc != EOK)
233 return rc;
234
235 ++ba;
236 --cnt;
237 buf += block_size;
238 }
[3ecc02e]239
[1ee00b7]240 return EOK;
241}
242
243/** Write multiple blocks to the device. */
[4802dd7]244static int gxe_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt,
245 const void *buf, size_t size)
246{
247 int disk_id = bd_srv_gxe(bd)->disk_id;
[1ee00b7]248 int rc;
[3ecc02e]249
[4802dd7]250 if (size < cnt * block_size)
251 return EINVAL;
252
[1ee00b7]253 while (cnt > 0) {
254 rc = gxe_bd_write_block(disk_id, ba, buf);
[3ecc02e]255 if (rc != EOK)
256 return rc;
257
[1ee00b7]258 ++ba;
259 --cnt;
[3ecc02e]260 buf += block_size;
261 }
262
263 return EOK;
264}
265
[4802dd7]266/** Get device block size. */
267static int gxe_bd_get_block_size(bd_srv_t *bd, size_t *rsize)
268{
269 *rsize = block_size;
270 return EOK;
271}
272
273/** Get number of blocks on device. */
274static int gxe_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb)
275{
276 return ENOTSUP;
277}
278
[1ee00b7]279/** Read a block from the device. */
280static int gxe_bd_read_block(int disk_id, uint64_t ba, void *buf)
[44a53fd]281{
282 uint32_t status;
[1ee00b7]283 uint64_t byte_addr;
[44a53fd]284 size_t i;
285 uint32_t w;
286
[1ee00b7]287 byte_addr = ba * block_size;
288
[12956e57]289 fibril_mutex_lock(&dev_lock[disk_id]);
[1ee00b7]290 pio_write_32(&dev->offset_lo, (uint32_t) byte_addr);
291 pio_write_32(&dev->offset_hi, byte_addr >> 32);
[44a53fd]292 pio_write_32(&dev->disk_id, disk_id);
293 pio_write_32(&dev->control, CTL_READ_START);
294
295 status = pio_read_32(&dev->status);
296 if (status == STATUS_FAILURE) {
[12956e57]297 fibril_mutex_unlock(&dev_lock[disk_id]);
[44a53fd]298 return EIO;
299 }
300
[1ee00b7]301 for (i = 0; i < block_size; i++) {
[39580667]302 ((uint8_t *) buf)[i] = w = pio_read_8(&dev->buffer[i]);
[44a53fd]303 }
304
[12956e57]305 fibril_mutex_unlock(&dev_lock[disk_id]);
[44a53fd]306 return EOK;
307}
308
[1ee00b7]309/** Write a block to the device. */
310static int gxe_bd_write_block(int disk_id, uint64_t ba, const void *buf)
[44a53fd]311{
312 uint32_t status;
[1ee00b7]313 uint64_t byte_addr;
[44a53fd]314 size_t i;
315
[1ee00b7]316 byte_addr = ba * block_size;
317
318 fibril_mutex_lock(&dev_lock[disk_id]);
319
320 for (i = 0; i < block_size; i++) {
[39580667]321 pio_write_8(&dev->buffer[i], ((const uint8_t *) buf)[i]);
[44a53fd]322 }
323
[1ee00b7]324 pio_write_32(&dev->offset_lo, (uint32_t) byte_addr);
325 pio_write_32(&dev->offset_hi, byte_addr >> 32);
[44a53fd]326 pio_write_32(&dev->disk_id, disk_id);
327 pio_write_32(&dev->control, CTL_WRITE_START);
328
329 status = pio_read_32(&dev->status);
330 if (status == STATUS_FAILURE) {
[12956e57]331 fibril_mutex_unlock(&dev_lock[disk_id]);
[44a53fd]332 return EIO;
333 }
334
[12956e57]335 fibril_mutex_unlock(&dev_lock[disk_id]);
[44a53fd]336 return EOK;
337}
338
339/**
340 * @}
341 */
Note: See TracBrowser for help on using the repository browser.