1433d6423SLionel Sambuc /* Faulty Block Device (fault injection proxy), by D.C. van Moolenbroek */
2433d6423SLionel Sambuc #include <stdlib.h>
3433d6423SLionel Sambuc #include <minix/drivers.h>
4433d6423SLionel Sambuc #include <minix/blockdriver.h>
5433d6423SLionel Sambuc #include <minix/drvlib.h>
6433d6423SLionel Sambuc #include <minix/ioctl.h>
7433d6423SLionel Sambuc #include <sys/ioc_fbd.h>
8433d6423SLionel Sambuc #include <minix/ds.h>
9433d6423SLionel Sambuc #include <minix/optset.h>
10433d6423SLionel Sambuc #include <assert.h>
11433d6423SLionel Sambuc
12433d6423SLionel Sambuc #include "rule.h"
13433d6423SLionel Sambuc
14433d6423SLionel Sambuc /* Constants. */
15433d6423SLionel Sambuc #define BUF_SIZE (NR_IOREQS * CLICK_SIZE) /* 256k */
16433d6423SLionel Sambuc
17433d6423SLionel Sambuc /* Function declarations. */
18433d6423SLionel Sambuc static int fbd_open(devminor_t minor, int access);
19433d6423SLionel Sambuc static int fbd_close(devminor_t minor);
20433d6423SLionel Sambuc static int fbd_transfer(devminor_t minor, int do_write, u64_t position,
21433d6423SLionel Sambuc endpoint_t endpt, iovec_t *iov, unsigned int nr_req, int flags);
22433d6423SLionel Sambuc static int fbd_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt,
23433d6423SLionel Sambuc cp_grant_id_t grant, endpoint_t user_endpt);
24433d6423SLionel Sambuc
25433d6423SLionel Sambuc /* Variables. */
26433d6423SLionel Sambuc static char *fbd_buf; /* scratch buffer */
27433d6423SLionel Sambuc
28433d6423SLionel Sambuc static char driver_label[32] = ""; /* driver DS label */
29433d6423SLionel Sambuc static devminor_t driver_minor = -1; /* driver's partition minor to use */
30433d6423SLionel Sambuc static endpoint_t driver_endpt; /* driver endpoint */
31433d6423SLionel Sambuc
32433d6423SLionel Sambuc /* Entry points to this driver. */
33433d6423SLionel Sambuc static struct blockdriver fbd_dtab = {
34433d6423SLionel Sambuc .bdr_type = BLOCKDRIVER_TYPE_OTHER,/* do not handle part. reqs */
35433d6423SLionel Sambuc .bdr_open = fbd_open, /* open request, initialize device */
36433d6423SLionel Sambuc .bdr_close = fbd_close, /* release device */
37433d6423SLionel Sambuc .bdr_transfer = fbd_transfer, /* do the I/O */
38433d6423SLionel Sambuc .bdr_ioctl = fbd_ioctl /* perform I/O control request */
39433d6423SLionel Sambuc };
40433d6423SLionel Sambuc
41433d6423SLionel Sambuc /* Options supported by this driver. */
42433d6423SLionel Sambuc static struct optset optset_table[] = {
43433d6423SLionel Sambuc { "label", OPT_STRING, driver_label, sizeof(driver_label) },
44433d6423SLionel Sambuc { "minor", OPT_INT, &driver_minor, 10 },
45433d6423SLionel Sambuc { NULL, 0, NULL, 0 }
46433d6423SLionel Sambuc };
47433d6423SLionel Sambuc
48433d6423SLionel Sambuc /*===========================================================================*
49433d6423SLionel Sambuc * sef_cb_init_fresh *
50433d6423SLionel Sambuc *===========================================================================*/
sef_cb_init_fresh(int type,sef_init_info_t * UNUSED (info))51433d6423SLionel Sambuc static int sef_cb_init_fresh(int type, sef_init_info_t *UNUSED(info))
52433d6423SLionel Sambuc {
53433d6423SLionel Sambuc
54433d6423SLionel Sambuc /* Parse the given parameters. */
55433d6423SLionel Sambuc if (env_argc > 1)
56433d6423SLionel Sambuc optset_parse(optset_table, env_argv[1]);
57433d6423SLionel Sambuc
58433d6423SLionel Sambuc if (driver_label[0] == '\0')
59433d6423SLionel Sambuc panic("no driver label given");
60433d6423SLionel Sambuc
61433d6423SLionel Sambuc if (ds_retrieve_label_endpt(driver_label, &driver_endpt))
62433d6423SLionel Sambuc panic("unable to resolve driver label");
63433d6423SLionel Sambuc
64433d6423SLionel Sambuc if (driver_minor > 255)
65433d6423SLionel Sambuc panic("no or invalid driver minor given");
66433d6423SLionel Sambuc
67433d6423SLionel Sambuc #if DEBUG
68433d6423SLionel Sambuc printf("FBD: driver label '%s' (endpt %d), minor %d\n",
69433d6423SLionel Sambuc driver_label, driver_endpt, driver_minor);
70433d6423SLionel Sambuc #endif
71433d6423SLionel Sambuc
72433d6423SLionel Sambuc /* Initialize resources. */
73433d6423SLionel Sambuc fbd_buf = alloc_contig(BUF_SIZE, 0, NULL);
74433d6423SLionel Sambuc
75*d91f738bSDavid van Moolenbroek if (fbd_buf == NULL)
76*d91f738bSDavid van Moolenbroek panic("unable to allocate buffer");
77433d6423SLionel Sambuc
78*d91f738bSDavid van Moolenbroek srand48(getticks());
79433d6423SLionel Sambuc
80433d6423SLionel Sambuc /* Announce we are up! */
81433d6423SLionel Sambuc blockdriver_announce(type);
82433d6423SLionel Sambuc
83433d6423SLionel Sambuc return OK;
84433d6423SLionel Sambuc }
85433d6423SLionel Sambuc
86433d6423SLionel Sambuc /*===========================================================================*
87433d6423SLionel Sambuc * sef_cb_signal_handler *
88433d6423SLionel Sambuc *===========================================================================*/
sef_cb_signal_handler(int signo)89433d6423SLionel Sambuc static void sef_cb_signal_handler(int signo)
90433d6423SLionel Sambuc {
91433d6423SLionel Sambuc /* Terminate immediately upon receiving a SIGTERM. */
92433d6423SLionel Sambuc if (signo != SIGTERM) return;
93433d6423SLionel Sambuc
94433d6423SLionel Sambuc #if DEBUG
95433d6423SLionel Sambuc printf("FBD: shutting down\n");
96433d6423SLionel Sambuc #endif
97433d6423SLionel Sambuc
98433d6423SLionel Sambuc /* Clean up resources. */
99433d6423SLionel Sambuc free_contig(fbd_buf, BUF_SIZE);
100433d6423SLionel Sambuc
101433d6423SLionel Sambuc exit(0);
102433d6423SLionel Sambuc }
103433d6423SLionel Sambuc
104433d6423SLionel Sambuc /*===========================================================================*
105433d6423SLionel Sambuc * sef_local_startup *
106433d6423SLionel Sambuc *===========================================================================*/
sef_local_startup(void)107433d6423SLionel Sambuc static void sef_local_startup(void)
108433d6423SLionel Sambuc {
109433d6423SLionel Sambuc /* Register init callbacks. */
110433d6423SLionel Sambuc sef_setcb_init_fresh(sef_cb_init_fresh);
111433d6423SLionel Sambuc sef_setcb_init_restart(sef_cb_init_fresh);
112433d6423SLionel Sambuc
113433d6423SLionel Sambuc /* Register signal callback. */
114433d6423SLionel Sambuc sef_setcb_signal_handler(sef_cb_signal_handler);
115433d6423SLionel Sambuc
116433d6423SLionel Sambuc /* Let SEF perform startup. */
117433d6423SLionel Sambuc sef_startup();
118433d6423SLionel Sambuc }
119433d6423SLionel Sambuc
120433d6423SLionel Sambuc /*===========================================================================*
121433d6423SLionel Sambuc * main *
122433d6423SLionel Sambuc *===========================================================================*/
main(int argc,char ** argv)123433d6423SLionel Sambuc int main(int argc, char **argv)
124433d6423SLionel Sambuc {
125433d6423SLionel Sambuc /* SEF local startup. */
126433d6423SLionel Sambuc env_setargs(argc, argv);
127433d6423SLionel Sambuc sef_local_startup();
128433d6423SLionel Sambuc
129433d6423SLionel Sambuc /* Call the generic receive loop. */
130433d6423SLionel Sambuc blockdriver_task(&fbd_dtab);
131433d6423SLionel Sambuc
132433d6423SLionel Sambuc return OK;
133433d6423SLionel Sambuc }
134433d6423SLionel Sambuc
135433d6423SLionel Sambuc /*===========================================================================*
136433d6423SLionel Sambuc * fbd_open *
137433d6423SLionel Sambuc *===========================================================================*/
fbd_open(devminor_t UNUSED (minor),int access)138433d6423SLionel Sambuc static int fbd_open(devminor_t UNUSED(minor), int access)
139433d6423SLionel Sambuc {
140433d6423SLionel Sambuc /* Open a device. */
141433d6423SLionel Sambuc message m;
142433d6423SLionel Sambuc int r;
143433d6423SLionel Sambuc
144433d6423SLionel Sambuc /* We simply forward this request to the real driver. */
145433d6423SLionel Sambuc memset(&m, 0, sizeof(m));
146433d6423SLionel Sambuc m.m_type = BDEV_OPEN;
147433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.minor = driver_minor;
148433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.access = access;
149433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.id = 0;
150433d6423SLionel Sambuc
151433d6423SLionel Sambuc if ((r = ipc_sendrec(driver_endpt, &m)) != OK)
152433d6423SLionel Sambuc panic("ipc_sendrec to driver failed (%d)\n", r);
153433d6423SLionel Sambuc
154433d6423SLionel Sambuc if (m.m_type != BDEV_REPLY)
155433d6423SLionel Sambuc panic("invalid reply from driver (%d)\n", m.m_type);
156433d6423SLionel Sambuc
157433d6423SLionel Sambuc return m.m_lblockdriver_lbdev_reply.status;
158433d6423SLionel Sambuc }
159433d6423SLionel Sambuc
160433d6423SLionel Sambuc /*===========================================================================*
161433d6423SLionel Sambuc * fbd_close *
162433d6423SLionel Sambuc *===========================================================================*/
fbd_close(devminor_t UNUSED (minor))163433d6423SLionel Sambuc static int fbd_close(devminor_t UNUSED(minor))
164433d6423SLionel Sambuc {
165433d6423SLionel Sambuc /* Close a device. */
166433d6423SLionel Sambuc message m;
167433d6423SLionel Sambuc int r;
168433d6423SLionel Sambuc
169433d6423SLionel Sambuc /* We simply forward this request to the real driver. */
170433d6423SLionel Sambuc memset(&m, 0, sizeof(m));
171433d6423SLionel Sambuc m.m_type = BDEV_CLOSE;
172433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.minor = driver_minor;
173433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.id = 0;
174433d6423SLionel Sambuc
175433d6423SLionel Sambuc if ((r = ipc_sendrec(driver_endpt, &m)) != OK)
176433d6423SLionel Sambuc panic("ipc_sendrec to driver failed (%d)\n", r);
177433d6423SLionel Sambuc
178433d6423SLionel Sambuc if (m.m_type != BDEV_REPLY)
179433d6423SLionel Sambuc panic("invalid reply from driver (%d)\n", m.m_type);
180433d6423SLionel Sambuc
181433d6423SLionel Sambuc return m.m_lblockdriver_lbdev_reply.status;
182433d6423SLionel Sambuc }
183433d6423SLionel Sambuc
184433d6423SLionel Sambuc /*===========================================================================*
185433d6423SLionel Sambuc * fbd_ioctl *
186433d6423SLionel Sambuc *===========================================================================*/
fbd_ioctl(devminor_t UNUSED (minor),unsigned long request,endpoint_t endpt,cp_grant_id_t grant,endpoint_t UNUSED (user_endpt))187433d6423SLionel Sambuc static int fbd_ioctl(devminor_t UNUSED(minor), unsigned long request,
188433d6423SLionel Sambuc endpoint_t endpt, cp_grant_id_t grant, endpoint_t UNUSED(user_endpt))
189433d6423SLionel Sambuc {
190433d6423SLionel Sambuc /* Handle an I/O control request. */
191433d6423SLionel Sambuc cp_grant_id_t gid;
192433d6423SLionel Sambuc message m;
193433d6423SLionel Sambuc int r;
194433d6423SLionel Sambuc
195433d6423SLionel Sambuc /* We only handle the FBD requests, and pass on everything else. */
196433d6423SLionel Sambuc switch (request) {
197433d6423SLionel Sambuc case FBDCADDRULE:
198433d6423SLionel Sambuc case FBDCDELRULE:
199433d6423SLionel Sambuc case FBDCGETRULE:
200433d6423SLionel Sambuc return rule_ctl(request, endpt, grant);
201433d6423SLionel Sambuc }
202433d6423SLionel Sambuc
203433d6423SLionel Sambuc assert(grant != GRANT_INVALID);
204433d6423SLionel Sambuc
205433d6423SLionel Sambuc gid = cpf_grant_indirect(driver_endpt, endpt, grant);
206433d6423SLionel Sambuc assert(gid != GRANT_INVALID);
207433d6423SLionel Sambuc
208433d6423SLionel Sambuc memset(&m, 0, sizeof(m));
209433d6423SLionel Sambuc m.m_type = BDEV_IOCTL;
210433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.minor = driver_minor;
211433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.request = request;
212433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.grant = gid;
213433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.user = NONE;
214433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.id = 0;
215433d6423SLionel Sambuc
216433d6423SLionel Sambuc if ((r = ipc_sendrec(driver_endpt, &m)) != OK)
217433d6423SLionel Sambuc panic("ipc_sendrec to driver failed (%d)\n", r);
218433d6423SLionel Sambuc
219433d6423SLionel Sambuc if (m.m_type != BDEV_REPLY)
220433d6423SLionel Sambuc panic("invalid reply from driver (%d)\n", m.m_type);
221433d6423SLionel Sambuc
222433d6423SLionel Sambuc cpf_revoke(gid);
223433d6423SLionel Sambuc
224433d6423SLionel Sambuc return m.m_lblockdriver_lbdev_reply.status;
225433d6423SLionel Sambuc }
226433d6423SLionel Sambuc
227433d6423SLionel Sambuc /*===========================================================================*
228433d6423SLionel Sambuc * fbd_transfer_direct *
229433d6423SLionel Sambuc *===========================================================================*/
fbd_transfer_direct(int do_write,u64_t position,endpoint_t endpt,iovec_t * iov,unsigned int count,int flags)230433d6423SLionel Sambuc static ssize_t fbd_transfer_direct(int do_write, u64_t position,
231433d6423SLionel Sambuc endpoint_t endpt, iovec_t *iov, unsigned int count, int flags)
232433d6423SLionel Sambuc {
233433d6423SLionel Sambuc /* Forward the entire transfer request, without any intervention. */
234433d6423SLionel Sambuc iovec_s_t iovec[NR_IOREQS];
235433d6423SLionel Sambuc cp_grant_id_t grant;
236433d6423SLionel Sambuc message m;
237433d6423SLionel Sambuc int i, r;
238433d6423SLionel Sambuc
239433d6423SLionel Sambuc for (i = 0; i < count; i++) {
240433d6423SLionel Sambuc iovec[i].iov_size = iov[i].iov_size;
241433d6423SLionel Sambuc iovec[i].iov_grant = cpf_grant_indirect(driver_endpt, endpt,
242433d6423SLionel Sambuc iov[i].iov_addr);
243433d6423SLionel Sambuc assert(iovec[i].iov_grant != GRANT_INVALID);
244433d6423SLionel Sambuc }
245433d6423SLionel Sambuc
246433d6423SLionel Sambuc grant = cpf_grant_direct(driver_endpt, (vir_bytes) iovec,
247433d6423SLionel Sambuc count * sizeof(iovec[0]), CPF_READ);
248433d6423SLionel Sambuc assert(grant != GRANT_INVALID);
249433d6423SLionel Sambuc
250433d6423SLionel Sambuc m.m_type = do_write ? BDEV_SCATTER : BDEV_GATHER;
251433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.minor = driver_minor;
252433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.count = count;
253433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.grant = grant;
254433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.flags = flags;
255433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.id = 0;
256433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.pos = position;
257433d6423SLionel Sambuc
258433d6423SLionel Sambuc if ((r = ipc_sendrec(driver_endpt, &m)) != OK)
259433d6423SLionel Sambuc panic("ipc_sendrec to driver failed (%d)\n", r);
260433d6423SLionel Sambuc
261433d6423SLionel Sambuc if (m.m_type != BDEV_REPLY)
262433d6423SLionel Sambuc panic("invalid reply from driver (%d)\n", m.m_type);
263433d6423SLionel Sambuc
264433d6423SLionel Sambuc cpf_revoke(grant);
265433d6423SLionel Sambuc
266433d6423SLionel Sambuc for (i = 0; i < count; i++)
267433d6423SLionel Sambuc cpf_revoke(iovec[i].iov_grant);
268433d6423SLionel Sambuc
269433d6423SLionel Sambuc return m.m_lblockdriver_lbdev_reply.status;
270433d6423SLionel Sambuc }
271433d6423SLionel Sambuc
272433d6423SLionel Sambuc /*===========================================================================*
273433d6423SLionel Sambuc * fbd_transfer_copy *
274433d6423SLionel Sambuc *===========================================================================*/
fbd_transfer_copy(int do_write,u64_t position,endpoint_t endpt,iovec_t * iov,unsigned int count,size_t size,int flags)275433d6423SLionel Sambuc static ssize_t fbd_transfer_copy(int do_write, u64_t position,
276433d6423SLionel Sambuc endpoint_t endpt, iovec_t *iov, unsigned int count, size_t size,
277433d6423SLionel Sambuc int flags)
278433d6423SLionel Sambuc {
279433d6423SLionel Sambuc /* Interpose on the request. */
280433d6423SLionel Sambuc iovec_s_t iovec[NR_IOREQS];
281433d6423SLionel Sambuc struct vscp_vec vscp_vec[SCPVEC_NR];
282433d6423SLionel Sambuc cp_grant_id_t grant;
283433d6423SLionel Sambuc size_t off, len;
284433d6423SLionel Sambuc message m;
285433d6423SLionel Sambuc char *ptr;
286433d6423SLionel Sambuc int i, j, r;
287433d6423SLionel Sambuc ssize_t rsize;
288433d6423SLionel Sambuc
289433d6423SLionel Sambuc assert(count > 0 && count <= SCPVEC_NR);
290433d6423SLionel Sambuc
291433d6423SLionel Sambuc if (size > BUF_SIZE) {
292433d6423SLionel Sambuc printf("FBD: allocating memory for %d bytes\n", size);
293433d6423SLionel Sambuc
294433d6423SLionel Sambuc ptr = alloc_contig(size, 0, NULL);
295433d6423SLionel Sambuc
296433d6423SLionel Sambuc assert(ptr != NULL);
297433d6423SLionel Sambuc }
298433d6423SLionel Sambuc else ptr = fbd_buf;
299433d6423SLionel Sambuc
300433d6423SLionel Sambuc /* For write operations, first copy in the data to write. */
301433d6423SLionel Sambuc if (do_write) {
302433d6423SLionel Sambuc for (i = off = 0; i < count; i++) {
303433d6423SLionel Sambuc len = iov[i].iov_size;
304433d6423SLionel Sambuc
305433d6423SLionel Sambuc vscp_vec[i].v_from = endpt;
306433d6423SLionel Sambuc vscp_vec[i].v_to = SELF;
307433d6423SLionel Sambuc vscp_vec[i].v_gid = iov[i].iov_addr;
308433d6423SLionel Sambuc vscp_vec[i].v_offset = 0;
309433d6423SLionel Sambuc vscp_vec[i].v_addr = (vir_bytes) (ptr + off);
310433d6423SLionel Sambuc vscp_vec[i].v_bytes = len;
311433d6423SLionel Sambuc
312433d6423SLionel Sambuc off += len;
313433d6423SLionel Sambuc }
314433d6423SLionel Sambuc
315433d6423SLionel Sambuc if ((r = sys_vsafecopy(vscp_vec, i)) != OK)
316433d6423SLionel Sambuc panic("vsafecopy failed (%d)\n", r);
317433d6423SLionel Sambuc
318433d6423SLionel Sambuc /* Trigger write hook. */
319433d6423SLionel Sambuc rule_io_hook(ptr, size, position, FBD_FLAG_WRITE);
320433d6423SLionel Sambuc }
321433d6423SLionel Sambuc
322433d6423SLionel Sambuc /* Allocate grants for the data, in the same chunking as the original
323433d6423SLionel Sambuc * vector. This avoids performance fluctuations with bad hardware as
324433d6423SLionel Sambuc * observed with the filter driver.
325433d6423SLionel Sambuc */
326433d6423SLionel Sambuc for (i = off = 0; i < count; i++) {
327433d6423SLionel Sambuc len = iov[i].iov_size;
328433d6423SLionel Sambuc
329433d6423SLionel Sambuc iovec[i].iov_size = len;
330433d6423SLionel Sambuc iovec[i].iov_grant = cpf_grant_direct(driver_endpt,
331433d6423SLionel Sambuc (vir_bytes) (ptr + off), len,
332433d6423SLionel Sambuc do_write ? CPF_READ : CPF_WRITE);
333433d6423SLionel Sambuc assert(iovec[i].iov_grant != GRANT_INVALID);
334433d6423SLionel Sambuc
335433d6423SLionel Sambuc off += len;
336433d6423SLionel Sambuc }
337433d6423SLionel Sambuc
338433d6423SLionel Sambuc grant = cpf_grant_direct(driver_endpt, (vir_bytes) iovec,
339433d6423SLionel Sambuc count * sizeof(iovec[0]), CPF_READ);
340433d6423SLionel Sambuc assert(grant != GRANT_INVALID);
341433d6423SLionel Sambuc
342433d6423SLionel Sambuc m.m_type = do_write ? BDEV_SCATTER : BDEV_GATHER;
343433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.minor = driver_minor;
344433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.count = count;
345433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.grant = grant;
346433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.flags = flags;
347433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.id = 0;
348433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.pos = position;
349433d6423SLionel Sambuc
350433d6423SLionel Sambuc if ((r = ipc_sendrec(driver_endpt, &m)) != OK)
351433d6423SLionel Sambuc panic("ipc_sendrec to driver failed (%d)\n", r);
352433d6423SLionel Sambuc
353433d6423SLionel Sambuc if (m.m_type != BDEV_REPLY)
354433d6423SLionel Sambuc panic("invalid reply from driver (%d)\n", m.m_type);
355433d6423SLionel Sambuc
356433d6423SLionel Sambuc cpf_revoke(grant);
357433d6423SLionel Sambuc
358433d6423SLionel Sambuc for (i = 0; i < count; i++)
359433d6423SLionel Sambuc cpf_revoke(iovec[i].iov_grant);
360433d6423SLionel Sambuc
361433d6423SLionel Sambuc /* For read operations, finish by copying out the data read. */
362433d6423SLionel Sambuc if (!do_write) {
363433d6423SLionel Sambuc /* Trigger read hook. */
364433d6423SLionel Sambuc rule_io_hook(ptr, size, position, FBD_FLAG_READ);
365433d6423SLionel Sambuc
366433d6423SLionel Sambuc /* Upon success, copy back whatever has been processed. */
367433d6423SLionel Sambuc rsize = m.m_lblockdriver_lbdev_reply.status;
368433d6423SLionel Sambuc for (i = j = off = 0; rsize > 0 && i < count; i++) {
369433d6423SLionel Sambuc len = MIN(rsize, iov[i].iov_size);
370433d6423SLionel Sambuc
371433d6423SLionel Sambuc vscp_vec[j].v_from = SELF;
372433d6423SLionel Sambuc vscp_vec[j].v_to = endpt;
373433d6423SLionel Sambuc vscp_vec[j].v_gid = iov[i].iov_addr;
374433d6423SLionel Sambuc vscp_vec[j].v_offset = 0;
375433d6423SLionel Sambuc vscp_vec[j].v_addr = (vir_bytes) (ptr + off);
376433d6423SLionel Sambuc vscp_vec[j].v_bytes = len;
377433d6423SLionel Sambuc
378433d6423SLionel Sambuc off += len;
379433d6423SLionel Sambuc rsize -= len;
380433d6423SLionel Sambuc j++;
381433d6423SLionel Sambuc }
382433d6423SLionel Sambuc
383433d6423SLionel Sambuc if (j > 0 && (r = sys_vsafecopy(vscp_vec, j)) != OK)
384433d6423SLionel Sambuc panic("vsafecopy failed (%d)\n", r);
385433d6423SLionel Sambuc }
386433d6423SLionel Sambuc
387433d6423SLionel Sambuc if (ptr != fbd_buf)
388433d6423SLionel Sambuc free_contig(ptr, size);
389433d6423SLionel Sambuc
390433d6423SLionel Sambuc return m.m_lblockdriver_lbdev_reply.status;
391433d6423SLionel Sambuc }
392433d6423SLionel Sambuc
393433d6423SLionel Sambuc /*===========================================================================*
394433d6423SLionel Sambuc * fbd_transfer *
395433d6423SLionel Sambuc *===========================================================================*/
fbd_transfer(devminor_t UNUSED (minor),int do_write,u64_t position,endpoint_t endpt,iovec_t * iov,unsigned int nr_req,int flags)396433d6423SLionel Sambuc static int fbd_transfer(devminor_t UNUSED(minor), int do_write, u64_t position,
397433d6423SLionel Sambuc endpoint_t endpt, iovec_t *iov, unsigned int nr_req, int flags)
398433d6423SLionel Sambuc {
399433d6423SLionel Sambuc /* Transfer data from or to the device. */
400433d6423SLionel Sambuc unsigned int count;
401433d6423SLionel Sambuc size_t size, osize;
402433d6423SLionel Sambuc int i, hooks;
403433d6423SLionel Sambuc ssize_t r;
404433d6423SLionel Sambuc
405433d6423SLionel Sambuc /* Compute the total size of the request. */
406433d6423SLionel Sambuc for (size = i = 0; i < nr_req; i++)
407433d6423SLionel Sambuc size += iov[i].iov_size;
408433d6423SLionel Sambuc
409433d6423SLionel Sambuc osize = size;
410433d6423SLionel Sambuc count = nr_req;
411433d6423SLionel Sambuc
412433d6423SLionel Sambuc hooks = rule_find(position, size,
413433d6423SLionel Sambuc do_write ? FBD_FLAG_WRITE : FBD_FLAG_READ);
414433d6423SLionel Sambuc
415433d6423SLionel Sambuc #if DEBUG
416433d6423SLionel Sambuc printf("FBD: %s operation for pos %"PRIx64" size %u -> hooks %x\n",
417433d6423SLionel Sambuc do_write ? "write" : "read", position, size, hooks);
418433d6423SLionel Sambuc #endif
419433d6423SLionel Sambuc
420433d6423SLionel Sambuc if (hooks & PRE_HOOK)
421433d6423SLionel Sambuc rule_pre_hook(iov, &count, &size, &position);
422433d6423SLionel Sambuc
423433d6423SLionel Sambuc if (count > 0) {
424433d6423SLionel Sambuc if (hooks & IO_HOOK) {
425433d6423SLionel Sambuc r = fbd_transfer_copy(do_write, position, endpt, iov,
426433d6423SLionel Sambuc count, size, flags);
427433d6423SLionel Sambuc } else {
428433d6423SLionel Sambuc r = fbd_transfer_direct(do_write, position, endpt, iov,
429433d6423SLionel Sambuc count, flags);
430433d6423SLionel Sambuc }
431433d6423SLionel Sambuc }
432433d6423SLionel Sambuc else r = 0;
433433d6423SLionel Sambuc
434433d6423SLionel Sambuc if (hooks & POST_HOOK)
435433d6423SLionel Sambuc rule_post_hook(osize, &r);
436433d6423SLionel Sambuc
437433d6423SLionel Sambuc #if DEBUG
438433d6423SLionel Sambuc printf("FBD: returning %d\n", r);
439433d6423SLionel Sambuc #endif
440433d6423SLionel Sambuc
441433d6423SLionel Sambuc return r;
442433d6423SLionel Sambuc }
443