From 31b22ce0171d5f314ab71ecfdc903cd5b4abff7c Mon Sep 17 00:00:00 2001 From: ambrisko Date: Fri, 5 May 2006 16:10:45 +0000 Subject: Enhance the Linux emulation layer to make MegaRAID SAS managements tool happy. Add back in a scheme to emulate old type major/minor numbers via hooks into stat, linprocfs to return major/minors that Linux app's expect. Currently only /dev/null is always registered. Drivers can register via the Linux type shim similar to the ioctl shim but by using linux_device_register_handler/linux_device_unregister_handler functions. The structure is: struct linux_device_handler { char *bsd_driver_name; char *linux_driver_name; char *bsd_device_name; char *linux_device_name; int linux_major; int linux_minor; int linux_char_device; }; Linprocfs uses this to display the major number of the driver. The soon to be available linsysfs will use it to fill in the driver name. Linux_stat uses it to translate the major/minor into Linux type values. Note major numbers are dynamically assigned via passing in a -1 for the major number so we don't need to keep track of them. This is somewhat needed due to us switching to our devfs. MegaCli will not run until I add in the linsysfs and mfi Linux compat changes. Sponsored by: IronPort Systems --- sys/compat/linux/linux_util.c | 137 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) (limited to 'sys/compat/linux/linux_util.c') diff --git a/sys/compat/linux/linux_util.c b/sys/compat/linux/linux_util.c index b0a6391..09c5131 100644 --- a/sys/compat/linux/linux_util.c +++ b/sys/compat/linux/linux_util.c @@ -33,8 +33,10 @@ __FBSDID("$FreeBSD$"); #include +#include #include #include +#include #include #include #include @@ -82,3 +84,138 @@ linux_msg(const struct thread *td, const char *fmt, ...) va_end(ap); printf("\n"); } + +MALLOC_DECLARE(M_LINUX); + +struct device_element +{ + TAILQ_ENTRY(device_element) list; + struct linux_device_handler entry; +}; + +static TAILQ_HEAD(, device_element) devices = + TAILQ_HEAD_INITIALIZER(devices); + +static struct linux_device_handler null_handler = + { "mem", "mem", "null", "null", 1, 3, 1}; + +DATA_SET(linux_device_handler_set, null_handler); + +char * +linux_driver_get_name_dev(device_t dev) +{ + struct device_element *de; + const char *device_name = device_get_name(dev); + + if (device_name == NULL) + return NULL; + TAILQ_FOREACH(de, &devices, list) { + if (strcmp(device_name, de->entry.bsd_driver_name) == 0) + return (de->entry.linux_driver_name); + } + + return NULL; +} + +int +linux_driver_get_major_minor(char *node, int *major, int *minor) +{ + struct device_element *de; + + if (node == NULL || major == NULL || minor == NULL) + return 1; + TAILQ_FOREACH(de, &devices, list) { + if (strcmp(node, de->entry.bsd_device_name) == 0) { + *major = de->entry.linux_major; + *minor = de->entry.linux_minor; + return 0; + } + } + + return 1; +} + +char * +linux_get_char_devices() +{ + struct device_element *de; + char *temp, *string, *last; + char formated[256]; + int current_size = 0, string_size = 1024; + + MALLOC(string, char *, string_size, M_LINUX, M_WAITOK); + string[0] = '\000'; + last = ""; + TAILQ_FOREACH(de, &devices, list) { + if (!de->entry.linux_char_device) + continue; + temp = string; + if (strcmp(last, de->entry.bsd_driver_name) != 0) { + last = de->entry.bsd_driver_name; + + snprintf(formated, sizeof(formated), "%3d %s\n", + de->entry.linux_major, + de->entry.linux_device_name); + if (strlen(formated) + current_size + >= string_size) { + string_size *= 2; + MALLOC(string, char *, string_size, + M_LINUX, M_WAITOK); + bcopy(temp, string, current_size); + FREE(temp, M_LINUX); + } + strcat(string, formated); + current_size = strlen(string); + } + } + + return string; +} + +void +linux_free_get_char_devices(char *string) +{ + FREE(string, M_LINUX); +} + +static int linux_major_starting = 200; + +int +linux_device_register_handler(struct linux_device_handler *d) +{ + struct device_element *de; + + if (d == NULL) + return (EINVAL); + + MALLOC(de, struct device_element *, sizeof(*de), + M_LINUX, M_WAITOK); + if (d->linux_major < 0) { + d->linux_major = linux_major_starting++; + } + bcopy(d, &de->entry, sizeof(*d)); + + /* Add the element to the list, sorted on span. */ + TAILQ_INSERT_TAIL(&devices, de, list); + + return (0); +} + +int +linux_device_unregister_handler(struct linux_device_handler *d) +{ + struct device_element *de; + + if (d == NULL) + return (EINVAL); + + TAILQ_FOREACH(de, &devices, list) { + if (bcmp(d, &de->entry, sizeof(*d)) == 0) { + TAILQ_REMOVE(&devices, de, list); + FREE(de, M_LINUX); + return (0); + } + } + + return (EINVAL); +} -- cgit v1.1