xref: /minix3/minix/drivers/storage/fbd/fbd.c (revision d91f738bd8d93aa6befa2a8d07581040607a512a)
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