1433d6423SLionel Sambuc /* This file contains the device independent block driver interface.
2433d6423SLionel Sambuc *
3433d6423SLionel Sambuc * Block drivers support the following requests. Message format m10 is used.
4433d6423SLionel Sambuc * Field names are prefixed with BDEV_. Separate field names are used for the
5433d6423SLionel Sambuc * "access", "request", and "user" fields.
6433d6423SLionel Sambuc *
7433d6423SLionel Sambuc * m_type MINOR COUNT GRANT FLAGS ID REQUEST POS
8433d6423SLionel Sambuc * +--------------+--------+----------+-------+-------+------+---------+------+
9433d6423SLionel Sambuc * | BDEV_OPEN | minor | access | | | id | | |
10433d6423SLionel Sambuc * |--------------+--------+----------+-------+-------+------+---------+------|
11433d6423SLionel Sambuc * | BDEV_CLOSE | minor | | | | id | | |
12433d6423SLionel Sambuc * |--------------+--------+----------+-------+-------+------+---------+------|
13433d6423SLionel Sambuc * | BDEV_READ | minor | bytes | grant | flags | id | | pos. |
14433d6423SLionel Sambuc * |--------------+--------+----------+-------+-------+------+---------+------|
15433d6423SLionel Sambuc * | BDEV_WRITE | minor | bytes | grant | flags | id | | pos. |
16433d6423SLionel Sambuc * |--------------+--------+----------+-------+-------+------+---------+------|
17433d6423SLionel Sambuc * | BDEV_GATHER | minor | elements | grant | flags | id | | pos. |
18433d6423SLionel Sambuc * |--------------+--------+----------+-------+-------+------+---------+------|
19433d6423SLionel Sambuc * | BDEV_SCATTER | minor | elements | grant | flags | id | | pos. |
20433d6423SLionel Sambuc * |--------------+--------+----------+-------+-------+------+---------+------|
21433d6423SLionel Sambuc * | BDEV_IOCTL | minor | | grant | user | id | request | |
22433d6423SLionel Sambuc * ----------------------------------------------------------------------------
23433d6423SLionel Sambuc *
24433d6423SLionel Sambuc * The following reply message is used for all requests.
25433d6423SLionel Sambuc *
26433d6423SLionel Sambuc * m_type STATUS ID
27433d6423SLionel Sambuc * +--------------+--------+----------+-------+-------+------+---------+------+
28433d6423SLionel Sambuc * | BDEV_REPLY | status | | | | id | | |
29433d6423SLionel Sambuc * ----------------------------------------------------------------------------
30433d6423SLionel Sambuc *
31433d6423SLionel Sambuc * Changes:
32433d6423SLionel Sambuc * Oct 16, 2011 split character and block protocol (D.C. van Moolenbroek)
33433d6423SLionel Sambuc * Aug 27, 2011 move common functions into driver.c (A. Welzel)
34433d6423SLionel Sambuc * Jul 25, 2005 added SYS_SIG type for signals (Jorrit N. Herder)
35433d6423SLionel Sambuc * Sep 15, 2004 added SYN_ALARM type for timeouts (Jorrit N. Herder)
36433d6423SLionel Sambuc * Jul 23, 2004 removed kernel dependencies (Jorrit N. Herder)
37433d6423SLionel Sambuc * Apr 02, 1992 constructed from AT wini and floppy driver (Kees J. Bot)
38433d6423SLionel Sambuc */
39433d6423SLionel Sambuc
40433d6423SLionel Sambuc #include <minix/drivers.h>
41433d6423SLionel Sambuc #include <minix/blockdriver.h>
42433d6423SLionel Sambuc #include <minix/ds.h>
43433d6423SLionel Sambuc #include <sys/ioc_block.h>
44433d6423SLionel Sambuc #include <sys/ioc_disk.h>
45433d6423SLionel Sambuc
46433d6423SLionel Sambuc #include "driver.h"
47433d6423SLionel Sambuc #include "mq.h"
48433d6423SLionel Sambuc #include "trace.h"
49433d6423SLionel Sambuc
50433d6423SLionel Sambuc /* Management data for opened devices. */
51433d6423SLionel Sambuc static int open_devs[MAX_NR_OPEN_DEVICES];
52433d6423SLionel Sambuc static int next_open_devs_slot = 0;
53433d6423SLionel Sambuc
54433d6423SLionel Sambuc /*===========================================================================*
55433d6423SLionel Sambuc * clear_open_devs *
56433d6423SLionel Sambuc *===========================================================================*/
clear_open_devs(void)57433d6423SLionel Sambuc static void clear_open_devs(void)
58433d6423SLionel Sambuc {
59433d6423SLionel Sambuc /* Reset the set of previously opened minor devices. */
60433d6423SLionel Sambuc next_open_devs_slot = 0;
61433d6423SLionel Sambuc }
62433d6423SLionel Sambuc
63433d6423SLionel Sambuc /*===========================================================================*
64433d6423SLionel Sambuc * is_open_dev *
65433d6423SLionel Sambuc *===========================================================================*/
is_open_dev(int device)66433d6423SLionel Sambuc static int is_open_dev(int device)
67433d6423SLionel Sambuc {
68433d6423SLionel Sambuc /* Check whether the given minor device has previously been opened. */
69433d6423SLionel Sambuc int i;
70433d6423SLionel Sambuc
71433d6423SLionel Sambuc for (i = 0; i < next_open_devs_slot; i++)
72433d6423SLionel Sambuc if (open_devs[i] == device)
73433d6423SLionel Sambuc return TRUE;
74433d6423SLionel Sambuc
75433d6423SLionel Sambuc return FALSE;
76433d6423SLionel Sambuc }
77433d6423SLionel Sambuc
78433d6423SLionel Sambuc /*===========================================================================*
79433d6423SLionel Sambuc * set_open_dev *
80433d6423SLionel Sambuc *===========================================================================*/
set_open_dev(int device)81433d6423SLionel Sambuc static void set_open_dev(int device)
82433d6423SLionel Sambuc {
83433d6423SLionel Sambuc /* Mark the given minor device as having been opened. */
84433d6423SLionel Sambuc
85433d6423SLionel Sambuc if (next_open_devs_slot >= MAX_NR_OPEN_DEVICES)
86433d6423SLionel Sambuc panic("out of slots for open devices");
87433d6423SLionel Sambuc
88433d6423SLionel Sambuc open_devs[next_open_devs_slot] = device;
89433d6423SLionel Sambuc next_open_devs_slot++;
90433d6423SLionel Sambuc }
91433d6423SLionel Sambuc
92433d6423SLionel Sambuc /*===========================================================================*
93433d6423SLionel Sambuc * blockdriver_announce *
94433d6423SLionel Sambuc *===========================================================================*/
blockdriver_announce(int type)95433d6423SLionel Sambuc void blockdriver_announce(int type)
96433d6423SLionel Sambuc {
97433d6423SLionel Sambuc /* Announce we are up after a fresh start or a restart. */
98433d6423SLionel Sambuc int r;
99433d6423SLionel Sambuc char key[DS_MAX_KEYLEN];
100433d6423SLionel Sambuc char label[DS_MAX_KEYLEN];
10165f76edbSDavid van Moolenbroek const char *driver_prefix = "drv.blk.";
102433d6423SLionel Sambuc
103433d6423SLionel Sambuc /* Callers are allowed to use ipc_sendrec to communicate with drivers.
104433d6423SLionel Sambuc * For this reason, there may blocked callers when a driver restarts.
105433d6423SLionel Sambuc * Ask the kernel to unblock them (if any). Note that most block drivers
106433d6423SLionel Sambuc * will not restart statefully, and thus will skip this code.
107433d6423SLionel Sambuc */
108433d6423SLionel Sambuc if (type == SEF_INIT_RESTART) {
109*41022be1SCristiano Giuffrida if ((r = sys_statectl(SYS_STATE_CLEAR_IPC_REFS, 0, 0)) != OK)
110433d6423SLionel Sambuc panic("blockdriver_init: sys_statectl failed: %d", r);
111433d6423SLionel Sambuc }
112433d6423SLionel Sambuc
113433d6423SLionel Sambuc /* Publish a driver up event. */
114433d6423SLionel Sambuc if ((r = ds_retrieve_label_name(label, sef_self())) != OK)
115433d6423SLionel Sambuc panic("blockdriver_init: unable to get own label: %d", r);
116433d6423SLionel Sambuc
117433d6423SLionel Sambuc snprintf(key, DS_MAX_KEYLEN, "%s%s", driver_prefix, label);
118433d6423SLionel Sambuc if ((r = ds_publish_u32(key, DS_DRIVER_UP, DSF_OVERWRITE)) != OK)
119433d6423SLionel Sambuc panic("blockdriver_init: unable to publish driver up event: %d", r);
120433d6423SLionel Sambuc
121433d6423SLionel Sambuc /* Expect an open for any device before serving regular driver requests. */
122433d6423SLionel Sambuc clear_open_devs();
123433d6423SLionel Sambuc
124433d6423SLionel Sambuc /* Initialize or reset the message queue. */
125433d6423SLionel Sambuc mq_init();
126433d6423SLionel Sambuc }
127433d6423SLionel Sambuc
128433d6423SLionel Sambuc /*===========================================================================*
129433d6423SLionel Sambuc * send_reply *
130433d6423SLionel Sambuc *===========================================================================*/
send_reply(endpoint_t endpt,message * m_ptr,int ipc_status)131433d6423SLionel Sambuc static void send_reply(endpoint_t endpt, message *m_ptr, int ipc_status)
132433d6423SLionel Sambuc {
133433d6423SLionel Sambuc /* Send a reply message to a request. */
134433d6423SLionel Sambuc int r;
135433d6423SLionel Sambuc
136433d6423SLionel Sambuc /* If we would block sending the message, send it asynchronously. The NOREPLY
137433d6423SLionel Sambuc * flag is set because the caller may also issue a SENDREC (mixing sync and
138433d6423SLionel Sambuc * async comm), and the asynchronous reply could otherwise end up satisfying
139433d6423SLionel Sambuc * the SENDREC's receive part, after which our next SENDNB call would fail.
140433d6423SLionel Sambuc */
141433d6423SLionel Sambuc if (IPC_STATUS_CALL(ipc_status) == SENDREC)
142433d6423SLionel Sambuc r = ipc_sendnb(endpt, m_ptr);
143433d6423SLionel Sambuc else
144433d6423SLionel Sambuc r = asynsend3(endpt, m_ptr, AMF_NOREPLY);
145433d6423SLionel Sambuc
146433d6423SLionel Sambuc if (r != OK)
147433d6423SLionel Sambuc printf("blockdriver: unable to send reply to %d: %d\n", endpt, r);
148433d6423SLionel Sambuc }
149433d6423SLionel Sambuc
150433d6423SLionel Sambuc /*===========================================================================*
151433d6423SLionel Sambuc * blockdriver_reply *
152433d6423SLionel Sambuc *===========================================================================*/
blockdriver_reply(message * m_ptr,int ipc_status,int reply)153433d6423SLionel Sambuc void blockdriver_reply(message *m_ptr, int ipc_status, int reply)
154433d6423SLionel Sambuc {
155433d6423SLionel Sambuc /* Reply to a block request sent to the driver. */
156433d6423SLionel Sambuc message m_reply;
157433d6423SLionel Sambuc
158433d6423SLionel Sambuc if (reply == EDONTREPLY)
159433d6423SLionel Sambuc return;
160433d6423SLionel Sambuc
161433d6423SLionel Sambuc memset(&m_reply, 0, sizeof(m_reply));
162433d6423SLionel Sambuc
163433d6423SLionel Sambuc m_reply.m_type = BDEV_REPLY;
164433d6423SLionel Sambuc m_reply.m_lblockdriver_lbdev_reply.status = reply;
165433d6423SLionel Sambuc m_reply.m_lblockdriver_lbdev_reply.id = m_ptr->m_lbdev_lblockdriver_msg.id;
166433d6423SLionel Sambuc
167433d6423SLionel Sambuc send_reply(m_ptr->m_source, &m_reply, ipc_status);
168433d6423SLionel Sambuc }
169433d6423SLionel Sambuc
170433d6423SLionel Sambuc /*===========================================================================*
171433d6423SLionel Sambuc * do_open *
172433d6423SLionel Sambuc *===========================================================================*/
do_open(struct blockdriver * bdp,message * mp)173433d6423SLionel Sambuc static int do_open(struct blockdriver *bdp, message *mp)
174433d6423SLionel Sambuc {
175433d6423SLionel Sambuc /* Open a minor device. */
176433d6423SLionel Sambuc
177433d6423SLionel Sambuc return (*bdp->bdr_open)(mp->m_lbdev_lblockdriver_msg.minor, mp->m_lbdev_lblockdriver_msg.access);
178433d6423SLionel Sambuc }
179433d6423SLionel Sambuc
180433d6423SLionel Sambuc /*===========================================================================*
181433d6423SLionel Sambuc * do_close *
182433d6423SLionel Sambuc *===========================================================================*/
do_close(struct blockdriver * bdp,message * mp)183433d6423SLionel Sambuc static int do_close(struct blockdriver *bdp, message *mp)
184433d6423SLionel Sambuc {
185433d6423SLionel Sambuc /* Close a minor device. */
186433d6423SLionel Sambuc
187433d6423SLionel Sambuc return (*bdp->bdr_close)(mp->m_lbdev_lblockdriver_msg.minor);
188433d6423SLionel Sambuc }
189433d6423SLionel Sambuc
190433d6423SLionel Sambuc /*===========================================================================*
191433d6423SLionel Sambuc * do_rdwt *
192433d6423SLionel Sambuc *===========================================================================*/
do_rdwt(struct blockdriver * bdp,message * mp)193433d6423SLionel Sambuc static int do_rdwt(struct blockdriver *bdp, message *mp)
194433d6423SLionel Sambuc {
195433d6423SLionel Sambuc /* Carry out a single read or write request. */
196433d6423SLionel Sambuc iovec_t iovec1;
197433d6423SLionel Sambuc u64_t position;
198433d6423SLionel Sambuc int do_write;
199433d6423SLionel Sambuc ssize_t r;
200433d6423SLionel Sambuc
201433d6423SLionel Sambuc /* Disk address? Address and length of the user buffer? */
202433d6423SLionel Sambuc if (mp->m_lbdev_lblockdriver_msg.count < 0) return EINVAL;
203433d6423SLionel Sambuc
204433d6423SLionel Sambuc /* Create a one element scatter/gather vector for the buffer. */
205433d6423SLionel Sambuc iovec1.iov_addr = mp->m_lbdev_lblockdriver_msg.grant;
206433d6423SLionel Sambuc iovec1.iov_size = mp->m_lbdev_lblockdriver_msg.count;
207433d6423SLionel Sambuc
208433d6423SLionel Sambuc /* Transfer bytes from/to the device. */
209433d6423SLionel Sambuc do_write = (mp->m_type == BDEV_WRITE);
210433d6423SLionel Sambuc position = mp->m_lbdev_lblockdriver_msg.pos;
211433d6423SLionel Sambuc
212433d6423SLionel Sambuc r = (*bdp->bdr_transfer)(mp->m_lbdev_lblockdriver_msg.minor, do_write, position, mp->m_source,
213433d6423SLionel Sambuc &iovec1, 1, mp->m_lbdev_lblockdriver_msg.flags);
214433d6423SLionel Sambuc
215433d6423SLionel Sambuc /* Return the number of bytes transferred or an error code. */
216433d6423SLionel Sambuc return r;
217433d6423SLionel Sambuc }
218433d6423SLionel Sambuc
219433d6423SLionel Sambuc /*===========================================================================*
220433d6423SLionel Sambuc * do_vrdwt *
221433d6423SLionel Sambuc *===========================================================================*/
do_vrdwt(struct blockdriver * bdp,message * mp,thread_id_t id)222433d6423SLionel Sambuc static int do_vrdwt(struct blockdriver *bdp, message *mp, thread_id_t id)
223433d6423SLionel Sambuc {
224433d6423SLionel Sambuc /* Carry out an device read or write to/from a vector of buffers. */
225433d6423SLionel Sambuc iovec_t iovec[NR_IOREQS];
22665f76edbSDavid van Moolenbroek unsigned int i, nr_req;
227433d6423SLionel Sambuc u64_t position;
22865f76edbSDavid van Moolenbroek int do_write;
229433d6423SLionel Sambuc ssize_t r, size;
230433d6423SLionel Sambuc
231433d6423SLionel Sambuc /* Copy the vector from the caller to kernel space. */
232433d6423SLionel Sambuc nr_req = mp->m_lbdev_lblockdriver_msg.count; /* Length of I/O vector */
233433d6423SLionel Sambuc if (nr_req > NR_IOREQS) nr_req = NR_IOREQS;
234433d6423SLionel Sambuc
235433d6423SLionel Sambuc if (OK != sys_safecopyfrom(mp->m_source, (vir_bytes) mp->m_lbdev_lblockdriver_msg.grant,
236433d6423SLionel Sambuc 0, (vir_bytes) iovec, nr_req * sizeof(iovec[0]))) {
237433d6423SLionel Sambuc printf("blockdriver: bad I/O vector by: %d\n", mp->m_source);
238433d6423SLionel Sambuc return EINVAL;
239433d6423SLionel Sambuc }
240433d6423SLionel Sambuc
241433d6423SLionel Sambuc /* Check for overflow condition, and update the size for block tracing. */
242433d6423SLionel Sambuc for (i = size = 0; i < nr_req; i++) {
243433d6423SLionel Sambuc if ((ssize_t) (size + iovec[i].iov_size) < size) return EINVAL;
244433d6423SLionel Sambuc size += iovec[i].iov_size;
245433d6423SLionel Sambuc }
246433d6423SLionel Sambuc
247433d6423SLionel Sambuc trace_setsize(id, size);
248433d6423SLionel Sambuc
249433d6423SLionel Sambuc /* Transfer bytes from/to the device. */
250433d6423SLionel Sambuc do_write = (mp->m_type == BDEV_SCATTER);
251433d6423SLionel Sambuc position = mp->m_lbdev_lblockdriver_msg.pos;
252433d6423SLionel Sambuc
253433d6423SLionel Sambuc r = (*bdp->bdr_transfer)(mp->m_lbdev_lblockdriver_msg.minor, do_write, position, mp->m_source,
254433d6423SLionel Sambuc iovec, nr_req, mp->m_lbdev_lblockdriver_msg.flags);
255433d6423SLionel Sambuc
256433d6423SLionel Sambuc /* Return the number of bytes transferred or an error code. */
257433d6423SLionel Sambuc return r;
258433d6423SLionel Sambuc }
259433d6423SLionel Sambuc
260433d6423SLionel Sambuc /*===========================================================================*
261433d6423SLionel Sambuc * do_dioctl *
262433d6423SLionel Sambuc *===========================================================================*/
do_dioctl(struct blockdriver * bdp,devminor_t minor,unsigned long request,endpoint_t endpt,cp_grant_id_t grant)26365f76edbSDavid van Moolenbroek static int do_dioctl(struct blockdriver *bdp, devminor_t minor,
264433d6423SLionel Sambuc unsigned long request, endpoint_t endpt, cp_grant_id_t grant)
265433d6423SLionel Sambuc {
266433d6423SLionel Sambuc /* Carry out a disk-specific I/O control request. */
267433d6423SLionel Sambuc struct device *dv;
268433d6423SLionel Sambuc struct part_geom entry;
269433d6423SLionel Sambuc int r = EINVAL;
270433d6423SLionel Sambuc
271433d6423SLionel Sambuc switch (request) {
272433d6423SLionel Sambuc case DIOCSETP:
273433d6423SLionel Sambuc /* Copy just this one partition table entry. */
274433d6423SLionel Sambuc r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &entry,
275433d6423SLionel Sambuc sizeof(entry));
276433d6423SLionel Sambuc if (r != OK)
277433d6423SLionel Sambuc return r;
278433d6423SLionel Sambuc
279433d6423SLionel Sambuc if ((dv = (*bdp->bdr_part)(minor)) == NULL)
280433d6423SLionel Sambuc return ENXIO;
281433d6423SLionel Sambuc dv->dv_base = entry.base;
282433d6423SLionel Sambuc dv->dv_size = entry.size;
283433d6423SLionel Sambuc
284433d6423SLionel Sambuc break;
285433d6423SLionel Sambuc
286433d6423SLionel Sambuc case DIOCGETP:
287433d6423SLionel Sambuc /* Return a partition table entry and the geometry of the drive. */
288433d6423SLionel Sambuc if ((dv = (*bdp->bdr_part)(minor)) == NULL)
289433d6423SLionel Sambuc return ENXIO;
290433d6423SLionel Sambuc entry.base = dv->dv_base;
291433d6423SLionel Sambuc entry.size = dv->dv_size;
292433d6423SLionel Sambuc if (bdp->bdr_geometry) {
293433d6423SLionel Sambuc (*bdp->bdr_geometry)(minor, &entry);
294433d6423SLionel Sambuc } else {
295433d6423SLionel Sambuc /* The driver doesn't care -- make up fake geometry. */
296433d6423SLionel Sambuc entry.cylinders = (unsigned long)(entry.size / SECTOR_SIZE) /
297433d6423SLionel Sambuc (64 * 32);
298433d6423SLionel Sambuc entry.heads = 64;
299433d6423SLionel Sambuc entry.sectors = 32;
300433d6423SLionel Sambuc }
301433d6423SLionel Sambuc
302433d6423SLionel Sambuc r = sys_safecopyto(endpt, grant, 0, (vir_bytes) &entry, sizeof(entry));
303433d6423SLionel Sambuc
304433d6423SLionel Sambuc break;
305433d6423SLionel Sambuc }
306433d6423SLionel Sambuc
307433d6423SLionel Sambuc return r;
308433d6423SLionel Sambuc }
309433d6423SLionel Sambuc
310433d6423SLionel Sambuc /*===========================================================================*
311433d6423SLionel Sambuc * do_ioctl *
312433d6423SLionel Sambuc *===========================================================================*/
do_ioctl(struct blockdriver * bdp,message * mp)313433d6423SLionel Sambuc static int do_ioctl(struct blockdriver *bdp, message *mp)
314433d6423SLionel Sambuc {
315433d6423SLionel Sambuc /* Carry out an I/O control request. We forward block trace control requests
316433d6423SLionel Sambuc * to the tracing module, and handle setting/getting partitions when the driver
317433d6423SLionel Sambuc * has specified that it is a disk driver.
318433d6423SLionel Sambuc */
31965f76edbSDavid van Moolenbroek devminor_t minor;
320433d6423SLionel Sambuc unsigned long request;
321433d6423SLionel Sambuc cp_grant_id_t grant;
322433d6423SLionel Sambuc endpoint_t user_endpt;
323433d6423SLionel Sambuc int r;
324433d6423SLionel Sambuc
325433d6423SLionel Sambuc minor = mp->m_lbdev_lblockdriver_msg.minor;
326433d6423SLionel Sambuc request = mp->m_lbdev_lblockdriver_msg.request;
327433d6423SLionel Sambuc grant = mp->m_lbdev_lblockdriver_msg.grant;
328433d6423SLionel Sambuc user_endpt = mp->m_lbdev_lblockdriver_msg.user;
329433d6423SLionel Sambuc
330433d6423SLionel Sambuc switch (request) {
331433d6423SLionel Sambuc case BIOCTRACEBUF:
332433d6423SLionel Sambuc case BIOCTRACECTL:
333433d6423SLionel Sambuc case BIOCTRACEGET:
334433d6423SLionel Sambuc /* Block trace control. */
335433d6423SLionel Sambuc r = trace_ctl(minor, request, mp->m_source, grant);
336433d6423SLionel Sambuc
337433d6423SLionel Sambuc break;
338433d6423SLionel Sambuc
339433d6423SLionel Sambuc case DIOCSETP:
340433d6423SLionel Sambuc case DIOCGETP:
341433d6423SLionel Sambuc /* Handle disk-specific IOCTLs only for disk-type drivers. */
342433d6423SLionel Sambuc if (bdp->bdr_type == BLOCKDRIVER_TYPE_DISK) {
343433d6423SLionel Sambuc /* Disk partition control. */
344433d6423SLionel Sambuc r = do_dioctl(bdp, minor, request, mp->m_source, grant);
345433d6423SLionel Sambuc
346433d6423SLionel Sambuc break;
347433d6423SLionel Sambuc }
348433d6423SLionel Sambuc
349433d6423SLionel Sambuc /* fall-through */
350433d6423SLionel Sambuc default:
351433d6423SLionel Sambuc if (bdp->bdr_ioctl)
352433d6423SLionel Sambuc r = (*bdp->bdr_ioctl)(minor, request, mp->m_source, grant,
353433d6423SLionel Sambuc user_endpt);
354433d6423SLionel Sambuc else
355433d6423SLionel Sambuc r = ENOTTY;
356433d6423SLionel Sambuc }
357433d6423SLionel Sambuc
358433d6423SLionel Sambuc return r;
359433d6423SLionel Sambuc }
360433d6423SLionel Sambuc
361433d6423SLionel Sambuc /*===========================================================================*
362433d6423SLionel Sambuc * do_char_open *
363433d6423SLionel Sambuc *===========================================================================*/
do_char_open(message * m_ptr,int ipc_status)364433d6423SLionel Sambuc static void do_char_open(message *m_ptr, int ipc_status)
365433d6423SLionel Sambuc {
366433d6423SLionel Sambuc /* Reply to a character driver open request stating there is no such device. */
367433d6423SLionel Sambuc message m_reply;
368433d6423SLionel Sambuc
369433d6423SLionel Sambuc memset(&m_reply, 0, sizeof(m_reply));
370433d6423SLionel Sambuc
371433d6423SLionel Sambuc m_reply.m_type = CDEV_REPLY;
372433d6423SLionel Sambuc m_reply.m_lchardriver_vfs_reply.status = ENXIO;
373433d6423SLionel Sambuc m_reply.m_lchardriver_vfs_reply.id = m_ptr->m_vfs_lchardriver_openclose.id;
374433d6423SLionel Sambuc
375433d6423SLionel Sambuc send_reply(m_ptr->m_source, &m_reply, ipc_status);
376433d6423SLionel Sambuc }
377433d6423SLionel Sambuc
378433d6423SLionel Sambuc /*===========================================================================*
379433d6423SLionel Sambuc * blockdriver_process_on_thread *
380433d6423SLionel Sambuc *===========================================================================*/
blockdriver_process_on_thread(struct blockdriver * bdp,message * m_ptr,int ipc_status,thread_id_t id)381433d6423SLionel Sambuc void blockdriver_process_on_thread(struct blockdriver *bdp, message *m_ptr,
382433d6423SLionel Sambuc int ipc_status, thread_id_t id)
383433d6423SLionel Sambuc {
384433d6423SLionel Sambuc /* Call the appropiate driver function, based on the type of request. Send
385433d6423SLionel Sambuc * a result code to the caller. The call is processed in the context of the
386433d6423SLionel Sambuc * given thread ID, which may be SINGLE_THREAD for single-threaded callers.
387433d6423SLionel Sambuc */
388433d6423SLionel Sambuc int r;
389433d6423SLionel Sambuc
390433d6423SLionel Sambuc /* Check for notifications first. We never reply to notifications. */
391433d6423SLionel Sambuc if (is_ipc_notify(ipc_status)) {
392433d6423SLionel Sambuc switch (_ENDPOINT_P(m_ptr->m_source)) {
393433d6423SLionel Sambuc case HARDWARE:
394433d6423SLionel Sambuc if (bdp->bdr_intr)
395433d6423SLionel Sambuc (*bdp->bdr_intr)(m_ptr->m_notify.interrupts);
396433d6423SLionel Sambuc break;
397433d6423SLionel Sambuc
398433d6423SLionel Sambuc case CLOCK:
399433d6423SLionel Sambuc if (bdp->bdr_alarm)
400433d6423SLionel Sambuc (*bdp->bdr_alarm)(m_ptr->m_notify.timestamp);
401433d6423SLionel Sambuc break;
402433d6423SLionel Sambuc
403433d6423SLionel Sambuc default:
404433d6423SLionel Sambuc if (bdp->bdr_other)
405433d6423SLionel Sambuc (*bdp->bdr_other)(m_ptr, ipc_status);
406433d6423SLionel Sambuc }
407433d6423SLionel Sambuc
408433d6423SLionel Sambuc return; /* do not send a reply */
409433d6423SLionel Sambuc }
410433d6423SLionel Sambuc
411433d6423SLionel Sambuc /* Reply to character driver open requests with an error code. Otherwise, if
412433d6423SLionel Sambuc * someone creates a character device node for a block driver, opening that
413433d6423SLionel Sambuc * device node will cause the corresponding VFS thread to block forever.
414433d6423SLionel Sambuc */
415433d6423SLionel Sambuc if (m_ptr->m_type == CDEV_OPEN) {
416433d6423SLionel Sambuc do_char_open(m_ptr, ipc_status);
417433d6423SLionel Sambuc
418433d6423SLionel Sambuc return;
419433d6423SLionel Sambuc }
420433d6423SLionel Sambuc
421433d6423SLionel Sambuc /* We might get spurious requests if the driver has been restarted. Deny any
422433d6423SLionel Sambuc * requests on devices that have not previously been opened, signaling the
423433d6423SLionel Sambuc * caller that something went wrong.
424433d6423SLionel Sambuc */
425433d6423SLionel Sambuc if (IS_BDEV_RQ(m_ptr->m_type) && !is_open_dev(m_ptr->m_lbdev_lblockdriver_msg.minor)) {
426433d6423SLionel Sambuc /* Reply ERESTART to spurious requests for unopened devices. */
427433d6423SLionel Sambuc if (m_ptr->m_type != BDEV_OPEN) {
428433d6423SLionel Sambuc blockdriver_reply(m_ptr, ipc_status, ERESTART);
429433d6423SLionel Sambuc
430433d6423SLionel Sambuc return;
431433d6423SLionel Sambuc }
432433d6423SLionel Sambuc
433433d6423SLionel Sambuc /* Mark the device as opened otherwise. */
434433d6423SLionel Sambuc set_open_dev(m_ptr->m_lbdev_lblockdriver_msg.minor);
435433d6423SLionel Sambuc }
436433d6423SLionel Sambuc
437433d6423SLionel Sambuc trace_start(id, m_ptr);
438433d6423SLionel Sambuc
439433d6423SLionel Sambuc /* Call the appropriate function(s) for this request. */
440433d6423SLionel Sambuc switch (m_ptr->m_type) {
441433d6423SLionel Sambuc case BDEV_OPEN: r = do_open(bdp, m_ptr); break;
442433d6423SLionel Sambuc case BDEV_CLOSE: r = do_close(bdp, m_ptr); break;
443433d6423SLionel Sambuc case BDEV_READ:
444433d6423SLionel Sambuc case BDEV_WRITE: r = do_rdwt(bdp, m_ptr); break;
445433d6423SLionel Sambuc case BDEV_GATHER:
446433d6423SLionel Sambuc case BDEV_SCATTER: r = do_vrdwt(bdp, m_ptr, id); break;
447433d6423SLionel Sambuc case BDEV_IOCTL: r = do_ioctl(bdp, m_ptr); break;
448433d6423SLionel Sambuc default:
449433d6423SLionel Sambuc if (bdp->bdr_other != NULL)
450433d6423SLionel Sambuc (*bdp->bdr_other)(m_ptr, ipc_status);
451433d6423SLionel Sambuc
452433d6423SLionel Sambuc return; /* do not send a reply */
453433d6423SLionel Sambuc }
454433d6423SLionel Sambuc
455433d6423SLionel Sambuc /* Let the driver perform any cleanup. */
456433d6423SLionel Sambuc if (bdp->bdr_cleanup != NULL)
457433d6423SLionel Sambuc (*bdp->bdr_cleanup)();
458433d6423SLionel Sambuc
459433d6423SLionel Sambuc trace_finish(id, r);
460433d6423SLionel Sambuc
461433d6423SLionel Sambuc blockdriver_reply(m_ptr, ipc_status, r);
462433d6423SLionel Sambuc }
463