1*433d6423SLionel Sambuc /* This file contains the table with device <-> driver mappings. It also 2*433d6423SLionel Sambuc * contains some routines to dynamically add and/ or remove device drivers 3*433d6423SLionel Sambuc * or change mappings. 4*433d6423SLionel Sambuc */ 5*433d6423SLionel Sambuc 6*433d6423SLionel Sambuc #include "fs.h" 7*433d6423SLionel Sambuc #include <assert.h> 8*433d6423SLionel Sambuc #include <string.h> 9*433d6423SLionel Sambuc #include <stdlib.h> 10*433d6423SLionel Sambuc #include <ctype.h> 11*433d6423SLionel Sambuc #include <unistd.h> 12*433d6423SLionel Sambuc #include <minix/callnr.h> 13*433d6423SLionel Sambuc #include <minix/ds.h> 14*433d6423SLionel Sambuc 15*433d6423SLionel Sambuc /* The order of the entries in the table determines the mapping between major 16*433d6423SLionel Sambuc * device numbers and device drivers. Character and block devices 17*433d6423SLionel Sambuc * can be intermixed at random. The ordering determines the device numbers in 18*433d6423SLionel Sambuc * /dev. Note that the major device numbers used in /dev are NOT the same as 19*433d6423SLionel Sambuc * the process numbers of the device drivers. See <minix/dmap.h> for mappings. 20*433d6423SLionel Sambuc */ 21*433d6423SLionel Sambuc 22*433d6423SLionel Sambuc struct dmap dmap[NR_DEVICES]; 23*433d6423SLionel Sambuc 24*433d6423SLionel Sambuc /*===========================================================================* 25*433d6423SLionel Sambuc * lock_dmap * 26*433d6423SLionel Sambuc *===========================================================================*/ 27*433d6423SLionel Sambuc void lock_dmap(struct dmap *dp) 28*433d6423SLionel Sambuc { 29*433d6423SLionel Sambuc /* Lock a driver */ 30*433d6423SLionel Sambuc struct worker_thread *org_self; 31*433d6423SLionel Sambuc int r; 32*433d6423SLionel Sambuc 33*433d6423SLionel Sambuc assert(dp != NULL); 34*433d6423SLionel Sambuc assert(dp->dmap_driver != NONE); 35*433d6423SLionel Sambuc 36*433d6423SLionel Sambuc org_self = worker_suspend(); 37*433d6423SLionel Sambuc 38*433d6423SLionel Sambuc if ((r = mutex_lock(&dp->dmap_lock)) != 0) 39*433d6423SLionel Sambuc panic("unable to get a lock on dmap: %d\n", r); 40*433d6423SLionel Sambuc 41*433d6423SLionel Sambuc worker_resume(org_self); 42*433d6423SLionel Sambuc } 43*433d6423SLionel Sambuc 44*433d6423SLionel Sambuc /*===========================================================================* 45*433d6423SLionel Sambuc * unlock_dmap * 46*433d6423SLionel Sambuc *===========================================================================*/ 47*433d6423SLionel Sambuc void unlock_dmap(struct dmap *dp) 48*433d6423SLionel Sambuc { 49*433d6423SLionel Sambuc /* Unlock a driver */ 50*433d6423SLionel Sambuc int r; 51*433d6423SLionel Sambuc 52*433d6423SLionel Sambuc assert(dp != NULL); 53*433d6423SLionel Sambuc 54*433d6423SLionel Sambuc if ((r = mutex_unlock(&dp->dmap_lock)) != 0) 55*433d6423SLionel Sambuc panic("unable to unlock dmap lock: %d\n", r); 56*433d6423SLionel Sambuc } 57*433d6423SLionel Sambuc 58*433d6423SLionel Sambuc /*===========================================================================* 59*433d6423SLionel Sambuc * map_driver * 60*433d6423SLionel Sambuc *===========================================================================*/ 61*433d6423SLionel Sambuc static int map_driver(const char label[LABEL_MAX], devmajor_t major, 62*433d6423SLionel Sambuc endpoint_t proc_nr_e) 63*433d6423SLionel Sambuc { 64*433d6423SLionel Sambuc /* Add a new device driver mapping in the dmap table. If the proc_nr is set to 65*433d6423SLionel Sambuc * NONE, we're supposed to unmap it. 66*433d6423SLionel Sambuc */ 67*433d6423SLionel Sambuc size_t len; 68*433d6423SLionel Sambuc struct dmap *dp; 69*433d6423SLionel Sambuc 70*433d6423SLionel Sambuc /* Get pointer to device entry in the dmap table. */ 71*433d6423SLionel Sambuc if (major < 0 || major >= NR_DEVICES) return(ENODEV); 72*433d6423SLionel Sambuc dp = &dmap[major]; 73*433d6423SLionel Sambuc 74*433d6423SLionel Sambuc /* Check if we're supposed to unmap it. */ 75*433d6423SLionel Sambuc if (proc_nr_e == NONE) { 76*433d6423SLionel Sambuc /* Even when a driver is now unmapped and is shortly to be mapped in 77*433d6423SLionel Sambuc * due to recovery, invalidate associated filps if they're character 78*433d6423SLionel Sambuc * special files. More sophisticated recovery mechanisms which would 79*433d6423SLionel Sambuc * reduce the need to invalidate files are possible, but would require 80*433d6423SLionel Sambuc * cooperation of the driver and more recovery framework between RS, 81*433d6423SLionel Sambuc * VFS, and DS. 82*433d6423SLionel Sambuc */ 83*433d6423SLionel Sambuc invalidate_filp_by_char_major(major); 84*433d6423SLionel Sambuc dp->dmap_driver = NONE; 85*433d6423SLionel Sambuc return(OK); 86*433d6423SLionel Sambuc } 87*433d6423SLionel Sambuc 88*433d6423SLionel Sambuc if (label != NULL) { 89*433d6423SLionel Sambuc len = strlen(label); 90*433d6423SLionel Sambuc if (len+1 > sizeof(dp->dmap_label)) { 91*433d6423SLionel Sambuc printf("VFS: map_driver: label too long: %d\n", len); 92*433d6423SLionel Sambuc return(EINVAL); 93*433d6423SLionel Sambuc } 94*433d6423SLionel Sambuc strlcpy(dp->dmap_label, label, sizeof(dp->dmap_label)); 95*433d6423SLionel Sambuc } 96*433d6423SLionel Sambuc 97*433d6423SLionel Sambuc /* Store driver I/O routines based on type of device */ 98*433d6423SLionel Sambuc dp->dmap_driver = proc_nr_e; 99*433d6423SLionel Sambuc 100*433d6423SLionel Sambuc return(OK); 101*433d6423SLionel Sambuc } 102*433d6423SLionel Sambuc 103*433d6423SLionel Sambuc /*===========================================================================* 104*433d6423SLionel Sambuc * do_mapdriver * 105*433d6423SLionel Sambuc *===========================================================================*/ 106*433d6423SLionel Sambuc int do_mapdriver(void) 107*433d6423SLionel Sambuc { 108*433d6423SLionel Sambuc /* Create a device->driver mapping. RS will tell us which major is driven by 109*433d6423SLionel Sambuc * this driver, what type of device it is (regular, TTY, asynchronous, clone, 110*433d6423SLionel Sambuc * etc), and its label. This label is registered with DS, and allows us to 111*433d6423SLionel Sambuc * retrieve the driver's endpoint. 112*433d6423SLionel Sambuc */ 113*433d6423SLionel Sambuc int r, major, slot; 114*433d6423SLionel Sambuc endpoint_t endpoint; 115*433d6423SLionel Sambuc vir_bytes label_vir; 116*433d6423SLionel Sambuc size_t label_len; 117*433d6423SLionel Sambuc char label[LABEL_MAX]; 118*433d6423SLionel Sambuc struct fproc *rfp; 119*433d6423SLionel Sambuc 120*433d6423SLionel Sambuc /* Only RS can map drivers. */ 121*433d6423SLionel Sambuc if (who_e != RS_PROC_NR) return(EPERM); 122*433d6423SLionel Sambuc 123*433d6423SLionel Sambuc label_vir = job_m_in.m_lsys_vfs_mapdriver.label; 124*433d6423SLionel Sambuc label_len = job_m_in.m_lsys_vfs_mapdriver.labellen; 125*433d6423SLionel Sambuc major = job_m_in.m_lsys_vfs_mapdriver.major; 126*433d6423SLionel Sambuc 127*433d6423SLionel Sambuc /* Get the label */ 128*433d6423SLionel Sambuc if (label_len > sizeof(label)) { /* Can we store this label? */ 129*433d6423SLionel Sambuc printf("VFS: do_mapdriver: label too long\n"); 130*433d6423SLionel Sambuc return(EINVAL); 131*433d6423SLionel Sambuc } 132*433d6423SLionel Sambuc r = sys_vircopy(who_e, label_vir, SELF, (vir_bytes) label, label_len, 133*433d6423SLionel Sambuc CP_FLAG_TRY); 134*433d6423SLionel Sambuc if (r != OK) { 135*433d6423SLionel Sambuc printf("VFS: do_mapdriver: sys_vircopy failed: %d\n", r); 136*433d6423SLionel Sambuc return(EINVAL); 137*433d6423SLionel Sambuc } 138*433d6423SLionel Sambuc if (label[label_len-1] != '\0') { 139*433d6423SLionel Sambuc printf("VFS: do_mapdriver: label not null-terminated\n"); 140*433d6423SLionel Sambuc return(EINVAL); 141*433d6423SLionel Sambuc } 142*433d6423SLionel Sambuc 143*433d6423SLionel Sambuc /* Now we know how the driver is called, fetch its endpoint */ 144*433d6423SLionel Sambuc r = ds_retrieve_label_endpt(label, &endpoint); 145*433d6423SLionel Sambuc if (r != OK) { 146*433d6423SLionel Sambuc printf("VFS: do_mapdriver: label '%s' unknown\n", label); 147*433d6423SLionel Sambuc return(EINVAL); 148*433d6423SLionel Sambuc } 149*433d6423SLionel Sambuc 150*433d6423SLionel Sambuc /* Process is a service */ 151*433d6423SLionel Sambuc if (isokendpt(endpoint, &slot) != OK) { 152*433d6423SLionel Sambuc printf("VFS: can't map driver to unknown endpoint %d\n", endpoint); 153*433d6423SLionel Sambuc return(EINVAL); 154*433d6423SLionel Sambuc } 155*433d6423SLionel Sambuc rfp = &fproc[slot]; 156*433d6423SLionel Sambuc rfp->fp_flags |= FP_SRV_PROC; 157*433d6423SLionel Sambuc 158*433d6423SLionel Sambuc /* Try to update device mapping. */ 159*433d6423SLionel Sambuc return map_driver(label, major, endpoint); 160*433d6423SLionel Sambuc } 161*433d6423SLionel Sambuc 162*433d6423SLionel Sambuc /*===========================================================================* 163*433d6423SLionel Sambuc * dmap_unmap_by_endpt * 164*433d6423SLionel Sambuc *===========================================================================*/ 165*433d6423SLionel Sambuc void dmap_unmap_by_endpt(endpoint_t proc_e) 166*433d6423SLionel Sambuc { 167*433d6423SLionel Sambuc /* Lookup driver in dmap table by endpoint and unmap it */ 168*433d6423SLionel Sambuc int major, r; 169*433d6423SLionel Sambuc 170*433d6423SLionel Sambuc for (major = 0; major < NR_DEVICES; major++) { 171*433d6423SLionel Sambuc if (dmap_driver_match(proc_e, major)) { 172*433d6423SLionel Sambuc /* Found driver; overwrite it with a NULL entry */ 173*433d6423SLionel Sambuc if ((r = map_driver(NULL, major, NONE)) != OK) { 174*433d6423SLionel Sambuc printf("VFS: unmapping driver %d for major %d failed:" 175*433d6423SLionel Sambuc " %d\n", proc_e, major, r); 176*433d6423SLionel Sambuc } 177*433d6423SLionel Sambuc } 178*433d6423SLionel Sambuc } 179*433d6423SLionel Sambuc } 180*433d6423SLionel Sambuc 181*433d6423SLionel Sambuc /*===========================================================================* 182*433d6423SLionel Sambuc * map_service * 183*433d6423SLionel Sambuc *===========================================================================*/ 184*433d6423SLionel Sambuc int map_service(struct rprocpub *rpub) 185*433d6423SLionel Sambuc { 186*433d6423SLionel Sambuc /* Map a new service by storing its device driver properties. */ 187*433d6423SLionel Sambuc int r, slot; 188*433d6423SLionel Sambuc struct fproc *rfp; 189*433d6423SLionel Sambuc 190*433d6423SLionel Sambuc if (IS_RPUB_BOOT_USR(rpub)) return(OK); 191*433d6423SLionel Sambuc 192*433d6423SLionel Sambuc /* Process is a service */ 193*433d6423SLionel Sambuc if (isokendpt(rpub->endpoint, &slot) != OK) { 194*433d6423SLionel Sambuc printf("VFS: can't map service with unknown endpoint %d\n", 195*433d6423SLionel Sambuc rpub->endpoint); 196*433d6423SLionel Sambuc return(EINVAL); 197*433d6423SLionel Sambuc } 198*433d6423SLionel Sambuc rfp = &fproc[slot]; 199*433d6423SLionel Sambuc rfp->fp_flags |= FP_SRV_PROC; 200*433d6423SLionel Sambuc 201*433d6423SLionel Sambuc /* Not a driver, nothing more to do. */ 202*433d6423SLionel Sambuc if (rpub->dev_nr == NO_DEV) return(OK); 203*433d6423SLionel Sambuc 204*433d6423SLionel Sambuc /* Map driver. */ 205*433d6423SLionel Sambuc r = map_driver(rpub->label, rpub->dev_nr, rpub->endpoint); 206*433d6423SLionel Sambuc if(r != OK) return(r); 207*433d6423SLionel Sambuc 208*433d6423SLionel Sambuc return(OK); 209*433d6423SLionel Sambuc } 210*433d6423SLionel Sambuc 211*433d6423SLionel Sambuc /*===========================================================================* 212*433d6423SLionel Sambuc * init_dmap * 213*433d6423SLionel Sambuc *===========================================================================*/ 214*433d6423SLionel Sambuc void init_dmap(void) 215*433d6423SLionel Sambuc { 216*433d6423SLionel Sambuc /* Initialize the device mapping table. */ 217*433d6423SLionel Sambuc int i; 218*433d6423SLionel Sambuc 219*433d6423SLionel Sambuc memset(dmap, 0, sizeof(dmap)); 220*433d6423SLionel Sambuc 221*433d6423SLionel Sambuc for (i = 0; i < NR_DEVICES; i++) { 222*433d6423SLionel Sambuc dmap[i].dmap_driver = NONE; 223*433d6423SLionel Sambuc dmap[i].dmap_servicing = INVALID_THREAD; 224*433d6423SLionel Sambuc if (mutex_init(&dmap[i].dmap_lock, NULL) != 0) 225*433d6423SLionel Sambuc panic("unable to initialize dmap lock"); 226*433d6423SLionel Sambuc } 227*433d6423SLionel Sambuc 228*433d6423SLionel Sambuc /* CTTY_MAJOR is a special case, which is handled by VFS itself. */ 229*433d6423SLionel Sambuc if (map_driver("vfs", CTTY_MAJOR, CTTY_ENDPT) != OK) 230*433d6423SLionel Sambuc panic("map_driver(CTTY_MAJOR) failed"); 231*433d6423SLionel Sambuc } 232*433d6423SLionel Sambuc 233*433d6423SLionel Sambuc /*===========================================================================* 234*433d6423SLionel Sambuc * dmap_driver_match * 235*433d6423SLionel Sambuc *===========================================================================*/ 236*433d6423SLionel Sambuc int dmap_driver_match(endpoint_t proc, int major) 237*433d6423SLionel Sambuc { 238*433d6423SLionel Sambuc if (major < 0 || major >= NR_DEVICES) return(0); 239*433d6423SLionel Sambuc if (dmap[major].dmap_driver != NONE && dmap[major].dmap_driver == proc) 240*433d6423SLionel Sambuc return(1); 241*433d6423SLionel Sambuc 242*433d6423SLionel Sambuc return(0); 243*433d6423SLionel Sambuc } 244*433d6423SLionel Sambuc 245*433d6423SLionel Sambuc /*===========================================================================* 246*433d6423SLionel Sambuc * dmap_by_major * 247*433d6423SLionel Sambuc *===========================================================================*/ 248*433d6423SLionel Sambuc struct dmap * 249*433d6423SLionel Sambuc get_dmap_by_major(int major) 250*433d6423SLionel Sambuc { 251*433d6423SLionel Sambuc if (major < 0 || major >= NR_DEVICES) return(NULL); 252*433d6423SLionel Sambuc if (dmap[major].dmap_driver == NONE) return(NULL); 253*433d6423SLionel Sambuc return(&dmap[major]); 254*433d6423SLionel Sambuc } 255*433d6423SLionel Sambuc 256*433d6423SLionel Sambuc /*===========================================================================* 257*433d6423SLionel Sambuc * dmap_endpt_up * 258*433d6423SLionel Sambuc *===========================================================================*/ 259*433d6423SLionel Sambuc void dmap_endpt_up(endpoint_t proc_e, int is_blk) 260*433d6423SLionel Sambuc { 261*433d6423SLionel Sambuc /* A device driver with endpoint proc_e has been restarted. Go tell everyone 262*433d6423SLionel Sambuc * that might be blocking on it that this device is 'up'. 263*433d6423SLionel Sambuc */ 264*433d6423SLionel Sambuc 265*433d6423SLionel Sambuc int major; 266*433d6423SLionel Sambuc struct dmap *dp; 267*433d6423SLionel Sambuc struct worker_thread *worker; 268*433d6423SLionel Sambuc 269*433d6423SLionel Sambuc if (proc_e == NONE) return; 270*433d6423SLionel Sambuc 271*433d6423SLionel Sambuc for (major = 0; major < NR_DEVICES; major++) { 272*433d6423SLionel Sambuc if ((dp = get_dmap_by_major(major)) == NULL) continue; 273*433d6423SLionel Sambuc if (dp->dmap_driver == proc_e) { 274*433d6423SLionel Sambuc if (is_blk) { 275*433d6423SLionel Sambuc if (dp->dmap_recovering) { 276*433d6423SLionel Sambuc printf("VFS: driver recovery failure for" 277*433d6423SLionel Sambuc " major %d\n", major); 278*433d6423SLionel Sambuc if (dp->dmap_servicing != INVALID_THREAD) { 279*433d6423SLionel Sambuc worker = worker_get(dp->dmap_servicing); 280*433d6423SLionel Sambuc worker_stop(worker); 281*433d6423SLionel Sambuc } 282*433d6423SLionel Sambuc dp->dmap_recovering = 0; 283*433d6423SLionel Sambuc continue; 284*433d6423SLionel Sambuc } 285*433d6423SLionel Sambuc dp->dmap_recovering = 1; 286*433d6423SLionel Sambuc bdev_up(major); 287*433d6423SLionel Sambuc dp->dmap_recovering = 0; 288*433d6423SLionel Sambuc } else { 289*433d6423SLionel Sambuc if (dp->dmap_servicing != INVALID_THREAD) { 290*433d6423SLionel Sambuc worker = worker_get(dp->dmap_servicing); 291*433d6423SLionel Sambuc worker_stop(worker); 292*433d6423SLionel Sambuc } 293*433d6423SLionel Sambuc invalidate_filp_by_char_major(major); 294*433d6423SLionel Sambuc } 295*433d6423SLionel Sambuc } 296*433d6423SLionel Sambuc } 297*433d6423SLionel Sambuc } 298*433d6423SLionel Sambuc 299*433d6423SLionel Sambuc /*===========================================================================* 300*433d6423SLionel Sambuc * get_dmap * 301*433d6423SLionel Sambuc *===========================================================================*/ 302*433d6423SLionel Sambuc struct dmap *get_dmap(endpoint_t proc_e) 303*433d6423SLionel Sambuc { 304*433d6423SLionel Sambuc /* See if 'proc_e' endpoint belongs to a valid dmap entry. If so, return a 305*433d6423SLionel Sambuc * pointer */ 306*433d6423SLionel Sambuc 307*433d6423SLionel Sambuc int major; 308*433d6423SLionel Sambuc for (major = 0; major < NR_DEVICES; major++) 309*433d6423SLionel Sambuc if (dmap_driver_match(proc_e, major)) 310*433d6423SLionel Sambuc return(&dmap[major]); 311*433d6423SLionel Sambuc 312*433d6423SLionel Sambuc return(NULL); 313*433d6423SLionel Sambuc } 314