xref: /minix3/minix/lib/libbdev/driver.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc /* libbdev - driver endpoint management */
2*433d6423SLionel Sambuc 
3*433d6423SLionel Sambuc #include <minix/drivers.h>
4*433d6423SLionel Sambuc #include <minix/bdev.h>
5*433d6423SLionel Sambuc #include <minix/ds.h>
6*433d6423SLionel Sambuc #include <assert.h>
7*433d6423SLionel Sambuc 
8*433d6423SLionel Sambuc #include "const.h"
9*433d6423SLionel Sambuc #include "type.h"
10*433d6423SLionel Sambuc #include "proto.h"
11*433d6423SLionel Sambuc 
12*433d6423SLionel Sambuc static struct {
13*433d6423SLionel Sambuc   endpoint_t endpt;
14*433d6423SLionel Sambuc   char label[DS_MAX_KEYLEN];
15*433d6423SLionel Sambuc } driver_tab[NR_DEVICES];
16*433d6423SLionel Sambuc 
bdev_driver_init(void)17*433d6423SLionel Sambuc void bdev_driver_init(void)
18*433d6423SLionel Sambuc {
19*433d6423SLionel Sambuc /* Initialize the driver table.
20*433d6423SLionel Sambuc  */
21*433d6423SLionel Sambuc   int i;
22*433d6423SLionel Sambuc 
23*433d6423SLionel Sambuc   for (i = 0; i < NR_DEVICES; i++) {
24*433d6423SLionel Sambuc 	driver_tab[i].endpt = NONE;
25*433d6423SLionel Sambuc 	driver_tab[i].label[0] = '\0';
26*433d6423SLionel Sambuc   }
27*433d6423SLionel Sambuc }
28*433d6423SLionel Sambuc 
bdev_driver_clear(dev_t dev)29*433d6423SLionel Sambuc void bdev_driver_clear(dev_t dev)
30*433d6423SLionel Sambuc {
31*433d6423SLionel Sambuc /* Clear information about a driver.
32*433d6423SLionel Sambuc  */
33*433d6423SLionel Sambuc   int major;
34*433d6423SLionel Sambuc 
35*433d6423SLionel Sambuc   major = major(dev);
36*433d6423SLionel Sambuc 
37*433d6423SLionel Sambuc   assert(major >= 0 && major < NR_DEVICES);
38*433d6423SLionel Sambuc 
39*433d6423SLionel Sambuc   driver_tab[major].endpt = NONE;
40*433d6423SLionel Sambuc   driver_tab[major].label[0] = '\0';
41*433d6423SLionel Sambuc }
42*433d6423SLionel Sambuc 
bdev_driver_set(dev_t dev,char * label)43*433d6423SLionel Sambuc endpoint_t bdev_driver_set(dev_t dev, char *label)
44*433d6423SLionel Sambuc {
45*433d6423SLionel Sambuc /* Set the label for a driver, and retrieve the associated endpoint.
46*433d6423SLionel Sambuc  */
47*433d6423SLionel Sambuc   int major;
48*433d6423SLionel Sambuc 
49*433d6423SLionel Sambuc   major = major(dev);
50*433d6423SLionel Sambuc 
51*433d6423SLionel Sambuc   assert(major >= 0 && major < NR_DEVICES);
52*433d6423SLionel Sambuc   assert(strlen(label) < sizeof(driver_tab[major].label));
53*433d6423SLionel Sambuc 
54*433d6423SLionel Sambuc   strlcpy(driver_tab[major].label, label, sizeof(driver_tab[major].label));
55*433d6423SLionel Sambuc 
56*433d6423SLionel Sambuc   driver_tab[major].endpt = NONE;
57*433d6423SLionel Sambuc 
58*433d6423SLionel Sambuc   return bdev_driver_update(dev);
59*433d6423SLionel Sambuc }
60*433d6423SLionel Sambuc 
bdev_driver_get(dev_t dev)61*433d6423SLionel Sambuc endpoint_t bdev_driver_get(dev_t dev)
62*433d6423SLionel Sambuc {
63*433d6423SLionel Sambuc /* Return the endpoint for a driver, or NONE if we do not know its endpoint.
64*433d6423SLionel Sambuc  */
65*433d6423SLionel Sambuc   int major;
66*433d6423SLionel Sambuc 
67*433d6423SLionel Sambuc   major = major(dev);
68*433d6423SLionel Sambuc 
69*433d6423SLionel Sambuc   assert(major >= 0 && major < NR_DEVICES);
70*433d6423SLionel Sambuc 
71*433d6423SLionel Sambuc   return driver_tab[major].endpt;
72*433d6423SLionel Sambuc }
73*433d6423SLionel Sambuc 
bdev_driver_update(dev_t dev)74*433d6423SLionel Sambuc endpoint_t bdev_driver_update(dev_t dev)
75*433d6423SLionel Sambuc {
76*433d6423SLionel Sambuc /* Update the endpoint of a driver. The caller of this function already knows
77*433d6423SLionel Sambuc  * that the current endpoint may no longer be valid, and must be updated.
78*433d6423SLionel Sambuc  * Return the new endpoint upon success, and NONE otherwise.
79*433d6423SLionel Sambuc  */
80*433d6423SLionel Sambuc   endpoint_t endpt;
81*433d6423SLionel Sambuc   int r, major, nr_tries;
82*433d6423SLionel Sambuc 
83*433d6423SLionel Sambuc   major = major(dev);
84*433d6423SLionel Sambuc 
85*433d6423SLionel Sambuc   assert(major >= 0 && major < NR_DEVICES);
86*433d6423SLionel Sambuc   assert(driver_tab[major].label[0] != '\0');
87*433d6423SLionel Sambuc 
88*433d6423SLionel Sambuc   /* Repeatedly retrieve the endpoint for the driver label, and see if it is a
89*433d6423SLionel Sambuc    * different, valid endpoint. If retrieval fails at first, we have to wait.
90*433d6423SLionel Sambuc    * We use polling, as opposed to a DS subscription, for a number of reasons:
91*433d6423SLionel Sambuc    * 1) DS supports only one subscription per process, and our main program may
92*433d6423SLionel Sambuc    *    already have a subscription;
93*433d6423SLionel Sambuc    * 2) if we block on receiving a notification from DS, we cannot impose an
94*433d6423SLionel Sambuc    *    upper bound on the retry time;
95*433d6423SLionel Sambuc    * 3) temporarily subscribing and then unsubscribing may cause leftover DS
96*433d6423SLionel Sambuc    *    notifications, which the main program would then have to deal with.
97*433d6423SLionel Sambuc    *    As of writing, unsubscribing from DS is not possible at all, anyway.
98*433d6423SLionel Sambuc    *
99*433d6423SLionel Sambuc    * In the normal case, the driver's label/endpoint mapping entry disappears
100*433d6423SLionel Sambuc    * completely for a short moment, before being replaced with the new mapping.
101*433d6423SLionel Sambuc    * Hence, failure to retrieve the entry at all does not constitute permanent
102*433d6423SLionel Sambuc    * failure. In fact, there is no way to determine reliably that a driver has
103*433d6423SLionel Sambuc    * failed permanently in the current approach. For this we simply rely on the
104*433d6423SLionel Sambuc    * retry limit.
105*433d6423SLionel Sambuc    */
106*433d6423SLionel Sambuc   for (nr_tries = 0; nr_tries < DS_NR_TRIES; nr_tries++) {
107*433d6423SLionel Sambuc 	r = ds_retrieve_label_endpt(driver_tab[major].label, &endpt);
108*433d6423SLionel Sambuc 
109*433d6423SLionel Sambuc 	if (r == OK && endpt != NONE && endpt != driver_tab[major].endpt) {
110*433d6423SLionel Sambuc 		driver_tab[major].endpt = endpt;
111*433d6423SLionel Sambuc 
112*433d6423SLionel Sambuc 		return endpt;
113*433d6423SLionel Sambuc 	}
114*433d6423SLionel Sambuc 
115*433d6423SLionel Sambuc 	if (nr_tries < DS_NR_TRIES - 1)
116*433d6423SLionel Sambuc 		micro_delay(DS_DELAY);
117*433d6423SLionel Sambuc   }
118*433d6423SLionel Sambuc 
119*433d6423SLionel Sambuc   driver_tab[major].endpt = NONE;
120*433d6423SLionel Sambuc 
121*433d6423SLionel Sambuc   return NONE;
122*433d6423SLionel Sambuc }
123