1433d6423SLionel Sambuc /* This file contains the table with device <-> driver mappings. It also 2433d6423SLionel Sambuc * contains some routines to dynamically add and/ or remove device drivers 3433d6423SLionel Sambuc * or change mappings. 4433d6423SLionel Sambuc */ 5433d6423SLionel Sambuc 6433d6423SLionel Sambuc #include "fs.h" 7433d6423SLionel Sambuc #include <assert.h> 8433d6423SLionel Sambuc #include <string.h> 9433d6423SLionel Sambuc #include <stdlib.h> 10433d6423SLionel Sambuc #include <ctype.h> 11433d6423SLionel Sambuc #include <unistd.h> 12433d6423SLionel Sambuc #include <minix/callnr.h> 13433d6423SLionel Sambuc #include <minix/ds.h> 14433d6423SLionel Sambuc 15433d6423SLionel Sambuc /* The order of the entries in the table determines the mapping between major 16433d6423SLionel Sambuc * device numbers and device drivers. Character and block devices 17433d6423SLionel Sambuc * can be intermixed at random. The ordering determines the device numbers in 18433d6423SLionel Sambuc * /dev. Note that the major device numbers used in /dev are NOT the same as 19433d6423SLionel Sambuc * the process numbers of the device drivers. See <minix/dmap.h> for mappings. 20433d6423SLionel Sambuc */ 21433d6423SLionel Sambuc 22433d6423SLionel Sambuc struct dmap dmap[NR_DEVICES]; 23433d6423SLionel Sambuc 24433d6423SLionel Sambuc /*===========================================================================* 25433d6423SLionel Sambuc * lock_dmap * 26433d6423SLionel Sambuc *===========================================================================*/ 27433d6423SLionel Sambuc void lock_dmap(struct dmap *dp) 28433d6423SLionel Sambuc { 29433d6423SLionel Sambuc /* Lock a driver */ 30433d6423SLionel Sambuc struct worker_thread *org_self; 31433d6423SLionel Sambuc int r; 32433d6423SLionel Sambuc 33433d6423SLionel Sambuc assert(dp != NULL); 34433d6423SLionel Sambuc assert(dp->dmap_driver != NONE); 35433d6423SLionel Sambuc 36433d6423SLionel Sambuc org_self = worker_suspend(); 37433d6423SLionel Sambuc 38433d6423SLionel Sambuc if ((r = mutex_lock(&dp->dmap_lock)) != 0) 39433d6423SLionel Sambuc panic("unable to get a lock on dmap: %d\n", r); 40433d6423SLionel Sambuc 41433d6423SLionel Sambuc worker_resume(org_self); 42433d6423SLionel Sambuc } 43433d6423SLionel Sambuc 44433d6423SLionel Sambuc /*===========================================================================* 45433d6423SLionel Sambuc * unlock_dmap * 46433d6423SLionel Sambuc *===========================================================================*/ 47433d6423SLionel Sambuc void unlock_dmap(struct dmap *dp) 48433d6423SLionel Sambuc { 49433d6423SLionel Sambuc /* Unlock a driver */ 50433d6423SLionel Sambuc int r; 51433d6423SLionel Sambuc 52433d6423SLionel Sambuc assert(dp != NULL); 53433d6423SLionel Sambuc 54433d6423SLionel Sambuc if ((r = mutex_unlock(&dp->dmap_lock)) != 0) 55433d6423SLionel Sambuc panic("unable to unlock dmap lock: %d\n", r); 56433d6423SLionel Sambuc } 57433d6423SLionel Sambuc 58433d6423SLionel Sambuc /*===========================================================================* 59433d6423SLionel Sambuc * map_driver * 60433d6423SLionel Sambuc *===========================================================================*/ 61433d6423SLionel Sambuc static int map_driver(const char label[LABEL_MAX], devmajor_t major, 62433d6423SLionel Sambuc endpoint_t proc_nr_e) 63433d6423SLionel Sambuc { 64433d6423SLionel Sambuc /* Add a new device driver mapping in the dmap table. If the proc_nr is set to 65433d6423SLionel Sambuc * NONE, we're supposed to unmap it. 66433d6423SLionel Sambuc */ 67433d6423SLionel Sambuc size_t len; 68433d6423SLionel Sambuc struct dmap *dp; 69433d6423SLionel Sambuc 70433d6423SLionel Sambuc /* Get pointer to device entry in the dmap table. */ 71433d6423SLionel Sambuc if (major < 0 || major >= NR_DEVICES) return(ENODEV); 72433d6423SLionel Sambuc dp = &dmap[major]; 73433d6423SLionel Sambuc 74433d6423SLionel Sambuc /* Check if we're supposed to unmap it. */ 75433d6423SLionel Sambuc if (proc_nr_e == NONE) { 76433d6423SLionel Sambuc /* Even when a driver is now unmapped and is shortly to be mapped in 77433d6423SLionel Sambuc * due to recovery, invalidate associated filps if they're character 78433d6423SLionel Sambuc * special files. More sophisticated recovery mechanisms which would 79433d6423SLionel Sambuc * reduce the need to invalidate files are possible, but would require 80433d6423SLionel Sambuc * cooperation of the driver and more recovery framework between RS, 81433d6423SLionel Sambuc * VFS, and DS. 82433d6423SLionel Sambuc */ 83433d6423SLionel Sambuc invalidate_filp_by_char_major(major); 84433d6423SLionel Sambuc dp->dmap_driver = NONE; 85433d6423SLionel Sambuc return(OK); 86433d6423SLionel Sambuc } 87433d6423SLionel Sambuc 88433d6423SLionel Sambuc if (label != NULL) { 89433d6423SLionel Sambuc len = strlen(label); 90433d6423SLionel Sambuc if (len+1 > sizeof(dp->dmap_label)) { 91*3c8950ccSBen Gras printf("VFS: map_driver: label too long: %zu\n", len); 92433d6423SLionel Sambuc return(EINVAL); 93433d6423SLionel Sambuc } 94433d6423SLionel Sambuc strlcpy(dp->dmap_label, label, sizeof(dp->dmap_label)); 95433d6423SLionel Sambuc } 96433d6423SLionel Sambuc 97433d6423SLionel Sambuc /* Store driver I/O routines based on type of device */ 98433d6423SLionel Sambuc dp->dmap_driver = proc_nr_e; 99433d6423SLionel Sambuc 100433d6423SLionel Sambuc return(OK); 101433d6423SLionel Sambuc } 102433d6423SLionel Sambuc 103433d6423SLionel Sambuc /*===========================================================================* 104433d6423SLionel Sambuc * do_mapdriver * 105433d6423SLionel Sambuc *===========================================================================*/ 106433d6423SLionel Sambuc int do_mapdriver(void) 107433d6423SLionel Sambuc { 108433d6423SLionel Sambuc /* Create a device->driver mapping. RS will tell us which major is driven by 109433d6423SLionel Sambuc * this driver, what type of device it is (regular, TTY, asynchronous, clone, 110433d6423SLionel Sambuc * etc), and its label. This label is registered with DS, and allows us to 111433d6423SLionel Sambuc * retrieve the driver's endpoint. 112433d6423SLionel Sambuc */ 1133b468884SDavid van Moolenbroek int r, slot; 1143b468884SDavid van Moolenbroek devmajor_t major; 115433d6423SLionel Sambuc endpoint_t endpoint; 116433d6423SLionel Sambuc vir_bytes label_vir; 117433d6423SLionel Sambuc size_t label_len; 118433d6423SLionel Sambuc char label[LABEL_MAX]; 119433d6423SLionel Sambuc struct fproc *rfp; 120433d6423SLionel Sambuc 121433d6423SLionel Sambuc /* Only RS can map drivers. */ 122433d6423SLionel Sambuc if (who_e != RS_PROC_NR) return(EPERM); 123433d6423SLionel Sambuc 124433d6423SLionel Sambuc label_vir = job_m_in.m_lsys_vfs_mapdriver.label; 125433d6423SLionel Sambuc label_len = job_m_in.m_lsys_vfs_mapdriver.labellen; 126433d6423SLionel Sambuc major = job_m_in.m_lsys_vfs_mapdriver.major; 127433d6423SLionel Sambuc 128433d6423SLionel Sambuc /* Get the label */ 129433d6423SLionel Sambuc if (label_len > sizeof(label)) { /* Can we store this label? */ 130433d6423SLionel Sambuc printf("VFS: do_mapdriver: label too long\n"); 131433d6423SLionel Sambuc return(EINVAL); 132433d6423SLionel Sambuc } 133433d6423SLionel Sambuc r = sys_vircopy(who_e, label_vir, SELF, (vir_bytes) label, label_len, 134433d6423SLionel Sambuc CP_FLAG_TRY); 135433d6423SLionel Sambuc if (r != OK) { 136433d6423SLionel Sambuc printf("VFS: do_mapdriver: sys_vircopy failed: %d\n", r); 137433d6423SLionel Sambuc return(EINVAL); 138433d6423SLionel Sambuc } 139433d6423SLionel Sambuc if (label[label_len-1] != '\0') { 140433d6423SLionel Sambuc printf("VFS: do_mapdriver: label not null-terminated\n"); 141433d6423SLionel Sambuc return(EINVAL); 142433d6423SLionel Sambuc } 143433d6423SLionel Sambuc 144433d6423SLionel Sambuc /* Now we know how the driver is called, fetch its endpoint */ 145433d6423SLionel Sambuc r = ds_retrieve_label_endpt(label, &endpoint); 146433d6423SLionel Sambuc if (r != OK) { 147433d6423SLionel Sambuc printf("VFS: do_mapdriver: label '%s' unknown\n", label); 148433d6423SLionel Sambuc return(EINVAL); 149433d6423SLionel Sambuc } 150433d6423SLionel Sambuc 151433d6423SLionel Sambuc /* Process is a service */ 152433d6423SLionel Sambuc if (isokendpt(endpoint, &slot) != OK) { 153433d6423SLionel Sambuc printf("VFS: can't map driver to unknown endpoint %d\n", endpoint); 154433d6423SLionel Sambuc return(EINVAL); 155433d6423SLionel Sambuc } 156433d6423SLionel Sambuc rfp = &fproc[slot]; 157433d6423SLionel Sambuc rfp->fp_flags |= FP_SRV_PROC; 158433d6423SLionel Sambuc 159433d6423SLionel Sambuc /* Try to update device mapping. */ 160433d6423SLionel Sambuc return map_driver(label, major, endpoint); 161433d6423SLionel Sambuc } 162433d6423SLionel Sambuc 163433d6423SLionel Sambuc /*===========================================================================* 164433d6423SLionel Sambuc * dmap_unmap_by_endpt * 165433d6423SLionel Sambuc *===========================================================================*/ 166433d6423SLionel Sambuc void dmap_unmap_by_endpt(endpoint_t proc_e) 167433d6423SLionel Sambuc { 168433d6423SLionel Sambuc /* Lookup driver in dmap table by endpoint and unmap it */ 1693b468884SDavid van Moolenbroek devmajor_t major; 1703b468884SDavid van Moolenbroek int r; 171433d6423SLionel Sambuc 172433d6423SLionel Sambuc for (major = 0; major < NR_DEVICES; major++) { 173433d6423SLionel Sambuc if (dmap_driver_match(proc_e, major)) { 174433d6423SLionel Sambuc /* Found driver; overwrite it with a NULL entry */ 175433d6423SLionel Sambuc if ((r = map_driver(NULL, major, NONE)) != OK) { 176433d6423SLionel Sambuc printf("VFS: unmapping driver %d for major %d failed:" 177433d6423SLionel Sambuc " %d\n", proc_e, major, r); 178433d6423SLionel Sambuc } 179433d6423SLionel Sambuc } 180433d6423SLionel Sambuc } 181433d6423SLionel Sambuc } 182433d6423SLionel Sambuc 183433d6423SLionel Sambuc /*===========================================================================* 184433d6423SLionel Sambuc * map_service * 185433d6423SLionel Sambuc *===========================================================================*/ 186433d6423SLionel Sambuc int map_service(struct rprocpub *rpub) 187433d6423SLionel Sambuc { 188433d6423SLionel Sambuc /* Map a new service by storing its device driver properties. */ 189433d6423SLionel Sambuc int r, slot; 190433d6423SLionel Sambuc struct fproc *rfp; 191433d6423SLionel Sambuc 192433d6423SLionel Sambuc if (IS_RPUB_BOOT_USR(rpub)) return(OK); 193433d6423SLionel Sambuc 194433d6423SLionel Sambuc /* Process is a service */ 195433d6423SLionel Sambuc if (isokendpt(rpub->endpoint, &slot) != OK) { 196433d6423SLionel Sambuc printf("VFS: can't map service with unknown endpoint %d\n", 197433d6423SLionel Sambuc rpub->endpoint); 198433d6423SLionel Sambuc return(EINVAL); 199433d6423SLionel Sambuc } 200433d6423SLionel Sambuc rfp = &fproc[slot]; 201433d6423SLionel Sambuc rfp->fp_flags |= FP_SRV_PROC; 202433d6423SLionel Sambuc 203433d6423SLionel Sambuc /* Not a driver, nothing more to do. */ 204433d6423SLionel Sambuc if (rpub->dev_nr == NO_DEV) return(OK); 205433d6423SLionel Sambuc 206433d6423SLionel Sambuc /* Map driver. */ 207433d6423SLionel Sambuc r = map_driver(rpub->label, rpub->dev_nr, rpub->endpoint); 208433d6423SLionel Sambuc if(r != OK) return(r); 209433d6423SLionel Sambuc 210433d6423SLionel Sambuc return(OK); 211433d6423SLionel Sambuc } 212433d6423SLionel Sambuc 213433d6423SLionel Sambuc /*===========================================================================* 214433d6423SLionel Sambuc * init_dmap * 215433d6423SLionel Sambuc *===========================================================================*/ 216433d6423SLionel Sambuc void init_dmap(void) 217433d6423SLionel Sambuc { 218433d6423SLionel Sambuc /* Initialize the device mapping table. */ 219433d6423SLionel Sambuc int i; 220433d6423SLionel Sambuc 221433d6423SLionel Sambuc memset(dmap, 0, sizeof(dmap)); 222433d6423SLionel Sambuc 223433d6423SLionel Sambuc for (i = 0; i < NR_DEVICES; i++) { 224433d6423SLionel Sambuc dmap[i].dmap_driver = NONE; 225433d6423SLionel Sambuc dmap[i].dmap_servicing = INVALID_THREAD; 226433d6423SLionel Sambuc if (mutex_init(&dmap[i].dmap_lock, NULL) != 0) 227433d6423SLionel Sambuc panic("unable to initialize dmap lock"); 228433d6423SLionel Sambuc } 229433d6423SLionel Sambuc 230433d6423SLionel Sambuc /* CTTY_MAJOR is a special case, which is handled by VFS itself. */ 231433d6423SLionel Sambuc if (map_driver("vfs", CTTY_MAJOR, CTTY_ENDPT) != OK) 232433d6423SLionel Sambuc panic("map_driver(CTTY_MAJOR) failed"); 233433d6423SLionel Sambuc } 234433d6423SLionel Sambuc 235433d6423SLionel Sambuc /*===========================================================================* 236433d6423SLionel Sambuc * dmap_driver_match * 237433d6423SLionel Sambuc *===========================================================================*/ 2383b468884SDavid van Moolenbroek int dmap_driver_match(endpoint_t proc, devmajor_t major) 239433d6423SLionel Sambuc { 240433d6423SLionel Sambuc if (major < 0 || major >= NR_DEVICES) return(0); 241433d6423SLionel Sambuc if (dmap[major].dmap_driver != NONE && dmap[major].dmap_driver == proc) 242433d6423SLionel Sambuc return(1); 243433d6423SLionel Sambuc 244433d6423SLionel Sambuc return(0); 245433d6423SLionel Sambuc } 246433d6423SLionel Sambuc 247433d6423SLionel Sambuc /*===========================================================================* 248433d6423SLionel Sambuc * dmap_by_major * 249433d6423SLionel Sambuc *===========================================================================*/ 250433d6423SLionel Sambuc struct dmap * 2513b468884SDavid van Moolenbroek get_dmap_by_major(devmajor_t major) 252433d6423SLionel Sambuc { 253433d6423SLionel Sambuc if (major < 0 || major >= NR_DEVICES) return(NULL); 254433d6423SLionel Sambuc if (dmap[major].dmap_driver == NONE) return(NULL); 255433d6423SLionel Sambuc return(&dmap[major]); 256433d6423SLionel Sambuc } 257433d6423SLionel Sambuc 258433d6423SLionel Sambuc /*===========================================================================* 259433d6423SLionel Sambuc * dmap_endpt_up * 260433d6423SLionel Sambuc *===========================================================================*/ 261433d6423SLionel Sambuc void dmap_endpt_up(endpoint_t proc_e, int is_blk) 262433d6423SLionel Sambuc { 263433d6423SLionel Sambuc /* A device driver with endpoint proc_e has been restarted. Go tell everyone 264433d6423SLionel Sambuc * that might be blocking on it that this device is 'up'. 265433d6423SLionel Sambuc */ 2663b468884SDavid van Moolenbroek devmajor_t major; 267433d6423SLionel Sambuc struct dmap *dp; 268433d6423SLionel Sambuc struct worker_thread *worker; 269433d6423SLionel Sambuc 270433d6423SLionel Sambuc if (proc_e == NONE) return; 271433d6423SLionel Sambuc 272433d6423SLionel Sambuc for (major = 0; major < NR_DEVICES; major++) { 273433d6423SLionel Sambuc if ((dp = get_dmap_by_major(major)) == NULL) continue; 274433d6423SLionel Sambuc if (dp->dmap_driver == proc_e) { 275433d6423SLionel Sambuc if (is_blk) { 276433d6423SLionel Sambuc if (dp->dmap_recovering) { 277433d6423SLionel Sambuc printf("VFS: driver recovery failure for" 278433d6423SLionel Sambuc " major %d\n", major); 279433d6423SLionel Sambuc if (dp->dmap_servicing != INVALID_THREAD) { 280433d6423SLionel Sambuc worker = worker_get(dp->dmap_servicing); 281433d6423SLionel Sambuc worker_stop(worker); 282433d6423SLionel Sambuc } 283433d6423SLionel Sambuc dp->dmap_recovering = 0; 284433d6423SLionel Sambuc continue; 285433d6423SLionel Sambuc } 286433d6423SLionel Sambuc dp->dmap_recovering = 1; 287433d6423SLionel Sambuc bdev_up(major); 288433d6423SLionel Sambuc dp->dmap_recovering = 0; 289433d6423SLionel Sambuc } else { 290433d6423SLionel Sambuc if (dp->dmap_servicing != INVALID_THREAD) { 291433d6423SLionel Sambuc worker = worker_get(dp->dmap_servicing); 292433d6423SLionel Sambuc worker_stop(worker); 293433d6423SLionel Sambuc } 294433d6423SLionel Sambuc invalidate_filp_by_char_major(major); 295433d6423SLionel Sambuc } 296433d6423SLionel Sambuc } 297433d6423SLionel Sambuc } 298433d6423SLionel Sambuc } 299433d6423SLionel Sambuc 300433d6423SLionel Sambuc /*===========================================================================* 301433d6423SLionel Sambuc * get_dmap * 302433d6423SLionel Sambuc *===========================================================================*/ 303433d6423SLionel Sambuc struct dmap *get_dmap(endpoint_t proc_e) 304433d6423SLionel Sambuc { 305433d6423SLionel Sambuc /* See if 'proc_e' endpoint belongs to a valid dmap entry. If so, return a 306433d6423SLionel Sambuc * pointer */ 3073b468884SDavid van Moolenbroek devmajor_t major; 308433d6423SLionel Sambuc 309433d6423SLionel Sambuc for (major = 0; major < NR_DEVICES; major++) 310433d6423SLionel Sambuc if (dmap_driver_match(proc_e, major)) 311433d6423SLionel Sambuc return(&dmap[major]); 312433d6423SLionel Sambuc 313433d6423SLionel Sambuc return(NULL); 314433d6423SLionel Sambuc } 315