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