diff options
Diffstat (limited to 'usr/src')
87 files changed, 3373 insertions, 8274 deletions
diff --git a/usr/src/cmd/devfsadm/devfsadm.c b/usr/src/cmd/devfsadm/devfsadm.c index 1017ed31df..152d3f6390 100644 --- a/usr/src/cmd/devfsadm/devfsadm.c +++ b/usr/src/cmd/devfsadm/devfsadm.c @@ -1936,7 +1936,7 @@ check_minor_type(di_node_t node, di_minor_t minor, void *arg) if ((dcip->dci_flags & DCA_CHECK_TYPE) && (nt = di_minor_nodetype(minor)) && - (strcmp(nt, DDI_NT_NET) == 0 || strcmp(nt, DDI_NT_MAC) == 0)) { + (strcmp(nt, DDI_NT_NET) == 0)) { dcip->dci_flags |= DCA_NOTIFY_RCM; dcip->dci_flags &= ~DCA_CHECK_TYPE; } @@ -7589,83 +7589,15 @@ lookup_nvpair(nvlist_t *nvl, char *name, data_type_t type) return (NULL); } -/* - * Send the specified event to RCM if the given nvlist contains a minor - * node of the specified type. - */ -static void -notify_event(nvlist_t *nvl, char *minor_node_type, char *event) -{ - nvpair_t *nvp, *mnvp; - char *path, *driver, *type; - int instance; - int err; - boolean_t do_notify = B_FALSE; - uint_t nminor; - char *minor_byte_array; - nvlist_t *mnvl; - - nvp = NULL; - while (!do_notify && ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL)) { - if (strcmp(nvpair_name(nvp), RCM_NV_MINOR_DATA) != 0) - continue; - if (nvpair_value_byte_array(nvp, - (uchar_t **)&minor_byte_array, &nminor) != 0) - goto error; - if (nvlist_unpack(minor_byte_array, - nminor, &mnvl, 0) != 0) - goto error; - - mnvp = NULL; - while (!do_notify && - ((mnvp = nvlist_next_nvpair(mnvl, mnvp)) != NULL)) { - if (strcmp(nvpair_name(mnvp), - RCM_NV_MINOR_NODE_TYPE) == 0) { - if (nvpair_value_string(mnvp, &type) != 0) { - nvlist_free(mnvl); - goto error; - } - do_notify = (strcmp(type, - minor_node_type) == 0); - } - } - - nvlist_free(mnvl); - } - - if (!do_notify) - return; - - if (librcm_notify_event(rcm_hdl, event, 0, nvl, NULL) == RCM_SUCCESS) - return; - -error: - err = errno; - - if (((nvp = lookup_nvpair(nvl, - RCM_NV_DEVFS_PATH, DATA_TYPE_STRING)) == NULL) || - (nvpair_value_string(nvp, &path) != 0)) - path = "unknown"; - - if (((nvp = lookup_nvpair(nvl, - RCM_NV_DRIVER_NAME, DATA_TYPE_STRING)) == NULL) || - (nvpair_value_string(nvp, &driver) != 0)) - driver = "unknown"; - - if (((nvp = lookup_nvpair(nvl, - RCM_NV_INSTANCE, DATA_TYPE_INT32)) == NULL) || - (nvpair_value_int32(nvp, &instance) != 0)) - instance = -1; - - err_print(RCM_NOTIFY_FAILED, path, driver, - instance, strerror(err)); -} - /*ARGSUSED*/ static void process_rcm_events(void *arg) { struct rcm_eventq *ev, *ev_next; + nvpair_t *nvp; + char *path, *driver; + int instance; + int err; int need_to_exit; for (;;) { @@ -7686,12 +7618,32 @@ process_rcm_events(void *arg) * we do not know whether the failure occurred in * librcm, rcm_daemon or rcm modules or scripts. */ - - notify_event(ev->nvl, DDI_NT_NET, - RCM_RESOURCE_NETWORK_NEW); - - notify_event(ev->nvl, DDI_NT_MAC, - RCM_RESOURCE_MAC_NEW); + if (librcm_notify_event(rcm_hdl, + RCM_RESOURCE_NETWORK_NEW, 0, ev->nvl, NULL) + != RCM_SUCCESS) { + + err = errno; + + if (((nvp = lookup_nvpair(ev->nvl, + RCM_NV_DEVFS_PATH, DATA_TYPE_STRING)) + == NULL) || + (nvpair_value_string(nvp, &path) != 0)) + path = "unknown"; + + if (((nvp = lookup_nvpair(ev->nvl, + RCM_NV_DRIVER_NAME, DATA_TYPE_STRING)) + == NULL) || + (nvpair_value_string(nvp, &driver) != 0)) + driver = "unknown"; + if (((nvp = lookup_nvpair(ev->nvl, + RCM_NV_INSTANCE, DATA_TYPE_INT32)) + == NULL) || + (nvpair_value_int32(nvp, &instance) != 0)) + instance = -1; + + err_print(RCM_NOTIFY_FAILED, path, driver, + instance, strerror(err)); + } ev_next = ev->next; nvlist_free(ev->nvl); diff --git a/usr/src/cmd/dladm/Makefile b/usr/src/cmd/dladm/Makefile index ae3f9167e4..0923fece9c 100644 --- a/usr/src/cmd/dladm/Makefile +++ b/usr/src/cmd/dladm/Makefile @@ -29,7 +29,7 @@ PROG= dladm ROOTFS_PROG= $(PROG) -CONFIGFILES= datalink.conf aggregation.conf +CONFIGFILES= aggregation.conf POFILE= $(PROG).po diff --git a/usr/src/cmd/dladm/datalink.conf b/usr/src/cmd/dladm/datalink.conf deleted file mode 100644 index 5cb5189578..0000000000 --- a/usr/src/cmd/dladm/datalink.conf +++ /dev/null @@ -1,31 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "%Z%%M% %I% %E% SMI" -# -# DO NOT EDIT OR PARSE THIS FILE! -# -# Use the dladm(1m) command to change the contents of this file. - diff --git a/usr/src/cmd/dladm/dladm.c b/usr/src/cmd/dladm/dladm.c index 404a1c3e92..f74eab440c 100644 --- a/usr/src/cmd/dladm/dladm.c +++ b/usr/src/cmd/dladm/dladm.c @@ -96,11 +96,7 @@ static port_state_t port_states[] = { #define NPORTSTATES (sizeof (port_states) / sizeof (port_state_t)) -static void do_create_vlan(int, char **); -static void do_delete_vlan(int, char **); static void do_show_link(int, char **); -static void do_up_link(int, char **); -static void do_init_link(int, char **); static void do_create_aggr(int, char **); static void do_delete_aggr(int, char **); static void do_add_aggr(int, char **); @@ -129,11 +125,8 @@ typedef struct cmd { } cmd_t; static cmd_t cmds[] = { - { "create-vlan", do_create_vlan }, - { "delete-vlan", do_delete_vlan }, { "show-link", do_show_link }, - { "up-link", do_up_link }, - { "init-link", do_init_link }, + { "show-dev", do_show_dev }, { "create-aggr", do_create_aggr }, { "delete-aggr", do_delete_aggr }, @@ -142,9 +135,7 @@ static cmd_t cmds[] = { { "modify-aggr", do_modify_aggr }, { "show-aggr", do_show_aggr }, { "up-aggr", do_up_aggr }, - { "down-aggr", do_down_aggr }, - - { "show-dev", do_show_dev } + { "down-aggr", do_down_aggr } }; static const struct option longopts[] = { @@ -176,9 +167,7 @@ static void usage(void) { (void) fprintf(stderr, gettext( - "usage: dladm create-vlan [-t] [-R <root-dir>] -v <vlan> -d <dev>\n" - " delete-vlan [-t] [-R <root-dir>] -v <vlan> -d <dev>\n" - " create-aggr [-t] [-R <root-dir>] [-P <policy>]\n" + "usage: dladm create-aggr [-t] [-R <root-dir>] [-P <policy>]\n" " [-l <mode>] [-T <time>]\n" " [-u <address>] -d <dev> ... <key>\n" " delete-aggr [-t] [-R <root-dir>] <key>\n" @@ -224,269 +213,6 @@ main(int argc, char *argv[]) return (0); } -static void -do_create_vlan(int argc, char *argv[]) -{ - char name[MAXNAMELEN]; - char driver[MAXNAMELEN]; - int instance; - dladm_attr_t dlattr; - int value; - char option; - boolean_t v_arg = B_FALSE; - boolean_t d_arg = B_FALSE; - boolean_t t_arg = B_FALSE; - char *altroot = NULL; - char *endp = NULL; - dladm_diag_t diag = 0; - - bzero(&dlattr, sizeof (dladm_attr_t)); - - opterr = 0; - while ((option = getopt_long(argc, argv, ":d:R:tv:", longopts, - NULL)) != -1) { - switch (option) { - case 'v': - if (v_arg) { - (void) fprintf(stderr, gettext("%s: the option " - "-v cannot be specified more than once\n"), - progname); - usage(); - } - - v_arg = B_TRUE; - - errno = 0; - value = (int)strtol(optarg, &endp, 10); - if (errno != 0 || value < 1 || value > 4094 || - *endp != '\0') { - (void) fprintf(stderr, - gettext("%s: illegal VLAN identifier" - " '%d'\n"), progname, value); - exit(1); - } - - dlattr.da_vid = (uint16_t)value; - - break; - case 'd': - if (d_arg) { - (void) fprintf(stderr, gettext( - "%s: the option -d cannot be specified " - "more than once\n"), progname); - usage(); - } - - d_arg = B_TRUE; - - if (strlcpy(dlattr.da_dev, optarg, MAXNAMELEN) >= - MAXNAMELEN) { - (void) fprintf(stderr, - gettext("%s: device name too long\n"), - progname); - exit(1); - } - break; - case 't': - t_arg = B_TRUE; - break; - case 'R': - altroot = optarg; - break; - case ':': - (void) fprintf(stderr, - gettext("%s: option requires a value '-%c'\n"), - progname, optopt); - exit(1); - break; - case '?': - default: - (void) fprintf(stderr, - gettext("%s: unrecognized option '-%c'\n"), - progname, optopt); - exit(1); - break; - } - } - - if (optind != argc) { - usage(); - } - - if (dlattr.da_dev[0] == '\0') { - (void) fprintf(stderr, - gettext("%s: no device specified\n"), - progname); - exit(1); - } - - if (dlattr.da_vid == 0) { - (void) fprintf(stderr, - gettext("%s: no VLAN ID specified\n"), - progname); - exit(1); - } - - if (dlpi_if_parse(dlattr.da_dev, driver, &instance) < 0 || - instance < 0) { - (void) fprintf(stderr, - gettext("%s: badly formatted device '%s'\n"), - progname, dlattr.da_dev); - exit(1); - } - - (void) snprintf(name, MAXNAMELEN, "%s%d", driver, - (dlattr.da_vid * 1000) + instance); - - /* - * For aggregations, the da_dev is always AGGR_DEV, and the - * aggregation key (the instance integer extracted above by - * dlpi_if_parse) is da_port. - */ - if (strcmp(driver, AGGR_DRIVER) == 0) { - (void) strlcpy(dlattr.da_dev, AGGR_DEV, MAXNAMELEN); - dlattr.da_port = instance; - } - - if (dladm_link(name, &dlattr, (t_arg ? DLADM_LINK_TEMP : 0), - altroot, &diag) < 0) { - PRINT_ERR_DIAG("%s: link operation failed: %s", diag, - dladm_diag); - exit(1); - } - - if (dladm_sync() < 0) { - (void) fprintf(stderr, - gettext("%s: sync operation failed"), - progname); - perror(" "); - exit(1); - } -} - -static void -do_delete_vlan(int argc, char *argv[]) -{ - char option; - boolean_t t_arg = B_FALSE; - boolean_t v_arg = B_FALSE; - boolean_t d_arg = B_FALSE; - char device[MAXNAMELEN]; - char name[MAXNAMELEN]; - char driver[MAXNAMELEN]; - int instance; - int vid; - char *altroot = NULL; - char *endp = NULL; - dladm_diag_t diag = 0; - - opterr = 0; - while ((option = getopt_long(argc, argv, ":R:td:v:", longopts, - NULL)) != -1) { - switch (option) { - case 'v': - if (v_arg) { - (void) fprintf(stderr, gettext("%s: the option " - "-v cannot be specified more than once\n"), - progname); - usage(); - } - - v_arg = B_TRUE; - - errno = 0; - vid = (int)strtol(optarg, &endp, 10); - if (errno != 0 || vid < 1 || vid > 4094 || - *endp != '\0') { - (void) fprintf(stderr, - gettext("%s: illegal VLAN identifier" - " '%d'\n"), progname, vid); - exit(1); - } - - break; - case 'd': - if (d_arg) { - (void) fprintf(stderr, gettext( - "%s: the option -d cannot be specified " - "more than once\n"), progname); - usage(); - } - - d_arg = B_TRUE; - - if (strlcpy(device, optarg, MAXNAMELEN) >= - MAXNAMELEN) { - (void) fprintf(stderr, - gettext("%s: device name too long\n"), - progname); - exit(1); - } - break; - case 't': - t_arg = B_TRUE; - break; - case 'R': - altroot = optarg; - break; - case ':': - (void) fprintf(stderr, - gettext("%s: option requires a value '-%c'\n"), - progname, optopt); - exit(1); - break; - case '?': - default: - (void) fprintf(stderr, - gettext("%s: unrecognized option '-%c'\n"), - progname, optopt); - exit(1); - break; - } - } - - if (optind != argc) - usage(); - - if (d_arg == B_FALSE) { - (void) fprintf(stderr, - gettext("%s: no device specified\n"), - progname); - exit(1); - } - - if (v_arg == B_FALSE) { - (void) fprintf(stderr, - gettext("%s: no VLAN ID specified\n"), - progname); - exit(1); - } - - if (dlpi_if_parse(device, driver, &instance) < 0 || - instance < 0) { - (void) fprintf(stderr, - gettext("%s: badly formatted device '%s'\n"), - progname, device); - exit(1); - } - - (void) snprintf(name, MAXNAMELEN, "%s%d", driver, - (vid * 1000) + instance); - - if (dladm_unlink(name, t_arg, altroot, &diag) < 0) { - PRINT_ERR_DIAG("%s: unlink operation failed: %s", diag, - dladm_diag); - exit(1); - } - - if (dladm_sync() < 0) { - (void) fprintf(stderr, - gettext("%s: sync operation failed"), - progname); - perror(" "); - exit(1); - } -} static void do_create_aggr(int argc, char *argv[]) @@ -1009,35 +735,6 @@ do_modify_aggr(int argc, char *argv[]) } static void -do_up_link(int argc, char *argv[]) -{ - char *name = NULL; - dladm_diag_t diag = 0; - - /* get link name (optional last argument) */ - if (argc == 2) - name = argv[1]; - else if (argc > 2) - usage(); - - if (dladm_up(name, &diag) < 0) { - if (name != NULL) { - (void) fprintf(stderr, - gettext("%s: could not bring up link '%s' : %s"), - progname, name, strerror(errno)); - if (diag != 0) - (void) fprintf(stderr, " (%s)", - dladm_diag(diag)); - (void) fprintf(stderr, "\n"); - } else { - PRINT_ERR_DIAG("%s: could not bring links up: %s", - diag, dladm_diag); - } - exit(1); - } -} - -static void do_up_aggr(int argc, char *argv[]) { uint16_t key = 0; @@ -1112,114 +809,118 @@ do_down_aggr(int argc, char *argv[]) } } +#define TYPE_WIDTH 10 + static void -create(void *arg, const char *dev, uint_t port) +print_link_parseable(const char *name, dladm_attr_t *dap, boolean_t legacy) { - dladm_attr_t dlattr; - dladm_diag_t diag; - int flags; - - if (port != 0) - return; + char type[TYPE_WIDTH]; - if (strlcpy(dlattr.da_dev, dev, MAXNAMELEN) >= MAXNAMELEN) { - (void) fprintf(stderr, - gettext("%s: device name too long\n"), - progname); - exit(1); + if (!legacy) { + if (dap->da_vid != 0) { + (void) snprintf(type, TYPE_WIDTH, "vlan %u", + dap->da_vid); + } else { + (void) snprintf(type, TYPE_WIDTH, "non-vlan"); + } + if (strcmp(dap->da_dev, AGGR_DEV) == 0) { + (void) printf("%s type=%s mtu=%d key=%u\n", + name, type, dap->da_max_sdu, dap->da_port); + } else { + (void) printf("%s type=%s mtu=%d device=%s\n", + name, type, dap->da_max_sdu, dap->da_dev); + } + } else { + (void) printf("%s type=legacy mtu=%d device=%s\n", + name, dap->da_max_sdu, name); } - - dlattr.da_port = 0; - dlattr.da_vid = 0; - - flags = DLADM_LINK_FORCED; - if (arg != NULL) - flags |= DLADM_LINK_TEMP; - - (void) dladm_link(dlattr.da_dev, &dlattr, flags, NULL, &diag); } -/* ARGSUSED */ static void -do_init_link(int argc, char *argv[]) +print_link(const char *name, dladm_attr_t *dap, boolean_t legacy) { - if (argc != 1 && strcmp(argv[1], "-t") != 0) - usage(); + char type[TYPE_WIDTH]; - (void) macadm_walk(create, (void *)(argc > 1), B_FALSE); + if (!legacy) { + if (dap->da_vid != 0) { + (void) snprintf(type, TYPE_WIDTH, gettext("vlan %u"), + dap->da_vid); + } else { + (void) snprintf(type, TYPE_WIDTH, gettext("non-vlan")); + } + if (strcmp(dap->da_dev, AGGR_DEV) == 0) { + (void) printf(gettext("%-9s\ttype: %s\tmtu: %d" + "\taggregation: key %u\n"), name, type, + dap->da_max_sdu, dap->da_port); + } else { + (void) printf(gettext("%-9s\ttype: %s\tmtu: " + "%d\tdevice: %s\n"), name, type, dap->da_max_sdu, + dap->da_dev); + } + } else { + (void) printf(gettext("%-9s\ttype: legacy\tmtu: " + "%d\tdevice: %s\n"), name, dap->da_max_sdu, name); + } } -#define TYPE_WIDTH 10 -#define MAC_WIDTH 23 -#define MTU_WIDTH 11 -#define STATE_WIDTH 15 +static int +get_if_info(const char *name, dladm_attr_t *dlattrp, boolean_t *legacy) +{ + int err; + + if ((err = dladm_info(name, dlattrp)) == 0) { + *legacy = B_FALSE; + } else if (err < 0 && errno == ENODEV) { + int fd; + dlpi_if_attr_t dia; + dl_info_ack_t dlia; + + /* + * A return value of ENODEV means that the specified + * device is not gldv3. + */ + if ((fd = dlpi_if_open(name, &dia, B_FALSE)) != -1 && + dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL, + NULL, NULL) != -1) { + (void) dlpi_close(fd); + + *legacy = B_TRUE; + bzero(dlattrp, sizeof (*dlattrp)); + dlattrp->da_max_sdu = (uint_t)dlia.dl_max_sdu; + } else { + errno = ENOENT; + return (-1); + } + } else { + /* + * If the return value is not ENODEV, this means that + * user is either passing in a bogus interface name + * or a vlan interface name that doesn't exist yet. + */ + errno = ENOENT; + return (-1); + } + return (0); +} /* ARGSUSED */ static void show_link(void *arg, const char *name) { dladm_attr_t dlattr; - char type[TYPE_WIDTH]; - int fd; - dlpi_if_attr_t dia; - dl_info_ack_t dlia; - t_uscalar_t dl_max_sdu; + boolean_t legacy = B_TRUE; show_link_state_t *state = (show_link_state_t *)arg; - if ((fd = dlpi_if_open(name, &dia, B_FALSE)) != -1 && - dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL, - NULL, NULL) != -1) { - (void) dlpi_close(fd); - dl_max_sdu = dlia.dl_max_sdu; - } else { - (void) fprintf(stderr, - gettext("%s: invalid device '%s'\n"), + if (get_if_info(name, &dlattr, &legacy) < 0) { + (void) fprintf(stderr, gettext("%s: invalid device '%s'\n"), progname, name); exit(1); } - if (dladm_info(name, &dlattr) < 0) { - if (!state->ls_parseable) { - (void) printf(gettext("%-9s\ttype: legacy" - "\tmtu: %d\tdevice: %s\n"), - name, (int)dl_max_sdu, name); - } else { - (void) printf("%s type=legacy mtu=%d device=%s\n", - name, (int)dl_max_sdu, name); - } + if (state->ls_parseable) { + print_link_parseable(name, &dlattr, legacy); } else { - if (dlattr.da_vid != 0) { - (void) snprintf(type, TYPE_WIDTH, - state->ls_parseable ? "vlan %u" : - gettext("vlan %u"), dlattr.da_vid); - } else { - (void) snprintf(type, TYPE_WIDTH, - state->ls_parseable ? "non-vlan" : - gettext("non-vlan")); - } - - if (strcmp(dlattr.da_dev, AGGR_DEV) == 0) { - if (!state->ls_parseable) { - (void) printf(gettext("%-9s\ttype: %s" - "\tmtu: %d\taggregation: key %u\n"), - name, type, (int)dl_max_sdu, - dlattr.da_port); - } else { - (void) printf("%s type=%s mtu=%d key=%u\n", - name, type, (int)dl_max_sdu, - dlattr.da_port); - } - } else { - if (!state->ls_parseable) { - (void) printf(gettext("%-9s\ttype: %s" - "\tmtu: %d\tdevice: %s\n"), - name, type, (int)dl_max_sdu, - dlattr.da_dev); - } else { - (void) printf("%s type=%s mtu=%d device=%s\n", - name, type, (int)dl_max_sdu, dlattr.da_dev); - } - } + print_link(name, &dlattr, legacy); } } @@ -1502,36 +1203,34 @@ kstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf) } static void -show_dev(void *arg, const char *dev, uint_t port) +show_dev(void *arg, const char *dev) { - show_mac_state_t *state = (show_mac_state_t *)arg; + show_mac_state_t *state = (show_mac_state_t *)arg; /* aggregations are already managed by a set of subcommands */ if (strcmp(dev, AGGR_DEV) == 0) return; (void) printf("%s", dev); - if (port != 0) - (void) printf("/%d", port); if (!state->ms_parseable) { (void) printf(gettext("\t\tlink: %s"), - mac_link_state(dev, port)); + mac_link_state(dev, 0)); (void) printf(gettext("\tspeed: %-5u Mbps"), - (unsigned int)(mac_ifspeed(dev, port) / 1000000ull)); + (unsigned int)(mac_ifspeed(dev, 0) / 1000000ull)); (void) printf(gettext("\tduplex: %s\n"), - mac_link_duplex(dev, port)); + mac_link_duplex(dev, 0)); } else { - (void) printf(" link=%s", mac_link_state(dev, port)); + (void) printf(" link=%s", mac_link_state(dev, 0)); (void) printf(" speed=%u", - (unsigned int)(mac_ifspeed(dev, port) / 1000000ull)); - (void) printf(" duplex=%s\n", mac_link_duplex(dev, port)); + (unsigned int)(mac_ifspeed(dev, 0) / 1000000ull)); + (void) printf(" duplex=%s\n", mac_link_duplex(dev, 0)); } } /*ARGSUSED*/ static void -show_dev_stats(void *arg, const char *dev, uint_t port) +show_dev_stats(void *arg, const char *dev) { show_mac_state_t *state = (show_mac_state_t *)arg; pktsum_t stats, diff_stats; @@ -1548,12 +1247,10 @@ show_dev_stats(void *arg, const char *dev, uint_t port) bzero(&state->ms_prevstats, sizeof (state->ms_prevstats)); } - get_mac_stats(dev, port, &stats); + get_mac_stats(dev, 0, &stats); stats_diff(&diff_stats, &stats, &state->ms_prevstats); (void) printf("%s", dev); - if (port != 0) - (void) printf("/%d", port); (void) printf("\t\t%-10llu", diff_stats.ipackets); (void) printf("%-12llu", diff_stats.rbytes); (void) printf("%-8u", diff_stats.ierrors); @@ -1648,10 +1345,11 @@ do_show_link(int argc, char *argv[]) return; } - if (name == NULL) + if (name == NULL) { (void) dladm_walk(show_link, &state); - else + } else { show_link(&state, name); + } } static void @@ -1886,29 +1584,22 @@ do_show_dev(int argc, char *argv[]) if (dev == NULL) (void) macadm_walk(show_dev, &state, B_TRUE); else - show_dev(&state, dev, 0); + show_dev(&state, dev); } /* ARGSUSED */ static void link_stats(const char *link, uint32_t interval) { - show_link_state_t state; + dladm_attr_t dlattr; + boolean_t legacy; + show_link_state_t state; - if (link != NULL) { - dlpi_if_attr_t dia; - int fd; - - if ((fd = dlpi_if_open(link, &dia, B_FALSE)) != -1) { - (void) dlpi_close(fd); - } else { - (void) fprintf(stderr, - gettext("%s: invalid device '%s'\n"), - progname, link); - exit(1); - } + if (link != NULL && get_if_info(link, &dlattr, &legacy) < 0) { + (void) fprintf(stderr, gettext("%s: invalid device '%s'\n"), + progname, link); + exit(1); } - bzero(&state, sizeof (state)); /* @@ -1932,7 +1623,6 @@ link_stats(const char *link, uint32_t interval) (void) sleep(interval); } - } /* ARGSUSED */ @@ -1988,11 +1678,10 @@ dev_stats(const char *dev, uint32_t interval) (void) printf("opackets obytes oerrors\n"); state.ms_donefirst = B_FALSE; - if (dev == NULL) { + if (dev == NULL) (void) macadm_walk(show_dev_stats, &state, B_TRUE); - } else { - show_dev_stats(&state, dev, 0); - } + else + show_dev_stats(&state, dev); if (interval == 0) break; diff --git a/usr/src/cmd/rcm_daemon/Makefile.com b/usr/src/cmd/rcm_daemon/Makefile.com index 8dd9114270..532f96f1b2 100644 --- a/usr/src/cmd/rcm_daemon/Makefile.com +++ b/usr/src/cmd/rcm_daemon/Makefile.com @@ -57,8 +57,7 @@ COMMON_MOD_SRC = \ $(COMMON)/pool_rcm.c \ $(COMMON)/mpxio_rcm.c \ $(COMMON)/ip_anon_rcm.c \ - $(COMMON)/svm_rcm.c \ - $(COMMON)/mac_rcm.c + $(COMMON)/svm_rcm.c sparc_MOD_SRC = $(COMMON)/ttymux_rcm.c @@ -72,8 +71,7 @@ COMMON_MOD_OBJ = \ pool_rcm.o \ mpxio_rcm.o \ ip_anon_rcm.o \ - svm_rcm.o \ - mac_rcm.o + svm_rcm.o sparc_MOD_OBJ = ttymux_rcm.o @@ -89,8 +87,7 @@ COMMON_RCM_MODS = \ SUNW_pool_rcm.so \ SUNW_mpxio_rcm.so \ SUNW_ip_anon_rcm.so \ - SUNW_svm_rcm.so \ - SUNW_mac_rcm.so + SUNW_svm_rcm.so sparc_RCM_MODS = SUNW_ttymux_rcm.so @@ -111,9 +108,7 @@ LINTFLAGS += -u -erroff=E_FUNC_ARG_UNUSED LDLIBS_MODULES = SUNW_pool_rcm.so := LDLIBS_MODULES += -L$(ROOT)/usr/lib -lpool SUNW_svm_rcm.so := LDLIBS_MODULES += -L$(ROOT)/usr/lib -lmeta -SUNW_mac_rcm.so := LDLIBS_MODULES += -L$(ROOT)/lib -ldladm -llaadm -SUNW_ip_rcm.so := LDLIBS_MODULES += -L$(ROOT)/lib -ldladm -ldlpi -SUNW_network_rcm.so := LDLIBS_MODULES += -L$(ROOT)/lib -ldlpi +SUNW_network_rcm.so := LDLIBS_MODULES += -L$(ROOT)/lib -llaadm LDLIBS += -lgen -lelf -lcmd -lrcm -lnvpair -ldevinfo -lnsl -lsocket -lrt diff --git a/usr/src/cmd/rcm_daemon/common/ip_rcm.c b/usr/src/cmd/rcm_daemon/common/ip_rcm.c index acc3e49c77..95ed823a74 100644 --- a/usr/src/cmd/rcm_daemon/common/ip_rcm.c +++ b/usr/src/cmd/rcm_daemon/common/ip_rcm.c @@ -54,8 +54,6 @@ #include <libdevinfo.h> #include <sys/systeminfo.h> #include <netdb.h> -#include <libdladm.h> -#include <libdlpi.h> #include <ipmp_mpathd.h> #include "rcm_module.h" @@ -87,8 +85,6 @@ #define RCM_STR_SUNW_IP "SUNW_ip/" /* IP address export prefix */ #define RCM_SIZE_SUNW_IP 9 /* strlen("SUNW_ip/") + 1 */ -#define MAXINTSTR 11 /* max integer string len */ - /* ifconfig(1M) */ #define USR_SBIN_IFCONFIG "/usr/sbin/ifconfig" /* ifconfig command */ #define CFGFILE_FMT_IPV4 "/etc/hostname." /* IPV4 config file */ @@ -2034,18 +2030,6 @@ ip_ipmp_undo_offline(ip_cache_t *node) } /* - * is_virtual() - Determine whether the specified device is a virtual - * device managed by dld. - */ -static boolean_t -is_virtual(char *ifname) -{ - dladm_attr_t attr; - - return (dladm_info(ifname, &attr) == 0); -} - -/* * getdlpi_style() - Determine the DLPI provider style of the interface */ static int @@ -2084,7 +2068,7 @@ get_ppa(char *rsrc) if (m == 1) { return (-1); } - return (is_virtual(rsrc) ? p : VLAN_GET_PPA(p)); /* VLAN support */ + return (VLAN_GET_PPA(p)); /* VLAN support */ } /* @@ -3014,8 +2998,6 @@ process_minor(char *devfs_path, char *name, int instance, struct ni_list **pp; char *cname; size_t cnamelen; - char dev_name[MAXPATHLEN]; - boolean_t virtual = B_FALSE; rcm_log_message(RCM_TRACE1, "IP: process_minor\n"); @@ -3028,31 +3010,8 @@ process_minor(char *devfs_path, char *name, int instance, rcm_log_message(RCM_TRACE1, "IP: Examining %s (%s)\n", devfs_path, mdata->minor_name); - /* - * Virtual DDI_NT_NET nodes created by dld are exposed by devfs - * for non-VLAN as well as VLANs. Determine if we're dealing - * with a virtual device. - */ - if (strncmp("/pseudo", devfs_path, strlen("/pseudo")) == 0) { - rcm_log_message(RCM_TRACE1, "IP: pseudo node %s (%s)\n", - devfs_path, mdata->minor_name); - if (strcmp(name, "dld") == 0) { - if (dlpi_if_parse(mdata->minor_name, dev_name, - &instance) < 0 || instance < 0) { - /* dld always also creates a style-2 */ - rcm_log_message(RCM_DEBUG, "IP: ignoring " - "\"%s\" (style 1)\n", devfs_path); - return; - } - name = dev_name; - virtual = B_TRUE; - rcm_log_message(RCM_TRACE1, "IP: virtual datalink " - "%s%d\n", name, instance); - } - } - /* Sanity check, instances > 999 are illegal */ - if (!virtual && instance > 999) { + if (instance > 999) { errno = EINVAL; rcm_log_message(RCM_ERROR, _("IP: invalid instance %d(%s)\n"), instance, strerror(errno)); @@ -3077,7 +3036,7 @@ process_minor(char *devfs_path, char *name, int instance, } (void) memcpy(nip->type, name, cnamelen); - cnamelen += MAXINTSTR; + cnamelen += 3; if ((cname = (char *)malloc(cnamelen)) == NULL) { free(nip->type); free(nip); diff --git a/usr/src/cmd/rcm_daemon/common/mac_rcm.c b/usr/src/cmd/rcm_daemon/common/mac_rcm.c deleted file mode 100644 index bfb90c1019..0000000000 --- a/usr/src/cmd/rcm_daemon/common/mac_rcm.c +++ /dev/null @@ -1,1446 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * This RCM module adds support to the RCM framework for datalinks - * managed by dladm(1M). - */ -#include <alloca.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <assert.h> -#include <string.h> -#include <synch.h> -#include <libintl.h> -#include <errno.h> -#include <libdevinfo.h> -#include <sys/types.h> -#include <libdladm.h> -#include <liblaadm.h> -#include <net/if.h> -#include "rcm_module.h" - -#define _KERNEL -#include <sys/sysmacros.h> -#undef _KERNEL - -#define CACHE_STALE 1 /* flags */ -#define CACHE_NEW 2 /* flags */ - -typedef enum mac_op { - MAC_OP_SUSPEND = 0, - MAC_OP_OFFLINE = 1, - MAC_OP_ONLINE = 2, - MAC_OP_REMOVE = 3, - MAC_OP_RESUME = 4 -} mac_op_t; - -char *mac_op_str[] = { - "SUSPEND", - "OFFLINE", - "ONLINE", - "REMOVE", - "RESUME" -}; - -/* devfsadm post-attach nvpair values */ -#define PROP_NV_DDI_MAC "ddi_mac" - -typedef struct mac_cache { - char *resource; - char *driver; - int instance; - int flags; - struct mac_cache *next; - struct mac_cache *prev; -} mac_cache_t; - -static mac_cache_t cache_head; -static mac_cache_t cache_tail; -static mutex_t cache_lock; -static int events_registered = 0; - -struct devfs_minor_data { - int32_t minor_type; - char *minor_name; - char *minor_node_type; -}; - -/* module interface routines */ -static int mac_register(rcm_handle_t *); -static int mac_unregister(rcm_handle_t *); -static int mac_getinfo(rcm_handle_t *, char *, id_t, uint_t, char **, - char **, nvlist_t *, rcm_info_t **); -static int mac_suspend(rcm_handle_t *, char *, id_t, timespec_t *, - uint_t, char **, rcm_info_t **); -static int mac_resume(rcm_handle_t *, char *, id_t, uint_t, char **, - rcm_info_t **); -static int mac_offline(rcm_handle_t *, char *, id_t, uint_t, char **, - rcm_info_t **); -static int mac_online(rcm_handle_t *, char *, id_t, uint_t, char **, - rcm_info_t **); -static int mac_remove(rcm_handle_t *, char *, id_t, uint_t, char **, - rcm_info_t **); -static int mac_notify_event(rcm_handle_t *, char *, id_t, uint_t, - char **, nvlist_t *, rcm_info_t **); - -/* module private routines */ -static void free_cache(void); -static void update_cache(rcm_handle_t *hd); -static int devfs_entry(di_node_t node, di_minor_t minor, void *arg); -static void cache_remove(mac_cache_t *node); -static mac_cache_t *cache_lookup(const char *resource); -static void free_node(mac_cache_t *); -static void cache_insert(mac_cache_t *); -static int process_nvlist(nvlist_t *); - -/* - * Module-Private data - */ -static struct rcm_mod_ops mac_ops = { - RCM_MOD_OPS_VERSION, - mac_register, - mac_unregister, - mac_getinfo, - mac_suspend, - mac_resume, - mac_offline, - mac_online, - mac_remove, - NULL, /* request_capacity_change */ - NULL, /* notify_capacity_change */ - mac_notify_event -}; - -/* - * Module Interface Routines - */ - -/* - * rcm_mod_init() - * - * Update registrations, and return the ops structure. - */ -struct rcm_mod_ops * -rcm_mod_init() -{ - cache_head.next = &cache_tail; - cache_head.prev = NULL; - cache_tail.prev = &cache_head; - cache_tail.next = NULL; - (void) mutex_init(&cache_lock, NULL, NULL); - - /* Return the ops vectors */ - return (&mac_ops); -} - -/* - * rcm_mod_info() - * - * Return a string describing this module. - */ -const char * -rcm_mod_info() -{ - return ("Network namespace module %I%"); -} - -/* - * rcm_mod_fini() - * - * Destroy the cache. - */ -int -rcm_mod_fini() -{ - free_cache(); - (void) mutex_destroy(&cache_lock); - return (RCM_SUCCESS); -} - -/* - * mac_register() - * - * Make sure the cache is properly sync'ed, and its registrations - * are in order. - * - * Locking: the cache is locked by update_cache, and is held - * throughout update_cache's execution because it reads and - * possibly modifies cache links continuously. - */ -static int -mac_register(rcm_handle_t *hd) -{ - if (!events_registered) { - if (rcm_register_event(hd, RCM_RESOURCE_MAC_NEW, 0, NULL) != - RCM_SUCCESS) { - rcm_log_message(RCM_ERROR, - gettext("MAC: failed to register for events %s\n"), - RCM_RESOURCE_MAC_NEW); - return (RCM_FAILURE); - } else { - rcm_log_message(RCM_TRACE1, "MAC: registered " - " for events %s\n", RCM_RESOURCE_MAC_NEW); - events_registered++; - } - } - update_cache(hd); - return (RCM_SUCCESS); -} - -/* - * mac_unregister() - * - * Manually walk through the cache, unregistering all the networks. - * - * Locking: the cache is locked throughout the execution of this routine - * because it reads and modifies cache links continuously. - */ -static int -mac_unregister(rcm_handle_t *hd) -{ - mac_cache_t *probe; - - /* Walk the cache, unregistering everything */ - (void) mutex_lock(&cache_lock); - probe = cache_head.next; - while (probe != &cache_tail) { - (void) rcm_unregister_interest(hd, probe->resource, 0); - cache_remove(probe); - free_node(probe); - probe = cache_head.next; - } - (void) mutex_unlock(&cache_lock); - if (events_registered) { - (void) rcm_unregister_event(hd, RCM_RESOURCE_MAC_NEW, 0); - events_registered--; - } - return (RCM_SUCCESS); -} - -typedef struct mac_dl_walker_state { - char *ws_dev_name; - uint_t ws_n_datalinks; - char **ws_datalink; - char **ws_paths; -} mac_dl_walker_state_t; - -/* - * Adds a datalink of the specified name to the list hanging off - * the specified state. Invoked by mac_dl_walker_db() and mac_dl_walker(). - */ -static void -mac_add_datalink(mac_dl_walker_state_t *state, const char *name) -{ - char dl_path[MAXPATHLEN]; - - (void) snprintf(dl_path, sizeof (dl_path), "/devices/pseudo/dld@0:%s", - name); - rcm_log_message(RCM_DEBUG, "MAC: found datalink \"%s\"\n", dl_path); - - state->ws_n_datalinks++; - - state->ws_datalink = realloc(state->ws_datalink, - (state->ws_n_datalinks + 1) * sizeof (char *)); - if (state->ws_datalink == NULL) - return; - state->ws_datalink[state->ws_n_datalinks-1] = strdup(name); - state->ws_datalink[state->ws_n_datalinks] = NULL; - - state->ws_paths = realloc(state->ws_paths, - (state->ws_n_datalinks + 1) * sizeof (char *)); - if (state->ws_paths == NULL) - return; - state->ws_paths[state->ws_n_datalinks-1] = strdup(dl_path); - state->ws_paths[state->ws_n_datalinks] = NULL; -} - -/* - * Invoked for each DDI_NT_NET node found by the dladm library. - */ -static -void -mac_dl_walker(void *arg, const char *name) -{ - dladm_attr_t dl_attr; - mac_dl_walker_state_t *state = (mac_dl_walker_state_t *)arg; - - rcm_log_message(RCM_DEBUG, "MAC: walker: DDI_NT_NET \"%s\"\n", name); - - if ((state->ws_datalink == NULL) || (state->ws_paths == NULL)) - return; - - if (dladm_info(name, &dl_attr) < 0) { - rcm_log_message(RCM_DEBUG, "MAC: dladm_info failed " - "(legacy)\n"); - return; - } - - /* - * We have a virtual data link that is defined on top - * of a MAC port. Ignore it unless the MAC port was - * registered by the device being acted upon. - */ - rcm_log_message(RCM_DEBUG, "MAC: rsrc \"%s\" matches link \"%s\"?\n", - state->ws_dev_name, dl_attr.da_dev); - if (strcmp(state->ws_dev_name, dl_attr.da_dev) != 0) { - rcm_log_message(RCM_DEBUG, "MAC: no match\n"); - return; - } - - mac_add_datalink(state, name); -} - -/* - * Allocate and return a list of strings containing the virtual - * data links that are currently configured on top of a device. - */ -static int -mac_list_datalinks(char *dev_name, char ***paths, char ***names) -{ - mac_dl_walker_state_t dl_state; - - /* - * Use the instance and driver from the cache node to find - * matching mac ports. - */ - dl_state.ws_dev_name = dev_name; - dl_state.ws_n_datalinks = 0; - - dl_state.ws_datalink = calloc(1, sizeof (char *)); - dl_state.ws_paths = calloc(1, sizeof (char *)); - if ((dl_state.ws_datalink == NULL) || (dl_state.ws_paths == NULL)) { - rcm_log_message(RCM_ERROR, gettext("MAC: malloc failure")); - goto bail; - } - - (void) dladm_walk(mac_dl_walker, &dl_state); - - if ((dl_state.ws_datalink == NULL) || (dl_state.ws_paths == NULL)) { - rcm_log_message(RCM_ERROR, gettext("MAC: malloc failure")); - goto bail; - } - - if (paths != NULL) - *paths = dl_state.ws_paths; - if (names != NULL) - *names = dl_state.ws_datalink; - - return (dl_state.ws_n_datalinks); - -bail: - free(dl_state.ws_datalink); - free(dl_state.ws_paths); - return (-1); -} - -/* - * Invoked for each virtual datalink defined in database. - */ -static void -mac_dl_walker_db(void *arg, const char *name, dladm_attr_t *dl_attr) -{ - mac_dl_walker_state_t *state = arg; - - rcm_log_message(RCM_DEBUG, "MAC: DB walker: \"%s\"\n", name); - - if ((state->ws_datalink == NULL) || (state->ws_paths == NULL)) - return; - - /* - * We have a virtual data link that is defined on top - * of a MAC port. Ignore it unless the MAC port was - * registered by the device being acted upon. - */ - rcm_log_message(RCM_DEBUG, "MAC: DB rsrc \"%s\" matches link " - "\"%s\"?\n", state->ws_dev_name, dl_attr->da_dev); - if (strcmp(state->ws_dev_name, dl_attr->da_dev) != 0) { - rcm_log_message(RCM_DEBUG, "MAC: no match\n"); - return; - } - - mac_add_datalink(state, name); -} - -/* - * Allocate and return a list of strings containing the virtual - * data links that are configured on top of a device. - */ -static int -mac_list_datalinks_db(char *dev_name, char ***paths, char ***names) -{ - mac_dl_walker_state_t dl_state; - - /* - * Use the instance and driver from the cache node to find - * matching mac ports. - */ - dl_state.ws_dev_name = dev_name; - dl_state.ws_n_datalinks = 0; - - dl_state.ws_datalink = calloc(1, sizeof (char *)); - dl_state.ws_paths = calloc(1, sizeof (char *)); - if ((dl_state.ws_datalink == NULL) || (dl_state.ws_paths == NULL)) { - rcm_log_message(RCM_ERROR, gettext("MAC: malloc failure")); - goto bail; - } - - (void) dladm_db_walk(mac_dl_walker_db, &dl_state); - - if ((dl_state.ws_datalink == NULL) || (dl_state.ws_paths == NULL)) { - rcm_log_message(RCM_ERROR, gettext("MAC: malloc failure")); - goto bail; - } - - if (paths != NULL) - *paths = dl_state.ws_paths; - if (names != NULL) - *names = dl_state.ws_datalink; - - return (dl_state.ws_n_datalinks); - -bail: - free(dl_state.ws_datalink); - free(dl_state.ws_paths); - return (-1); -} - -/* - * Link aggregation walker state. - */ -typedef struct mac_aggr_walker_state { - char *as_dev_name; - uint_t as_n_aggr; - uint32_t *as_aggr; -} mac_aggr_walker_state_t; - -/* - * Link aggregation walker. - */ -static int -mac_list_aggr_walker(void *arg, laadm_grp_attr_sys_t *grp) -{ - mac_aggr_walker_state_t *state = (mac_aggr_walker_state_t *)arg; - laadm_port_attr_sys_t *port; - int i, j; - - rcm_log_message(RCM_TRACE1, "MAC: aggr sys walker: key %u\n", - grp->lg_key); - - if (state->as_aggr == NULL) - return (0); - - /* - * Add an entry for each aggregated MAC port that was registered - * by the device being acted upon by RCM. - */ - for (i = 0; i < grp->lg_nports; i++) { - port = &grp->lg_ports[i]; - - rcm_log_message(RCM_TRACE1, "MAC: aggr (%d) port %s/%d\n", - grp->lg_key, port->lp_devname, port->lp_port); - - if (strcmp(port->lp_devname, state->as_dev_name) != 0) - continue; - - /* - * Found matching port. Add aggregation key to list - * if it not already there, since multiple ports of - * the same device could be added to the same - * aggregation. - */ - for (j = 0; j < state->as_n_aggr; j++) { - if (state->as_aggr[j] == grp->lg_key) - break; - } - if (j < state->as_n_aggr) - /* aggregation group already in list */ - continue; - - state->as_n_aggr++; - state->as_aggr = realloc(state->as_aggr, - (state->as_n_aggr + 1) * sizeof (uint32_t)); - if (state->as_aggr == NULL) - return (0); - state->as_aggr[state->as_n_aggr-1] = grp->lg_key; - state->as_aggr[state->as_n_aggr] = 0; - } - - return (0); -} - -/* - * Allocate and return a list of key values of aggregations that - * are currently configured on top of the MAC ports registered - * by a device. - */ -static int -mac_list_aggr(char *dev_name, uint32_t **aggr) -{ - mac_aggr_walker_state_t ag_state; - int rv; - - ag_state.as_dev_name = dev_name; - ag_state.as_n_aggr = 0; - - ag_state.as_aggr = calloc(1, sizeof (uint32_t)); - if (ag_state.as_aggr == NULL) { - rcm_log_message(RCM_ERROR, gettext("MAC: malloc failure")); - return (-1); - } - - rv = laadm_walk_sys(mac_list_aggr_walker, &ag_state); - if (rv != 0) { - rcm_log_message(RCM_ERROR, - gettext("MAC: cannot list aggregations " - "(%s)\n"), strerror(errno)); - free(ag_state.as_aggr); - return (-1); - } - - if (ag_state.as_aggr == NULL) { - rcm_log_message(RCM_ERROR, gettext("MAC: malloc failure")); - return (-1); - } - - if (aggr != NULL) - *aggr = ag_state.as_aggr; - - return (ag_state.as_n_aggr); -} - -static void -mac_list_free(char **list) -{ - int i; - - if (list == NULL) - return; - - for (i = 0; list[i] != NULL; i++) - free(list[i]); - - free(list); -} - -static int -mac_dl_down_list(char **list) -{ - int i; - dladm_diag_t diag; - - if (list == NULL) - return (RCM_SUCCESS); - - for (i = 0; list[i] != NULL; i++) { - rcm_log_message(RCM_DEBUG, "MAC: dl_down() for \"%s\"\n", - list[i]); - if (dladm_down(list[i], &diag) != 0) { - char diag_str[256]; - - if (diag != 0) { - (void) snprintf(diag_str, sizeof (diag_str), - " (%s)", dladm_diag(diag)); - } else { - diag_str[0] = '\0'; - } - - rcm_log_message(RCM_ERROR, - gettext("MAC: failed to bring " - "down link %s%s"), list[i], diag_str); - goto error; - } - } - - return (RCM_SUCCESS); - -error: - /* bring data links back up */ - for (i--; i >= 0; i--) { - dladm_diag_t diag; - (void) dladm_up(list[i], &diag); - } - return (RCM_FAILURE); -} - -static int -mac_dl_up_list(char **list) -{ - int i; - dladm_diag_t diag; - - if (list == NULL) - return (RCM_SUCCESS); - - for (i = 0; list[i] != NULL; i++) { - rcm_log_message(RCM_DEBUG, "MAC: dl_up() for \"%s\"\n", - list[i]); - if (dladm_up(list[i], &diag) != 0) { - char diag_str[256]; - - if (diag != 0) { - (void) snprintf(diag_str, sizeof (diag_str), - " (%s)", dladm_diag(diag)); - } else { - diag_str[0] = '\0'; - } - - rcm_log_message(RCM_ERROR, - gettext("MAC: failed to bring " - "up link %s%s\n"), list[i], diag_str); - goto error; - } - } - - return (RCM_SUCCESS); - -error: - /* bring data links down */ - for (i--; i >= 0; i--) { - dladm_diag_t diag; - (void) dladm_down(list[i], &diag); - } - return (RCM_FAILURE); -} - -/* - * Since all we do is pass operations thru, we provide a general - * routine for passing through operations. - */ -/*ARGSUSED*/ -static int -mac_propagate(rcm_handle_t *hd, mac_op_t op, const char *rsrc, uint_t flag, - char **reason, rcm_info_t **dependent_reason, void *arg) -{ - mac_cache_t *node; - int rv = RCM_SUCCESS; - int ndep, naggr; - char **dl_paths = NULL; - char **dl_names = NULL; - char dev_name[MAXNAMELEN]; - uint32_t *aggr = NULL; - - /* - * Lock the cache just long enough to extract information about this - * resource. - */ - (void) mutex_lock(&cache_lock); - node = cache_lookup(rsrc); - if (node == NULL) { - rcm_log_message(RCM_WARNING, - gettext("MAC: unrecognized resource %s\n"), rsrc); - (void) mutex_unlock(&cache_lock); - return (RCM_SUCCESS); - } - - (void) snprintf(dev_name, sizeof (dev_name), "%s%d", node->driver, - node->instance); - rcm_log_message(RCM_DEBUG, "MAC: mac_propagate() %s for \"%s\" (%s)\n", - mac_op_str[op], rsrc, dev_name); - - /* - * We need to propagate the notification to the MAC clients - * that are configured on top of the MACs of the specified - * device. These MAC clients can be virtual links, - * or link aggregation groups. - */ - - /* - * Remove notifications are unconditional in the RCM state model, - * so it's safe to remove the node from the cache at this point. - * And we need to remove it so that we will recognize it as a new - * resource following the reattachment of the resource. - */ - if (op == MAC_OP_REMOVE) { - cache_remove(node); - free_node(node); - } - (void) mutex_unlock(&cache_lock); - - /* - * Obtain the list of virtual datalinks configured on currently - * active on top of the MAC ports registered by the device. - */ - if ((op == MAC_OP_SUSPEND) || (op == MAC_OP_OFFLINE) || - (op == MAC_OP_RESUME)) - ndep = mac_list_datalinks(dev_name, &dl_paths, &dl_names); - else - ndep = mac_list_datalinks_db(dev_name, &dl_paths, &dl_names); - - if (ndep == -1) { - rv = RCM_FAILURE; - goto done; - } else if ((ndep == 0) && (op != MAC_OP_OFFLINE)) { - goto done; - } - - switch (op) { - case MAC_OP_SUSPEND: - rv = rcm_request_suspend_list(hd, dl_paths, flag, - (timespec_t *)arg, dependent_reason); - break; - - case MAC_OP_OFFLINE: - /* refuse operation if aggregation defined on a MAC port */ - naggr = mac_list_aggr(dev_name, &aggr); - if (naggr == -1) { - rv = RCM_FAILURE; - break; - } else if (naggr > 0) { - /* - * Active link aggregation(s) defined on at least - * one of the MAC ports registered by the device - * being offlined. - */ - char *errstr; - char errgrp[64]; - int i; - - errstr = strdup(gettext( - "Resource is in use by aggregation")); - if (errstr == NULL) { - rcm_log_message(RCM_ERROR, - gettext("MAC: malloc failure")); - rv = RCM_FAILURE; - goto done; - } - - for (i = 0; i < naggr; i++) { - (void) snprintf(errgrp, sizeof (errgrp), " %d", - aggr[i]); - errstr = realloc(errstr, strlen(errstr) + - strlen(errgrp) + 1); - if (errstr == NULL) { - rcm_log_message(RCM_ERROR, - gettext("MAC: malloc failure")); - rv = RCM_FAILURE; - goto done; - } - (void) strcat(errstr, errgrp); - } - *reason = errstr; - rcm_log_message(RCM_ERROR, "MAC: %s %s\n", - dev_name, *reason); - errno = EBUSY; - rv = RCM_FAILURE; - break; - } - - if (ndep == 0) - break; - - /* propagate offline request */ - rv = rcm_request_offline_list(hd, dl_paths, flag, - dependent_reason); - if (rv != RCM_SUCCESS) - break; - if (flag & RCM_QUERY) - break; - rv = mac_dl_down_list(dl_names); - break; - - case MAC_OP_REMOVE: - rv = rcm_notify_remove_list(hd, dl_paths, flag, - dependent_reason); - break; - - case MAC_OP_ONLINE: - rv = mac_dl_up_list(dl_names); - if (rv != RCM_SUCCESS) - break; - rv = rcm_notify_online_list(hd, dl_paths, flag, - dependent_reason); - break; - - case MAC_OP_RESUME: - rv = rcm_notify_resume_list(hd, dl_paths, flag, - dependent_reason); - break; - - default: - rcm_log_message(RCM_WARNING, - gettext("MAC: bad RCM operation %d\n"), op); - errno = EINVAL; - return (RCM_FAILURE); - } - -done: - if (rv != RCM_SUCCESS) { - rcm_log_message(RCM_WARNING, - gettext("MAC: %s operation failed\n"), - mac_op_str[op]); - } - - mac_list_free(dl_paths); - mac_list_free(dl_names); - free(aggr); - - return (rv); -} - - -/* - * mac_offline() - * - * Determine dependents of the resource being offlined, and offline - * them all. - */ -static int -mac_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, - char **reason, rcm_info_t **dependent_reason) -{ - rcm_log_message(RCM_TRACE1, "MAC: offline(%s)\n", rsrc); - - return (mac_propagate(hd, MAC_OP_OFFLINE, rsrc, flags, reason, - dependent_reason, NULL)); -} - -/* - * mac_online() - * - * Remount the previously offlined filesystem, and online its dependents. - */ -static int -mac_online(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flag, char **reason, - rcm_info_t **dependent_reason) -{ - rcm_log_message(RCM_DEBUG, "MAC: online(%s)\n", rsrc); - - return (mac_propagate(hd, MAC_OP_ONLINE, rsrc, flag, reason, - dependent_reason, NULL)); -} - -/* - * mac_getinfo() - * - * Gather usage information for this resource. - * - * Locking: the cache is locked while this routine looks up the - * resource and extracts copies of any piece of information it needs. - * The cache is then unlocked, and this routine performs the rest of - * its functions without touching any part of the cache. - */ -/*ARGSUSED*/ -static int -mac_getinfo(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flag, - char **info, char **errstr, nvlist_t *proplist, rcm_info_t **depend_info) -{ - int len; - char nic[LIFNAMSIZ]; - const char *info_fmt; - mac_cache_t *node; - char **dl_paths; - - rcm_log_message(RCM_TRACE1, "MAC: getinfo(%s)\n", rsrc); - - info_fmt = "MAC %s"; - - (void) mutex_lock(&cache_lock); - node = cache_lookup(rsrc); - if (!node) { - rcm_log_message(RCM_WARNING, - gettext("MAC: unrecognized resource %s\n"), rsrc); - (void) mutex_unlock(&cache_lock); - errno = ENOENT; - return (RCM_FAILURE); - } - - (void) snprintf(nic, sizeof (nic), "%s%d", node->driver, - node->instance); - - len = strlen(info_fmt) + strlen(nic) + 1; - if ((*info = (char *)malloc(len)) == NULL) { - rcm_log_message(RCM_ERROR, gettext("MAC: malloc failure")); - return (RCM_FAILURE); - } - - /* Fill in the string */ - (void) snprintf(*info, len, info_fmt, nic); - - if (flag & RCM_INCLUDE_DEPENDENT) { - char dev_name[MAXNAMELEN]; - int ndep; - - rcm_log_message(RCM_DEBUG, "MAC: getting dependents\n"); - /* get list of configured datalinks */ - (void) snprintf(dev_name, sizeof (dev_name), "%s%d", - node->driver, node->instance); - ndep = mac_list_datalinks(dev_name, &dl_paths, NULL); - if (ndep != 0) { - (void) rcm_get_info_list(hd, dl_paths, flag, - depend_info); - mac_list_free(dl_paths); - } - } - - (void) mutex_unlock(&cache_lock); - - return (RCM_SUCCESS); -} - -/* - * mac_suspend() - * - * Notify all dependents that the resource is being suspended. - * Since no real operation is involved, QUERY or not doesn't matter. - * - * Locking: the cache is only used to retrieve some information about - * this resource, so it is only locked during that retrieval. - */ -static int -mac_suspend(rcm_handle_t *hd, char *rsrc, id_t id, timespec_t *interval, - uint_t flag, char **reason, rcm_info_t **dependent_reason) -{ - rcm_log_message(RCM_TRACE1, "MAC: suspend(%s)\n", rsrc); - - return (mac_propagate(hd, MAC_OP_SUSPEND, rsrc, flag, reason, - dependent_reason, (void *)interval)); -} - -/* - * mac_resume() - * - * Resume all the dependents of a suspended network. - * - * Locking: the cache is only used to retrieve some information about - * this resource, so it is only locked during that retrieval. - */ -static int -mac_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flag, char **info, - rcm_info_t **dependent_info) -{ - rcm_log_message(RCM_TRACE1, "MAC: resume(%s)\n", rsrc); - - return (mac_propagate(hd, MAC_OP_RESUME, rsrc, flag, info, - dependent_info, NULL)); -} - -/* - * mac_remove() - * - * This is another NO-OP for us, we propagate the information. We - * don't need to remove it from our cache. We don't unregister - * interest at this point either; the network device name is still - * around. This way we don't have to change this logic when we - * gain the ability to learn about DR attach operations. - */ -static int -mac_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flag, char **info, - rcm_info_t **dependent_info) -{ - rcm_log_message(RCM_TRACE1, "MAC: remove(%s)\n", rsrc); - - return (mac_propagate(hd, MAC_OP_REMOVE, rsrc, flag, info, - dependent_info, NULL)); -} - -/* - * Process post-attach notifications sent by devfs for devices - * that created DDI_NT_MAC minor nodes. Bring up the links - * that are configured on top of the corresponding MAC ports. - */ -/*ARGSUSED*/ -static int -mac_notify_event(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flag, - char **errstr, nvlist_t *nvl, rcm_info_t **result) -{ - rcm_log_message(RCM_DEBUG, "MAC: notify_event(%s)\n", rsrc); - - if (strcmp(rsrc, RCM_RESOURCE_MAC_NEW) != 0) { - rcm_log_message(RCM_WARNING, - gettext("MAC: unrecognized event for %s\n"), rsrc); - return (RCM_FAILURE); - } - - /* update cache to reflect attached nodes */ - update_cache(hd); - - /* Process the nvlist for the event */ - if (process_nvlist(nvl) != 0) { - rcm_log_message(RCM_WARNING, - gettext("MAC: Error processing resource attributes(%s)\n"), - rsrc); - rcm_log_message(RCM_WARNING, - gettext("MAC: One or more devices may not be " - "configured.\n")); - } - - return (RCM_SUCCESS); -} - -/* - * Cache management routines. Note that the cache is implemented as a - * trivial linked list, and is only required because RCM doesn't - * provide enough state about our own registrations back to us. This - * linked list implementation probably clobbers the CPU cache pretty - * well. - */ - -/* - * cache_lookup() - * - * Get a cache node for a resource. Call with cache lock held. - */ -static mac_cache_t * -cache_lookup(const char *resource) -{ - mac_cache_t *probe; - - probe = cache_head.next; - while (probe != &cache_tail) { - if (probe->resource && - (strcmp(resource, probe->resource) == 0)) { - return (probe); - } - probe = probe->next; - } - return (NULL); -} - -/* - * free_node() - * - * Free a node. Make sure it isn't in the list! - */ -static void -free_node(mac_cache_t *node) -{ - if (node != NULL) { - free(node->resource); - free(node->driver); - free(node); - } -} - -/* - * cache_insert() - * - * Call with the cache_lock held. - */ -static void -cache_insert(mac_cache_t *node) -{ - /* insert at the head for best performance */ - node->next = cache_head.next; - node->prev = &cache_head; - - node->next->prev = node; - cache_head.next = node; -} - -/* - * cache_remove() - * - * Call with the cache_lock held. - */ -static void -cache_remove(mac_cache_t *node) -{ - node->next->prev = node->prev; - node->prev->next = node->next; - node->next = NULL; - node->prev = NULL; -} - -/* - * di_walk_minor() walker. Invoked for each DDI_NT_MAC device. - */ -/*ARGSUSED*/ -static int -devfs_entry(di_node_t node, di_minor_t minor, void *arg) -{ - char *devfspath; - char resource[MAXPATHLEN]; - char *name; - char *cp; - uint_t port_num; - int instance; - mac_cache_t *probe; - - cp = di_minor_nodetype(minor); - if ((cp == NULL) || (strcmp(cp, DDI_NT_MAC) != 0)) { - /* doesn't look like a MAC device */ - return (DI_WALK_CONTINUE); - } - - /* - * We need to register interest for devices that - * can be unconfigured, suspended, etc, and registered - * one or more MAC ports with the kernel. - * - * In our cache, we keep one entry per device that registered - * MAC ports. Each cache entry is also associated with a - * list of MAC ports that have been registered by the - * device associated with that cache entry. - */ - - name = di_driver_name(node); - if (name == NULL) { - /* what else can we do? */ - return (DI_WALK_CONTINUE); - } - rcm_log_message(RCM_DEBUG, "MAC: node driver name: \"%s\"\n", name); - - instance = di_instance(node); - rcm_log_message(RCM_DEBUG, "MAC: node instance: %d\n", instance); - - port_num = getminor(di_minor_devt(minor)); - rcm_log_message(RCM_DEBUG, "MAC: port number: %u\n", port_num); - - devfspath = di_devfs_path(node); - if (devfspath == NULL) { - /* no devfs path?!? */ - rcm_log_message(RCM_DEBUG, "MAC: missing devfs path\n"); - return (DI_WALK_CONTINUE); - } - - if (strncmp("/pseudo", devfspath, strlen("/pseudo")) == 0) { - /* ignore pseudo devices, they are not NICs */ - rcm_log_message(RCM_DEBUG, "MAC: ignoring pseudo device %s\n", - devfspath); - di_devfs_path_free(devfspath); - return (DI_WALK_CONTINUE); - } - - (void) snprintf(resource, sizeof (resource), "/devices%s", devfspath); - di_devfs_path_free(devfspath); - - probe = cache_lookup(resource); - if (probe != NULL) { - rcm_log_message(RCM_DEBUG, "MAC: %s already registered\n", - resource); - probe->flags &= ~(CACHE_STALE); - } else { - rcm_log_message(RCM_DEBUG, "MAC: %s is new resource\n", - resource); - probe = calloc(1, sizeof (mac_cache_t)); - if (probe == NULL) { - rcm_log_message(RCM_ERROR, - gettext("MAC: malloc failure")); - return (DI_WALK_CONTINUE); - } - - probe->resource = strdup(resource); - probe->instance = instance; - probe->driver = strdup(name); - - if (probe->resource == NULL || probe->driver == NULL) { - free_node(probe); - return (DI_WALK_CONTINUE); - } - - probe->flags |= CACHE_NEW; - cache_insert(probe); - } - - return (DI_WALK_CONTINUE); -} - -static void -update_cache(rcm_handle_t *hd) -{ - mac_cache_t *probe; - di_node_t root; - int rv; - - (void) mutex_lock(&cache_lock); - - /* first we walk the entire cache, marking each entry stale */ - probe = cache_head.next; - while (probe != &cache_tail) { - probe->flags |= CACHE_STALE; - probe = probe->next; - } - - root = di_init("/", DINFOSUBTREE | DINFOMINOR); - if (root == DI_NODE_NIL) { - goto done; - } - - (void) di_walk_minor(root, DDI_NT_MAC, DI_CHECK_ALIAS, NULL, - devfs_entry); - - di_fini(root); - - probe = cache_head.next; - while (probe != &cache_tail) { - mac_cache_t *freeit; - - if (probe->flags & CACHE_STALE) { - (void) rcm_unregister_interest(hd, probe->resource, 0); - rcm_log_message(RCM_DEBUG, "MAC: unregistered %s\n", - probe->resource); - freeit = probe; - probe = probe->next; - cache_remove(freeit); - free_node(freeit); - continue; - } - - if (!(probe->flags & CACHE_NEW)) { - probe = probe->next; - continue; - } - - rcm_log_message(RCM_DEBUG, "MAC: registering %s\n", - probe->resource); - rv = rcm_register_interest(hd, probe->resource, 0, NULL); - if (rv != RCM_SUCCESS) { - rcm_log_message(RCM_ERROR, - gettext("MAC: failed to register %s\n"), - probe->resource); - } else { - rcm_log_message(RCM_DEBUG, - "MAC: registered %s\n", probe->resource); - probe->flags &= ~(CACHE_NEW); - } - probe = probe->next; - } - -done: - (void) mutex_unlock(&cache_lock); -} - -static void -free_cache(void) -{ - mac_cache_t *probe; - - (void) mutex_lock(&cache_lock); - probe = cache_head.next; - while (probe != &cache_tail) { - cache_remove(probe); - free_node(probe); - probe = cache_head.next; - } - (void) mutex_unlock(&cache_lock); -} - -/* - * Walker state and function used to bring up the virtual datalinks - * that are configured on top of a MAC port for which we received - * a post-attach notification. - */ - -typedef struct dl_evt_walker_state { - char ws_dev_name[MAXNAMELEN]; - int ws_port_num; -} dl_evt_walker_state_t; - -static void -dl_evt_walker(void *arg, const char *name, dladm_attr_t *dl_attr) -{ - dl_evt_walker_state_t *state = (dl_evt_walker_state_t *)arg; - int rc; - dladm_diag_t diag; - - rcm_log_message(RCM_DEBUG, "MAC: dl evt walker match %s/%d with " - "config %s/%d?\n", dl_attr->da_dev, dl_attr->da_port, - state->ws_dev_name, state->ws_port_num); - - if ((strcmp(state->ws_dev_name, dl_attr->da_dev) != 0) || - (state->ws_port_num != dl_attr->da_port)) { - /* no match */ - rcm_log_message(RCM_DEBUG, "MAC: no dl match, skip entry\n"); - return; - } - - /* we have a match, bring up the datalink */ - rc = dladm_up(name, &diag); - if (rc != 0) { - char diag_str[256]; - - if (diag != 0) { - (void) snprintf(diag_str, sizeof (diag_str), " (%s)", - dladm_diag(diag)); - } else { - diag_str[0] = '\0'; - } - - rcm_log_message(RCM_ERROR, - gettext("MAC: error (%s) configuring " - "virtual datalink %s%s\n"), strerror(rc), name, diag_str); - } -} - -/* - * Process a notification received for a MAC minor node. Bring up - * each link that is configured on top of the MAC port. - */ -static void -process_minor(char *devfs_path, char *name, int instance, - struct devfs_minor_data *mdata) -{ - dl_evt_walker_state_t state; - - rcm_log_message(RCM_TRACE1, "MAC: process_minor\n"); - - if ((mdata->minor_node_type != NULL) && - strcmp(mdata->minor_node_type, PROP_NV_DDI_MAC) != 0) { - /* Process MAC devices only */ - return; - } - - rcm_log_message(RCM_TRACE1, "MAC: Examining %s (%s)\n", - devfs_path, mdata->minor_name); - - if (strncmp("/pseudo", devfs_path, strlen("/pseudo")) == 0) { - rcm_log_message(RCM_TRACE1, "MAC: ignoring pseudo %s (%s)\n", - devfs_path, mdata->minor_name); - return; - } - - rcm_log_message(RCM_TRACE1, "MAC: process MAC minor " - "(dev=%s, name=%s, inst=%d, port=\"%s\")\n", - devfs_path, name, instance, mdata->minor_name); - - (void) snprintf(state.ws_dev_name, sizeof (state.ws_dev_name), "%s%d", - name, instance); - state.ws_port_num = atoi(mdata->minor_name); - (void) dladm_db_walk(dl_evt_walker, &state); -} - -/* - * Process a post-attached notification nvlist sent by devfs. - */ -static int -process_nvlist(nvlist_t *nvl) -{ - nvpair_t *nvp = NULL; - char *driver_name; - char *devfs_path; - int32_t instance; - char *minor_byte_array; - uint_t nminor; - struct devfs_minor_data *mdata = NULL; - nvlist_t *mnvl = NULL; - nvpair_t *mnvp = NULL; - - rcm_log_message(RCM_TRACE1, "MAC: process_nvlist\n"); - - while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { - /* Get driver name */ - if (strcmp(nvpair_name(nvp), RCM_NV_DRIVER_NAME) == 0) { - if (nvpair_value_string(nvp, &driver_name) != 0) { - rcm_log_message(RCM_WARNING, - gettext("MAC: cannot get driver name\n")); - return (-1); - } - } - /* Get instance */ - if (strcmp(nvpair_name(nvp), RCM_NV_INSTANCE) == 0) { - if (nvpair_value_int32(nvp, &instance) != 0) { - rcm_log_message(RCM_WARNING, gettext( - "MAC: cannot get device instance\n")); - return (-1); - } - } - /* Get devfs_path */ - if (strcmp(nvpair_name(nvp), RCM_NV_DEVFS_PATH) == 0) { - if (nvpair_value_string(nvp, &devfs_path) != 0) { - rcm_log_message(RCM_WARNING, - gettext("MAC: cannot get device path\n")); - return (-1); - } - } - /* Get minor data */ - if (strcmp(nvpair_name(nvp), RCM_NV_MINOR_DATA) == 0) { - if (nvpair_value_byte_array(nvp, - (uchar_t **)&minor_byte_array, &nminor) != 0) { - rcm_log_message(RCM_WARNING, gettext( - "MAC: cannot get device minor data\n")); - return (-1); - } - if (nvlist_unpack(minor_byte_array, - nminor, &mnvl, 0) != 0) { - rcm_log_message(RCM_WARNING, gettext( - "MAC: cannot get minor node data\n")); - return (-1); - } - mdata = (struct devfs_minor_data *)calloc(1, - sizeof (struct devfs_minor_data)); - if (mdata == NULL) { - rcm_log_message(RCM_WARNING, - gettext("MAC: calloc error(%s)\n"), - strerror(errno)); - goto bail; - } - /* Enumerate minor node data */ - while ((mnvp = nvlist_next_nvpair(mnvl, mnvp)) != - NULL) { - /* Get minor type */ - if (strcmp(nvpair_name(mnvp), - RCM_NV_MINOR_TYPE) == 0) { - if (nvpair_value_int32(mnvp, - &mdata->minor_type) != 0) { - rcm_log_message(RCM_WARNING, - gettext("MAC: cannot get " - "minor type \n")); - goto bail; - } - } - /* Get minor name */ - if (strcmp(nvpair_name(mnvp), - RCM_NV_MINOR_NAME) == 0) { - if (nvpair_value_string(mnvp, - &mdata->minor_name) != 0) { - rcm_log_message(RCM_WARNING, - gettext("MAC: cannot get " - "minor name \n")); - goto bail; - } - } - /* Get minor node type */ - if (strcmp(nvpair_name(mnvp), - RCM_NV_MINOR_NODE_TYPE) == 0) { - if (nvpair_value_string(mnvp, - &mdata->minor_node_type) != 0) { - rcm_log_message(RCM_WARNING, - gettext("MAC: cannot get " - "minor node type \n")); - goto bail; - } - } - } - process_minor(devfs_path, driver_name, instance, - mdata); - nvlist_free(mnvl); - } - } - - rcm_log_message(RCM_TRACE1, "MAC: process_nvlist success\n"); - return (0); - -bail: - if (mnvl != NULL) - nvlist_free(mnvl); - if (mdata != NULL) - free(mdata); - return (-1); -} diff --git a/usr/src/cmd/rcm_daemon/common/network_rcm.c b/usr/src/cmd/rcm_daemon/common/network_rcm.c index 6072ff510a..85325a3409 100644 --- a/usr/src/cmd/rcm_daemon/common/network_rcm.c +++ b/usr/src/cmd/rcm_daemon/common/network_rcm.c @@ -40,9 +40,9 @@ #include <libintl.h> #include <errno.h> #include <libdevinfo.h> -#include <ctype.h> #include <sys/types.h> -#include <libdlpi.h> +#include <net/if.h> +#include <liblaadm.h> #include "rcm_module.h" /* @@ -70,8 +70,6 @@ */ #define NET_DELIMITER "" -#define DLD_NAME "dld" - typedef struct net_cache { char *resource; @@ -114,6 +112,7 @@ static void cache_remove(net_cache_t *node); static net_cache_t *cache_lookup(const char *resource); static void free_node(net_cache_t *); static void cache_insert(net_cache_t *); +static boolean_t is_aggregated(char *driver, int ppa); /* * Module-Private data @@ -285,6 +284,18 @@ net_passthru(rcm_handle_t *hd, int op, const char *rsrc, uint_t flag, (timespec_t *)arg, dependent_reason); break; case NET_OFFLINE: + if (is_aggregated(node->driver, node->ppa)) { + /* device is aggregated */ + *reason = strdup(gettext( + "Resource is in use by aggregation")); + if (*reason == NULL) { + rcm_log_message(RCM_ERROR, + gettext("NET: malloc failure")); + } + errno = EBUSY; + return (RCM_FAILURE); + } + rv = rcm_request_offline(hd, exported, flag, dependent_reason); break; case NET_ONLINE: @@ -727,7 +738,6 @@ devfs_entry(di_node_t node, di_minor_t minor, void *arg) char ifname [MAXPATHLEN]; /* should be big enough! */ char *devfspath; char resource[MAXPATHLEN]; - char dev_name[MAXPATHLEN]; char *name; char *cp; int instance; @@ -747,6 +757,9 @@ devfs_entry(di_node_t node, di_minor_t minor, void *arg) instance = di_instance(node); + (void) snprintf(ifname, sizeof (ifname), "SUNW_network/%s%s%d", + name, NET_DELIMITER, instance); + devfspath = di_devfs_path(node); if (!devfspath) { /* no devfs path?!? */ @@ -755,39 +768,16 @@ devfs_entry(di_node_t node, di_minor_t minor, void *arg) } if (strncmp("/pseudo", devfspath, strlen("/pseudo")) == 0) { - char *minor_name; - - if (strcmp(DLD_NAME, name) != 0) { - /* ignore pseudo devices, probably not really NICs */ - rcm_log_message(RCM_DEBUG, "NET: ignoring pseudo " - "device %s\n", devfspath); - di_devfs_path_free(devfspath); - return (DI_WALK_CONTINUE); - } - - /* we have a virtual datalink created by dld */ - di_devfs_path_free(devfspath); - devfspath = di_devfs_minor_path(minor); - rcm_log_message(RCM_DEBUG, "NET: virtual datalink \"%s\"\n", + /* ignore pseudo devices, probably not really NICs */ + rcm_log_message(RCM_DEBUG, "NET: ignoring pseudo device %s\n", devfspath); - - minor_name = di_minor_name(minor); - if (dlpi_if_parse(minor_name, dev_name, &instance) < 0 || - instance < 0) { - rcm_log_message(RCM_DEBUG, "NET: ignoring \"%s\" " - "(style 1)\n", devfspath); - di_devfs_path_free(devfspath); - return (DI_WALK_CONTINUE); - } - name = dev_name; + di_devfs_path_free(devfspath); + return (DI_WALK_CONTINUE); } (void) snprintf(resource, sizeof (resource), "/devices%s", devfspath); di_devfs_path_free(devfspath); - (void) snprintf(ifname, sizeof (ifname), "SUNW_network/%s%s%d", - name, NET_DELIMITER, instance); - probe = cache_lookup(resource); if (probe != NULL) { rcm_log_message(RCM_DEBUG, "NET: %s already registered\n", @@ -907,3 +897,54 @@ free_cache(void) } (void) mutex_unlock(&cache_lock); } + +/* + * is_aggregated() checks whether a NIC being removed is part of an + * aggregation. + */ + +typedef struct aggr_walker_state_s { + uint_t naggr; + char dev_name[LIFNAMSIZ]; +} aggr_walker_state_t; + +static int +aggr_walker(void *arg, laadm_grp_attr_sys_t *grp) +{ + aggr_walker_state_t *state = arg; + laadm_port_attr_sys_t *port; + int i; + + for (i = 0; i < grp->lg_nports; i++) { + port = &grp->lg_ports[i]; + + rcm_log_message(RCM_TRACE1, "MAC: aggr (%d) port %s/%d\n", + grp->lg_key, port->lp_devname, port->lp_port); + + if (strcmp(port->lp_devname, state->dev_name) != 0) + continue; + + /* found matching MAC port */ + state->naggr++; + } + + return (0); +} + +static boolean_t +is_aggregated(char *driver, int ppa) +{ + aggr_walker_state_t state; + + state.naggr = 0; + (void) snprintf(state.dev_name, sizeof (state.dev_name), "%s%d", + driver, ppa); + + if (laadm_walk_sys(aggr_walker, &state) != 0) { + rcm_log_message(RCM_ERROR, gettext("NET: cannot walk " + "aggregations (%s)\n"), strerror(errno)); + return (B_FALSE); + } + + return (state.naggr > 0); +} diff --git a/usr/src/cmd/svc/milestone/Makefile b/usr/src/cmd/svc/milestone/Makefile index eebdf29046..be0440da40 100644 --- a/usr/src/cmd/svc/milestone/Makefile +++ b/usr/src/cmd/svc/milestone/Makefile @@ -43,9 +43,6 @@ FSSVCS= \ FSMANIFESTS= $(FSSVCS:%=$(ROOTSVCSYSTEMFILESYSTEM)/%) NETSVCS= \ - datalink.xml \ - datalink-init.xml \ - aggregation.xml \ network-initial.xml \ network-loopback.xml \ network-physical.xml \ @@ -94,11 +91,8 @@ MANIFEST= $(FSSVCS) $(NETSVCS) $(MAINMILESTONES) $(SYSTEMSVCS) \ $(SYSDEVSVCS) $(SYSTEMSVCSVCS) SVCMETHOD=\ - aggregation \ boot-archive \ console-login \ - datalink \ - datalink-init \ devices-local \ fs-local \ fs-minimal \ diff --git a/usr/src/cmd/svc/milestone/aggregation b/usr/src/cmd/svc/milestone/aggregation deleted file mode 100644 index 88317277e3..0000000000 --- a/usr/src/cmd/svc/milestone/aggregation +++ /dev/null @@ -1,40 +0,0 @@ -#!/sbin/sh -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "%Z%%M% %I% %E% SMI" - -if [ `/sbin/zonename` != "global" ]; then - exit 0 -fi - -case "$1" in -'start') - /sbin/dladm up-aggr - ;; -'stop') - /sbin/dladm down-aggr - ;; -esac diff --git a/usr/src/cmd/svc/milestone/aggregation.xml b/usr/src/cmd/svc/milestone/aggregation.xml deleted file mode 100644 index d7f38fafed..0000000000 --- a/usr/src/cmd/svc/milestone/aggregation.xml +++ /dev/null @@ -1,73 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1"> -<!-- - Copyright 2005 Sun Microsystems, Inc. All rights reserved. - Use is subject to license terms. - - CDDL HEADER START - - The contents of this file are subject to the terms of the - Common Development and Distribution License, Version 1.0 only - (the "License"). You may not use this file except in compliance - with the License. - - You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - or http://www.opensolaris.org/os/licensing. - See the License for the specific language governing permissions - and limitations under the License. - - When distributing Covered Code, include this CDDL HEADER in each - file and include the License file at usr/src/OPENSOLARIS.LICENSE. - If applicable, add the following below this CDDL HEADER, with the - fields enclosed by brackets "[]" replaced with your own identifying - information: Portions Copyright [yyyy] [name of copyright owner] - - CDDL HEADER END - - ident "%Z%%M% %I% %E% SMI" ---> - -<service_bundle type='manifest' name='SUNWcsr:net-aggregation'> - -<service - name='network/aggregation' - type='service' - version='1'> - - <create_default_instance enabled='true' /> - - <single_instance/> - - <exec_method - type='method' - name='start' - exec='/lib/svc/method/aggregation %m' - timeout_seconds='30' /> - - <exec_method - type='method' - name='stop' - exec='/lib/svc/method/aggregation %m' - timeout_seconds='30' /> - - <property_group name='startd' type='framework'> - <propval name='duration' type='astring' - value='transient' /> - </property_group> - - <stability value='Evolving' /> - - <template> - <common_name> - <loctext xml:lang='C'> - network aggregations - </loctext> - </common_name> - <documentation> - <manpage title='dladm' section='1M' - manpath='/usr/share/man' /> - </documentation> - </template> -</service> - -</service_bundle> diff --git a/usr/src/cmd/svc/milestone/datalink b/usr/src/cmd/svc/milestone/datalink deleted file mode 100644 index 5bc22b5a06..0000000000 --- a/usr/src/cmd/svc/milestone/datalink +++ /dev/null @@ -1,37 +0,0 @@ -#!/sbin/sh -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "%Z%%M% %I% %E% SMI" - -if [ `/sbin/zonename` != "global" ]; then - exit 0 -fi - -v1=`svcprop -p system/reconfigure system/svc/restarter:default` -if [ "$v1" = "true" -o -f /etc/.UNCONFIGURED ]; then - /sbin/dladm init-link -t > /dev/msglog 2>&1 -fi -/sbin/dladm up-link diff --git a/usr/src/cmd/svc/milestone/datalink-init b/usr/src/cmd/svc/milestone/datalink-init deleted file mode 100644 index 6217e2003c..0000000000 --- a/usr/src/cmd/svc/milestone/datalink-init +++ /dev/null @@ -1,44 +0,0 @@ -#!/sbin/sh -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "%Z%%M% %I% %E% SMI" - -# -# Populate the /etc/links file during a reconfiguration reboot -# - -if [ `/sbin/zonename` != "global" ]; then - exit 0 -fi - -svcprop -p system/reconfigure system/svc/restarter:default | ( - read v1 - if [ "$v1" = "true" ]; then - /sbin/dladm init-link > /dev/msglog 2>&1 - fi -) - -exit 0 diff --git a/usr/src/cmd/svc/milestone/datalink-init.xml b/usr/src/cmd/svc/milestone/datalink-init.xml deleted file mode 100644 index 2729eaddc2..0000000000 --- a/usr/src/cmd/svc/milestone/datalink-init.xml +++ /dev/null @@ -1,83 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1"> -<!-- - Copyright 2005 Sun Microsystems, Inc. All rights reserved. - Use is subject to license terms. - - CDDL HEADER START - - The contents of this file are subject to the terms of the - Common Development and Distribution License, Version 1.0 only - (the "License"). You may not use this file except in compliance - with the License. - - You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - or http://www.opensolaris.org/os/licensing. - See the License for the specific language governing permissions - and limitations under the License. - - When distributing Covered Code, include this CDDL HEADER in each - file and include the License file at usr/src/OPENSOLARIS.LICENSE. - If applicable, add the following below this CDDL HEADER, with the - fields enclosed by brackets "[]" replaced with your own identifying - information: Portions Copyright [yyyy] [name of copyright owner] - - CDDL HEADER END - - ident "%Z%%M% %I% %E% SMI" ---> - -<service_bundle type='manifest' name='SUNWcsr:datalink-init'> - -<service - name='network/datalink-init' - type='service' - version='1'> - - <create_default_instance enabled='true' /> - - <single_instance/> - - <dependency - name='usr' - grouping='require_all' - restart_on='none' - type='service'> - <service_fmri value='svc:/system/filesystem/usr' /> - </dependency> - - <exec_method - type='method' - name='start' - exec='/lib/svc/method/datalink-init' - timeout_seconds='6000' /> - - <exec_method - type='method' - name='refresh' - exec='/lib/svc/method/datalink-init' - timeout_seconds='6000' /> - - <exec_method - type='method' - name='stop' - exec=':true' - timeout_seconds='3' /> - - <property_group name='startd' type='framework'> - <propval name='duration' type='astring' - value='transient' /> - </property_group> - - <stability value='Evolving' /> - - <template> - <common_name> - <loctext xml:lang='C'> - Solaris datalink initialization - </loctext> - </common_name> - </template> -</service> - -</service_bundle> diff --git a/usr/src/cmd/svc/milestone/datalink.xml b/usr/src/cmd/svc/milestone/datalink.xml deleted file mode 100644 index 37153eb52d..0000000000 --- a/usr/src/cmd/svc/milestone/datalink.xml +++ /dev/null @@ -1,88 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1"> -<!-- - Copyright 2005 Sun Microsystems, Inc. All rights reserved. - Use is subject to license terms. - - CDDL HEADER START - - The contents of this file are subject to the terms of the - Common Development and Distribution License, Version 1.0 only - (the "License"). You may not use this file except in compliance - with the License. - - You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - or http://www.opensolaris.org/os/licensing. - See the License for the specific language governing permissions - and limitations under the License. - - When distributing Covered Code, include this CDDL HEADER in each - file and include the License file at usr/src/OPENSOLARIS.LICENSE. - If applicable, add the following below this CDDL HEADER, with the - fields enclosed by brackets "[]" replaced with your own identifying - information: Portions Copyright [yyyy] [name of copyright owner] - - CDDL HEADER END - - ident "%Z%%M% %I% %E% SMI" ---> - -<service_bundle type='manifest' name='SUNWcsr:datalink'> - -<service - name='network/datalink' - type='service' - version='1'> - - <create_default_instance enabled='true' /> - - <single_instance/> - - <dependency - name='aggregation' - grouping='optional_all' - restart_on='none' - type='service'> - <service_fmri value='svc:/network/aggregation' /> - </dependency> - - <dependent - name='data_network' - grouping='optional_all' - restart_on='none'> - <service_fmri value='svc:/network/physical' /> - </dependent> - - <exec_method - type='method' - name='start' - exec='/lib/svc/method/datalink' - timeout_seconds='600' /> - - <exec_method - type='method' - name='stop' - exec=':true' - timeout_seconds='3' /> - - <property_group name='startd' type='framework'> - <propval name='duration' type='astring' - value='transient' /> - </property_group> - - <stability value='Evolving' /> - - <template> - <common_name> - <loctext xml:lang='C'> - network datalinks - </loctext> - </common_name> - <documentation> - <manpage title='dladm' section='1M' - manpath='/usr/share/man' /> - </documentation> - </template> -</service> - -</service_bundle> diff --git a/usr/src/cmd/svc/milestone/net-physical b/usr/src/cmd/svc/milestone/net-physical index 73775643be..d5702f6331 100644 --- a/usr/src/cmd/svc/milestone/net-physical +++ b/usr/src/cmd/svc/milestone/net-physical @@ -61,6 +61,11 @@ SUNW_NO_MPATHD=; export SUNW_NO_MPATHD smf_netstrategy # +# Bring up link aggregations +# +/sbin/dladm up-aggr + +# # If the system was net booted by DHCP, hand DHCP management off to the # DHCP agent (ifconfig communicates to the DHCP agent through the # loopback interface). diff --git a/usr/src/cmd/svc/seed/Makefile b/usr/src/cmd/svc/seed/Makefile index aa3d728fc2..262a2c835c 100644 --- a/usr/src/cmd/svc/seed/Makefile +++ b/usr/src/cmd/svc/seed/Makefile @@ -53,7 +53,6 @@ INSTALLSEED = $(ROOT)/usr/sadm/install # COMMON_DESCRIPTIONS = \ ../milestone/boot-archive.xml \ - ../milestone/datalink.xml \ ../milestone/devices-local.xml \ ../milestone/identity.xml \ ../milestone/local-fs.xml \ @@ -75,9 +74,7 @@ COMMON_DESCRIPTIONS = \ # GLOBAL_ZONE_DESCRIPTIONS = \ ../milestone/console-login.xml \ - ../milestone/datalink-init.xml \ ../milestone/multi-user-server.xml \ - ../milestone/aggregation.xml \ ../../cmd-inet/usr.lib/inetd/inetd-upgrade.xml \ ../../utmpd/utmp.xml \ ../../lvm/util/metainit.xml \ @@ -89,14 +86,12 @@ GLOBAL_ZONE_DESCRIPTIONS = \ NONGLOBAL_ZONE_DESCRIPTIONS = \ ../milestone/console-login.xml \ ../milestone/multi-user-server.xml \ - ../milestone/aggregation.xml \ ../../utmpd/utmp.xml # # Additional manifests for the install miniroot. # MINIROOT_DESCRIPTIONS= \ - ../milestone/datalink-init.xml \ ../milestone/sysconfig.xml \ ../../cmd-inet/usr.lib/inetd/inetd.xml \ ../../cmd-inet/usr.sbin/login.xml \ diff --git a/usr/src/cmd/truss/codes.c b/usr/src/cmd/truss/codes.c index b2e7ca4dd0..c0a20c6a64 100644 --- a/usr/src/cmd/truss/codes.c +++ b/usr/src/cmd/truss/codes.c @@ -852,13 +852,9 @@ const struct ioc { "laioc_add_rem"}, { (uint_t)LAIOC_MODIFY, "LAIOC_MODIFY", "laioc_modify"}, - /* dld data-link configuration ioctls */ - { (uint_t)DLDIOCCREATE, "DLDIOCCREATE", - "dld_ioc_create"}, - { (uint_t)DLDIOCDESTROY, "DLDIOCDESTROY", - "dld_ioc_destroy"}, + /* dld data-link ioctls */ { (uint_t)DLDIOCATTR, "DLDIOCATTR", "dld_ioc_attr"}, - + { (uint_t)DLDIOCVLAN, "DLDIOCVLAN", "dld_ioc_vlan"}, { (uint_t)0, NULL, NULL } }; diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile index d25f6b0ccf..9375332e21 100644 --- a/usr/src/lib/Makefile +++ b/usr/src/lib/Makefile @@ -399,7 +399,7 @@ libefi: libuuid libelfsign: libike libcryptoutil pkcs11 libinetcfg: libnsl libsocket libdevinfo libnsl: libmd5 libscf -libmacadm: libdevinfo +libmacadm: libdevinfo libdladm libdlpi libuuid: libsocket libinetutil: libsocket libsecdb: libcmd libnsl diff --git a/usr/src/lib/libdladm/common/libdladm.c b/usr/src/lib/libdladm/common/libdladm.c index 27c99135a8..8d97e4d708 100644 --- a/usr/src/lib/libdladm/common/libdladm.c +++ b/usr/src/lib/libdladm/common/libdladm.c @@ -28,7 +28,6 @@ #include <stdio.h> #include <sys/types.h> -#include <sys/stat.h> #include <string.h> #include <fcntl.h> #include <unistd.h> @@ -38,428 +37,27 @@ #include <libdevinfo.h> #include <libdlpi.h> #include <libdladm.h> -#include <libintl.h> #include <sys/dld.h> #include <net/if.h> -#define DLADM_DB "/etc/datalink.conf" -#define DLADM_DB_TMP "/etc/datalink.conf.new" -#define DLADM_DB_LOCK "/tmp/datalink.conf.lock" -#define DLADM_DB_PERMS S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH - -#define MAXLINELEN 1024 -#define LISTSZ 1024 -#define MAXPATHLEN 1024 - -#define BLANK_LINE(s) ((s[0] == '\0') || (s[0] == '#') || (s[0] == '\n')) - -typedef struct i_dladm_walk { - int fd; - boolean_t found; - const char *name; -} i_dladm_walk_t; - -/* - * Open and lock the aggregation configuration file lock. The lock is - * acquired as a reader (F_RDLCK) or writer (F_WRLCK). - */ -static int -i_dladm_lock_db(short type) -{ - int lock_fd; - struct flock lock; - - if ((lock_fd = open(DLADM_DB_LOCK, O_RDWR | O_CREAT | O_TRUNC, - DLADM_DB_PERMS)) < 0) - return (-1); - - lock.l_type = type; - lock.l_whence = SEEK_SET; - lock.l_start = 0; - lock.l_len = 0; - - if (fcntl(lock_fd, F_SETLKW, &lock) < 0) { - (void) close(lock_fd); - (void) unlink(DLADM_DB_LOCK); - return (-1); - } - return (lock_fd); -} - -/* - * Unlock and close the specified file. - */ -static void -i_dladm_unlock_db(int fd) -{ - struct flock lock; - - if (fd < 0) - return; - - lock.l_type = F_UNLCK; - lock.l_whence = SEEK_SET; - lock.l_start = 0; - lock.l_len = 0; - - (void) fcntl(fd, F_SETLKW, &lock); - (void) close(fd); - (void) unlink(DLADM_DB_LOCK); -} - -/* - * Parse a line of the configuration file, returns -1 if an error - * occured. - */ -static int -i_dladm_db_decode(char *buf, char *name, dladm_attr_t *dap) -{ - char *attr[DLADM_NATTR + 1]; - char *endp = NULL; - char *lasts = NULL; - uint_t i; - - attr[0] = strtok_r(buf, " \t\n", &lasts); - for (i = 1; i < DLADM_NATTR + 1; i++) { - if ((attr[i] = strtok_r(NULL, " \t\n", &lasts)) == NULL) - return (-1); - } - - if (i != DLADM_NATTR + 1) { - errno = EINVAL; - return (-1); - } - - (void) strlcpy(name, attr[0], IFNAMSIZ); - (void) strlcpy(dap->da_dev, attr[1], MAXNAMELEN); - - errno = 0; - dap->da_port = (int)strtol(attr[2], &endp, 10); - if (errno != 0 || *endp != '\0') { - return (-1); - } - - errno = 0; - dap->da_vid = (int)strtol(attr[3], &endp, 10); - if (errno != 0 || *endp != '\0') { - return (-1); - } - - return (0); -} - -/* - * Add a datalink of the specified name and attributes to - * the configuration repository. - */ -static int -i_dladm_db_add(const char *name, dladm_attr_t *dap, const char *root, - dladm_diag_t *diag) -{ - FILE *fp; - int lock_fd, retval = -1; - char line[MAXLINELEN]; - char dl_name[IFNAMSIZ]; - dladm_attr_t da; - char *db_file; - char db_file_buf[MAXPATHLEN]; - - if (root == NULL) { - db_file = DLADM_DB; - } else { - (void) snprintf(db_file_buf, MAXPATHLEN, "%s%s", root, - DLADM_DB); - db_file = db_file_buf; - } - - if ((lock_fd = i_dladm_lock_db(F_WRLCK)) < 0) - return (-1); - - if ((fp = fopen(db_file, "r+")) == NULL && - (fp = fopen(db_file, "w")) == NULL) { - *diag = DLADM_DIAG_REPOSITORY_OPENFAIL; - i_dladm_unlock_db(lock_fd); - return (-1); - } - - while (fgets(line, MAXLINELEN, fp) != NULL) { - /* skip comments and blank lines */ - if (BLANK_LINE(line)) - continue; - - /* skip corrupted lines */ - if (i_dladm_db_decode(line, dl_name, &da) < 0) - continue; - - if (strcmp(dl_name, name) == 0) { - errno = EEXIST; - goto failed; - } - - if (strcmp(da.da_dev, dap->da_dev) == 0 && - da.da_port == dap->da_port && - da.da_vid == dap->da_vid) { - errno = EEXIST; - goto failed; - } - } - - (void) snprintf(line, MAXPATHLEN, "%s\t%s\t%u\t%u\n", - name, dap->da_dev, dap->da_port, dap->da_vid); - - if (fputs(line, fp) == EOF) { - *diag = DLADM_DIAG_REPOSITORY_WRITEFAIL; - goto failed; - } - - if (fflush(fp) == EOF) - goto failed; - - retval = 0; - -failed: - (void) fclose(fp); - i_dladm_unlock_db(lock_fd); - return (retval); -} - -/* - * Remove the datalink of the specified name from the configuration repository. - */ -static int -i_dladm_db_remove(const char *name, const char *root) -{ - FILE *fp; - FILE *nfp; - int nfd, lock_fd; - char line[MAXLINELEN]; - char copy[MAXLINELEN]; - char dl_name[IFNAMSIZ]; - dladm_attr_t da; - boolean_t found = B_FALSE; - char *db_file, *tmp_db_file; - char db_file_buf[MAXPATHLEN]; - char tmp_db_file_buf[MAXPATHLEN]; - - if (root == NULL) { - db_file = DLADM_DB; - tmp_db_file = DLADM_DB_TMP; - } else { - (void) snprintf(db_file_buf, MAXPATHLEN, "%s%s", root, - DLADM_DB); - (void) snprintf(tmp_db_file_buf, MAXPATHLEN, "%s%s", root, - DLADM_DB_TMP); - db_file = db_file_buf; - tmp_db_file = tmp_db_file_buf; - } - - if ((lock_fd = i_dladm_lock_db(F_WRLCK)) < 0) - return (-1); - - if ((fp = fopen(db_file, "r")) == NULL) { - i_dladm_unlock_db(lock_fd); - return (-1); - } - - if ((nfd = open(tmp_db_file, O_WRONLY | O_CREAT | O_TRUNC, - DLADM_DB_PERMS)) < 0) { - (void) fclose(fp); - i_dladm_unlock_db(lock_fd); - return (-1); - } - - if ((nfp = fdopen(nfd, "w")) == NULL) { - (void) close(nfd); - (void) fclose(fp); - (void) unlink(tmp_db_file); - i_dladm_unlock_db(lock_fd); - return (-1); - } - - while (fgets(line, MAXLINELEN, fp) != NULL) { - (void) strlcpy(copy, line, MAXLINELEN); - - /* skip comments */ - if (!BLANK_LINE(line)) { - if (i_dladm_db_decode(line, dl_name, &da) < 0) { - continue; - } - - if (strcmp(dl_name, name) == 0) { - found = B_TRUE; - continue; - } - } - - if (fputs(copy, nfp) == EOF) - goto failed; - } - - if (!found) { - errno = ENOENT; - goto failed; - } - - if (fflush(nfp) == EOF) - goto failed; - - (void) fclose(fp); - (void) fclose(nfp); - if (rename(tmp_db_file, db_file) < 0) { - (void) unlink(tmp_db_file); - i_dladm_unlock_db(lock_fd); - return (-1); - } - - i_dladm_unlock_db(lock_fd); - return (0); - -failed: - (void) fclose(fp); - (void) fclose(nfp); - (void) unlink(tmp_db_file); - i_dladm_unlock_db(lock_fd); - - return (-1); -} - -/* - * For each datalink in the configuration repository, invoke the specified - * callback. If the datalink name is specified, the callback is invoked - * only for datalink of the matching name. - */ -static void -i_dladm_db_walk(void (*fn)(void *, const char *, dladm_attr_t *), - const char *name, void *arg) -{ - FILE *fp; - int lock_fd; - char line[MAXLINELEN]; - char dl_name[IFNAMSIZ]; - dladm_attr_t da; - - lock_fd = i_dladm_lock_db(F_RDLCK); - - if ((fp = fopen(DLADM_DB, "r")) == NULL) { - i_dladm_unlock_db(lock_fd); - return; - } - - while (fgets(line, MAXLINELEN, fp) != NULL) { - /* skip comments */ - if (BLANK_LINE(line)) - continue; - - if (i_dladm_db_decode(line, dl_name, &da) < 0) - continue; - - if (name != NULL && strcmp(name, dl_name) != 0) - continue; - - fn(arg, dl_name, &da); - } - - (void) fclose(fp); - i_dladm_unlock_db(lock_fd); -} - -/* - * For each datalink in the configuration repository, invoke the - * specified callback. - */ -void -dladm_db_walk(void (*fn)(void *, const char *, dladm_attr_t *), - void *arg) -{ - i_dladm_db_walk(fn, NULL, arg); -} - /* * Issue an ioctl to the specified file descriptor attached to the * DLD control driver interface. */ static int -i_dladm_ioctl(int fd, char *ic_dp, int ic_cmd, int ic_len) +i_dladm_ioctl(int fd, int ic_cmd, void *ic_dp, int ic_len) { struct strioctl iocb; iocb.ic_cmd = ic_cmd; iocb.ic_timout = 0; iocb.ic_len = ic_len; - iocb.ic_dp = ic_dp; + iocb.ic_dp = (char *)ic_dp; return (ioctl(fd, I_STR, &iocb)); } /* - * Issue a DLDIOCCREATE ioctl command. - */ -static int -i_dladm_create(int fd, const char *name, dladm_attr_t *dap) -{ - dld_ioc_create_t dic; - - if (strlen(name) >= IFNAMSIZ) { - errno = EINVAL; - return (-1); - } - - (void) strlcpy(dic.dic_name, name, IFNAMSIZ); - (void) strlcpy(dic.dic_dev, dap->da_dev, MAXNAMELEN); - dic.dic_port = dap->da_port; - dic.dic_vid = dap->da_vid; - - return (i_dladm_ioctl(fd, (char *)&dic, DLDIOCCREATE, sizeof (dic))); -} - -/* - * Datalink bringup callback. Brings up the specified datalink. - */ -static void -i_dladm_up(void *arg, const char *name, dladm_attr_t *dap) -{ - i_dladm_walk_t *wp = arg; - - wp->found = B_TRUE; - (void) i_dladm_create(wp->fd, name, dap); -} - -/* - * Bring down the datalink of the specified name. - */ -static int -i_dladm_destroy(int fd, const char *name) -{ - dld_ioc_destroy_t did; - - if (strlen(name) >= IFNAMSIZ) { - errno = EINVAL; - return (-1); - } - - (void) strlcpy(did.did_name, name, IFNAMSIZ); - - return (i_dladm_ioctl(fd, (char *)&did, DLDIOCDESTROY, sizeof (did))); -} - -/* - * Bring down one or all currently active datalinks. - */ -/*ARGSUSED*/ -static void -i_dladm_down(void *arg, const char *name) -{ - i_dladm_walk_t *wp = (i_dladm_walk_t *)arg; - - wp->found = B_TRUE; - - if (wp->name != NULL && strcmp(name, wp->name) != 0) - return; - - (void) i_dladm_destroy(wp->fd, name); -} - -/* * Return the attributes of the specified datalink from the DLD driver. */ static int @@ -474,10 +72,11 @@ i_dladm_info(int fd, const char *name, dladm_attr_t *dap) (void) strlcpy(dia.dia_name, name, IFNAMSIZ); - if (i_dladm_ioctl(fd, (char *)&dia, DLDIOCATTR, sizeof (dia)) < 0) + if (i_dladm_ioctl(fd, DLDIOCATTR, &dia, sizeof (dia)) < 0) return (-1); (void) strlcpy(dap->da_dev, dia.dia_dev, MAXNAMELEN); + dap->da_max_sdu = dia.dia_max_sdu; dap->da_port = dia.dia_port; dap->da_vid = dia.dia_vid; @@ -581,7 +180,7 @@ dladm_walk(void (*fn)(void *, const char *), void *arg) i_dladm_nt_net_count); if (count == 0) - return (0); + return (dladm_walk_vlan(fn, arg)); if ((array = malloc(count * sizeof (char *))) == NULL) goto done; @@ -610,136 +209,56 @@ dladm_walk(void (*fn)(void *, const char *), void *arg) done: free(array); - return (0); + return (dladm_walk_vlan(fn, arg)); } /* - * Create the link of specified name and attributes. Adds it to the - * configuration repository if DLADM_LINK_TEMP is not set. Errors - * will be ignored if DLADM_LINK_FORCED is set. + * Invoke the specified callback function for each vlan managed by dld */ int -dladm_link(const char *name, dladm_attr_t *dap, int flags, - const char *root, dladm_diag_t *diag) +dladm_walk_vlan(void (*fn)(void *, const char *), void *arg) { - int fd; - boolean_t tempop = (flags & DLADM_LINK_TEMP); - boolean_t forced = (flags & DLADM_LINK_FORCED); + int fd, bufsize, rc, i; + int nvlan = 512; + dld_ioc_vlan_t *iocp = NULL; + dld_vlan_info_t *dvip; - if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) { - *diag = DLADM_DIAG_DEVICE_OPENFAIL; + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) return (-1); - } - - if (!tempop) { - if (i_dladm_db_add(name, dap, root, diag) < 0 && !forced) - goto failed; - } - - if (i_dladm_create(fd, name, dap) < 0 && !forced) { - if (errno == EINVAL) { - *diag = DLADM_DIAG_INVALID_INTFNAME; - } - if (!tempop) - (void) i_dladm_db_remove(name, root); - goto failed; - } - - (void) close(fd); - return (0); -failed: - (void) close(fd); - return (-1); -} + for (;;) { + bufsize = sizeof (dld_ioc_vlan_t) + + nvlan * sizeof (dld_vlan_info_t); -/* - * Instantiate the datalink of specified name. Brings up all datalinks - * if name is NULL. - */ -int -dladm_up(const char *name, dladm_diag_t *diag) -{ - i_dladm_walk_t walk; + iocp = (dld_ioc_vlan_t *)calloc(1, bufsize); + if (iocp == NULL) + goto done; - if ((walk.fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) { - *diag = - DLADM_DIAG_DEVICE_OPENFAIL; - return (-1); - } + rc = i_dladm_ioctl(fd, DLDIOCVLAN, iocp, bufsize); + if (rc == 0) + break; - walk.found = B_FALSE; - i_dladm_db_walk(i_dladm_up, name, (void *)&walk); - if (name != NULL && !walk.found) { - (void) close(walk.fd); - errno = ENOENT; - return (-1); + if (errno == ENOSPC) { + nvlan *= 2; + free(iocp); + continue; + } + goto done; } - (void) close(walk.fd); - return (0); -} - -/* - * Deletes the link of specified name. - */ -int -dladm_unlink(const char *name, boolean_t tempop, const char *root, - dladm_diag_t *diag) -{ - int fd; + dvip = (dld_vlan_info_t *)(iocp + 1); - if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) { - *diag = DLADM_DIAG_DEVICE_OPENFAIL; - return (-1); - } - - if (i_dladm_destroy(fd, name) < 0) { - if (errno == EINVAL) - *diag = DLADM_DIAG_INVALID_LINKNAME; - goto failed; + for (i = 0; i < iocp->div_count; i++) { + if (dvip[i].dvi_vid != 0) + (*fn)(arg, dvip[i].dvi_name); } - if (!tempop) - (void) i_dladm_db_remove(name, root); +done: + free(iocp); (void) close(fd); return (0); - -failed: - (void) close(fd); - return (-1); } -/* - * Brings down the datalink of specified name. Brings down all datalinks - * if name == NULL. - */ -int -dladm_down(const char *name, dladm_diag_t *diag) -{ - i_dladm_walk_t walk; - - if ((walk.fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) { - *diag = DLADM_DIAG_DEVICE_OPENFAIL; - return (-1); - } - walk.found = B_FALSE; - walk.name = name; - - if (dladm_walk(i_dladm_down, (void *)&walk) < 0) { - (void) close(walk.fd); - return (-1); - } - - if (name != NULL && !walk.found) { - (void) close(walk.fd); - errno = ENOENT; - return (-1); - } - - (void) close(walk.fd); - return (0); -} /* * Returns the current attributes of the specified datalink. @@ -762,43 +281,3 @@ failed: (void) close(fd); return (-1); } - -/* - * Causes the nodes corresponding to created or deleted datalinks to - * be created or deleted. - */ -int -dladm_sync(void) -{ - di_devlink_handle_t hdl; - - if ((hdl = di_devlink_init(DLD_DRIVER_NAME, DI_MAKE_LINK)) == NULL) - return (-1); - - if (di_devlink_fini(&hdl) < 0) - return (-1); - - return (0); -} - -const char * -dladm_diag(dladm_diag_t diag) { - switch (diag) { - case DLADM_DIAG_INVALID_LINKNAME: - return (gettext("invalid datalink name")); - case DLADM_DIAG_INVALID_INTFNAME: - return (gettext("invalid interface name")); - case DLADM_DIAG_CORRUPT_REPOSITORY: - return (gettext("configuration repository corrupt")); - case DLADM_DIAG_REPOSITORY_OPENFAIL: - return (gettext("configuration repository open failed")); - case DLADM_DIAG_REPOSITORY_WRITEFAIL: - return (gettext("write to configuration repository failed")); - case DLADM_DIAG_REPOSITORY_CLOSEFAIL: - return (gettext("configuration repository close failed")); - case DLADM_DIAG_DEVICE_OPENFAIL: - return (gettext("dld device open fail")); - default: - return (gettext("unknown diagnostic")); - } -} diff --git a/usr/src/lib/libdladm/common/libdladm.h b/usr/src/lib/libdladm/common/libdladm.h index 32c1a08736..8ae84bc51b 100644 --- a/usr/src/lib/libdladm/common/libdladm.h +++ b/usr/src/lib/libdladm/common/libdladm.h @@ -41,44 +41,14 @@ typedef struct dladm_attr dladm_attr_t; struct dladm_attr { char da_dev[MAXNAMELEN]; + uint_t da_max_sdu; uint_t da_port; uint16_t da_vid; }; -/* number of attributes per devices in database file */ -#define DLADM_NATTR 3 - -/* - * Diagnostic codes. These supplement error messages. - */ -typedef enum { - DLADM_DIAG_INVALID_LINKNAME = 1, - DLADM_DIAG_INVALID_INTFNAME = 2, - DLADM_DIAG_CORRUPT_REPOSITORY = 3, - DLADM_DIAG_REPOSITORY_OPENFAIL = 4, - DLADM_DIAG_REPOSITORY_WRITEFAIL = 5, - DLADM_DIAG_REPOSITORY_CLOSEFAIL = 6, - DLADM_DIAG_DEVICE_OPENFAIL = 7 -} dladm_diag_t; - -/* - * Flags recognized by dladm_link() - */ -#define DLADM_LINK_TEMP 0x01 -#define DLADM_LINK_FORCED 0x02 - -extern int dladm_link(const char *, dladm_attr_t *, - int, const char *, dladm_diag_t *); -extern int dladm_up(const char *, dladm_diag_t *); -extern int dladm_unlink(const char *, boolean_t, const char *, - dladm_diag_t *); -extern int dladm_down(const char *, dladm_diag_t *); extern int dladm_walk(void (*)(void *, const char *), void *); +extern int dladm_walk_vlan(void (*)(void *, const char *), void *); extern int dladm_info(const char *, dladm_attr_t *); -extern void dladm_db_walk(void (*)(void *, const char *, - dladm_attr_t *), void *); -extern int dladm_sync(void); -extern const char *dladm_diag(dladm_diag_t); #ifdef __cplusplus } diff --git a/usr/src/lib/libdladm/spec/dladm.spec b/usr/src/lib/libdladm/spec/dladm.spec index 3bb89fb4a7..6aca5746ee 100644 --- a/usr/src/lib/libdladm/spec/dladm.spec +++ b/usr/src/lib/libdladm/spec/dladm.spec @@ -25,32 +25,6 @@ #pragma ident "%Z%%M% %I% %E% SMI" # -function dladm_link -include <libdladm.h> -declaration int dladm_link(const char *, dladm_attr_t *, \ - int, const char *, dladm_diag_t *) -version SUNWprivate_1.1 -end - -function dladm_up -include <libdladm.h> -declaration int dladm_up(const char *, dladm_diag_t *) -version SUNWprivate_1.1 -end - -function dladm_unlink -include <libdladm.h> -declaration int dladm_unlink(const char *, boolean_t, const char *, \ - dladm_diag_t *) -version SUNWprivate_1.1 -end - -function dladm_down -include <libdladm.h> -declaration int dladm_down(const char *, dladm_diag_t *) -version SUNWprivate_1.1 -end - function dladm_walk include <libdladm.h> declaration int dladm_walk(void (*fn)(void *, const char *), \ @@ -58,27 +32,15 @@ declaration int dladm_walk(void (*fn)(void *, const char *), \ version SUNWprivate_1.1 end -function dladm_info -include <libdladm.h> -declaration int dladm_info(const char *, dladm_attr_t *) -version SUNWprivate_1.1 -end - -function dladm_db_walk +function dladm_walk_vlan include <libdladm.h> -declaration int dladm_db_walk(void (*)(void *, const char *, - dladm_attr_t *), void *) -version SUNWprivate_1.1 -end - -function dladm_sync -include <libdladm.h> -declaration void dladm_sync(void) +declaration int dladm_walk_vlan(void (*fn)(void *, const char *), \ + void *) version SUNWprivate_1.1 end -function dladm_diag +function dladm_info include <libdladm.h> -declaration const char * dladm_diag(dladm_diag_t) +declaration int dladm_info(const char *, dladm_attr_t *) version SUNWprivate_1.1 end diff --git a/usr/src/lib/libdlpi/common/libdlpi.c b/usr/src/lib/libdlpi/common/libdlpi.c index 2ae1ccc349..59d213fffc 100644 --- a/usr/src/lib/libdlpi/common/libdlpi.c +++ b/usr/src/lib/libdlpi/common/libdlpi.c @@ -178,12 +178,6 @@ dlpi_open(const char *provider) if ((fd = open(devname, O_RDWR)) != -1) return (fd); - (void) snprintf(devname, MAXPATHLEN, "/devices/pseudo/dld@0:%s", - provider); - - if ((fd = open(devname, O_RDWR)) != -1) - return (fd); - (void) snprintf(path, MAXPATHLEN, "/devices/pseudo/clone@0:%s", provider); diff --git a/usr/src/lib/liblaadm/common/liblaadm.c b/usr/src/lib/liblaadm/common/liblaadm.c index 4eafc61f7c..6add61fcb8 100644 --- a/usr/src/lib/liblaadm/common/liblaadm.c +++ b/usr/src/lib/liblaadm/common/liblaadm.c @@ -185,6 +185,18 @@ typedef struct add_db_state { static int i_laadm_fput_grp(FILE *, laadm_grp_attr_db_t *); +static int +i_laadm_strioctl(int fd, int cmd, void *ptr, int ilen) +{ + struct strioctl str; + + str.ic_cmd = cmd; + str.ic_timout = 0; + str.ic_len = ilen; + str.ic_dp = ptr; + + return (ioctl(fd, I_STR, &str)); +} /* * Open and lock the aggregation configuration file lock. The lock is @@ -261,8 +273,7 @@ laadm_walk_sys(int (*fn)(void *, laadm_grp_attr_sys_t *), void *arg) } tryagain: - ioc->li_bufsize = bufsize; - rc = ioctl(fd, LAIOC_INFO, ioc); + rc = i_laadm_strioctl(fd, LAIOC_INFO, ioc, bufsize); if (rc != 0) { if (errno == ENOSPC) { @@ -501,19 +512,18 @@ failed: static int i_laadm_add_rem_sys(laadm_grp_attr_db_t *attr, int cmd, laadm_diag_t *diag) { - int i, rc, fd; - laioc_add_t ioc; + int i, rc, fd, len; + laioc_add_rem_t *iocp; laioc_port_t *ports; - ioc.la_key = attr->lt_key; - ioc.la_nports = attr->lt_nports; - - ioc.la_ports = malloc(attr->lt_nports * sizeof (laioc_port_t)); - if (ioc.la_ports == NULL) + len = sizeof (*iocp) + attr->lt_nports * sizeof (laioc_port_t); + iocp = malloc(len); + if (iocp == NULL) goto failed; - /* LINTED E_BAD_PTR_CAST_ALIGN */ - ports = (laioc_port_t *)ioc.la_ports; + iocp->la_key = attr->lt_key; + iocp->la_nports = attr->lt_nports; + ports = (laioc_port_t *)(iocp + 1); for (i = 0; i < attr->lt_nports; i++) { if (strlcpy(ports[i].lp_devname, @@ -528,17 +538,17 @@ i_laadm_add_rem_sys(laadm_grp_attr_db_t *attr, int cmd, laadm_diag_t *diag) goto failed; } - rc = ioctl(fd, cmd, &ioc); + rc = i_laadm_strioctl(fd, cmd, iocp, len); if ((rc < 0) && (errno == EINVAL)) *diag = LAADM_DIAG_INVALID_INTFNAME; (void) close(fd); - free(ioc.la_ports); + free(iocp); return (rc); failed: - free(ioc.la_ports); + free(iocp); return (-1); } @@ -575,7 +585,7 @@ i_laadm_modify_sys(uint32_t key, uint32_t mask, laadm_modify_attr_t *attr, return (-1); } - rc = ioctl(fd, LAIOC_MODIFY, &ioc); + rc = i_laadm_strioctl(fd, LAIOC_MODIFY, &ioc, sizeof (ioc)); if ((rc < 0) && (errno == EINVAL)) *diag = LAADM_DIAG_INVALID_MACADDR; @@ -590,28 +600,29 @@ i_laadm_modify_sys(uint32_t key, uint32_t mask, laadm_modify_attr_t *attr, static int i_laadm_create_sys(int fd, laadm_grp_attr_db_t *attr, laadm_diag_t *diag) { - int i, rc; - laioc_create_t ioc; + int i, rc, len; + laioc_create_t *iocp; laioc_port_t *ports; - ioc.lc_key = attr->lt_key; - ioc.lc_nports = attr->lt_nports; - ioc.lc_policy = attr->lt_policy; - ioc.lc_lacp_mode = attr->lt_lacp_mode; - ioc.lc_lacp_timer = attr->lt_lacp_timer; - - ioc.lc_ports = malloc(attr->lt_nports * sizeof (laioc_port_t)); - if (ioc.lc_ports == NULL) + len = sizeof (*iocp) + attr->lt_nports * sizeof (laioc_port_t); + iocp = malloc(len); + if (iocp == NULL) return (-1); - /* LINTED E_BAD_PTR_CAST_ALIGN */ - ports = (laioc_port_t *)ioc.lc_ports; + iocp->lc_key = attr->lt_key; + iocp->lc_nports = attr->lt_nports; + iocp->lc_policy = attr->lt_policy; + iocp->lc_lacp_mode = attr->lt_lacp_mode; + iocp->lc_lacp_timer = attr->lt_lacp_timer; + + ports = (laioc_port_t *)(iocp + 1); for (i = 0; i < attr->lt_nports; i++) { if (strlcpy(ports[i].lp_devname, attr->lt_ports[i].lp_devname, MAXNAMELEN) >= MAXNAMELEN) { - free(ioc.lc_ports); + errno = EINVAL; + free(iocp); return (-1); } ports[i].lp_port = attr->lt_ports[i].lp_port; @@ -622,18 +633,18 @@ i_laadm_create_sys(int fd, laadm_grp_attr_db_t *attr, laadm_diag_t *diag) (attr->lt_mac[0] & 0x01))) { errno = EINVAL; *diag = LAADM_DIAG_INVALID_MACADDR; - free(ioc.lc_ports); + free(iocp); return (-1); } - bcopy(attr->lt_mac, ioc.lc_mac, ETHERADDRL); - ioc.lc_mac_fixed = attr->lt_mac_fixed; + bcopy(attr->lt_mac, iocp->lc_mac, ETHERADDRL); + iocp->lc_mac_fixed = attr->lt_mac_fixed; - rc = ioctl(fd, LAIOC_CREATE, &ioc); + rc = i_laadm_strioctl(fd, LAIOC_CREATE, iocp, len); if (rc < 0) *diag = LAADM_DIAG_INVALID_INTFNAME; - free(ioc.lc_ports); + free(iocp); return (rc); } @@ -700,7 +711,7 @@ i_laadm_delete_sys(int fd, laadm_grp_attr_sys_t *attr) ioc.ld_key = attr->lg_key; - return (ioctl(fd, LAIOC_DELETE, &ioc)); + return (i_laadm_strioctl(fd, LAIOC_DELETE, &ioc, sizeof (ioc))); } /* @@ -1486,9 +1497,17 @@ laadm_create(uint32_t key, uint32_t nports, laadm_port_attr_db_t *ports, return (-1); } else { laadm_up_t up; + int rc; + up.lu_key = key; up.lu_found = B_FALSE; - return (i_laadm_up((void *)&up, &attr, diag)); + up.lu_fd = open(LAADM_DEV, O_RDWR); + if (up.lu_fd < 0) + return (-1); + + rc = i_laadm_up((void *)&up, &attr, diag); + (void) close(up.lu_fd); + return (rc); } /* bring up the link aggregation group */ diff --git a/usr/src/lib/libmacadm/Makefile.com b/usr/src/lib/libmacadm/Makefile.com index 95e9cf09f4..b3d7635878 100644 --- a/usr/src/lib/libmacadm/Makefile.com +++ b/usr/src/lib/libmacadm/Makefile.com @@ -37,7 +37,7 @@ include ../../Makefile.rootfs LIBS = $(DYNLIB) $(LINTLIB) -LDLIBS += -ldevinfo -lc +LDLIBS += -ldevinfo -ldladm -ldlpi -lc $(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) SRCDIR = ../common diff --git a/usr/src/lib/libmacadm/common/libmacadm.c b/usr/src/lib/libmacadm/common/libmacadm.c index 2dd66131aa..053d1c5011 100644 --- a/usr/src/lib/libmacadm/common/libmacadm.c +++ b/usr/src/lib/libmacadm/common/libmacadm.c @@ -33,6 +33,8 @@ #include <stropts.h> #include <sys/dld.h> #include <libdevinfo.h> +#include <libdladm.h> +#include <libdlpi.h> #define _KERNEL #include <sys/sysmacros.h> @@ -48,24 +50,39 @@ typedef struct macadm_walk { void *mw_arg; - void (*mw_fn)(void *, const char *, uint_t); + void (*mw_fn)(void *, const char *); } macadm_walk_t; /* - * Local callback invoked for each DDI_NT_MAC node. + * Local callback invoked for each DDI_NT_NET node. */ +/* ARGSUSED */ static int i_macadm_apply(di_node_t node, di_minor_t minor, void *arg) { macadm_walk_t *mwp = arg; char dev[MAXNAMELEN]; - uint_t port; + dladm_attr_t dlattr; + int fd; (void) snprintf(dev, MAXNAMELEN, "%s%d", di_driver_name(node), di_instance(node)); - port = getminor(di_minor_devt(minor)); - mwp->mw_fn(mwp->mw_arg, dev, port); + /* + * We need to be able to report devices that are + * reported by the walker, but have not yet attached + * to the system. Attempting to opening them will + * cause them to temporarely attach and be known + * by dld. + */ + if ((fd = dlpi_open(dev)) == -1 && errno != EPERM) + return (DI_WALK_CONTINUE); + if (fd != 0) + (void) dlpi_close(fd); + + /* invoke callback only for non-legacy devices */ + if (dladm_info(dev, &dlattr) == 0) + mwp->mw_fn(mwp->mw_arg, dev); return (DI_WALK_CONTINUE); } @@ -74,7 +91,7 @@ i_macadm_apply(di_node_t node, di_minor_t minor, void *arg) * Invoke the specified callback for each DDI_NT_MAC node. */ int -macadm_walk(void (*fn)(void *, const char *, uint_t), void *arg, +macadm_walk(void (*fn)(void *, const char *), void *arg, boolean_t use_cache) { di_node_t root; @@ -94,7 +111,7 @@ macadm_walk(void (*fn)(void *, const char *, uint_t), void *arg, mw.mw_fn = fn; mw.mw_arg = arg; - (void) di_walk_minor(root, DDI_NT_MAC, 0, &mw, i_macadm_apply); + (void) di_walk_minor(root, DDI_NT_NET, 0, &mw, i_macadm_apply); di_fini(root); return (0); diff --git a/usr/src/lib/libmacadm/common/libmacadm.h b/usr/src/lib/libmacadm/common/libmacadm.h index a5ae05ef7c..2f21b53d55 100644 --- a/usr/src/lib/libmacadm/common/libmacadm.h +++ b/usr/src/lib/libmacadm/common/libmacadm.h @@ -36,7 +36,7 @@ extern "C" { #endif -extern int macadm_walk(void (*)(void *, const char *, uint_t), +extern int macadm_walk(void (*)(void *, const char *), void *, boolean_t); #ifdef __cplusplus diff --git a/usr/src/lib/libmacadm/spec/macadm.spec b/usr/src/lib/libmacadm/spec/macadm.spec index 5bab70293a..32cbe46145 100644 --- a/usr/src/lib/libmacadm/spec/macadm.spec +++ b/usr/src/lib/libmacadm/spec/macadm.spec @@ -28,7 +28,7 @@ function macadm_walk include <libmacadm.h> declaration int macadm_walk( \ - void (*fn)(void *, const char *, uint_t), \ + void (*fn)(void *, const char *), \ void *, boolean_t); version SUNWprivate_1.1 end diff --git a/usr/src/pkgdefs/SUNWckr/prototype_i386 b/usr/src/pkgdefs/SUNWckr/prototype_i386 index bb47ae02e6..a7041ad90e 100644 --- a/usr/src/pkgdefs/SUNWckr/prototype_i386 +++ b/usr/src/pkgdefs/SUNWckr/prototype_i386 @@ -149,7 +149,6 @@ f none kernel/misc/ctf 755 root sys l none kernel/misc/des=../../kernel/crypto/des f none kernel/misc/dls 755 root sys f none kernel/misc/fssnap_if 755 root sys -f none kernel/misc/ght 755 root sys f none kernel/misc/gld 755 root sys f none kernel/misc/hpcsvc 755 root sys f none kernel/misc/i2o_msg 755 root sys @@ -314,7 +313,6 @@ f none kernel/misc/amd64/ctf 755 root sys l none kernel/misc/amd64/des=../../../kernel/crypto/amd64/des f none kernel/misc/amd64/dls 755 root sys f none kernel/misc/amd64/fssnap_if 755 root sys -f none kernel/misc/amd64/ght 755 root sys f none kernel/misc/amd64/gld 755 root sys f none kernel/misc/amd64/hpcsvc 755 root sys f none kernel/misc/amd64/ipc 755 root sys diff --git a/usr/src/pkgdefs/SUNWckr/prototype_sparc b/usr/src/pkgdefs/SUNWckr/prototype_sparc index 71ae7c662f..957f64a0b8 100644 --- a/usr/src/pkgdefs/SUNWckr/prototype_sparc +++ b/usr/src/pkgdefs/SUNWckr/prototype_sparc @@ -154,7 +154,6 @@ f none kernel/misc/sparcv9/dada 755 root sys l none kernel/misc/sparcv9/des=../../../kernel/crypto/sparcv9/des f none kernel/misc/sparcv9/dls 755 root sys f none kernel/misc/sparcv9/fssnap_if 755 root sys -f none kernel/misc/sparcv9/ght 755 root sys f none kernel/misc/sparcv9/gld 755 root sys f none kernel/misc/sparcv9/hpcsvc 755 root sys f none kernel/misc/sparcv9/ipc 755 root sys diff --git a/usr/src/pkgdefs/SUNWcnetr/Makefile b/usr/src/pkgdefs/SUNWcnetr/Makefile index c8a4f49fbf..99b31cc824 100644 --- a/usr/src/pkgdefs/SUNWcnetr/Makefile +++ b/usr/src/pkgdefs/SUNWcnetr/Makefile @@ -28,11 +28,11 @@ include ../Makefile.com -DATAFILES += i.ipsecalgsbase i.preserve i.sock2path i.datalinkconf +DATAFILES += i.ipsecalgsbase i.preserve i.sock2path .KEEP_STATE: -all: $(FILES) postinstall +all: $(FILES) install: all pkg diff --git a/usr/src/pkgdefs/SUNWcnetr/pkginfo.tmpl b/usr/src/pkgdefs/SUNWcnetr/pkginfo.tmpl index 5b1bf64231..ee6f722581 100644 --- a/usr/src/pkgdefs/SUNWcnetr/pkginfo.tmpl +++ b/usr/src/pkgdefs/SUNWcnetr/pkginfo.tmpl @@ -41,7 +41,7 @@ DESC="core software for network infrastructure configuration" VENDOR="Sun Microsystems, Inc." HOTLINE="Please contact your local service provider" EMAIL="" -CLASSES="none ipsecalgsbase preserve sock2path datalinkconf" +CLASSES="none ipsecalgsbase preserve sock2path" BASEDIR=/ SUNW_PKGVERS="1.0" SUNW_PKG_ALLZONES="true" diff --git a/usr/src/pkgdefs/SUNWcnetr/postinstall b/usr/src/pkgdefs/SUNWcnetr/postinstall deleted file mode 100644 index 9473d07cd6..0000000000 --- a/usr/src/pkgdefs/SUNWcnetr/postinstall +++ /dev/null @@ -1,46 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" -# - -if [ ! -r $PKG_INSTALL_ROOT/etc/svc/volatile/repository_door ]; then - # - # smf(5) is not presently running for the destination environment. - # Which means we're likely in an upgrade situation and need - # to add a svcadm clear for the network/physical service since - # it is likely to go into maintenance on first reboot due to - # the network/datalink service - # - - UPGRADE=$BASEDIR/var/svc/profile/upgrade - -cat >> $UPGRADE <<-EOF - -svcadm clear svc:/network/physical:default - -EOF - -fi diff --git a/usr/src/pkgdefs/SUNWcnetr/prototype_com b/usr/src/pkgdefs/SUNWcnetr/prototype_com index 9456e9678a..636fadd79e 100644 --- a/usr/src/pkgdefs/SUNWcnetr/prototype_com +++ b/usr/src/pkgdefs/SUNWcnetr/prototype_com @@ -39,11 +39,9 @@ # packaging files i pkginfo i copyright -i postinstall i i.ipsecalgsbase i i.preserve i i.sock2path -i i.datalinkconf # # source locations relative to the prototype file # @@ -51,7 +49,6 @@ i i.datalinkconf # d none etc 755 root sys e preserve etc/aggregation.conf 644 root sys -e datalinkconf etc/datalink.conf 644 root sys d none etc/default 755 root sys e preserve etc/default/dhcpagent 644 root sys e preserve etc/default/inetinit 644 root sys diff --git a/usr/src/pkgdefs/SUNWcsr/postinstall b/usr/src/pkgdefs/SUNWcsr/postinstall index 225d1819eb..9ff3d11ad5 100644 --- a/usr/src/pkgdefs/SUNWcsr/postinstall +++ b/usr/src/pkgdefs/SUNWcsr/postinstall @@ -101,6 +101,32 @@ cat >> $BASEDIR/var/svc/profile/upgrade <<\_DEL_BIND8 _DEL_BIND8 # +# Remove stale GLD services +# +SVCCFG_REPOSITORY=$PKG_INSTALL_ROOT/etc/svc/repository.db +export SVCCFG_REPOSITORY +if [ ! -r $PKG_INSTALL_ROOT/etc/svc/volatile/repository_door ]; then + # + # smf(5) is not presently running for the destination environment. + # It is safe to remove the manifests from the repository. + # + svccfg delete svc:/network/aggregation + svccfg delete svc:/network/datalink-init + svccfg delete svc:/network/datalink +else + # + # Local package install. Need to disable the services first + # before deleting. + # + svcadm disable -s svc:/network/aggregation + svccfg delete svc:/network/aggregation + svcadm disable -s svc:/network/datalink-init + svccfg delete svc:/network/datalink-init + svcadm disable -s svc:/network/datalink + svccfg delete svc:/network/datalink +fi + +# # svc:/network/rpc/keyserv is expected to be off on systems that don't # set domainname. On systems that do define a default domain, leave the # setting as previously set. diff --git a/usr/src/pkgdefs/SUNWcsr/prototype_com b/usr/src/pkgdefs/SUNWcsr/prototype_com index 77a82a5a41..154aef85a3 100644 --- a/usr/src/pkgdefs/SUNWcsr/prototype_com +++ b/usr/src/pkgdefs/SUNWcsr/prototype_com @@ -328,11 +328,8 @@ f none lib/svc/bin/svc.configd 0555 root sys f none lib/svc/bin/svc.startd 0555 root sys d none lib/svc/capture 0755 root bin d none lib/svc/method 0755 root bin -f none lib/svc/method/aggregation 0555 root bin f none lib/svc/method/boot-archive 0555 root bin f none lib/svc/method/console-login 0555 root bin -f none lib/svc/method/datalink 0555 root bin -f none lib/svc/method/datalink-init 0555 root bin f none lib/svc/method/devices-local 0555 root bin f none lib/svc/method/fs-local 0555 root bin f none lib/svc/method/fs-minimal 0555 root bin @@ -463,9 +460,6 @@ f manifest var/svc/manifest/milestone/network.xml 0444 root sys f manifest var/svc/manifest/milestone/single-user.xml 0444 root sys f manifest var/svc/manifest/milestone/sysconfig.xml 0444 root sys d none var/svc/manifest/network 755 root sys -f manifest var/svc/manifest/network/aggregation.xml 0444 root sys -f manifest var/svc/manifest/network/datalink.xml 0444 root sys -f manifest var/svc/manifest/network/datalink-init.xml 0444 root sys f manifest var/svc/manifest/network/inetd.xml 0444 root sys f manifest var/svc/manifest/network/inetd-upgrade.xml 0444 root sys f manifest var/svc/manifest/network/network-initial.xml 0444 root sys diff --git a/usr/src/pkgdefs/SUNWcsu/prototype_com b/usr/src/pkgdefs/SUNWcsu/prototype_com index 45475ebf21..1e7210d9a3 100644 --- a/usr/src/pkgdefs/SUNWcsu/prototype_com +++ b/usr/src/pkgdefs/SUNWcsu/prototype_com @@ -577,7 +577,6 @@ f none usr/lib/rcm/modules/SUNW_network_rcm.so 555 root bin f none usr/lib/rcm/modules/SUNW_swap_rcm.so 555 root bin f none usr/lib/rcm/modules/SUNW_cluster_rcm.so 555 root bin f none usr/lib/rcm/modules/SUNW_ip_anon_rcm.so 555 root bin -f none usr/lib/rcm/modules/SUNW_mac_rcm.so 555 root bin f none usr/lib/rcm/modules/SUNW_mpxio_rcm.so 555 root bin f none usr/lib/rcm/rcm_daemon 555 root bin d none usr/lib/rcm/scripts 755 root bin diff --git a/usr/src/pkgdefs/SUNWhea/prototype_com b/usr/src/pkgdefs/SUNWhea/prototype_com index b29958df97..afc3165640 100644 --- a/usr/src/pkgdefs/SUNWhea/prototype_com +++ b/usr/src/pkgdefs/SUNWhea/prototype_com @@ -657,7 +657,6 @@ f none usr/include/sys/fss.h 644 root bin f none usr/include/sys/fsspriocntl.h 644 root bin f none usr/include/sys/fx.h 644 root bin f none usr/include/sys/fxpriocntl.h 644 root bin -f none usr/include/sys/ght.h 644 root bin f none usr/include/sys/gld.h 644 root bin f none usr/include/sys/gldpriv.h 644 root bin d none usr/include/sys/hotplug 755 root bin diff --git a/usr/src/pkgdefs/common_files/i.datalinkconf b/usr/src/pkgdefs/common_files/i.datalinkconf deleted file mode 100644 index ff9e170279..0000000000 --- a/usr/src/pkgdefs/common_files/i.datalinkconf +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/sh -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "%Z%%M% %I% %E% SMI" - -while read src dest -do - if [ ! -f $dest ] ; then - cp $src $dest - fi - - drivers="bge xge" - conf=$dest - - ls -1 $PKG_INSTALL_ROOT/etc | \ - egrep -e '^hostname.|^hostname6.|^dhcp.' | \ - cut -d . -f2 | sort -u > /tmp/ifnames.$$ - - for driver in $drivers - do - grep $driver /tmp/ifnames.$$ | \ - while read ifname - do - devnum=`echo $ifname | sed "s/$driver//g` - if [ "$driver$devnum" != $ifname -o \ - -n "`echo $devnum | tr -d '[0-9]'`" ]; then - echo "skipping invalid interface $ifname" - continue - fi - - vid=`expr $devnum / 1000` - inst=`expr $devnum % 1000` - - awk '{ print $1 }' $conf | grep $ifname > /dev/null - if [ $? -ne 0 ]; then - # An entry for that interface does not exist - printf \ - "$ifname\t$driver$inst\t0\t$vid\n" \ - >> $conf - fi - done - done - - rm -f /tmp/ifnames.$$ -done -exit 0 diff --git a/usr/src/tools/scripts/bfu.sh b/usr/src/tools/scripts/bfu.sh index f845949a50..227b8acc42 100644 --- a/usr/src/tools/scripts/bfu.sh +++ b/usr/src/tools/scripts/bfu.sh @@ -84,7 +84,6 @@ all_zones_files=" etc/cron.d/at.deny etc/cron.d/cron.deny etc/crypto/pkcs11.conf - etc/datalink.conf etc/default/* etc/dfs/dfstab etc/dumpdates @@ -318,9 +317,6 @@ superfluous_local_zone_files=" var/adm/pool var/fm var/log/pool - var/svc/manifest/network/aggregation.xml - var/svc/manifest/network/datalink-init.xml - var/svc/manifest/network/datalink.xml var/svc/manifest/network/ipfilter.xml var/svc/manifest/network/pfil.xml var/svc/manifest/platform @@ -432,15 +428,6 @@ smf_inetd_conversions=" walld " -enable_next_boot () { - if [ -x /tmp/bfubin/svccfg ]; then - svcadm disable -t $1 - [ $? = 0 ] || echo "warning: unable to temporarily disable $1" - svccfg -s $1 setprop general/enabled = true - [ $? = 0 ] || echo "warning: unable to enable $1 for next boot" - fi -} - smf_inetd_disable() { inetconf=$rootprefix/etc/inet/inetd.conf inettmp=/tmp/inetd.tmp.$$ @@ -986,6 +973,9 @@ smf_obsolete_rc_files=" smf_obsolete_manifests=" var/svc/manifest/network/tftp.xml var/svc/manifest/network/lp.xml + var/svc/manifest/network/aggregation.xml + var/svc/manifest/network/datalink.xml + var/svc/manifest/network/datalink-init.xml " # smf services whose manifests have been renamed @@ -997,6 +987,9 @@ smf_renamed_manifests=" # Obsolete smf methods smf_obsolete_methods=" lib/svc/method/print-server + lib/svc/method/aggregation + lib/svc/method/datalink + lib/svc/method/datalink-init " smf_cleanup () { @@ -1628,52 +1621,6 @@ EOFA EOF fi - # If we're in the global zone, and using an alternate root, see if - # we are in an smf root. If so, import datalink and aggregation svcs. - # If we're not bfu'ing an alternate root, and we're post-smf, - # import datalink and aggregation. This is to get them - # in the repository before reboot. If we're bfu'ing from pre-smf, - # this isn't an issue, as they are in the seed repository. - if [[ $zone = global && - -f $rootprefix/var/svc/manifest/network/datalink.xml ]]; then - if [[ -n $rootprefix ]]; then - if [ -x /usr/sbin/svccfg ]; then - SVCCFG_REPOSITORY=$rootprefix/etc/svc/repository.db - sed -e "s/enabled='true'/enabled='false'/" \ - $rootprefix/var/svc/manifest/network/aggregation.xml \ - | svccfg import - - sed -e "s/enabled='true'/enabled='false'/" \ - $rootprefix/var/svc/manifest/network/datalink.xml \ - | svccfg import - - sed -e "s/enabled='true'/enabled='false'/" \ - $rootprefix/var/svc/manifest/network/datalink-init.xml \ - | svccfg import - - else - echo "Warning: This system does not have SMF, so I" - echo "cannot ensure the pre-import of datalink and" - echo "network aggregation. If they do not work" - echo "reboot your alternate root to fix it." - fi - elif [ -x /tmp/bfubin/svccfg ]; then - sed -e "s/enabled='true'/enabled='false'/" \ - /var/svc/manifest/network/aggregation.xml | \ - svccfg import - - sed -e "s/enabled='true'/enabled='false'/" \ - /var/svc/manifest/network/datalink.xml | \ - svccfg import - - sed -e "s/enabled='true'/enabled='false'/" \ - /var/svc/manifest/network/datalink-init.xml | \ - svccfg import - - fi - - # - # Make sure the services are enabled after reboot. - # - enable_next_boot svc:/network/aggregation:default - enable_next_boot svc:/network/datalink:default - enable_next_boot svc:/network/datalink-init:default - fi - # Enable new NFS status and nlockmgr services if client is enabled cat >> $rootprefix/var/svc/profile/upgrade <<-EOF cl="svc:/network/nfs/client:default" @@ -2320,49 +2267,6 @@ if [ $multiboot_archives = yes ]; then done fi -create_datalink_conf() -{ - # /etc/datalink.conf needs to be populated. - drivers="bge xge" - conf=$rootprefix/etc/datalink.conf - - if [ ! -f $conf ]; then - # nothing to do if we bfu'ed from an archive that doesn't - # provide /etc/datalink.conf - return - fi - - ls -1 $rootprefix/etc | egrep -e '^hostname.|^hostname6.|^dhcp.' | \ - cut -d . -f2 | sort -u > /tmp/ifnames.$$ - - for driver in $drivers - do - grep $driver /tmp/ifnames.$$ | \ - while read ifname - do - devnum=`echo $ifname | sed "s/$driver//g"` - if [ "$driver$devnum" != $ifname -o \ - -n "`echo $devnum | tr -d '[0-9]'`" ]; then - echo "skipping invalid interface $ifname" - continue - fi - - vid=`expr $devnum / 1000` - inst=`expr $devnum % 1000` - - awk '{ print $1 }' $conf | grep $ifname > /dev/null - if [ $? -ne 0 ]; then - # An entry for that interface does not exist - printf \ - "$ifname\t$driver$inst\t0\t$vid\n" \ - >> $conf - fi - done - done - - rm -f /tmp/ifnames.$$ -} - remove_initd_links() { # If we're delivering a new version of an existing /etc/init.d script, @@ -5631,11 +5535,6 @@ mondo_loop() { # Cleanup old Kerberos mechanisms cleanup_kerberos_mechanisms - # Fix network datalink configuration - if [ $zone = global ]; then - create_datalink_conf - fi - print "\nRestoring configuration files.\n" cd $root diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files index c748139976..e802144a19 100644 --- a/usr/src/uts/common/Makefile.files +++ b/usr/src/uts/common/Makefile.files @@ -487,8 +487,7 @@ CLONE_OBJS += clone.o CN_OBJS += cons.o -DLD_OBJS += dld_drv.o dld_ioc.o dld_minor.o dld_node.o dld_ppa.o \ - dld_proto.o dld_str.o +DLD_OBJS += dld_drv.o dld_proto.o dld_str.o DLS_OBJS += dls.o dls_link.o dls_mod.o dls_stat.o dls_vlan.o @@ -499,8 +498,6 @@ MAC_OBJS += mac.o mac_mod.o mac_stat.o AGGR_OBJS += aggr_dev.o aggr_ctl.o aggr_grp.o aggr_port.o \ aggr_send.o aggr_recv.o aggr_lacp.o -GHT_OBJS += ght.o - TAVOR_OBJS += tavor.o tavor_agents.o tavor_cfg.o tavor_ci.o tavor_cmd.o \ tavor_cq.o tavor_event.o tavor_ioctl.o tavor_misc.o \ tavor_mr.o tavor_qp.o tavor_qpmod.o tavor_rsrc.o \ diff --git a/usr/src/uts/common/inet/ip.h b/usr/src/uts/common/inet/ip.h index 45cba93039..9709a106f3 100644 --- a/usr/src/uts/common/inet/ip.h +++ b/usr/src/uts/common/inet/ip.h @@ -2959,7 +2959,7 @@ struct ill_zerocopy_capab_s { * include mac.h in this file. */ typedef void (*ip_mac_blank_t)(void *, time_t, uint_t); -typedef mblk_t *(*ip_mac_tx_t)(void *, mblk_t *); +typedef void (*ip_mac_tx_t)(void *, mblk_t *); struct ill_rx_ring { ip_mac_blank_t rr_blank; /* Driver interrupt blanking func */ diff --git a/usr/src/uts/common/inet/tcp/tcp.c b/usr/src/uts/common/inet/tcp/tcp.c index 236e0e3d70..a4874f27b2 100644 --- a/usr/src/uts/common/inet/tcp/tcp.c +++ b/usr/src/uts/common/inet/tcp/tcp.c @@ -18759,15 +18759,7 @@ tcp_send_data(tcp_t *tcp, queue_t *q, mblk_t *mp) ASSERT(ill_poll->ill_tx != NULL); ASSERT(ill_poll->ill_tx_handle != NULL); - mp = ill_poll->ill_tx(ill_poll->ill_tx_handle, mp); - /* - * Driver couldn't send it. Drop it here and the connections - * will automatically slow down when no ack comes back. We - * should make this a better mechanism but this is a very - * rare case. - */ - if (mp != NULL) - freemsg(mp); + ill_poll->ill_tx(ill_poll->ill_tx_handle, mp); } else { putnext(ire->ire_stq, mp); } diff --git a/usr/src/uts/common/io/aggr/aggr_ctl.c b/usr/src/uts/common/io/aggr/aggr_ctl.c index a545363fb4..8606ecd1ee 100644 --- a/usr/src/uts/common/io/aggr/aggr_ctl.c +++ b/usr/src/uts/common/io/aggr/aggr_ctl.c @@ -33,64 +33,49 @@ #include <sys/ddi.h> #include <sys/aggr.h> #include <sys/aggr_impl.h> +#include <sys/strsun.h> -static int aggr_ioc_create(int, void *, int); -static int aggr_ioc_delete(int, void *, int); -static int aggr_ioc_info(int, void *, int); -static int aggr_ioc_add_remove(int, void *, int); -static int aggr_ioc_status(int, void *, int); -static int aggr_ioc_modify(int, void *, int); +static int aggr_ioc_create(mblk_t *, int); +static int aggr_ioc_delete(mblk_t *, int); +static int aggr_ioc_info(mblk_t *, int); +static int aggr_ioc_add(mblk_t *, int); +static int aggr_ioc_remove(mblk_t *, int); +static int aggr_ioc_status(mblk_t *, int); +static int aggr_ioc_modify(mblk_t *, int); typedef struct ioc_cmd_s { int ic_cmd; - int (*ic_func)(int, void *, int); + int (*ic_func)(mblk_t *, int); } ioc_cmd_t; static ioc_cmd_t ioc_cmd[] = { {LAIOC_CREATE, aggr_ioc_create}, {LAIOC_DELETE, aggr_ioc_delete}, {LAIOC_INFO, aggr_ioc_info}, - {LAIOC_ADD, aggr_ioc_add_remove}, - {LAIOC_REMOVE, aggr_ioc_add_remove}, + {LAIOC_ADD, aggr_ioc_add}, + {LAIOC_REMOVE, aggr_ioc_remove}, {LAIOC_MODIFY, aggr_ioc_modify}}; -/*ARGSUSED*/ -int -aggr_open(dev_t *devp, int flag, int otyp, cred_t *cred_p) -{ - /* only the control interface can be opened */ - if (getminor(*devp) != AGGR_MINOR_CTL) - return (ENOSYS); - return (0); -} - -/*ARGSUSED*/ -int -aggr_close(dev_t dev, int flag, int otyp, cred_t *cred_p) -{ - return (0); -} +#define IOC_CMD_SZ (sizeof (ioc_cmd) / sizeof (ioc_cmd_t)) /* * Process a LAIOC_MODIFY request. */ -/* ARGSUSED */ static int -aggr_ioc_modify(int cmd, void *arg, int mode) +aggr_ioc_modify(mblk_t *mp, int mode) { - STRUCT_DECL(laioc_modify, modify_arg); + STRUCT_HANDLE(laioc_modify, modify_arg); uint32_t policy; boolean_t mac_fixed; uchar_t mac_addr[ETHERADDRL]; uint8_t modify_mask_arg, modify_mask = 0; - uint32_t key; + uint32_t rc, key; aggr_lacp_mode_t lacp_mode; aggr_lacp_timer_t lacp_timer; - STRUCT_INIT(modify_arg, mode); - - if (copyin(arg, STRUCT_BUF(modify_arg), STRUCT_SIZE(modify_arg)) != 0) - return (EFAULT); + STRUCT_SET_HANDLE(modify_arg, mode, (void *)mp->b_cont->b_rptr); + if (MBLKL(mp->b_cont) < STRUCT_SIZE(modify_arg)) + return (EINVAL); key = STRUCT_FGET(modify_arg, lu_key); modify_mask_arg = STRUCT_FGET(modify_arg, lu_modify_mask); @@ -116,18 +101,21 @@ aggr_ioc_modify(int cmd, void *arg, int mode) lacp_timer = STRUCT_FGET(modify_arg, lu_lacp_timer); } - return (aggr_grp_modify(key, NULL, modify_mask, policy, mac_fixed, - mac_addr, lacp_mode, lacp_timer)); + rc = aggr_grp_modify(key, NULL, modify_mask, policy, mac_fixed, + mac_addr, lacp_mode, lacp_timer); + + freemsg(mp->b_cont); + mp->b_cont = NULL; + return (rc); } /* * Process a LAIOC_CREATE request. */ -/* ARGSUSED */ static int -aggr_ioc_create(int cmd, void *arg, int mode) +aggr_ioc_create(mblk_t *mp, int mode) { - STRUCT_DECL(laioc_create, create_arg); + STRUCT_HANDLE(laioc_create, create_arg); uint16_t nports; laioc_port_t *ports = NULL; uint32_t policy; @@ -135,12 +123,11 @@ aggr_ioc_create(int cmd, void *arg, int mode) uchar_t mac_addr[ETHERADDRL]; aggr_lacp_mode_t lacp_mode; aggr_lacp_timer_t lacp_timer; - int rc; + int rc, len; - STRUCT_INIT(create_arg, mode); - - if (copyin(arg, STRUCT_BUF(create_arg), STRUCT_SIZE(create_arg)) != 0) - return (EFAULT); + STRUCT_SET_HANDLE(create_arg, mode, (void *)mp->b_cont->b_rptr); + if ((len = MBLKL(mp->b_cont)) < STRUCT_SIZE(create_arg)) + return (EINVAL); nports = STRUCT_FGET(create_arg, lc_nports); if (nports > AGGR_MAX_PORTS) @@ -150,13 +137,10 @@ aggr_ioc_create(int cmd, void *arg, int mode) lacp_mode = STRUCT_FGET(create_arg, lc_lacp_mode); lacp_timer = STRUCT_FGET(create_arg, lc_lacp_timer); - ports = kmem_alloc(nports * sizeof (laioc_port_t), KM_SLEEP); + if (len < STRUCT_SIZE(create_arg) + (nports * sizeof (laioc_port_t))) + return (EINVAL); - if (copyin(STRUCT_FGETP(create_arg, lc_ports), ports, - nports * sizeof (laioc_port_t)) != 0) { - rc = EFAULT; - goto bail; - } + ports = (laioc_port_t *)(STRUCT_BUF(create_arg) + 1); bcopy(STRUCT_FGET(create_arg, lc_mac), mac_addr, ETHERADDRL); mac_fixed = STRUCT_FGET(create_arg, lc_mac_fixed); @@ -164,28 +148,31 @@ aggr_ioc_create(int cmd, void *arg, int mode) rc = aggr_grp_create(STRUCT_FGET(create_arg, lc_key), nports, ports, policy, mac_fixed, mac_addr, lacp_mode, lacp_timer); -bail: - kmem_free(ports, nports * sizeof (laioc_port_t)); + freemsg(mp->b_cont); + mp->b_cont = NULL; return (rc); } -/* ARGSUSED */ static int -aggr_ioc_delete(int cmd, void *arg, int mode) +aggr_ioc_delete(mblk_t *mp, int mode) { - STRUCT_DECL(laioc_delete, delete_arg); + STRUCT_HANDLE(laioc_delete, delete_arg); + int rc; - STRUCT_INIT(delete_arg, mode); + STRUCT_SET_HANDLE(delete_arg, mode, (void *)mp->b_cont->b_rptr); + if (STRUCT_SIZE(delete_arg) > MBLKL(mp)) + return (EINVAL); - if (copyin(arg, STRUCT_BUF(delete_arg), STRUCT_SIZE(delete_arg)) != 0) - return (EFAULT); + rc = aggr_grp_delete(STRUCT_FGET(delete_arg, ld_key)); - return (aggr_grp_delete(STRUCT_FGET(delete_arg, ld_key))); + freemsg(mp->b_cont); + mp->b_cont = NULL; + return (rc); } typedef struct aggr_ioc_info_state { uint32_t bytes_left; - uchar_t *where; /* in user buffer */ + uchar_t *where; } aggr_ioc_info_state_t; static int @@ -207,9 +194,7 @@ aggr_ioc_info_new_grp(void *arg, uint32_t key, uchar_t *mac, grp.lg_lacp_mode = lacp_mode; grp.lg_lacp_timer = lacp_timer; - if (copyout(&grp, state->where, sizeof (grp)) != 0) - return (EFAULT); - + bcopy(&grp, state->where, sizeof (grp)); state->where += sizeof (grp); state->bytes_left -= sizeof (grp); @@ -232,9 +217,7 @@ aggr_ioc_info_new_port(void *arg, char *devname, uint32_t portnum, port.lp_state = portstate; port.lp_lacp_state = *lacp_state; - if (copyout(&port, state->where, sizeof (port)) != 0) - return (EFAULT); - + bcopy(&port, state->where, sizeof (port)); state->where += sizeof (port); state->bytes_left -= sizeof (port); @@ -243,125 +226,130 @@ aggr_ioc_info_new_port(void *arg, char *devname, uint32_t portnum, /*ARGSUSED*/ static int -aggr_ioc_info(int cmd, void *arg, int mode) +aggr_ioc_info(mblk_t *mp, int mode) { - laioc_info_t info_arg; + laioc_info_t *info_argp; uint32_t ngroups, group_key; - int rc; + int rc, len; aggr_ioc_info_state_t state; - if (copyin(arg, &info_arg, sizeof (info_arg)) != 0) - return (EFAULT); + if ((len = MBLKL(mp->b_cont)) < sizeof (*info_argp)) + return (EINVAL); + info_argp = (laioc_info_t *)mp->b_cont->b_rptr; /* * Key of the group to return. If zero, the call returns information * regarding all groups currently defined. */ - group_key = info_arg.li_group_key; + group_key = info_argp->li_group_key; - state.bytes_left = info_arg.li_bufsize - sizeof (laioc_info_t); - state.where = (uchar_t *)arg + sizeof (laioc_info_t); + state.bytes_left = len - sizeof (laioc_info_t); + state.where = (uchar_t *)(info_argp + 1); rc = aggr_grp_info(&ngroups, group_key, &state, aggr_ioc_info_new_grp, aggr_ioc_info_new_port); - if (rc == 0) { - info_arg.li_ngroups = ngroups; - if (copyout(&info_arg, arg, sizeof (info_arg)) != 0) - return (EFAULT); - } + if (rc == 0) + info_argp->li_ngroups = ngroups; + return (rc); } -/*ARGSUSED*/ static int -aggr_ioc_add_remove(int cmd, void *arg, int mode) +aggr_ioc_add(mblk_t *mp, int mode) { - STRUCT_DECL(laioc_add_rem, add_rem_arg); - uint16_t nports; + STRUCT_HANDLE(laioc_add_rem, add_arg); + uint32_t nports; laioc_port_t *ports = NULL; - int rc; - - STRUCT_INIT(add_rem_arg, mode); + int rc, len; - if (copyin(arg, STRUCT_BUF(add_rem_arg), STRUCT_SIZE(add_rem_arg)) != 0) - return (EFAULT); + STRUCT_SET_HANDLE(add_arg, mode, (void *)mp->b_cont->b_rptr); + if ((len = MBLKL(mp->b_cont)) < STRUCT_SIZE(add_arg)) + return (EINVAL); - nports = STRUCT_FGET(add_rem_arg, la_nports); + nports = STRUCT_FGET(add_arg, la_nports); if (nports > AGGR_MAX_PORTS) return (EINVAL); - ports = kmem_alloc(nports * sizeof (laioc_port_t), KM_SLEEP); + if (len < STRUCT_SIZE(add_arg) + (nports * sizeof (laioc_port_t))) + return (EINVAL); - if (copyin(STRUCT_FGETP(add_rem_arg, la_ports), ports, - nports * sizeof (laioc_port_t)) != 0) { - rc = EFAULT; - goto bail; - } + ports = (laioc_port_t *)(STRUCT_BUF(add_arg) + 1); - switch (cmd) { - case LAIOC_ADD: - rc = aggr_grp_add_ports(STRUCT_FGET(add_rem_arg, la_key), - nports, ports); - break; - case LAIOC_REMOVE: - rc = aggr_grp_rem_ports(STRUCT_FGET(add_rem_arg, la_key), - nports, ports); - break; - default: - rc = EINVAL; - } + rc = aggr_grp_add_ports(STRUCT_FGET(add_arg, la_key), + nports, ports); -bail: - if (ports != NULL) - kmem_free(ports, nports * sizeof (laioc_port_t)); + freemsg(mp->b_cont); + mp->b_cont = NULL; return (rc); } -/*ARGSUSED*/ static int -aggr_ioc_remove(void *arg, int mode) +aggr_ioc_remove(mblk_t *mp, int mode) { - STRUCT_DECL(laioc_add_rem, rem_arg); - uint16_t nports; + STRUCT_HANDLE(laioc_add_rem, rem_arg); + uint32_t nports; laioc_port_t *ports = NULL; - int rc; - - STRUCT_INIT(rem_arg, mode); + int rc, len; - if (copyin(arg, STRUCT_BUF(rem_arg), STRUCT_SIZE(rem_arg)) != 0) - return (EFAULT); + STRUCT_SET_HANDLE(rem_arg, mode, (void *)mp->b_cont->b_rptr); + if ((len = MBLKL(mp->b_cont)) < STRUCT_SIZE(rem_arg)) + return (EINVAL); nports = STRUCT_FGET(rem_arg, la_nports); if (nports > AGGR_MAX_PORTS) return (EINVAL); - ports = kmem_alloc(nports * sizeof (laioc_port_t), KM_SLEEP); + if (len < STRUCT_SIZE(rem_arg) + (nports * sizeof (laioc_port_t))) + return (EINVAL); - if (copyin(STRUCT_FGETP(rem_arg, la_ports), ports, - nports * sizeof (laioc_port_t)) != 0) { - rc = EFAULT; - goto bail; - } + ports = (laioc_port_t *)(STRUCT_BUF(rem_arg) + 1); rc = aggr_grp_rem_ports(STRUCT_FGET(rem_arg, la_key), nports, ports); -bail: - if (ports != NULL) - kmem_free(ports, nports * sizeof (laioc_port_t)); + freemsg(mp->b_cont); + mp->b_cont = NULL; return (rc); } -/*ARGSUSED*/ -int -aggr_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rv) +void +aggr_ioctl(queue_t *wq, mblk_t *mp) { - int i; + struct iocblk *iocp = (struct iocblk *)mp->b_rptr; + int i, err = EINVAL; + mblk_t *nmp; + + if (mp->b_cont == NULL) + goto done; + + /* + * Construct contiguous message + */ + if ((nmp = msgpullup(mp->b_cont, -1)) == NULL) { + err = ENOMEM; + goto done; + } + + freemsg(mp->b_cont); + mp->b_cont = nmp; + + for (i = 0; i < IOC_CMD_SZ; i++) { + if (iocp->ioc_cmd == ioc_cmd[i].ic_cmd) { + err = ioc_cmd[i].ic_func(mp, (int)iocp->ioc_flag); + break; + } + } + + if (err == 0) { + int len = 0; - for (i = 0; i < sizeof (ioc_cmd) / sizeof (ioc_cmd_t); i++) { - if (cmd == ioc_cmd[i].ic_cmd) - return (ioc_cmd[i].ic_func(cmd, (void *)arg, mode)); + if (mp->b_cont != NULL) { + len = MBLKL(mp->b_cont); + } + miocack(wq, mp, len, 0); + return; } - return (EINVAL); +done: + miocnak(wq, mp, 0, err); } diff --git a/usr/src/uts/common/io/aggr/aggr_dev.c b/usr/src/uts/common/io/aggr/aggr_dev.c index 97107495b6..148374f0e0 100644 --- a/usr/src/uts/common/io/aggr/aggr_dev.c +++ b/usr/src/uts/common/io/aggr/aggr_dev.c @@ -38,17 +38,21 @@ #include <sys/ksynch.h> #include <sys/kmem.h> #include <sys/stream.h> +#include <sys/strsun.h> #include <sys/modctl.h> #include <sys/ddi.h> #include <sys/sunddi.h> #include <sys/atomic.h> #include <sys/stat.h> +#include <sys/dld_impl.h> #include <sys/aggr.h> #include <sys/aggr_impl.h> +#include <inet/common.h> /* module description */ #define AGGR_LINKINFO "Link Aggregation MAC" +#define AGGR_DRIVER_NAME "aggr" /* device info ptr, only one for instance 0 */ dev_info_t *aggr_dip; @@ -58,51 +62,74 @@ static int aggr_dev_fini(void); static int aggr_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); static int aggr_attach(dev_info_t *, ddi_attach_cmd_t); static int aggr_detach(dev_info_t *, ddi_detach_cmd_t); +static int aggr_open(queue_t *, dev_t *, int, int, cred_t *); +static int aggr_close(queue_t *); +static void aggr_wput(queue_t *, mblk_t *); -static struct cb_ops aggr_cb_ops = { - aggr_open, /* open */ - aggr_close, /* close */ - nulldev, /* strategy */ - nulldev, /* print */ - nodev, /* dump */ - nodev, /* read */ - nodev, /* write */ - aggr_ioctl, /* ioctl */ - nodev, /* devmap */ - nodev, /* mmap */ - nodev, /* segmap */ - nochpoll, /* poll */ - ddi_prop_op, /* cb_prop_op */ - 0, /* streamtab */ - D_NEW | D_MP /* driver compatibility flag */ +/* + * mi_hiwat is set to 1 because of the flow control mechanism implemented + * in dld. refer to the comments in dld_str.c for details. + */ +static struct module_info aggr_module_info = { + 0, + AGGR_DRIVER_NAME, + 0, + INFPSZ, + 1, + 0 +}; + +static struct qinit aggr_r_qinit = { /* read queues */ + NULL, + NULL, + aggr_open, + aggr_close, + NULL, + &aggr_module_info +}; + +static struct qinit aggr_w_qinit = { /* write queues */ + (pfi_t)dld_wput, + (pfi_t)dld_wsrv, + NULL, + NULL, + NULL, + &aggr_module_info +}; + +/* + * Entry points for aggr control node + */ +static struct qinit aggr_w_ctl_qinit = { + (pfi_t)aggr_wput, + NULL, + NULL, + NULL, + NULL, + &aggr_module_info }; -static struct dev_ops aggr_ops = { - DEVO_REV, /* devo_rev */ - 0, /* refcnt */ - aggr_getinfo, /* getinfo */ - nulldev, /* identify */ - nulldev, /* probe */ - aggr_attach, /* attach */ - aggr_detach, /* detach */ - nodev, /* reset */ - &aggr_cb_ops, /* driver operations */ - NULL, /* bus operations */ - nodev /* dev power */ +static struct streamtab aggr_streamtab = { + &aggr_r_qinit, + &aggr_w_qinit }; -static struct modldrv modldrv = { - &mod_driverops, - AGGR_LINKINFO, - &aggr_ops +DDI_DEFINE_STREAM_OPS(aggr_dev_ops, nulldev, nulldev, aggr_attach, aggr_detach, + nodev, aggr_getinfo, D_MP, &aggr_streamtab); + +static struct modldrv aggr_modldrv = { + &mod_driverops, /* Type of module. This one is a driver */ + AGGR_LINKINFO, /* short description */ + &aggr_dev_ops /* driver specific ops */ }; -static struct modlinkage modlinkage = { +static struct modlinkage modlinkage = { MODREV_1, - &modldrv, + &aggr_modldrv, NULL }; + int _init(void) { @@ -116,7 +143,6 @@ _init(void) } aggr_dip = NULL; - return (0); } @@ -142,6 +168,53 @@ _info(struct modinfo *modinfop) return (mod_info(&modlinkage, modinfop)); } +static int +aggr_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) +{ + if (q->q_ptr != NULL) + return (EBUSY); + + if (getminor(*devp) == AGGR_MINOR_CTL) { + dld_str_t *dsp; + + dsp = dld_str_create(q, DLD_CONTROL, getmajor(*devp), + DL_STYLE1); + if (dsp == NULL) + return (ENOSR); + + /* + * The aggr control node uses its own set of entry points. + */ + WR(q)->q_qinfo = &aggr_w_ctl_qinit; + *devp = makedevice(getmajor(*devp), dsp->ds_minor); + qprocson(q); + return (0); + } + return (dld_open(q, devp, flag, sflag, credp)); +} + +static int +aggr_close(queue_t *q) +{ + dld_str_t *dsp = q->q_ptr; + + if (dsp->ds_type == DLD_CONTROL) { + qprocsoff(q); + dld_str_destroy(dsp); + return (0); + } + return (dld_close(q)); +} + +static void +aggr_wput(queue_t *q, mblk_t *mp) +{ + if (DB_TYPE(mp) == M_IOCTL) + aggr_ioctl(q, mp); + else + freemsg(mp); +} + static void aggr_dev_init(void) { @@ -216,8 +289,11 @@ aggr_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) { switch (cmd) { case DDI_DETACH: + if (aggr_grp_count() > 0) + return (DDI_FAILURE); + aggr_dip = NULL; - ddi_remove_minor_node(dip, NULL); + ddi_remove_minor_node(dip, AGGR_DEVNAME_CTL); return (DDI_SUCCESS); diff --git a/usr/src/uts/common/io/aggr/aggr_grp.c b/usr/src/uts/common/io/aggr/aggr_grp.c index c51e1c5fbf..091d6c4550 100644 --- a/usr/src/uts/common/io/aggr/aggr_grp.c +++ b/usr/src/uts/common/io/aggr/aggr_grp.c @@ -31,7 +31,7 @@ * * An instance of the structure aggr_grp_t is allocated for each * link aggregation group. When created, aggr_grp_t objects are - * entered into the aggr_grp_hash hash table maintained by the GHT + * entered into the aggr_grp_hash hash table maintained by the modhash * module. The hash key is the port number associated with the link * aggregation group. The port number associated with a group corresponds * the key associated with the group. @@ -52,7 +52,7 @@ #include <sys/sunddi.h> #include <sys/atomic.h> #include <sys/stat.h> -#include <sys/ght.h> +#include <sys/modhash.h> #include <sys/strsun.h> #include <sys/dlpi.h> @@ -75,10 +75,13 @@ static void aggr_stats_op(enum mac_stat, uint64_t *, uint64_t *, boolean_t); static void aggr_grp_capab_set(aggr_grp_t *); static boolean_t aggr_grp_capab_check(aggr_grp_t *, aggr_port_t *); -static kmem_cache_t *aggr_grp_cache; -static ght_t aggr_grp_hash; +static kmem_cache_t *aggr_grp_cache; +static mod_hash_t *aggr_grp_hash; +static krwlock_t aggr_grp_lock; +static uint_t aggr_grp_cnt; #define GRP_HASHSZ 64 +#define GRP_HASH_KEY(key) ((mod_hash_key_t)(uintptr_t)key) static uchar_t aggr_zero_mac[] = {0, 0, 0, 0, 0, 0}; static uchar_t aggr_brdcst_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; @@ -126,28 +129,39 @@ aggr_grp_destructor(void *buf, void *arg) void aggr_grp_init(void) { - int err; - aggr_grp_cache = kmem_cache_create("aggr_grp_cache", sizeof (aggr_grp_t), 0, aggr_grp_constructor, aggr_grp_destructor, NULL, NULL, NULL, 0); - err = ght_scalar_create("aggr_grp_hash", GRP_HASHSZ, - &aggr_grp_hash); - ASSERT(err == 0); + aggr_grp_hash = mod_hash_create_idhash("aggr_grp_hash", + GRP_HASHSZ, mod_hash_null_valdtor); + rw_init(&aggr_grp_lock, NULL, RW_DEFAULT, NULL); + aggr_grp_cnt = 0; } int aggr_grp_fini(void) { - int err; + if (aggr_grp_cnt > 0) + return (EBUSY); - if ((err = ght_destroy(aggr_grp_hash)) != 0) - return (err); + rw_destroy(&aggr_grp_lock); + mod_hash_destroy_idhash(aggr_grp_hash); kmem_cache_destroy(aggr_grp_cache); return (0); } +uint_t +aggr_grp_count(void) +{ + uint_t count; + + rw_enter(&aggr_grp_lock, RW_READER); + count = aggr_grp_cnt; + rw_exit(&aggr_grp_lock); + return (count); +} + /* * Attach a port to a link aggregation group. * @@ -390,21 +404,18 @@ int aggr_grp_add_ports(uint32_t key, uint_t nports, laioc_port_t *ports) { int rc, i, nadded = 0; - ghte_t hte; aggr_grp_t *grp = NULL; aggr_port_t *port; /* get group corresponding to key */ - ght_lock(aggr_grp_hash, GHT_READ); - if ((rc = ght_find(aggr_grp_hash, GHT_SCALAR_TO_KEY(key), - &hte)) == ENOENT) { - ght_unlock(aggr_grp_hash); - return (rc); + rw_enter(&aggr_grp_lock, RW_READER); + if (mod_hash_find(aggr_grp_hash, GRP_HASH_KEY(key), + (mod_hash_val_t *)&grp) != 0) { + rw_exit(&aggr_grp_lock); + return (ENOENT); } - ASSERT(rc == 0); - grp = (aggr_grp_t *)GHT_VAL(hte); AGGR_GRP_REFHOLD(grp); - ght_unlock(aggr_grp_hash); + rw_exit(&aggr_grp_lock); AGGR_LACP_LOCK(grp); rw_enter(&grp->lg_lock, RW_WRITER); @@ -479,18 +490,17 @@ aggr_grp_modify(uint32_t key, aggr_grp_t *grp_arg, uint8_t update_mask, aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer) { int rc = 0; - ghte_t hte; aggr_grp_t *grp = NULL; boolean_t mac_addr_changed = B_FALSE; if (grp_arg == NULL) { /* get group corresponding to key */ - ght_lock(aggr_grp_hash, GHT_READ); - if ((rc = ght_find(aggr_grp_hash, GHT_SCALAR_TO_KEY(key), - &hte)) == ENOENT) + rw_enter(&aggr_grp_lock, RW_READER); + if (mod_hash_find(aggr_grp_hash, GRP_HASH_KEY(key), + (mod_hash_val_t *)&grp) != 0) { + rc = ENOENT; goto bail; - ASSERT(rc == 0); - grp = (aggr_grp_t *)GHT_VAL(hte); + } AGGR_LACP_LOCK(grp); rw_enter(&grp->lg_lock, RW_WRITER); } else { @@ -551,7 +561,7 @@ bail: rw_exit(&grp->lg_lock); AGGR_LACP_UNLOCK(grp); } - ght_unlock(aggr_grp_hash); + rw_exit(&aggr_grp_lock); /* pass new unicast address up to MAC layer */ if (grp != NULL && mac_addr_changed && !grp->lg_closing) mac_unicst_update(&grp->lg_mac, grp->lg_addr); @@ -574,7 +584,6 @@ aggr_grp_create(uint32_t key, uint_t nports, laioc_port_t *ports, { aggr_grp_t *grp = NULL; aggr_port_t *port; - ghte_t hte; mac_t *mac; mac_info_t *mip; int err; @@ -584,12 +593,13 @@ aggr_grp_create(uint32_t key, uint_t nports, laioc_port_t *ports, if (nports == 0) return (EINVAL); - ght_lock(aggr_grp_hash, GHT_WRITE); + rw_enter(&aggr_grp_lock, RW_WRITER); /* does a group with the same key already exist? */ - err = ght_find(aggr_grp_hash, GHT_SCALAR_TO_KEY(key), &hte); - if (err != ENOENT) { - ght_unlock(aggr_grp_hash); + err = mod_hash_find(aggr_grp_hash, GRP_HASH_KEY(key), + (mod_hash_val_t *)&grp); + if (err == 0) { + rw_exit(&aggr_grp_lock); return (EEXIST); } @@ -688,18 +698,14 @@ aggr_grp_create(uint32_t key, uint_t nports, laioc_port_t *ports, aggr_lacp_set_mode(grp, lacp_mode, lacp_timer); /* add new group to hash table */ - hte = ght_alloc(aggr_grp_hash, KM_SLEEP); - GHT_KEY(hte) = GHT_SCALAR_TO_KEY(key); - GHT_VAL(hte) = GHT_PTR_TO_VAL(grp); - grp->lg_hte = hte; - - err = ght_insert(hte); + err = mod_hash_insert(aggr_grp_hash, GRP_HASH_KEY(key), + (mod_hash_val_t)grp); ASSERT(err == 0); + aggr_grp_cnt++; rw_exit(&grp->lg_lock); AGGR_LACP_UNLOCK(grp); - ght_unlock(aggr_grp_hash); - + rw_exit(&aggr_grp_lock); return (0); bail: @@ -719,7 +725,7 @@ bail: kmem_cache_free(aggr_grp_cache, grp); } - ght_unlock(aggr_grp_hash); + rw_exit(&aggr_grp_lock); return (err); } @@ -837,22 +843,20 @@ int aggr_grp_rem_ports(uint32_t key, uint_t nports, laioc_port_t *ports) { int rc = 0, i; - ghte_t hte; aggr_grp_t *grp = NULL; aggr_port_t *port; boolean_t notify = B_FALSE, grp_mac_addr_changed; /* get group corresponding to key */ - ght_lock(aggr_grp_hash, GHT_READ); - if ((rc = ght_find(aggr_grp_hash, GHT_SCALAR_TO_KEY(key), - &hte)) == ENOENT) { - ght_unlock(aggr_grp_hash); - return (rc); + rw_enter(&aggr_grp_lock, RW_READER); + if (mod_hash_find(aggr_grp_hash, GRP_HASH_KEY(key), + (mod_hash_val_t *)&grp) != 0) { + rw_exit(&aggr_grp_lock); + return (ENOENT); } - ASSERT(rc == 0); - grp = (aggr_grp_t *)GHT_VAL(hte); AGGR_GRP_REFHOLD(grp); - ght_unlock(aggr_grp_hash); + rw_exit(&aggr_grp_lock); + AGGR_LACP_LOCK(grp); rw_enter(&grp->lg_lock, RW_WRITER); @@ -907,22 +911,17 @@ bail: int aggr_grp_delete(uint32_t key) { - int err; - ghte_t hte; - aggr_grp_t *grp; + aggr_grp_t *grp = NULL; aggr_port_t *port, *cport; + mod_hash_val_t val; - ght_lock(aggr_grp_hash, GHT_WRITE); + rw_enter(&aggr_grp_lock, RW_WRITER); - err = ght_find(aggr_grp_hash, GHT_SCALAR_TO_KEY(key), &hte); - if (err == ENOENT) { - ght_unlock(aggr_grp_hash); - return (err); + if (mod_hash_find(aggr_grp_hash, GRP_HASH_KEY(key), + (mod_hash_val_t *)&grp) != 0) { + rw_exit(&aggr_grp_lock); + return (ENOENT); } - ASSERT(err == 0); - - grp = (aggr_grp_t *)GHT_VAL(hte); - AGGR_LACP_LOCK(grp); rw_enter(&grp->lg_lock, RW_WRITER); grp->lg_closing = B_TRUE; @@ -935,7 +934,7 @@ aggr_grp_delete(uint32_t key) if (mac_unregister(&grp->lg_mac)) { rw_exit(&grp->lg_lock); AGGR_LACP_UNLOCK(grp); - ght_unlock(aggr_grp_hash); + rw_exit(&aggr_grp_lock); return (EBUSY); } @@ -955,10 +954,13 @@ aggr_grp_delete(uint32_t key) rw_exit(&grp->lg_lock); AGGR_LACP_UNLOCK(grp); - ght_remove(hte); - ght_free(hte); + (void) mod_hash_remove(aggr_grp_hash, GRP_HASH_KEY(key), &val); + ASSERT(grp == (aggr_grp_t *)val); + + ASSERT(aggr_grp_cnt > 0); + aggr_grp_cnt--; - ght_unlock(aggr_grp_hash); + rw_exit(&aggr_grp_lock); AGGR_GRP_REFRELE(grp); return (0); @@ -976,17 +978,18 @@ aggr_grp_free(aggr_grp_t *grp) * their ports that must be passed up to user-space. */ -static boolean_t -aggr_grp_info_walker(void *arg, ghte_t hte) +/*ARGSUSED*/ +static uint_t +aggr_grp_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) { aggr_grp_t *grp; aggr_port_t *port; aggr_grp_info_state_t *state = arg; if (state->ls_rc != 0) - return (B_FALSE); /* terminate walk */ + return (MH_WALK_TERMINATE); /* terminate walk */ - grp = (aggr_grp_t *)GHT_VAL(hte); + grp = (aggr_grp_t *)val; rw_enter(&grp->lg_lock, RW_READER); @@ -1018,7 +1021,7 @@ aggr_grp_info_walker(void *arg, ghte_t hte) bail: rw_exit(&grp->lg_lock); - return (state->ls_rc == 0); + return ((state->ls_rc == 0) ? MH_WALK_CONTINUE : MH_WALK_TERMINATE); } int @@ -1029,9 +1032,9 @@ aggr_grp_info(uint_t *ngroups, uint32_t group_key, void *fn_arg, aggr_grp_info_state_t state; int rc = 0; - ght_lock(aggr_grp_hash, GHT_READ); + rw_enter(&aggr_grp_lock, RW_READER); - *ngroups = ght_count(aggr_grp_hash); + *ngroups = aggr_grp_cnt; bzero(&state, sizeof (state)); state.ls_group_key = group_key; @@ -1039,13 +1042,13 @@ aggr_grp_info(uint_t *ngroups, uint32_t group_key, void *fn_arg, state.ls_new_port_fn = new_port_fn; state.ls_fn_arg = fn_arg; - ght_walk(aggr_grp_hash, aggr_grp_info_walker, &state); + mod_hash_walk(aggr_grp_hash, aggr_grp_info_walker, &state); if ((rc = state.ls_rc) == 0 && group_key != 0 && !state.ls_group_found) rc = ENOENT; - ght_unlock(aggr_grp_hash); + rw_exit(&aggr_grp_lock); return (rc); } @@ -1059,16 +1062,6 @@ typedef struct aggr_grp_walker_state_s { } aggr_grp_walker_state_t; void -aggr_grp_walker(void *arg, ghte_t hte) -{ - aggr_grp_walker_state_t *state = arg; - aggr_grp_t *grp; - - grp = (aggr_grp_t *)GHT_VAL(hte); - state->ws_walker_fn(grp, state->ws_arg); -} - -void aggr_grp_walk(aggr_grp_walker_fn_t walker, void *arg) { aggr_grp_walker_state_t state; @@ -1076,9 +1069,9 @@ aggr_grp_walk(aggr_grp_walker_fn_t walker, void *arg) state.ws_walker_fn = walker; state.ws_arg = arg; - ght_lock(aggr_grp_hash, GHT_READ); - ght_walk(aggr_grp_hash, aggr_grp_info_walker, &state); - ght_unlock(aggr_grp_hash); + rw_enter(&aggr_grp_lock, RW_READER); + mod_hash_walk(aggr_grp_hash, aggr_grp_info_walker, &state); + rw_exit(&aggr_grp_lock); } static void diff --git a/usr/src/uts/common/io/bge/bge_main.c b/usr/src/uts/common/io/bge/bge_main.c index 3a96a2e09e..e1dcafecf9 100644 --- a/usr/src/uts/common/io/bge/bge_main.c +++ b/usr/src/uts/common/io/bge/bge_main.c @@ -2075,40 +2075,8 @@ bge_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) #undef BGE_DBG #define BGE_DBG BGE_DBG_INIT /* debug flag for this code */ -static struct cb_ops bge_cb_ops = { - nulldev, /* cb_open */ - nulldev, /* cb_close */ - nodev, /* cb_strategy */ - nodev, /* cb_print */ - nodev, /* cb_dump */ - nodev, /* cb_read */ - nodev, /* cb_write */ - nodev, /* cb_ioctl */ - nodev, /* cb_devmap */ - nodev, /* cb_mmap */ - nodev, /* cb_segmap */ - nochpoll, /* cb_chpoll */ - ddi_prop_op, /* cb_prop_op */ - NULL, /* cb_stream */ - D_MP, /* cb_flag */ - CB_REV, /* cb_rev */ - nodev, /* cb_aread */ - nodev /* cb_awrite */ -}; - -static struct dev_ops bge_dev_ops = { - DEVO_REV, /* devo_rev */ - 0, /* devo_refcnt */ - nulldev, /* devo_getinfo */ - nulldev, /* devo_identify */ - nulldev, /* devo_probe */ - bge_attach, /* devo_attach */ - bge_detach, /* devo_detach */ - nodev, /* devo_reset */ - &bge_cb_ops, /* devo_cb_ops */ - (struct bus_ops *)NULL, /* devo_bus_ops */ - NULL /* devo_power */ -}; +DDI_DEFINE_STREAM_OPS(bge_dev_ops, nulldev, nulldev, bge_attach, bge_detach, + nodev, NULL, D_MP, NULL); static struct modldrv bge_modldrv = { &mod_driverops, /* Type of module. This one is a driver */ @@ -2132,9 +2100,12 @@ _init(void) { int status; + mac_init_ops(&bge_dev_ops, "bge"); status = mod_install(&modlinkage); if (status == DDI_SUCCESS) mutex_init(bge_log_mutex, NULL, MUTEX_DRIVER, NULL); + else + mac_fini_ops(&bge_dev_ops); return (status); } @@ -2144,8 +2115,10 @@ _fini(void) int status; status = mod_remove(&modlinkage); - if (status == DDI_SUCCESS) + if (status == DDI_SUCCESS) { + mac_fini_ops(&bge_dev_ops); mutex_destroy(bge_log_mutex); + } return (status); } diff --git a/usr/src/uts/common/io/dld/dld_drv.c b/usr/src/uts/common/io/dld/dld_drv.c index e502f99874..5d34f79f7e 100644 --- a/usr/src/uts/common/io/dld/dld_drv.c +++ b/usr/src/uts/common/io/dld/dld_drv.c @@ -30,20 +30,23 @@ * Data-Link Driver */ -#include <sys/types.h> -#include <sys/stream.h> #include <sys/conf.h> -#include <sys/stat.h> -#include <sys/ddi.h> -#include <sys/sunddi.h> -#include <sys/dlpi.h> +#include <sys/mkdev.h> #include <sys/modctl.h> -#include <sys/kmem.h> -#include <inet/common.h> - -#include <sys/dls.h> +#include <sys/stat.h> +#include <sys/strsun.h> #include <sys/dld.h> #include <sys/dld_impl.h> +#include <sys/dls_impl.h> +#include <inet/common.h> + +/* + * dld control node state, one per open control node session. + */ +typedef struct dld_ctl_str_s { + minor_t cs_minor; + queue_t *cs_wq; +} dld_ctl_str_t; static void drv_init(void); static int drv_fini(void); @@ -52,6 +55,11 @@ static int drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); static int drv_attach(dev_info_t *, ddi_attach_cmd_t); static int drv_detach(dev_info_t *, ddi_detach_cmd_t); +/* + * The following entry points are private to dld and are used for control + * operations only. The entry points exported to mac drivers are defined + * in dld_str.c. Refer to the comment on top of dld_str.c for details. + */ static int drv_open(queue_t *, dev_t *, int, int, cred_t *); static int drv_close(queue_t *); @@ -59,13 +67,8 @@ static void drv_uw_put(queue_t *, mblk_t *); static void drv_uw_srv(queue_t *); dev_info_t *dld_dip; /* dev_info_t for the driver */ -uint32_t dld_opt; /* Global options */ -boolean_t dld_open; /* Flag to note that the control */ - /* node is open */ -boolean_t dld_aul = B_TRUE; /* Set to B_FALSE to prevent driver */ - /* unloading */ - -static kmutex_t drv_lock; /* Needs no initialization */ +uint32_t dld_opt = 0; /* Global options */ +static vmem_t *dld_ctl_vmem; /* for control minor numbers */ static struct module_info drv_info = { 0, /* mi_idnum */ @@ -104,7 +107,7 @@ static struct streamtab drv_stream = { }; DDI_DEFINE_STREAM_OPS(drv_ops, nulldev, nulldev, drv_attach, drv_detach, - nodev, drv_getinfo, D_MP | D_MTQPAIR | D_MTPUTSHARED, &drv_stream); + nodev, drv_getinfo, D_MP, &drv_stream); /* * Module linkage information for the kernel. @@ -129,13 +132,11 @@ _init(void) { int err; + drv_init(); + if ((err = mod_install(&drv_modlinkage)) != 0) return (err); -#ifdef DEBUG - cmn_err(CE_NOTE, "!%s loaded", DLD_INFO); -#endif /* DEBUG */ - return (0); } @@ -144,15 +145,13 @@ _fini(void) { int err; - if (!dld_aul) - return (ENOTSUP); - if ((err = mod_remove(&drv_modlinkage)) != 0) return (err); -#ifdef DEBUG - cmn_err(CE_NOTE, "!%s unloaded", DLD_INFO); -#endif /* DEBUG */ + if (drv_fini() != 0) { + (void) mod_install(&drv_modlinkage); + return (DDI_FAILURE); + } return (err); } @@ -165,15 +164,14 @@ _info(struct modinfo *modinfop) /* - * Initialize compoment modules. + * Initialize component modules. */ static void drv_init(void) { - dld_minor_init(); - dld_node_init(); + dld_ctl_vmem = vmem_create("dld_ctl", (void *)1, MAXMIN, 1, + NULL, NULL, NULL, 1, VM_SLEEP | VMC_IDENTIFIER); dld_str_init(); - dld_ppa_init(); } static int @@ -181,18 +179,10 @@ drv_fini(void) { int err; - if ((err = dld_ppa_fini()) != 0) + if ((err = dld_str_fini()) != 0) return (err); - err = dld_str_fini(); - ASSERT(err == 0); - - err = dld_node_fini(); - ASSERT(err == 0); - - err = dld_minor_fini(); - ASSERT(err == 0); - + vmem_destroy(dld_ctl_vmem); return (0); } @@ -227,34 +217,17 @@ static void drv_set_opt(dev_info_t *dip) { if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, - DLD_PROP_NO_STYLE1, 0) != 0) { -#ifdef DEBUG - cmn_err(CE_NOTE, "%s: ON", DLD_PROP_NO_STYLE1); -#endif /* DEBUG */ - dld_opt |= DLD_OPT_NO_STYLE1; - } - - if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, DLD_PROP_NO_FASTPATH, 0) != 0) { -#ifdef DEBUG - cmn_err(CE_NOTE, "%s: ON", DLD_PROP_NO_FASTPATH); -#endif /* DEBUG */ dld_opt |= DLD_OPT_NO_FASTPATH; } if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, DLD_PROP_NO_POLL, 0) != 0) { -#ifdef DEBUG - cmn_err(CE_NOTE, "%s: ON", DLD_PROP_NO_POLL); -#endif /* DEBUG */ dld_opt |= DLD_OPT_NO_POLL; } if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, DLD_PROP_NO_ZEROCOPY, 0) != 0) { -#ifdef DEBUG - cmn_err(CE_NOTE, "%s: ON", DLD_PROP_NO_ZEROCOPY); -#endif /* DEBUG */ dld_opt |= DLD_OPT_NO_ZEROCOPY; } } @@ -270,7 +243,6 @@ drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) ASSERT(ddi_get_instance(dip) == 0); - drv_init(); drv_set_opt(dip); /* @@ -298,9 +270,6 @@ drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) if (cmd != DDI_DETACH) return (DDI_FAILURE); - if (drv_fini() != 0) - return (DDI_FAILURE); - ASSERT(dld_dip == dip); /* @@ -313,83 +282,41 @@ drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) } /* - * qi_qopen: open(9e) + * dld control node open procedure. */ /*ARGSUSED*/ static int drv_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp) { - dld_str_t *dsp; - dld_node_t *dnp; - dld_ppa_t *dpp; + dld_ctl_str_t *ctls; minor_t minor; - int err; + queue_t *oq = OTHERQ(rq); - ASSERT(sflag != MODOPEN); + if (sflag == MODOPEN) + return (ENOTSUP); /* * This is a cloning driver and therefore each queue should only * ever get opened once. */ - ASSERT(rq->q_ptr == NULL); if (rq->q_ptr != NULL) return (EBUSY); - /* - * Grab the minor number of the dev_t that was opened. Because this - * is a cloning driver this will be distinct from the actual minor - * of the dev_t handed back. - */ - minor = getminor(*devp); + minor = (minor_t)(uintptr_t)vmem_alloc(dld_ctl_vmem, 1, VM_NOSLEEP); + if (minor == 0) + return (ENOMEM); - /* - * Create a new dld_str_t for the stream. This will grab a new minor - * number that will be handed back in the cloned dev_t. - */ - dsp = dld_str_create(rq); - - if (minor != DLD_CONTROL_MINOR) { - /* - * This is not the control node, so look up the DLPI - * provider node that is being opened. - */ - if ((dnp = dld_node_find(minor)) == NULL) { - err = ENODEV; - goto failed; - } - - dsp->ds_dnp = dnp; - dsp->ds_type = DLD_DLPI; - - ASSERT(dsp->ds_dlstate == DL_UNATTACHED); - if (dnp->dn_style == DL_STYLE1) { - /* - * This is a style 1 provider node so we have a - * non-ambiguous PPA. - */ - dpp = dld_node_ppa_find(dnp, -1); - - if ((err = dld_str_attach(dsp, dpp)) != 0) - goto failed; - dsp->ds_dlstate = DL_UNBOUND; - } - } else { - /* - * This is the control node. It is exclusive-access so - * verify that it is not already open. - */ - mutex_enter(&drv_lock); - if (dld_open) { - err = EBUSY; - mutex_exit(&drv_lock); - goto failed; - } + ctls = kmem_zalloc(sizeof (dld_ctl_str_t), KM_NOSLEEP); + if (ctls == NULL) { + vmem_free(dld_ctl_vmem, (void *)(uintptr_t)minor, 1); + return (ENOMEM); + } - dld_open = B_TRUE; - mutex_exit(&drv_lock); + ctls->cs_minor = minor; + ctls->cs_wq = WR(rq); - dsp->ds_type = DLD_CONTROL; - } + rq->q_ptr = ctls; + oq->q_ptr = ctls; /* * Enable the queue srv(9e) routine. @@ -399,102 +326,191 @@ drv_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp) /* * Construct a cloned dev_t to hand back. */ - *devp = makedevice(getmajor(*devp), dsp->ds_minor); + *devp = makedevice(getmajor(*devp), ctls->cs_minor); return (0); - -failed: - dld_str_destroy(dsp); - return (err); } /* - * qi_qclose: close(9e) + * dld control node close procedure. */ static int drv_close(queue_t *rq) { - dld_str_t *dsp; + dld_ctl_str_t *ctls; - dsp = rq->q_ptr; - ASSERT(dsp != NULL); + ctls = rq->q_ptr; + ASSERT(ctls != NULL); /* * Disable the queue srv(9e) routine. */ qprocsoff(rq); - if (dsp->ds_type != DLD_CONTROL) { - /* - * This stream was open to a provider node. Check to see - * if it has been cleanly shut down. - */ - if (dsp->ds_dlstate != DL_UNATTACHED) { - /* - * The stream is either open to a style 1 provider or - * this is not clean shutdown. Detach from the PPA. - * (This is still ok even in the style 1 case). - */ - dld_str_detach(dsp); - dsp->ds_dlstate = DL_UNATTACHED; - } - } else { - /* - * This stream was open to the control node. Clear the flag - * to allow another stream access. - */ - ASSERT(dld_open); - dld_open = B_FALSE; - } + vmem_free(dld_ctl_vmem, (void *)(uintptr_t)ctls->cs_minor, 1); + + kmem_free(ctls, sizeof (dld_ctl_str_t)); - dld_str_destroy(dsp); return (0); } /* - * qi_qputp: put(9e) + * DLDIOCATTR */ static void -drv_uw_put(queue_t *wq, mblk_t *mp) +drv_ioc_attr(dld_ctl_str_t *ctls, mblk_t *mp) { - dld_str_t *dsp; + dld_ioc_attr_t *diap; + dls_vlan_t *dvp = NULL; + dls_link_t *dlp = NULL; + int err; + queue_t *q = ctls->cs_wq; - dsp = wq->q_ptr; - ASSERT(dsp != NULL); + if ((err = miocpullup(mp, sizeof (dld_ioc_attr_t))) != 0) + goto failed; - /* - * Call the put(9e) processor. - */ - dld_str_put(dsp, mp); + diap = (dld_ioc_attr_t *)mp->b_cont->b_rptr; + diap->dia_name[IFNAMSIZ - 1] = '\0'; + + if (dls_vlan_hold(diap->dia_name, &dvp, B_FALSE) != 0) { + err = ENOENT; + goto failed; + } + + dlp = dvp->dv_dlp; + (void) strlcpy(diap->dia_dev, dlp->dl_dev, MAXNAMELEN); + diap->dia_port = dlp->dl_port; + diap->dia_vid = dvp->dv_id; + diap->dia_max_sdu = dlp->dl_mip->mi_sdu_max; + + dls_vlan_rele(dvp); + miocack(q, mp, sizeof (dld_ioc_attr_t), 0); + return; + +failed: + ASSERT(err != 0); + if (err == ENOENT) { + char devname[MAXNAMELEN]; + uint_t instance; + major_t major; + + /* + * Try to detect if the specified device is gldv3 + * and return ENODEV if it is not. + */ + if (ddi_parse(diap->dia_name, devname, &instance) == 0 && + (major = ddi_name_to_major(devname)) != (major_t)-1 && + !GLDV3_DRV(major)) + err = ENODEV; + } + miocnak(q, mp, 0, err); } + /* - * qi_srvp: srv(9e) + * DLDIOCVLAN */ +typedef struct dld_ioc_vlan_state { + uint_t bytes_left; + uint_t count; + dld_vlan_info_t *vlanp; +} dld_ioc_vlan_state_t; + +static int +drv_ioc_vlan_info(dls_vlan_t *dvp, void *arg) +{ + dld_ioc_vlan_state_t *statep = arg; + + if (statep->bytes_left < sizeof (dld_vlan_info_t)) + return (ENOSPC); + + (void) strlcpy(statep->vlanp->dvi_name, dvp->dv_name, IFNAMSIZ); + statep->vlanp->dvi_vid = dvp->dv_id; + + statep->count++; + statep->bytes_left -= sizeof (dld_vlan_info_t); + statep->vlanp += 1; + return (0); +} + static void -drv_uw_srv(queue_t *wq) +drv_ioc_vlan(dld_ctl_str_t *ctls, mblk_t *mp) { - mblk_t *mp = NULL; - mblk_t *p; - mblk_t **pp; - dld_str_t *dsp; + dld_ioc_vlan_t *divp; + dld_ioc_vlan_state_t state; + int err = EINVAL; + queue_t *q = ctls->cs_wq; - dsp = wq->q_ptr; - ASSERT(dsp != NULL); + if ((err = miocpullup(mp, sizeof (dld_ioc_vlan_t))) != 0) + goto failed; - /* - * Loop round and pull a chain of messages from the queue. - */ - for (pp = ∓ (p = getq(wq)) != NULL; pp = &(p->b_next)) - *pp = p; + divp = (dld_ioc_vlan_t *)mp->b_cont->b_rptr; + state.bytes_left = MBLKL(mp->b_cont) - sizeof (dld_ioc_vlan_t); + state.count = 0; + state.vlanp = (dld_vlan_info_t *)(divp + 1); - /* - * If there was nothing on the queue then there's nothing to do. - */ - if (mp == NULL) + err = dls_vlan_walk(drv_ioc_vlan_info, &state); + if (err != 0) + goto failed; + + divp->div_count = state.count; + miocack(q, mp, sizeof (dld_ioc_vlan_t) + + state.count * sizeof (dld_vlan_info_t), 0); + return; + +failed: + ASSERT(err != 0); + miocnak(q, mp, 0, err); +} + + +/* + * Process an IOCTL message received by the control node. + */ +static void +drv_ioc(dld_ctl_str_t *ctls, mblk_t *mp) +{ + uint_t cmd; + + cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd; + switch (cmd) { + case DLDIOCATTR: + drv_ioc_attr(ctls, mp); + return; + case DLDIOCVLAN: + drv_ioc_vlan(ctls, mp); return; + default: + miocnak(ctls->cs_wq, mp, 0, ENOTSUP); + return; + } +} - /* - * Call the srv(9e) processor. - */ - dld_str_srv(dsp, mp); +/* + * Write side put routine of the dld control node. + */ +static void +drv_uw_put(queue_t *q, mblk_t *mp) +{ + dld_ctl_str_t *ctls = q->q_ptr; + + switch (mp->b_datap->db_type) { + case M_IOCTL: + drv_ioc(ctls, mp); + break; + default: + freemsg(mp); + break; + } +} + +/* + * Write-side service procedure. + */ +void +drv_uw_srv(queue_t *q) +{ + mblk_t *mp; + + while (mp = getq(q)) + drv_uw_put(q, mp); } diff --git a/usr/src/uts/common/io/dld/dld_ioc.c b/usr/src/uts/common/io/dld/dld_ioc.c deleted file mode 100644 index cbb3016df0..0000000000 --- a/usr/src/uts/common/io/dld/dld_ioc.c +++ /dev/null @@ -1,396 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Data-Link Driver - */ - -#include <sys/types.h> -#include <sys/stream.h> -#include <sys/strsubr.h> -#include <sys/ddi.h> -#include <sys/sunddi.h> -#include <sys/strsun.h> -#include <sys/dlpi.h> -#include <sys/mac.h> -#include <sys/dls.h> -#include <sys/dld.h> -#include <sys/dld_impl.h> - -static void ioc_excl(queue_t *, mblk_t *); -static void ioc_raw(dld_str_t *, mblk_t *); -static void ioc_fast(dld_str_t *, mblk_t *); -static void ioc_create(dld_str_t *, mblk_t *); -static void ioc_destroy(dld_str_t *, mblk_t *); -static void ioc_attr(dld_str_t *, mblk_t *); -static void ioc(dld_str_t *, mblk_t *); - -typedef struct ioc_info { - int i_cmd; - const char *i_txt; - uint_t i_type; - void (*i_fn)(dld_str_t *, mblk_t *); -} ioc_info_t; - -/* - * DLIOC category jump table. - */ -static ioc_info_t ioc_i[] = { - { 0x00, "unknown", DLD_CONTROL | DLD_DLPI, ioc }, - { DLIOCRAW, "DLIOCRAW", DLD_DLPI, ioc_raw }, - { 0x02, "unknown", DLD_CONTROL | DLD_DLPI, ioc }, - { 0x03, "unknown", DLD_CONTROL | DLD_DLPI, ioc }, - { 0x04, "unknown", DLD_CONTROL | DLD_DLPI, ioc }, - { 0x05, "unknown", DLD_CONTROL | DLD_DLPI, ioc }, - { 0x06, "unknown", DLD_CONTROL | DLD_DLPI, ioc }, - { 0x07, "unknown", DLD_CONTROL | DLD_DLPI, ioc }, - { 0x08, "unknown", DLD_CONTROL | DLD_DLPI, ioc }, - { 0x09, "unknown", DLD_CONTROL | DLD_DLPI, ioc }, - { DLIOCHDRINFO, "DLIOCHDRINFO", DLD_DLPI, ioc_fast } -}; - -#define IOC_I_COUNT (sizeof (ioc_i) / sizeof (ioc_i[0])) - -/* - * DLDIOC category jump table. - */ -static ioc_info_t ioc_li[] = { - { 0x00, "unknown", DLD_CONTROL | DLD_DLPI, ioc }, - { DLDIOCCREATE, "DLDIOC_CREATE", DLD_CONTROL, ioc_create }, - { DLDIOCDESTROY, "DLDIOC_DESTROY", DLD_CONTROL, ioc_destroy }, - { DLDIOCATTR, "DLDIOC_ATTR", DLD_CONTROL, ioc_attr } -}; - -#define IOC_LI_COUNT (sizeof (ioc_li) / sizeof (ioc_li[0])) - -/* - * Process an M_IOCTL message. - */ -void -dld_ioc(dld_str_t *dsp, mblk_t *mp) -{ - /* - * We only have shared access and we need exclusive access. - */ - ASSERT(!PERIM_EXCL(dsp->ds_wq)); - - qwriter(dsp->ds_wq, mp, ioc_excl, PERIM_INNER); -} - -/* - * Called via qwriter(9f). - */ -static void -ioc_excl(queue_t *q, mblk_t *mp) -{ - dld_str_t *dsp = q->q_ptr; - struct iocblk *iocp; - uint_t cmd; - ioc_info_t *ip; - uint_t cat; - - iocp = (struct iocblk *)mp->b_rptr; - cmd = iocp->ioc_cmd; - - /* - * We treat the least significate byte as the actual command and - * the rest of it as a category. - */ - cat = cmd & ~0xff; - cmd &= 0xff; - - /* - * Select the jump table according to the category. - */ - switch (cat) { - case DLIOC: - if (cmd >= IOC_I_COUNT) - goto unknown; - - ip = &ioc_i[cmd]; - break; - - case DLDIOC: - if (cmd >= IOC_LI_COUNT) - goto unknown; - - ip = &ioc_li[cmd]; - break; - - default: - goto unknown; - } - - ASSERT(ip->i_cmd == (cat | cmd)); - - /* - * Different ioctls are restricted to different types of stream. (I.e. - * some ioctls are only for the control node, some are for provider - * nodes). - */ - if (!(dsp->ds_type & ip->i_type)) { - miocnak(dsp->ds_wq, mp, 0, ENOTSUP); - return; - } - - ASSERT(ip->i_fn != NULL); - - ip->i_fn(dsp, mp); - return; - -unknown: - ioc(dsp, mp); -} - -/* - * DLIOCRAW - */ -static void -ioc_raw(dld_str_t *dsp, mblk_t *mp) -{ - ASSERT(PERIM_EXCL(dsp->ds_wq)); - ASSERT(dsp->ds_type == DLD_DLPI); - - if (dsp->ds_polling) { - miocnak(dsp->ds_wq, mp, 0, EPROTO); - return; - } - - if (dsp->ds_dlstate == DL_IDLE) { - /* - * Set the receive callback. - */ - dls_rx_set(dsp->ds_dc, dld_str_rx_raw, dsp); - - /* - * Set the M_DATA handler. - */ - dld_str_tx_raw(dsp); - } - - /* - * Note that raw mode is enabled. - */ - dsp->ds_mode = DLD_RAW; - - miocack(dsp->ds_wq, mp, 0, 0); -} - -/* - * DLIOCHDRINFO - */ -static void -ioc_fast(dld_str_t *dsp, mblk_t *mp) -{ - dl_unitdata_req_t *dlp; - off_t off; - size_t len; - const uint8_t *addr; - uint16_t sap; - mblk_t *nmp; - mblk_t *hmp; - const mac_info_t *mip; - uint_t addr_length; - - ASSERT(PERIM_EXCL(dsp->ds_wq)); - ASSERT(dsp->ds_type == DLD_DLPI); - - if (dld_opt & DLD_OPT_NO_FASTPATH) { - miocnak(dsp->ds_wq, mp, 0, ENOTSUP); - return; - } - - nmp = mp->b_cont; - - dlp = (dl_unitdata_req_t *)nmp->b_rptr; - if (MBLKL(nmp) < sizeof (dl_unitdata_req_t) || - dlp->dl_primitive != DL_UNITDATA_REQ) { - miocnak(dsp->ds_wq, mp, 0, EINVAL); - return; - } - - off = dlp->dl_dest_addr_offset; - len = dlp->dl_dest_addr_length; - - if (!MBLKIN(nmp, off, len)) { - miocnak(dsp->ds_wq, mp, 0, EINVAL); - return; - } - - if (dsp->ds_dlstate != DL_IDLE) { - miocnak(dsp->ds_wq, mp, 0, ENOTSUP); - return; - } - - mip = dsp->ds_mip; - addr_length = mip->mi_addr_length; - if (len != addr_length + sizeof (uint16_t)) { - miocnak(dsp->ds_wq, mp, 0, EINVAL); - return; - } - - addr = nmp->b_rptr + off; - sap = *(uint16_t *)(nmp->b_rptr + off + addr_length); - - if ((hmp = dls_header(dsp->ds_dc, addr, sap, dsp->ds_pri)) == NULL) { - miocnak(dsp->ds_wq, mp, 0, ENOMEM); - return; - } - - freemsg(nmp->b_cont); - nmp->b_cont = hmp; - - /* - * Set the receive callback (unless polling is enabled). - */ - if (!dsp->ds_polling) - dls_rx_set(dsp->ds_dc, dld_str_rx_fastpath, (void *)dsp); - - /* - * Set the M_DATA handler. - */ - dld_str_tx_fastpath(dsp); - - /* - * Note that fast-path mode is enabled. - */ - dsp->ds_mode = DLD_FASTPATH; - - miocack(dsp->ds_wq, mp, MBLKL(nmp) + MBLKL(hmp), 0); -} - -/* - * DLDIOCCREATE - */ -static void -ioc_create(dld_str_t *dsp, mblk_t *mp) -{ - dld_ioc_create_t *dicp; - mblk_t *nmp; - int err; - - ASSERT(PERIM_EXCL(dsp->ds_wq)); - ASSERT(dsp->ds_type == DLD_CONTROL); - - if ((err = miocpullup(mp, sizeof (dld_ioc_create_t))) != 0) { - miocnak(dsp->ds_wq, mp, 0, err); - return; - } - - nmp = mp->b_cont; - - dicp = (dld_ioc_create_t *)nmp->b_rptr; - if ((err = dld_ppa_create(dicp->dic_name, dicp->dic_dev, - dicp->dic_port, dicp->dic_vid)) != 0) { - miocnak(dsp->ds_wq, mp, 0, err); - return; - } - - miocack(dsp->ds_wq, mp, 0, 0); -} - -/* - * DLDIOCDESTROY - */ -static void -ioc_destroy(dld_str_t *dsp, mblk_t *mp) -{ - dld_ioc_destroy_t *didp; - mblk_t *nmp; - int err; - - ASSERT(PERIM_EXCL(dsp->ds_wq)); - ASSERT(dsp->ds_type == DLD_CONTROL); - - if ((err = miocpullup(mp, sizeof (dld_ioc_destroy_t))) != 0) { - miocnak(dsp->ds_wq, mp, 0, err); - return; - } - - nmp = mp->b_cont; - - didp = (dld_ioc_destroy_t *)nmp->b_rptr; - if ((err = dld_ppa_destroy(didp->did_name)) != 0) { - miocnak(dsp->ds_wq, mp, 0, err); - return; - } - - miocack(dsp->ds_wq, mp, 0, 0); -} - -/* - * DLDIOCATTR - */ -static void -ioc_attr(dld_str_t *dsp, mblk_t *mp) -{ - dld_ioc_attr_t *diap; - mblk_t *nmp; - int err; - - ASSERT(PERIM_EXCL(dsp->ds_wq)); - ASSERT(dsp->ds_type == DLD_CONTROL); - - if ((err = miocpullup(mp, sizeof (dld_ioc_attr_t))) != 0) { - miocnak(dsp->ds_wq, mp, 0, err); - return; - } - - nmp = mp->b_cont; - - diap = (dld_ioc_attr_t *)nmp->b_rptr; - if ((err = dld_ppa_attr(diap->dia_name, diap->dia_dev, - &diap->dia_port, &diap->dia_vid)) != 0) { - miocnak(dsp->ds_wq, mp, 0, err); - return; - } - - miocack(dsp->ds_wq, mp, sizeof (dld_ioc_attr_t), 0); -} - -/* - * Catch-all handler. - */ -static void -ioc(dld_str_t *dsp, mblk_t *mp) -{ - ASSERT(PERIM_EXCL(dsp->ds_wq)); - - if (dsp->ds_type == DLD_CONTROL) { - miocnak(dsp->ds_wq, mp, 0, EINVAL); - return; - } - - if (dsp->ds_dlstate == DL_UNATTACHED) { - miocnak(dsp->ds_wq, mp, 0, EINVAL); - return; - } - - ASSERT(dsp->ds_mh != NULL); - mac_ioctl(dsp->ds_mh, dsp->ds_wq, mp); -} diff --git a/usr/src/uts/common/io/dld/dld_minor.c b/usr/src/uts/common/io/dld/dld_minor.c deleted file mode 100644 index d729e54833..0000000000 --- a/usr/src/uts/common/io/dld/dld_minor.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Data-Link Driver - */ - -#include <sys/types.h> -#include <sys/mkdev.h> -#include <sys/conf.h> -#include <sys/stat.h> -#include <sys/ddi.h> -#include <sys/sunddi.h> -#include <sys/vmem.h> -#include <sys/atomic.h> - -#include <sys/dld.h> -#include <sys/dld_impl.h> - -static vmem_t *minor_arenap; -static uint32_t minor_count; - -#define MINOR_TO_PTR(minor) ((void *)(uintptr_t)(minor)) -#define PTR_TO_MINOR(ptr) ((minor_t)(uintptr_t)(ptr)) - -/* - * Initialize this module's data structures. - */ -void -dld_minor_init(void) -{ - /* - * Allocate a vmem arena to manage minor numbers. The range of the - * arena will be from 1 to MAXMIN (maximum legal minor number). - */ - minor_arenap = vmem_create("dld_minor_arena", MINOR_TO_PTR(1), MAXMIN, - 1, NULL, NULL, NULL, 0, VM_SLEEP); - ASSERT(minor_arenap != NULL); -} - -/* - * Tear down this module's data structures. - */ -int -dld_minor_fini(void) -{ - /* - * Check to see if there are any minor numbers still in use. - */ - if (minor_count != 0) - return (EBUSY); - - vmem_destroy(minor_arenap); - return (0); -} - -/* - * Allocate a new minor number. - */ -minor_t -dld_minor_hold(boolean_t sleep) -{ - minor_t minor; - - /* - * Grab a value from the arena. - */ - if ((minor = PTR_TO_MINOR(vmem_alloc(minor_arenap, 1, - (sleep) ? VM_SLEEP : VM_NOSLEEP))) == 0) - return (0); - - atomic_add_32(&minor_count, 1); - return (minor); -} - -/* - * Release a previously allocated minor number. - */ -void -dld_minor_rele(minor_t minor) -{ - /* - * Return the value to the arena. - */ - vmem_free(minor_arenap, MINOR_TO_PTR(minor), 1); - - atomic_add_32(&minor_count, -1); -} diff --git a/usr/src/uts/common/io/dld/dld_node.c b/usr/src/uts/common/io/dld/dld_node.c deleted file mode 100644 index 57d28787ab..0000000000 --- a/usr/src/uts/common/io/dld/dld_node.c +++ /dev/null @@ -1,544 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Data-Link Driver - */ - -#include <sys/types.h> -#include <sys/conf.h> -#include <sys/stat.h> -#include <sys/ddi.h> -#include <sys/sunddi.h> -#include <sys/ght.h> -#include <sys/atomic.h> -#include <sys/fs/dv_node.h> -#include <sys/dld.h> -#include <sys/dld_impl.h> - -static int node_constructor(void *, void *, int); -static void node_destructor(void *, void *); -static dld_node_t *node_create(const char *, t_uscalar_t); -static void node_destroy(dld_node_t *); -static int node_insert(dld_node_t *); -static void node_remove(dld_node_t *); -static dld_node_t *node_find_byminor(minor_t); -static dld_node_t *node_find_byname(const char *); - -static kmem_cache_t *node_cachep; -static ght_t node_byminor_hash; -static ght_t node_byname_hash; - -#define NODE_HASHSZ 67 /* prime value */ - -/* - * Initialize this module's data structures. - */ -void -dld_node_init(void) -{ - int err; - - /* - * Create a cache of dld_node_t structures. - */ - node_cachep = kmem_cache_create("dld_node_cache", sizeof (dld_node_t), - 0, node_constructor, node_destructor, NULL, NULL, NULL, 0); - ASSERT(node_cachep != NULL); - - /* - * Create a scalar hash to be keyed by minor number. - */ - err = ght_scalar_create("dld_node_byminor_hash", NODE_HASHSZ, - &node_byminor_hash); - ASSERT(err == 0); - - /* - * Create a string hash to be keyed by name. - */ - err = ght_str_create("dld_node_byname_hash", NODE_HASHSZ, - &node_byname_hash); - ASSERT(err == 0); -} - -/* - * Tear down this module's data structures. - */ -int -dld_node_fini(void) -{ - int err; - - /* - * Check to make sure that the hash tables are empty. - */ - ASSERT(ght_count(node_byname_hash) == ght_count(node_byminor_hash)); - if (ght_count(node_byname_hash) != 0) - return (EBUSY); - - err = ght_destroy(node_byname_hash); - ASSERT(err == 0); - - err = ght_destroy(node_byminor_hash); - ASSERT(err == 0); - - kmem_cache_destroy(node_cachep); - return (0); -} - -/* - * Find an existing node of the given style or create one if none is found. - * Bump a reference count on the node to note that fact that a reference to - * it is now held. - */ -dld_node_t * -dld_node_hold(const char *name, t_uscalar_t style) -{ - dld_node_t *dnp; - int err; - - ght_lock(node_byname_hash, GHT_WRITE); - if ((dnp = node_find_byname(name)) == NULL) { - - if ((dnp = node_create(name, style)) == NULL) { - ght_unlock(node_byname_hash); - return (NULL); - } - - ght_lock(node_byminor_hash, GHT_WRITE); - err = node_insert(dnp); - ght_unlock(node_byminor_hash); - - if (err != 0) { - node_destroy(dnp); - ght_unlock(node_byname_hash); - return (NULL); - } - } else { - /* - * Make sure it's the right style. - */ - if (dnp->dn_style != style) { - ght_unlock(node_byname_hash); - return (NULL); - } - } - - dnp->dn_ref++; - ght_unlock(node_byname_hash); - return (dnp); -} - -/* - * Look up a node by minor number. No reference count is bumped in this case - * because of the transient nature of how the reference is used. (See - * drv_open()). - */ -dld_node_t * -dld_node_find(minor_t minor) -{ - dld_node_t *dnp; - - ght_lock(node_byminor_hash, GHT_READ); - dnp = node_find_byminor(minor); - ght_unlock(node_byminor_hash); - - return (dnp); -} - -/* - * Release a previously held reference to a dld_node_t. - */ -void -dld_node_rele(dld_node_t *dnp) -{ - ght_lock(node_byname_hash, GHT_WRITE); - if (--dnp->dn_ref == 0) { - ght_lock(node_byminor_hash, GHT_WRITE); - node_remove(dnp); - ght_unlock(node_byminor_hash); - node_destroy(dnp); - } - ght_unlock(node_byname_hash); -} - -/* - * kmem_cache constructor function: see kmem_cache_create(9f). - */ -/*ARGSUSED*/ -static int -node_constructor(void *buf, void *cdrarg, int kmflags) -{ - dld_node_t *dnp = buf; - - bzero(buf, sizeof (dld_node_t)); - - /* - * Reserve a minor number for this node. - */ - if ((dnp->dn_minor = dld_minor_hold(kmflags == KM_SLEEP)) == 0) - return (-1); - - return (0); -} - -/* - * kmem_cache destructor function. - */ -/*ARGSUSED*/ -static void -node_destructor(void *buf, void *cdrarg) -{ - dld_node_t *dnp = buf; - - /* - * Release the minor number. - */ - dld_minor_rele(dnp->dn_minor); -} - -/* - * Create a new dld_node_t object. - */ -static dld_node_t * -node_create(const char *name, t_uscalar_t style) -{ - dld_node_t *dnp; - char *buf; - int err; -#define SUFFIX "_ppa_hash" - - ASSERT(strlen(name) < IFNAMSIZ); - ASSERT(style == DL_STYLE1 || style == DL_STYLE2); - - dnp = kmem_cache_alloc(node_cachep, KM_SLEEP); - - (void) strlcpy(dnp->dn_name, name, IFNAMSIZ); - - dnp->dn_style = style; - - if (style == DL_STYLE2) { - /* - * For style 2 nodes we need to create a private hash table - * to manage the multiple PPAs. - */ - size_t size = strlen(dnp->dn_name) + strlen(SUFFIX) + 1; - buf = kmem_alloc(size, KM_SLEEP); - (void) sprintf(buf, "%s" SUFFIX, name); - - err = ght_scalar_create(buf, NODE_HASHSZ, &(dnp->dn_hash)); - ASSERT(err == 0); - - kmem_free(buf, size); - } - - /* - * Create a dev_t in the file system with the given name. - */ - if (ddi_create_minor_node(dld_dip, (char *)dnp->dn_name, S_IFCHR, - dnp->dn_minor, DDI_NT_NET, 0) != DDI_SUCCESS) - goto failed; - - return (dnp); - -failed: - node_destroy(dnp); - return (NULL); - -#undef SUFFIX -} - -/* - * Destroy a dld_node_t object. - */ -static void -node_destroy(dld_node_t *dnp) -{ - int err; - - ASSERT(dnp->dn_ref == 0); - - if (dnp->dn_style == DL_STYLE2) { - /* - * This was a style 2 node so we must destroy the private - * hash table. - */ - err = ght_destroy(dnp->dn_hash); - ASSERT(err == 0); - } - - /* - * Remove the dev_t from the file system. - */ - ddi_remove_minor_node(dld_dip, dnp->dn_name); - - /* - * Work around an apparent bug in devfs where /devices is not - * kept up-to-date. - */ - (void) devfs_clean(ddi_get_parent(dld_dip), NULL, 0); - - kmem_cache_free(node_cachep, dnp); -} - -/* - * Insert a node into both global hash tables. - */ -static int -node_insert(dld_node_t *dnp) -{ - ghte_t byminor_hte; - ghte_t byname_hte; - int err; - - /* - * Allocate a new entry for the 'by minor' hash table. - */ - if ((byminor_hte = ght_alloc(node_byminor_hash, KM_NOSLEEP)) == NULL) - return (ENOMEM); - - /* - * Fill in the information. - */ - GHT_KEY(byminor_hte) = GHT_SCALAR_TO_KEY(dnp->dn_minor); - GHT_VAL(byminor_hte) = GHT_PTR_TO_VAL(dnp); - - /* - * Insert the node into the table. - */ - if ((err = ght_insert(byminor_hte)) != 0) { - ght_free(byminor_hte); - return (err); - } - - ASSERT(dnp->dn_byminor_hte == NULL); - dnp->dn_byminor_hte = byminor_hte; - - /* - * Allocate a new node for the 'by name' hash table. - */ - if ((byname_hte = ght_alloc(node_byname_hash, KM_NOSLEEP)) == NULL) - goto failed; - - /* - * Fill in the information. - */ - GHT_KEY(byname_hte) = GHT_PTR_TO_KEY(dnp->dn_name); - GHT_VAL(byname_hte) = GHT_PTR_TO_VAL(dnp); - - /* - * Insert the node into the table. - */ - if ((err = ght_insert(byname_hte)) != 0) { - ght_free(byname_hte); - goto failed; - } - - ASSERT(dnp->dn_byname_hte == NULL); - dnp->dn_byname_hte = byname_hte; - - return (0); - -failed: - ght_remove(dnp->dn_byminor_hte); - dnp->dn_byminor_hte = NULL; - - return (err); -} - -/* - * Remove a node from both the global hash tables. - */ -static void -node_remove(dld_node_t *dnp) -{ - /* - * Remove the node from the 'by name' hash table and free. - */ - ASSERT(dnp->dn_byname_hte != NULL); - ght_remove(dnp->dn_byname_hte); - ght_free(dnp->dn_byname_hte); - dnp->dn_byname_hte = NULL; - - /* - * Remove the node from the 'by minor' hash table and free. - */ - ASSERT(dnp->dn_byminor_hte != NULL); - ght_remove(dnp->dn_byminor_hte); - ght_free(dnp->dn_byminor_hte); - dnp->dn_byminor_hte = NULL; -} - -/* - * Look up a node in the 'by minor' table. - */ -static dld_node_t * -node_find_byminor(minor_t minor) -{ - ghte_t hte; - - if (ght_find(node_byminor_hash, GHT_SCALAR_TO_KEY(minor), &hte) != 0) - return (NULL); - - return ((dld_node_t *)GHT_VAL(hte)); -} - -/* - * Look up a node in the 'by name' table. - */ -static dld_node_t * -node_find_byname(const char *name) -{ - ghte_t hte; - - if (ght_find(node_byname_hash, GHT_PTR_TO_KEY(name), &hte) != 0) - return (NULL); - - return ((dld_node_t *)GHT_VAL(hte)); -} - -/* - * Add a PPA to a node. - */ -int -dld_node_ppa_add(dld_node_t *dnp, t_scalar_t index, dld_ppa_t *dpp) -{ - ghte_t hte; - int err; - - if (dnp->dn_style == DL_STYLE1) { - /* - * Only a single PPA can be added to a style 1 node so we - * insist that the index number argument is set to -1. - */ - ASSERT(index == -1); - - /* - * Check to see if there is an existing PPA. - */ - if (dnp->dn_dpp != NULL) - return (EEXIST); - - dnp->dn_dpp = dpp; - return (0); - } - ASSERT(dnp->dn_style == DL_STYLE2); - - /* - * Multiple PPAs can be added to a style 2 node and so we - * insist that the index number argument is zero or greater. - */ - ASSERT(index >= 0); - - /* - * Allocate an entry for the private hash table. - */ - hte = ght_alloc(dnp->dn_hash, KM_SLEEP); - - /* - * Fill in the information. - */ - GHT_KEY(hte) = GHT_SCALAR_TO_KEY(index); - GHT_VAL(hte) = GHT_PTR_TO_VAL(dpp); - - /* - * Lock the table. - */ - ght_lock(dnp->dn_hash, GHT_WRITE); - - /* - * Insert the node into the table. - */ - if ((err = ght_insert(hte)) != 0) - ght_free(hte); - - /* - * Unlock the table. - */ - ght_unlock(dnp->dn_hash); - return (err); -} - -/* - * Remove a PPA from the node. - */ -int -dld_node_ppa_remove(dld_node_t *dnp, t_scalar_t index) -{ - ghte_t hte; - int err; - - if (dnp->dn_style == DL_STYLE1) { - ASSERT(index == -1); - - if (dnp->dn_dpp == NULL) - return (ENOENT); - - dnp->dn_dpp = NULL; - return (0); - } - ASSERT(dnp->dn_style == DL_STYLE2); - - ASSERT(index >= 0); - - ght_lock(dnp->dn_hash, GHT_WRITE); - if ((err = ght_find(dnp->dn_hash, GHT_SCALAR_TO_KEY(index), - &hte)) == 0) { - ght_remove(hte); - ght_free(hte); - } - ght_unlock(dnp->dn_hash); - - return (err); -} - -/* - * Look up a dld_ppa_t from a dld_node_t. - */ -dld_ppa_t * -dld_node_ppa_find(dld_node_t *dnp, t_scalar_t index) -{ - ghte_t hte; - - if (dnp->dn_style == DL_STYLE1) { - ASSERT(index == -1); - return (dnp->dn_dpp); - } - ASSERT(dnp->dn_style == DL_STYLE2); - - ASSERT(index >= 0); - - ght_lock(dnp->dn_hash, GHT_READ); - if (ght_find(dnp->dn_hash, GHT_SCALAR_TO_KEY(index), &hte) != 0) { - ght_unlock(dnp->dn_hash); - return (NULL); - } - ght_unlock(dnp->dn_hash); - - return ((dld_ppa_t *)GHT_VAL(hte)); -} diff --git a/usr/src/uts/common/io/dld/dld_ppa.c b/usr/src/uts/common/io/dld/dld_ppa.c deleted file mode 100644 index 450bef44fc..0000000000 --- a/usr/src/uts/common/io/dld/dld_ppa.c +++ /dev/null @@ -1,373 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Data-Link Driver - */ - -#include <sys/types.h> -#include <sys/dlpi.h> -#include <sys/atomic.h> -#include <sys/ctype.h> -#include <sys/ght.h> -#include <net/if.h> - -#include <sys/dld.h> -#include <sys/dld_impl.h> - -static int ppa_constructor(void *, void *, int); -static void ppa_destructor(void *, void *); -static int ppa_create(const char *, const char *, uint_t, uint16_t, - dld_ppa_t **); -static int ppa_destroy(dld_ppa_t *); -static void ppa_attr(dld_ppa_t *, char *, uint_t *, uint16_t *); - -static kmem_cache_t *ppa_cachep; -static ght_t ppa_hash; - -#define PPA_HASHSZ 23 /* prime value */ - -/* - * Initialize this module's data structures. - */ -void -dld_ppa_init(void) -{ - int err; - - /* - * Create a cache of dld_ppa_t objects. - */ - ppa_cachep = kmem_cache_create("dld_ppa_cache", sizeof (dld_ppa_t), 0, - ppa_constructor, ppa_destructor, NULL, NULL, NULL, 0); - ASSERT(ppa_cachep != NULL); - - /* - * Create a string hash table to be keyed by name. - */ - err = ght_str_create("dld_ppa_hash", PPA_HASHSZ, &ppa_hash); - ASSERT(err == 0); -} - -/* - * Tear down this module's data structures. - */ -int -dld_ppa_fini(void) -{ - int err; - - /* - * If the hash table cannot be destroyed then it is not empty. - */ - if ((err = ght_destroy(ppa_hash)) != 0) - return (err); - - kmem_cache_destroy(ppa_cachep); - return (0); -} - -/* - * Create a new dld_ppa_t object. - */ -int -dld_ppa_create(const char *name, const char *dev, uint_t port, uint16_t vid) -{ - dld_ppa_t *dpp; - ghte_t hte; - int err; - - ASSERT(strlen(name) < IFNAMSIZ); - ASSERT(strlen(dev) < MAXNAMELEN); - - /* - * Create the object. - */ - if ((err = ppa_create(name, dev, port, vid, &dpp)) != 0) - return (err); - - /* - * Allocate an entry for the hash table. - */ - hte = ght_alloc(ppa_hash, KM_SLEEP); - - /* - * Fill in the information. - */ - GHT_KEY(hte) = GHT_PTR_TO_KEY(dpp->dp_name); - GHT_VAL(hte) = GHT_PTR_TO_VAL(dpp); - - /* - * Lock the table. - */ - ght_lock(ppa_hash, GHT_WRITE); - - /* - * Insert the entry. - */ - if ((err = ght_insert(hte)) != 0) { - ght_free(hte); - (void) ppa_destroy(dpp); - } - - /* - * Unlock the table. - */ - ght_unlock(ppa_hash); - return (err); -} - -/* - * Destroy a dld_ppa_t object. - */ -int -dld_ppa_destroy(const char *name) -{ - ghte_t hte; - int err; - dld_ppa_t *dpp; - - ASSERT(strlen(name) < IFNAMSIZ); - - ght_lock(ppa_hash, GHT_WRITE); - if ((err = ght_find(ppa_hash, GHT_PTR_TO_KEY(name), &hte)) != 0) - goto failed; - - dpp = (dld_ppa_t *)GHT_VAL(hte); - if ((err = ppa_destroy(dpp)) != 0) - goto failed; - - ght_remove(hte); - ght_free(hte); - -failed: - ght_unlock(ppa_hash); - return (err); -} - -/* - * Get the attributes of a dld_ppa_t object. - */ -int -dld_ppa_attr(const char *name, char *dev, uint_t *portp, uint16_t *vidp) -{ - ghte_t hte; - int err; - dld_ppa_t *dpp; - - ASSERT(strlen(name) < IFNAMSIZ); - - ght_lock(ppa_hash, GHT_READ); - if ((err = ght_find(ppa_hash, (ght_key_t)name, &hte)) == 0) { - dpp = (dld_ppa_t *)GHT_VAL(hte); - ppa_attr(dpp, dev, portp, vidp); - } - ght_unlock(ppa_hash); - - return (err); -} - -/* - * kmem_cache constructor function: see kmem_cache_create(9f). - */ -/*ARGSUSED*/ -static int -ppa_constructor(void *buf, void *cdrarg, int kmflags) -{ - dld_ppa_t *dpp = buf; - - bzero(buf, sizeof (dld_ppa_t)); - dpp->dp_index = -1; - - return (0); -} - -/* - * kmem_cache destructor function - */ -/*ARGSUSED*/ -static void -ppa_destructor(void *buf, void *cdrarg) -{ - dld_ppa_t *dpp = buf; - - ASSERT(dpp->dp_index == -1); - ASSERT(dpp->dp_style1 == NULL); - ASSERT(dpp->dp_style2 == NULL); -} - -/* - * Create a new dld_ppa_t. - */ -static int -ppa_create(const char *name, const char *dev, uint_t port, uint16_t vid, - dld_ppa_t **dppp) -{ - dld_ppa_t *dpp; - dld_node_t *dnp; - char provider[IFNAMSIZ]; - uint_t index; - int err; - - /* - * All dld_ppa_t must be represented by both style 1 and style 2 - * providers. Therefore their name must always be of the form - * <DLS provider>##<PPA index>. - */ - if (ddi_parse(name, provider, &index) != DDI_SUCCESS) - return (EINVAL); - - /* - * Allocate a dld_ppa_t from the cache. - */ - dpp = kmem_cache_alloc(ppa_cachep, KM_SLEEP); - (void) strlcpy(dpp->dp_name, name, IFNAMSIZ); - (void) strlcpy(dpp->dp_dev, dev, MAXNAMELEN); - dpp->dp_port = port; - dpp->dp_vid = vid; - - /* - * Create a data-link. - */ - if ((err = dls_create(dpp->dp_name, dev, port, vid)) != 0) { - kmem_cache_free(ppa_cachep, dpp); - return (err); - } - - /* - * Create a style 1 dld_node_t, unless their use has been disabled. - */ - if (!(dld_opt & DLD_OPT_NO_STYLE1)) { - if ((dnp = dld_node_hold(name, DL_STYLE1)) == NULL) { - err = ENOENT; - goto failed; - } - - /* - * Add the dld_ppa_t to the dld_node_t and keep a backwards - * reference. - */ - if ((err = dld_node_ppa_add(dnp, -1, dpp)) != 0) { - dld_node_rele(dnp); - goto failed; - } - - dpp->dp_style1 = dnp; - } - - /* - * Create, or grab a reference to an existing style 2 dld_node_t. - */ - if ((dnp = dld_node_hold(provider, DL_STYLE2)) == NULL) { - err = ENOENT; - goto failed; - } - - /* - * Add the dld_ppa_t to the dld_node_t. - */ - dpp->dp_index = index; - if ((err = dld_node_ppa_add(dnp, dpp->dp_index, dpp)) != 0) { - dld_node_rele(dnp); - goto failed; - } - - /* - * Keep a backwards reference. - */ - dpp->dp_style2 = dnp; - -done: - *dppp = dpp; - return (0); - -failed: - (void) ppa_destroy(dpp); - return (err); -} - -/* - * Destroy a dld_ppa_t. - */ -static int -ppa_destroy(dld_ppa_t *dpp) -{ - dld_node_t *dnp; - int err; - - /* - * Destroy the data-link. - */ - if ((err = dls_destroy(dpp->dp_name)) != 0) { - ASSERT(err == EBUSY); - return (EBUSY); - } - - /* - * If the style 2 dld_node_t exists then release it. - */ - if ((dnp = dpp->dp_style2) != NULL) { - ASSERT(dpp->dp_index != -1); - - err = dld_node_ppa_remove(dnp, dpp->dp_index); - ASSERT(err == 0); - dpp->dp_index = -1; - - dld_node_rele(dnp); - dpp->dp_style2 = NULL; - } - ASSERT(dpp->dp_index == -1); - - /* - * If the style 1 dld_node_t exists then release it. - */ - if ((dnp = dpp->dp_style1) != NULL) { - err = dld_node_ppa_remove(dnp, -1); - ASSERT(err == 0); - - dld_node_rele(dnp); - dpp->dp_style1 = NULL; - } - - /* - * Free the object back to the cache. - */ - kmem_cache_free(ppa_cachep, dpp); - return (0); -} - -/* - * Get the attributes of a dld_ppa_t. - */ -static void -ppa_attr(dld_ppa_t *dpp, char *dev, uint_t *portp, uint16_t *vidp) -{ - (void) strlcpy(dev, dpp->dp_dev, MAXNAMELEN); - *portp = dpp->dp_port; - *vidp = dpp->dp_vid; -} diff --git a/usr/src/uts/common/io/dld/dld_proto.c b/usr/src/uts/common/io/dld/dld_proto.c index 55da18f487..4dce2ecc6d 100644 --- a/usr/src/uts/common/io/dld/dld_proto.c +++ b/usr/src/uts/common/io/dld/dld_proto.c @@ -55,139 +55,9 @@ static proto_reqfunc_t proto_info_req, proto_attach_req, proto_detach_req, proto_setphysaddr_req, proto_udqos_req, proto_req, proto_capability_req, proto_notify_req, proto_unitdata_req, proto_passive_req; -static void proto_excl(queue_t *, mblk_t *); -static void proto_info_ack(dld_str_t *, mblk_t *); -static void proto_attach_ack(dld_str_t *, mblk_t *, int); -static void proto_detach_ack(dld_str_t *, mblk_t *); -static void proto_bind_ack(dld_str_t *, mblk_t *, int); -static void proto_unbind_ack(dld_str_t *, mblk_t *); -static void proto_promiscon_ack(dld_str_t *, mblk_t *, int); -static void proto_promiscoff_ack(dld_str_t *, mblk_t *, int); -static void proto_enabmulti_ack(dld_str_t *, mblk_t *, int); -static void proto_disabmulti_ack(dld_str_t *, mblk_t *, int); -static void proto_setphysaddr_ack(dld_str_t *, mblk_t *, int); -static void proto_physaddr_ack(dld_str_t *, mblk_t *, t_uscalar_t); -static void proto_udqos_ack(dld_str_t *, mblk_t *); -static void proto_poll_disable(dld_str_t *); -static boolean_t proto_poll_enable(dld_str_t *, dl_capab_poll_t *); -static void proto_capability_ack(dld_str_t *, mblk_t *); -static void proto_capability_enable(dld_str_t *, mblk_t *); -static void proto_notify_ack(dld_str_t *, mblk_t *, uint_t, - uint_t); - -#define DL_SOLARIS 0x100 - -/* - * M_PROTO/M_PCPROTO request handlers - */ - -typedef struct proto_req_info { - t_uscalar_t pri_prim; - const char *pri_txt; - boolean_t pri_needexcl; - boolean_t pri_active; - proto_reqfunc_t *pri_fn; -} proto_req_info_t; - -static proto_req_info_t proto_ri[] = { - { DL_INFO_REQ, "DL_INFO_REQ", B_FALSE, B_FALSE, proto_info_req }, - { DL_BIND_REQ, "DL_BIND_REQ", B_TRUE, B_TRUE, proto_bind_req }, - { DL_UNBIND_REQ, "DL_UNBIND_REQ", B_TRUE, B_FALSE, proto_unbind_req }, - { DL_INFO_ACK, "DL_INFO_ACK", B_FALSE, B_FALSE, proto_req }, - { DL_BIND_ACK, "DL_BIND_ACK", B_FALSE, B_FALSE, proto_req }, - { DL_ERROR_ACK, "DL_ERROR_ACK", B_FALSE, B_FALSE, proto_req }, - { DL_OK_ACK, "DL_OK_ACK", B_FALSE, B_FALSE, proto_req }, - { DL_UNITDATA_REQ, "DL_UNITDATA_REQ", B_FALSE, B_FALSE, - proto_unitdata_req }, - { DL_UNITDATA_IND, "DL_UNITDATA_IND", B_FALSE, B_FALSE, proto_req }, - { DL_UDERROR_IND, "DL_UDERROR_IND", B_FALSE, B_FALSE, proto_req }, - { DL_UDQOS_REQ, "DL_UDQOS_REQ", B_TRUE, B_FALSE, proto_udqos_req }, - { DL_ATTACH_REQ, "DL_ATTACH_REQ", B_TRUE, B_FALSE, proto_attach_req }, - { DL_DETACH_REQ, "DL_DETACH_REQ", B_TRUE, B_FALSE, proto_detach_req }, - { DL_CONNECT_REQ, "DL_CONNECT_REQ", B_FALSE, B_FALSE, proto_req }, - { DL_CONNECT_IND, "DL_CONNECT_IND", B_FALSE, B_FALSE, proto_req }, - { DL_CONNECT_RES, "DL_CONNECT_RES", B_FALSE, B_FALSE, proto_req }, - { DL_CONNECT_CON, "DL_CONNECT_CON", B_FALSE, B_FALSE, proto_req }, - { DL_TOKEN_REQ, "DL_TOKEN_REQ", B_FALSE, B_FALSE, proto_req }, - { DL_TOKEN_ACK, "DL_TOKEN_ACK", B_FALSE, B_FALSE, proto_req }, - { DL_DISCONNECT_REQ, "DL_DISCONNECT_REQ", B_FALSE, B_FALSE, proto_req }, - { DL_DISCONNECT_IND, "DL_DISCONNECT_IND", B_FALSE, B_FALSE, proto_req }, - { DL_SUBS_UNBIND_REQ, "DL_SUBS_UNBIND_REQ", B_FALSE, B_FALSE, - proto_req }, - { 0x16, "undefined", B_FALSE, B_FALSE, proto_req }, - { DL_RESET_REQ, "DL_RESET_REQ", B_FALSE, B_FALSE, proto_req }, - { DL_RESET_IND, "DL_RESET_IND", B_FALSE, B_FALSE, proto_req }, - { DL_RESET_RES, "DL_RESET_RES", B_FALSE, B_FALSE, proto_req }, - { DL_RESET_CON, "DL_RESET_CON", B_FALSE, B_FALSE, proto_req }, - { DL_SUBS_BIND_REQ, "DL_SUBS_BIND_REQ", B_FALSE, B_FALSE, proto_req }, - { DL_SUBS_BIND_ACK, "DL_SUBS_BIND_ACK", B_FALSE, B_FALSE, proto_req }, - { DL_ENABMULTI_REQ, "DL_ENABMULTI_REQ", B_TRUE, B_TRUE, - proto_enabmulti_req }, - { DL_DISABMULTI_REQ, "DL_DISABMULTI_REQ", B_TRUE, B_FALSE, - proto_disabmulti_req }, - { DL_PROMISCON_REQ, "DL_PROMISCON_REQ", B_TRUE, B_TRUE, - proto_promiscon_req }, - { DL_PROMISCOFF_REQ, "DL_PROMISCOFF_REQ", B_TRUE, B_FALSE, - proto_promiscoff_req }, - { DL_DATA_ACK_REQ, "DL_DATA_ACK_REQ", B_FALSE, B_FALSE, proto_req }, - { DL_DATA_ACK_IND, "DL_DATA_ACK_IND", B_FALSE, B_FALSE, proto_req }, - { DL_DATA_ACK_STATUS_IND, "DL_DATA_ACK_STATUS_IND", B_FALSE, B_FALSE, - proto_req }, - { DL_REPLY_REQ, "DL_REPLY_REQ", B_FALSE, B_FALSE, proto_req }, - { DL_REPLY_IND, "DL_REPLY_IND", B_FALSE, B_FALSE, proto_req }, - { DL_REPLY_STATUS_IND, "DL_REPLY_STATUS_IND", B_FALSE, B_FALSE, - proto_req }, - { DL_REPLY_UPDATE_REQ, "DL_REPLY_UPDATE_REQ", B_FALSE, B_FALSE, - proto_req }, - { DL_REPLY_UPDATE_STATUS_IND, "DL_REPLY_UPDATE_STATUS_IND", B_FALSE, - B_FALSE, proto_req }, - { DL_XID_REQ, "DL_XID_REQ", B_FALSE, B_FALSE, proto_req }, - { DL_XID_IND, "DL_XID_IND", B_FALSE, B_FALSE, proto_req }, - { DL_XID_RES, "DL_XID_RES", B_FALSE, B_FALSE, proto_req }, - { DL_XID_CON, "DL_XID_CON", B_FALSE, B_FALSE, proto_req }, - { DL_TEST_REQ, "DL_TEST_REQ", B_FALSE, B_FALSE, proto_req }, - { DL_TEST_IND, "DL_TEST_IND", B_FALSE, B_FALSE, proto_req }, - { DL_TEST_RES, "DL_TEST_RES", B_FALSE, B_FALSE, proto_req }, - { DL_TEST_CON, "DL_TEST_CON", B_FALSE, B_FALSE, proto_req }, - { DL_PHYS_ADDR_REQ, "DL_PHYS_ADDR_REQ", B_FALSE, B_FALSE, - proto_physaddr_req }, - { DL_PHYS_ADDR_ACK, "DL_PHYS_ADDR_ACK", B_FALSE, B_FALSE, proto_req }, - { DL_SET_PHYS_ADDR_REQ, "DL_SET_PHYS_ADDR_REQ", B_TRUE, B_TRUE, - proto_setphysaddr_req }, - { DL_GET_STATISTICS_REQ, "DL_GET_STATISTICS_REQ", B_FALSE, B_FALSE, - proto_req }, - { DL_GET_STATISTICS_ACK, "DL_GET_STATISTICS_ACK", B_FALSE, B_FALSE, - proto_req } -}; - -#define PROTO_RI_COUNT (sizeof (proto_ri) / sizeof (proto_ri[0])) - -static proto_req_info_t proto_sri[] = { - { DL_NOTIFY_REQ, "DL_NOTIFY_REQ", B_FALSE, B_FALSE, proto_notify_req }, - { DL_NOTIFY_ACK, "DL_NOTIFY_ACK", B_FALSE, B_FALSE, proto_req }, - { DL_NOTIFY_IND, "DL_NOTIFY_IND", B_FALSE, B_FALSE, proto_req }, - { DL_AGGR_REQ, "DL_AGGR_REQ", B_FALSE, B_TRUE, proto_req }, - { DL_AGGR_IND, "DL_AGGR_IND", B_FALSE, B_FALSE, proto_req }, - { DL_UNAGGR_REQ, "DL_UNAGGR_REQ", B_FALSE, B_TRUE, proto_req }, - { 0x106, "undefined", B_FALSE, B_FALSE, proto_req }, - { 0x107, "undefined", B_FALSE, B_FALSE, proto_req }, - { 0x108, "undefined", B_FALSE, B_FALSE, proto_req }, - { 0x109, "undefined", B_FALSE, B_FALSE, proto_req }, - { 0x10a, "undefined", B_FALSE, B_FALSE, proto_req }, - { 0x10b, "undefined", B_FALSE, B_FALSE, proto_req }, - { 0x10c, "undefined", B_FALSE, B_FALSE, proto_req }, - { 0x10d, "undefined", B_FALSE, B_FALSE, proto_req }, - { 0x10e, "undefined", B_FALSE, B_FALSE, proto_req }, - { 0x10f, "undefined", B_FALSE, B_FALSE, proto_req }, - { DL_CAPABILITY_REQ, "DL_CAPABILITY_REQ", B_FALSE, B_FALSE, - proto_capability_req }, - { DL_CAPABILITY_ACK, "DL_CAPABILITY_ACK", B_FALSE, B_FALSE, proto_req }, - { DL_CONTROL_REQ, "DL_CONTROL_REQ", B_FALSE, B_TRUE, proto_req }, - { DL_CONTROL_ACK, "DL_CONTROL_ACK", B_FALSE, B_FALSE, proto_req }, - { DL_PASSIVE_REQ, "DL_PASSIVE_REQ", B_TRUE, B_FALSE, proto_passive_req } -}; - -#define PROTO_SRI_COUNT (sizeof (proto_sri) / sizeof (proto_sri[0])) +static void proto_poll_disable(dld_str_t *); +static boolean_t proto_poll_enable(dld_str_t *, dl_capab_poll_t *); +static boolean_t proto_capability_advertise(dld_str_t *, mblk_t *); #define DL_ACK_PENDING(state) \ ((state) == DL_ATTACH_PENDING || \ @@ -196,15 +66,18 @@ static proto_req_info_t proto_sri[] = { (state) == DL_UNBIND_PENDING) /* - * Process a DLPI protocol message. (Only ever called from put(9e)). + * Process a DLPI protocol message. + * The primitives DL_BIND_REQ, DL_ENABMULTI_REQ, DL_PROMISCON_REQ, + * DL_SET_PHYS_ADDR_REQ put the data link below our dld_str_t into an + * 'active' state. The primitive DL_PASSIVE_REQ marks our dld_str_t + * as 'passive' and forbids it from being subsequently made 'active' + * by the above primitives. */ void dld_proto(dld_str_t *dsp, mblk_t *mp) { union DL_primitives *udlp; t_uscalar_t prim; - proto_req_info_t *prip; - boolean_t success; if (MBLKL(mp) < sizeof (t_uscalar_t)) { freemsg(mp); @@ -214,159 +87,279 @@ dld_proto(dld_str_t *dsp, mblk_t *mp) udlp = (union DL_primitives *)mp->b_rptr; prim = udlp->dl_primitive; + switch (prim) { + case DL_INFO_REQ: + (void) proto_info_req(dsp, udlp, mp); + break; + case DL_BIND_REQ: + (void) proto_bind_req(dsp, udlp, mp); + break; + case DL_UNBIND_REQ: + (void) proto_unbind_req(dsp, udlp, mp); + break; + case DL_UNITDATA_REQ: + (void) proto_unitdata_req(dsp, udlp, mp); + break; + case DL_UDQOS_REQ: + (void) proto_udqos_req(dsp, udlp, mp); + break; + case DL_ATTACH_REQ: + (void) proto_attach_req(dsp, udlp, mp); + break; + case DL_DETACH_REQ: + (void) proto_detach_req(dsp, udlp, mp); + break; + case DL_ENABMULTI_REQ: + (void) proto_enabmulti_req(dsp, udlp, mp); + break; + case DL_DISABMULTI_REQ: + (void) proto_disabmulti_req(dsp, udlp, mp); + break; + case DL_PROMISCON_REQ: + (void) proto_promiscon_req(dsp, udlp, mp); + break; + case DL_PROMISCOFF_REQ: + (void) proto_promiscoff_req(dsp, udlp, mp); + break; + case DL_PHYS_ADDR_REQ: + (void) proto_physaddr_req(dsp, udlp, mp); + break; + case DL_SET_PHYS_ADDR_REQ: + (void) proto_setphysaddr_req(dsp, udlp, mp); + break; + case DL_NOTIFY_REQ: + (void) proto_notify_req(dsp, udlp, mp); + break; + case DL_CAPABILITY_REQ: + (void) proto_capability_req(dsp, udlp, mp); + break; + case DL_PASSIVE_REQ: + (void) proto_passive_req(dsp, udlp, mp); + break; + default: + (void) proto_req(dsp, udlp, mp); + break; + } +} + +/* + * Finish any pending operations. At this moment we are single-threaded, + * hence there is no need to hold ds_lock as writer because we're already + * exclusive. + */ +void +dld_finish_pending_ops(dld_str_t *dsp) +{ + ASSERT(MUTEX_HELD(&dsp->ds_thr_lock)); + ASSERT(dsp->ds_thr == 0); + + /* Pending DL_DETACH_REQ? */ + if (dsp->ds_detach_req != NULL) { + mblk_t *mp; + + ASSERT(dsp->ds_dlstate == DL_DETACH_PENDING); + dld_str_detach(dsp); + + mp = dsp->ds_detach_req; + dsp->ds_detach_req = NULL; + + mutex_exit(&dsp->ds_thr_lock); + dlokack(dsp->ds_wq, mp, DL_DETACH_REQ); + } else { + mutex_exit(&dsp->ds_thr_lock); + } +} + +#define NEG(x) -(x) + +typedef struct dl_info_ack_wrapper { + dl_info_ack_t dl_info; + uint8_t dl_addr[MAXADDRLEN + sizeof (uint16_t)]; + uint8_t dl_brdcst_addr[MAXADDRLEN]; + dl_qos_cl_range1_t dl_qos_range1; + dl_qos_cl_sel1_t dl_qos_sel1; +} dl_info_ack_wrapper_t; + +/* + * DL_INFO_REQ + */ +/*ARGSUSED*/ +static boolean_t +proto_info_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) +{ + dl_info_ack_wrapper_t *dlwp; + dl_info_ack_t *dlp; + dl_qos_cl_sel1_t *selp; + dl_qos_cl_range1_t *rangep; + uint8_t *addr; + uint8_t *brdcst_addr; + uint_t addr_length; + uint_t sap_length; + mac_info_t minfo; + mac_info_t *minfop; + queue_t *q = dsp->ds_wq; + /* - * Select the correct jump table. + * Swap the request message for one large enough to contain the + * wrapper structure defined above. */ - if (prim & DL_SOLARIS) { - /* - * Entries in the 'solaris extensions' jump table - * have an extra bit in the primitive value. Clear it - * to do the lookup. - */ - prim &= ~DL_SOLARIS; + if ((mp = mexchange(q, mp, sizeof (dl_info_ack_wrapper_t), + M_PCPROTO, 0)) == NULL) + return (B_FALSE); - /* - * Check the primitive is in range. - */ - if (prim >= PROTO_SRI_COUNT) - goto unsupported; + rw_enter(&dsp->ds_lock, RW_READER); - /* - * Grab the jump table entry. - */ - prip = &proto_sri[prim]; + bzero(mp->b_rptr, sizeof (dl_info_ack_wrapper_t)); + dlwp = (dl_info_ack_wrapper_t *)mp->b_rptr; - /* - * OR the cleared bit back in to make the primitive valid - * again. - */ - prim |= DL_SOLARIS; - } else { - /* - * Check the primitive is in range. - */ - if (prim >= PROTO_RI_COUNT) - goto unsupported; + dlp = &(dlwp->dl_info); + ASSERT(dlp == (dl_info_ack_t *)mp->b_rptr); - /* - * Grab the jump table entry. - */ - prip = &proto_ri[prim]; - } + dlp->dl_primitive = DL_INFO_ACK; - ASSERT(prip->pri_prim == prim); + /* + * Set up the sub-structure pointers. + */ + addr = dlwp->dl_addr; + brdcst_addr = dlwp->dl_brdcst_addr; + rangep = &(dlwp->dl_qos_range1); + selp = &(dlwp->dl_qos_sel1); /* - * If this primitive causes the data-link channel used by this - * object to become active, then we need to notify dls. Note that - * if we're already passive by having succesfully processed a - * DL_PASSIVE_REQ, then active primitives do not cause us to become - * active. + * This driver supports only version 2 connectionless DLPI provider + * nodes. */ - if (prip->pri_active && dsp->ds_passivestate == DLD_UNINITIALIZED) { - if (!dls_active_set(dsp->ds_dc)) { - dlerrorack(dsp->ds_wq, mp, prim, DL_SYSERR, EBUSY); - return; - } - } + dlp->dl_service_mode = DL_CLDLS; + dlp->dl_version = DL_VERSION_2; /* - * Check whether we need, and whether we have, exclusive access to - * the stream. + * Set the style of the provider */ - if (prip->pri_needexcl) { - /* - * We only have shared access and we need exclusive access. - */ - ASSERT(!PERIM_EXCL(dsp->ds_wq)); + dlp->dl_provider_style = dsp->ds_style; + ASSERT(dlp->dl_provider_style == DL_STYLE1 || + dlp->dl_provider_style == DL_STYLE2); - /* - * Process via qwriter(9f). - */ - qwriter(dsp->ds_wq, mp, proto_excl, PERIM_INNER); - return; - } + /* + * Set the current DLPI state. + */ + dlp->dl_current_state = dsp->ds_dlstate; - success = prip->pri_fn(dsp, udlp, mp); - if (prip->pri_active && dsp->ds_passivestate == DLD_UNINITIALIZED) { - if (success) - dsp->ds_passivestate = DLD_ACTIVE; - else - dls_active_clear(dsp->ds_dc); + /* + * Gratuitously set the media type. This is to deal with modules + * that assume the media type is known prior to DL_ATTACH_REQ + * being completed. + */ + dlp->dl_mac_type = DL_ETHER; + + /* + * If the stream is not at least attached we try to retrieve the + * mac_info using mac_info_get() + */ + if (dsp->ds_dlstate == DL_UNATTACHED || + dsp->ds_dlstate == DL_ATTACH_PENDING || + dsp->ds_dlstate == DL_DETACH_PENDING) { + if (!mac_info_get(ddi_major_to_name(dsp->ds_major), &minfo)) { + /* + * Cannot find mac_info. giving up. + */ + goto done; + } + minfop = &minfo; + } else { + minfop = (mac_info_t *)dsp->ds_mip; } - return; + /* + * Set the media type (properly this time). + */ + dlp->dl_mac_type = minfop->mi_media; -unsupported: - (void) proto_req(dsp, udlp, mp); -} + /* + * Set the DLSAP length. We only support 16 bit values and they + * appear after the MAC address portion of DLSAP addresses. + */ + sap_length = sizeof (uint16_t); + dlp->dl_sap_length = NEG(sap_length); -/* - * Called via qwriter(9f). - */ -static void -proto_excl(queue_t *q, mblk_t *mp) -{ - dld_str_t *dsp = q->q_ptr; - union DL_primitives *udlp; - t_uscalar_t prim; - proto_req_info_t *prip; - boolean_t success; + /* + * Set the minimum and maximum payload sizes. + */ + dlp->dl_min_sdu = minfop->mi_sdu_min; + dlp->dl_max_sdu = minfop->mi_sdu_max; - ASSERT(MBLKL(mp) >= sizeof (t_uscalar_t)); + addr_length = minfop->mi_addr_length; + ASSERT(addr_length != 0); - udlp = (union DL_primitives *)mp->b_rptr; - prim = udlp->dl_primitive; + /* + * Copy in the media broadcast address. + */ + dlp->dl_brdcst_addr_offset = (uintptr_t)brdcst_addr - (uintptr_t)dlp; + bcopy(minfop->mi_brdcst_addr, brdcst_addr, addr_length); + dlp->dl_brdcst_addr_length = addr_length; /* - * Select the correct jump table. + * We only support QoS information for VLAN interfaces. */ - if (prim & DL_SOLARIS) { - /* - * Entries in the 'solaris extensions' jump table - * have an extra bit in the primitive value. Clear it - * to do the lookup. - */ - prim &= ~DL_SOLARIS; + if (dsp->ds_vid != VLAN_ID_NONE) { + dlp->dl_qos_range_offset = (uintptr_t)rangep - (uintptr_t)dlp; + dlp->dl_qos_range_length = sizeof (dl_qos_cl_range1_t); + + rangep->dl_qos_type = DL_QOS_CL_RANGE1; + rangep->dl_trans_delay.dl_target_value = DL_UNKNOWN; + rangep->dl_trans_delay.dl_accept_value = DL_UNKNOWN; + rangep->dl_protection.dl_min = DL_UNKNOWN; + rangep->dl_protection.dl_max = DL_UNKNOWN; + rangep->dl_residual_error = DL_UNKNOWN; /* - * Grab the jump table entry. + * Specify the supported range of priorities. */ - ASSERT(prim < PROTO_SRI_COUNT); - prip = &proto_sri[prim]; + rangep->dl_priority.dl_min = 0; + rangep->dl_priority.dl_max = (1 << VLAN_PRI_SIZE) - 1; + + dlp->dl_qos_offset = (uintptr_t)selp - (uintptr_t)dlp; + dlp->dl_qos_length = sizeof (dl_qos_cl_sel1_t); + + selp->dl_qos_type = DL_QOS_CL_SEL1; + selp->dl_trans_delay = DL_UNKNOWN; + selp->dl_protection = DL_UNKNOWN; + selp->dl_residual_error = DL_UNKNOWN; /* - * OR the cleared bit back in to make the primitive valid - * again. + * Specify the current priority (which can be changed by + * the DL_UDQOS_REQ primitive). */ - prim |= DL_SOLARIS; + selp->dl_priority = dsp->ds_pri; } else { /* - * Grab the jump table entry. + * Shorten the buffer to lose the unused QoS information + * structures. */ - ASSERT(prim < PROTO_RI_COUNT); - prip = &proto_ri[prim]; + mp->b_wptr = (uint8_t *)rangep; } - ASSERT(prip->pri_prim == prim); - - success = prip->pri_fn(dsp, udlp, mp); - if (prip->pri_active && dsp->ds_passivestate == DLD_UNINITIALIZED) { - if (success) - dsp->ds_passivestate = DLD_ACTIVE; - else - dls_active_clear(dsp->ds_dc); + dlp->dl_addr_length = addr_length + sizeof (uint16_t); + if (dsp->ds_dlstate == DL_IDLE) { + /* + * The stream is bound. Therefore we can formulate a valid + * DLSAP address. + */ + dlp->dl_addr_offset = (uintptr_t)addr - (uintptr_t)dlp; + bcopy(dsp->ds_curr_addr, addr, addr_length); + *(uint16_t *)(addr + addr_length) = dsp->ds_sap; } -} -/* - * DL_INFO_REQ - */ -/*ARGSUSED*/ -static boolean_t -proto_info_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) -{ - proto_info_ack(dsp, mp); +done: + ASSERT(IMPLY(dlp->dl_qos_offset != 0, dlp->dl_qos_length != 0)); + ASSERT(IMPLY(dlp->dl_qos_range_offset != 0, + dlp->dl_qos_range_length != 0)); + ASSERT(IMPLY(dlp->dl_addr_offset != 0, dlp->dl_addr_length != 0)); + ASSERT(IMPLY(dlp->dl_brdcst_addr_offset != 0, + dlp->dl_brdcst_addr_length != 0)); + + rw_exit(&dsp->ds_lock); + + qreply(q, mp); return (B_TRUE); } @@ -376,39 +369,49 @@ proto_info_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) static boolean_t proto_attach_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) { - dl_attach_req_t *dlp = (dl_attach_req_t *)udlp; - t_scalar_t index; - dld_node_t *dnp; - dld_ppa_t *dpp; - int err; + dl_attach_req_t *dlp = (dl_attach_req_t *)udlp; + int err = 0; + t_uscalar_t dl_err; + queue_t *q = dsp->ds_wq; - ASSERT(PERIM_EXCL(dsp->ds_wq)); + rw_enter(&dsp->ds_lock, RW_WRITER); - if (dsp->ds_dlstate != DL_UNATTACHED) { - dlerrorack(dsp->ds_wq, mp, DL_ATTACH_REQ, DL_OUTSTATE, 0); - return (B_FALSE); + if (MBLKL(mp) < sizeof (dl_attach_req_t) || + dlp->dl_ppa < 0 || dsp->ds_style == DL_STYLE1) { + dl_err = DL_BADPRIM; + goto failed; } - if (MBLKL(mp) < sizeof (dl_attach_req_t)) { - dlerrorack(dsp->ds_wq, mp, DL_ATTACH_REQ, DL_BADPRIM, 0); - return (B_FALSE); + if (dsp->ds_dlstate != DL_UNATTACHED) { + dl_err = DL_OUTSTATE; + goto failed; } - index = dlp->dl_ppa; - - dnp = dsp->ds_dnp; - ASSERT(dnp->dn_style == DL_STYLE2); + dsp->ds_dlstate = DL_ATTACH_PENDING; - if ((dpp = dld_node_ppa_find(dnp, index)) == NULL) { - dlerrorack(dsp->ds_wq, mp, DL_ATTACH_REQ, DL_BADPPA, 0); - return (B_FALSE); + err = dld_str_attach(dsp, dlp->dl_ppa); + if (err != 0) { + switch (err) { + case ENOENT: + dl_err = DL_BADPPA; + err = 0; + break; + default: + dl_err = DL_SYSERR; + break; + } + dsp->ds_dlstate = DL_UNATTACHED; + goto failed; } + ASSERT(dsp->ds_dlstate == DL_UNBOUND); + rw_exit(&dsp->ds_lock); - dsp->ds_dlstate = DL_ATTACH_PENDING; - - err = dld_str_attach(dsp, dpp); - proto_attach_ack(dsp, mp, err); - return (err == 0); + dlokack(q, mp, DL_ATTACH_REQ); + return (B_TRUE); +failed: + rw_exit(&dsp->ds_lock); + dlerrorack(q, mp, DL_ATTACH_REQ, dl_err, (t_uscalar_t)err); + return (B_FALSE); } /* @@ -418,28 +421,42 @@ proto_attach_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) static boolean_t proto_detach_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) { - ASSERT(PERIM_EXCL(dsp->ds_wq)); + queue_t *q = dsp->ds_wq; + t_uscalar_t dl_err; - if (dsp->ds_dlstate != DL_UNBOUND) { - dlerrorack(dsp->ds_wq, mp, DL_DETACH_REQ, DL_OUTSTATE, 0); - return (B_FALSE); - } + rw_enter(&dsp->ds_lock, RW_WRITER); if (MBLKL(mp) < sizeof (dl_detach_req_t)) { - dlerrorack(dsp->ds_wq, mp, DL_DETACH_REQ, DL_BADPRIM, 0); - return (B_FALSE); + dl_err = DL_BADPRIM; + goto failed; } - if ((dsp->ds_dnp)->dn_style == DL_STYLE1) { - dlerrorack(dsp->ds_wq, mp, DL_DETACH_REQ, DL_BADPRIM, 0); - return (B_FALSE); + if (dsp->ds_dlstate != DL_UNBOUND) { + dl_err = DL_OUTSTATE; + goto failed; + } + + if (dsp->ds_style == DL_STYLE1) { + dl_err = DL_BADPRIM; + goto failed; } dsp->ds_dlstate = DL_DETACH_PENDING; - dld_str_detach(dsp); - proto_detach_ack(dsp, mp); + /* + * Complete the detach when the driver is single-threaded. + */ + mutex_enter(&dsp->ds_thr_lock); + ASSERT(dsp->ds_detach_req == NULL); + dsp->ds_detach_req = mp; + mutex_exit(&dsp->ds_thr_lock); + rw_exit(&dsp->ds_lock); + return (B_TRUE); +failed: + rw_exit(&dsp->ds_lock); + dlerrorack(q, mp, DL_DETACH_REQ, dl_err, 0); + return (B_FALSE); } /* @@ -448,33 +465,44 @@ proto_detach_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) static boolean_t proto_bind_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) { - dl_bind_req_t *dlp = (dl_bind_req_t *)udlp; - int err; - - ASSERT(PERIM_EXCL(dsp->ds_wq)); - - if (dsp->ds_dlstate != DL_UNBOUND) { - dlerrorack(dsp->ds_wq, mp, DL_BIND_REQ, DL_OUTSTATE, 0); - return (B_FALSE); - } + dl_bind_req_t *dlp = (dl_bind_req_t *)udlp; + int err = 0; + uint8_t addr[MAXADDRLEN]; + uint_t addr_length; + t_uscalar_t dl_err; + t_scalar_t sap; + queue_t *q = dsp->ds_wq; if (MBLKL(mp) < sizeof (dl_bind_req_t)) { - dlerrorack(dsp->ds_wq, mp, DL_BIND_REQ, DL_BADPRIM, 0); - return (B_FALSE); + dl_err = DL_BADPRIM; + goto failed; } if (dlp->dl_xidtest_flg != 0) { - dlerrorack(dsp->ds_wq, mp, DL_BIND_REQ, DL_NOAUTO, 0); - return (B_FALSE); + dl_err = DL_NOAUTO; + goto failed; } if (dlp->dl_service_mode != DL_CLDLS) { - dlerrorack(dsp->ds_wq, mp, DL_BIND_REQ, DL_UNSUPPORTED, 0); - return (B_FALSE); + dl_err = DL_UNSUPPORTED; + goto failed; } - dsp->ds_dlstate = DL_BIND_PENDING; + rw_enter(&dsp->ds_lock, RW_WRITER); + + if (dsp->ds_dlstate != DL_UNBOUND) { + dl_err = DL_OUTSTATE; + goto failed; + } + + if (dsp->ds_passivestate == DLD_UNINITIALIZED && + !dls_active_set(dsp->ds_dc)) { + dl_err = DL_SYSERR; + err = EBUSY; + goto failed; + } + dsp->ds_dlstate = DL_BIND_PENDING; /* * Set the receive callback. */ @@ -482,19 +510,51 @@ proto_bind_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) dld_str_rx_raw : dld_str_rx_unitdata, dsp); /* - * Set the M_DATA handler. + * Bind the channel such that it can receive packets. */ - if (dsp->ds_mode == DLD_RAW) - dld_str_tx_raw(dsp); + sap = dsp->ds_sap = dlp->dl_sap; + err = dls_bind(dsp->ds_dc, dlp->dl_sap); + if (err != 0) { + switch (err) { + case EINVAL: + dl_err = DL_BADADDR; + err = 0; + break; + default: + dl_err = DL_SYSERR; + break; + } + dsp->ds_dlstate = DL_UNBOUND; + if (dsp->ds_passivestate == DLD_UNINITIALIZED) + dls_active_clear(dsp->ds_dc); + + goto failed; + } /* - * Bind the channel such that it can receive packets. + * Copy in MAC address. */ - dsp->ds_sap = dlp->dl_sap; - err = dls_bind(dsp->ds_dc, dlp->dl_sap); + addr_length = dsp->ds_mip->mi_addr_length; + bcopy(dsp->ds_curr_addr, addr, addr_length); + + /* + * Copy in the DLSAP. + */ + *(uint16_t *)(addr + addr_length) = dsp->ds_sap; + addr_length += sizeof (uint16_t); + + dsp->ds_dlstate = DL_IDLE; + if (dsp->ds_passivestate == DLD_UNINITIALIZED) + dsp->ds_passivestate = DLD_ACTIVE; - proto_bind_ack(dsp, mp, err); - return (err == 0); + rw_exit(&dsp->ds_lock); + + dlbindack(q, mp, sap, (void *)addr, addr_length, 0, 0); + return (B_TRUE); +failed: + rw_exit(&dsp->ds_lock); + dlerrorack(q, mp, DL_BIND_REQ, dl_err, (t_uscalar_t)err); + return (B_FALSE); } /* @@ -504,16 +564,19 @@ proto_bind_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) static boolean_t proto_unbind_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) { - ASSERT(PERIM_EXCL(dsp->ds_wq)); + queue_t *q = dsp->ds_wq; + t_uscalar_t dl_err; - if (dsp->ds_dlstate != DL_IDLE) { - dlerrorack(dsp->ds_wq, mp, DL_UNBIND_REQ, DL_OUTSTATE, 0); - return (B_FALSE); - } + rw_enter(&dsp->ds_lock, RW_WRITER); if (MBLKL(mp) < sizeof (dl_unbind_req_t)) { - dlerrorack(dsp->ds_wq, mp, DL_BIND_REQ, DL_BADPRIM, 0); - return (B_FALSE); + dl_err = DL_BADPRIM; + goto failed; + } + + if (dsp->ds_dlstate != DL_IDLE) { + dl_err = DL_OUTSTATE; + goto failed; } dsp->ds_dlstate = DL_UNBIND_PENDING; @@ -521,12 +584,7 @@ proto_unbind_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) /* * Flush any remaining packets scheduled for transmission. */ - flushq(dsp->ds_wq, FLUSHALL); - - /* - * Reset the M_DATA handler. - */ - dld_str_tx_drop(dsp); + dld_tx_flush(dsp); /* * Unbind the channel to stop packets being received. @@ -548,8 +606,15 @@ proto_unbind_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) */ dsp->ds_mode = DLD_UNITDATA; - proto_unbind_ack(dsp, mp); + dsp->ds_dlstate = DL_UNBOUND; + rw_exit(&dsp->ds_lock); + + dlokack(q, mp, DL_UNBIND_REQ); return (B_TRUE); +failed: + rw_exit(&dsp->ds_lock); + dlerrorack(q, mp, DL_UNBIND_REQ, dl_err, 0); + return (B_FALSE); } /* @@ -558,22 +623,26 @@ proto_unbind_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) static boolean_t proto_promiscon_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) { - dl_promiscon_req_t *dlp = (dl_promiscon_req_t *)udlp; - int err; + dl_promiscon_req_t *dlp = (dl_promiscon_req_t *)udlp; + int err = 0; + t_uscalar_t dl_err; + uint32_t promisc_saved; + queue_t *q = dsp->ds_wq; - ASSERT(PERIM_EXCL(dsp->ds_wq)); + if (MBLKL(mp) < sizeof (dl_promiscon_req_t)) { + dl_err = DL_BADPRIM; + goto failed; + } + + rw_enter(&dsp->ds_lock, RW_WRITER); if (dsp->ds_dlstate == DL_UNATTACHED || DL_ACK_PENDING(dsp->ds_dlstate)) { - dlerrorack(dsp->ds_wq, mp, DL_PROMISCON_REQ, DL_OUTSTATE, 0); - return (B_FALSE); - } - - if (MBLKL(mp) < sizeof (dl_promiscon_req_t)) { - dlerrorack(dsp->ds_wq, mp, DL_PROMISCON_REQ, DL_BADPRIM, 0); - return (B_FALSE); + dl_err = DL_OUTSTATE; + goto failed; } + promisc_saved = dsp->ds_promisc; switch (dlp->dl_level) { case DL_PROMISC_SAP: dsp->ds_promisc |= DLS_PROMISC_SAP; @@ -588,17 +657,41 @@ proto_promiscon_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) break; default: - dlerrorack(dsp->ds_wq, mp, DL_PROMISCON_REQ, DL_NOTSUPPORTED, - 0); - return (B_FALSE); + dl_err = DL_NOTSUPPORTED; + goto failed; + } + + if (dsp->ds_passivestate == DLD_UNINITIALIZED && + !dls_active_set(dsp->ds_dc)) { + dsp->ds_promisc = promisc_saved; + dl_err = DL_SYSERR; + err = EBUSY; + goto failed; } /* * Adjust channel promiscuity. */ err = dls_promisc(dsp->ds_dc, dsp->ds_promisc); - proto_promiscon_ack(dsp, mp, err); - return (err == 0); + if (err != 0) { + dl_err = DL_SYSERR; + dsp->ds_promisc = promisc_saved; + if (dsp->ds_passivestate == DLD_UNINITIALIZED) + dls_active_clear(dsp->ds_dc); + + goto failed; + } + + if (dsp->ds_passivestate == DLD_UNINITIALIZED) + dsp->ds_passivestate = DLD_ACTIVE; + + rw_exit(&dsp->ds_lock); + dlokack(q, mp, DL_PROMISCON_REQ); + return (B_TRUE); +failed: + rw_exit(&dsp->ds_lock); + dlerrorack(q, mp, DL_PROMISCON_REQ, dl_err, (t_uscalar_t)err); + return (B_FALSE); } /* @@ -607,60 +700,73 @@ proto_promiscon_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) static boolean_t proto_promiscoff_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) { - dl_promiscoff_req_t *dlp = (dl_promiscoff_req_t *)udlp; - int err; + dl_promiscoff_req_t *dlp = (dl_promiscoff_req_t *)udlp; + int err = 0; + t_uscalar_t dl_err; + uint32_t promisc_saved; + queue_t *q = dsp->ds_wq; - ASSERT(PERIM_EXCL(dsp->ds_wq)); - if (dsp->ds_dlstate == DL_UNATTACHED || - DL_ACK_PENDING(dsp->ds_dlstate)) { - dlerrorack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ, DL_OUTSTATE, 0); - return (B_FALSE); + if (MBLKL(mp) < sizeof (dl_promiscoff_req_t)) { + dl_err = DL_BADPRIM; + goto failed; } - if (MBLKL(mp) < sizeof (dl_promiscoff_req_t)) { - dlerrorack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ, DL_BADPRIM, 0); - return (B_FALSE); + rw_enter(&dsp->ds_lock, RW_WRITER); + + if (dsp->ds_dlstate == DL_UNATTACHED || + DL_ACK_PENDING(dsp->ds_dlstate)) { + dl_err = DL_OUTSTATE; + goto failed; } + promisc_saved = dsp->ds_promisc; switch (dlp->dl_level) { case DL_PROMISC_SAP: - if (!(dsp->ds_promisc & DLS_PROMISC_SAP)) - goto notenab; - + if (!(dsp->ds_promisc & DLS_PROMISC_SAP)) { + dl_err = DL_NOTENAB; + goto failed; + } dsp->ds_promisc &= ~DLS_PROMISC_SAP; break; case DL_PROMISC_MULTI: - if (!(dsp->ds_promisc & DLS_PROMISC_MULTI)) - goto notenab; - + if (!(dsp->ds_promisc & DLS_PROMISC_MULTI)) { + dl_err = DL_NOTENAB; + goto failed; + } dsp->ds_promisc &= ~DLS_PROMISC_MULTI; break; case DL_PROMISC_PHYS: - if (!(dsp->ds_promisc & DLS_PROMISC_PHYS)) - goto notenab; - + if (!(dsp->ds_promisc & DLS_PROMISC_PHYS)) { + dl_err = DL_NOTENAB; + goto failed; + } dsp->ds_promisc &= ~DLS_PROMISC_PHYS; break; default: - dlerrorack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ, DL_NOTSUPPORTED, - 0); - return (B_FALSE); + dl_err = DL_NOTSUPPORTED; + goto failed; } /* * Adjust channel promiscuity. */ err = dls_promisc(dsp->ds_dc, dsp->ds_promisc); + if (err != 0) { + dsp->ds_promisc = promisc_saved; + dl_err = DL_SYSERR; + goto failed; + } - proto_promiscoff_ack(dsp, mp, err); - return (err == 0); - -notenab: - dlerrorack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ, DL_NOTENAB, 0); + rw_exit(&dsp->ds_lock); + dlokack(q, mp, DL_PROMISCOFF_REQ); + return (B_TRUE); +failed: + rw_exit(&dsp->ds_lock); + dlerrorack(q, mp, DL_PROMISCOFF_REQ, dl_err, (t_uscalar_t)err); return (B_FALSE); } @@ -670,27 +776,64 @@ notenab: static boolean_t proto_enabmulti_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) { - dl_enabmulti_req_t *dlp = (dl_enabmulti_req_t *)udlp; - int err; + dl_enabmulti_req_t *dlp = (dl_enabmulti_req_t *)udlp; + int err = 0; + t_uscalar_t dl_err; + queue_t *q = dsp->ds_wq; - ASSERT(PERIM_EXCL(dsp->ds_wq)); + rw_enter(&dsp->ds_lock, RW_WRITER); if (dsp->ds_dlstate == DL_UNATTACHED || DL_ACK_PENDING(dsp->ds_dlstate)) { - dlerrorack(dsp->ds_wq, mp, DL_ENABMULTI_REQ, DL_OUTSTATE, 0); - return (B_FALSE); + dl_err = DL_OUTSTATE; + goto failed; } if (MBLKL(mp) < sizeof (dl_enabmulti_req_t) || !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) || dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) { - dlerrorack(dsp->ds_wq, mp, DL_ENABMULTI_REQ, DL_BADPRIM, 0); - return (B_FALSE); + dl_err = DL_BADPRIM; + goto failed; + } + + if (dsp->ds_passivestate == DLD_UNINITIALIZED && + !dls_active_set(dsp->ds_dc)) { + dl_err = DL_SYSERR; + err = EBUSY; + goto failed; } err = dls_multicst_add(dsp->ds_dc, mp->b_rptr + dlp->dl_addr_offset); - proto_enabmulti_ack(dsp, mp, err); - return (err == 0); + if (err != 0) { + switch (err) { + case EINVAL: + dl_err = DL_BADADDR; + err = 0; + break; + case ENOSPC: + dl_err = DL_TOOMANY; + err = 0; + break; + default: + dl_err = DL_SYSERR; + break; + } + if (dsp->ds_passivestate == DLD_UNINITIALIZED) + dls_active_clear(dsp->ds_dc); + + goto failed; + } + + if (dsp->ds_passivestate == DLD_UNINITIALIZED) + dsp->ds_passivestate = DLD_ACTIVE; + + rw_exit(&dsp->ds_lock); + dlokack(q, mp, DL_ENABMULTI_REQ); + return (B_TRUE); +failed: + rw_exit(&dsp->ds_lock); + dlerrorack(q, mp, DL_ENABMULTI_REQ, dl_err, (t_uscalar_t)err); + return (B_FALSE); } /* @@ -699,27 +842,53 @@ proto_enabmulti_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) static boolean_t proto_disabmulti_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) { - dl_disabmulti_req_t *dlp = (dl_disabmulti_req_t *)udlp; - int err; + dl_disabmulti_req_t *dlp = (dl_disabmulti_req_t *)udlp; + int err = 0; + t_uscalar_t dl_err; + queue_t *q = dsp->ds_wq; - ASSERT(PERIM_EXCL(dsp->ds_wq)); + rw_enter(&dsp->ds_lock, RW_READER); if (dsp->ds_dlstate == DL_UNATTACHED || DL_ACK_PENDING(dsp->ds_dlstate)) { - dlerrorack(dsp->ds_wq, mp, DL_DISABMULTI_REQ, DL_OUTSTATE, 0); - return (B_FALSE); + dl_err = DL_OUTSTATE; + goto failed; } if (MBLKL(mp) < sizeof (dl_disabmulti_req_t) || !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) || dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) { - dlerrorack(dsp->ds_wq, mp, DL_DISABMULTI_REQ, DL_BADPRIM, 0); - return (B_FALSE); + dl_err = DL_BADPRIM; + goto failed; } err = dls_multicst_remove(dsp->ds_dc, mp->b_rptr + dlp->dl_addr_offset); - proto_disabmulti_ack(dsp, mp, err); - return (err == 0); + if (err != 0) { + switch (err) { + case EINVAL: + dl_err = DL_BADADDR; + err = 0; + break; + + case ENOENT: + dl_err = DL_NOTENAB; + err = 0; + break; + + default: + dl_err = DL_SYSERR; + break; + } + goto failed; + } + + rw_exit(&dsp->ds_lock); + dlokack(q, mp, DL_DISABMULTI_REQ); + return (B_TRUE); +failed: + rw_exit(&dsp->ds_lock); + dlerrorack(q, mp, DL_DISABMULTI_REQ, dl_err, (t_uscalar_t)err); + return (B_FALSE); } /* @@ -728,27 +897,54 @@ proto_disabmulti_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) static boolean_t proto_physaddr_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) { - dl_phys_addr_req_t *dlp = (dl_phys_addr_req_t *)udlp; + dl_phys_addr_req_t *dlp = (dl_phys_addr_req_t *)udlp; + queue_t *q = dsp->ds_wq; + t_uscalar_t dl_err; + char *addr; + uint_t addr_length; - if (dsp->ds_dlstate == DL_UNATTACHED || - DL_ACK_PENDING(dsp->ds_dlstate)) { - dlerrorack(dsp->ds_wq, mp, DL_PHYS_ADDR_REQ, DL_OUTSTATE, 0); - return (B_FALSE); - } + rw_enter(&dsp->ds_lock, RW_READER); if (MBLKL(mp) < sizeof (dl_phys_addr_req_t)) { - dlerrorack(dsp->ds_wq, mp, DL_PHYS_ADDR_REQ, DL_BADPRIM, 0); - return (B_FALSE); + dl_err = DL_BADPRIM; + goto failed; + } + + if (dsp->ds_dlstate == DL_UNATTACHED || + DL_ACK_PENDING(dsp->ds_dlstate)) { + dl_err = DL_OUTSTATE; + goto failed; } if (dlp->dl_addr_type != DL_CURR_PHYS_ADDR && dlp->dl_addr_type != DL_FACT_PHYS_ADDR) { - dlerrorack(dsp->ds_wq, mp, DL_PHYS_ADDR_REQ, DL_UNSUPPORTED, 0); + dl_err = DL_UNSUPPORTED; + goto failed; + } + + addr_length = dsp->ds_mip->mi_addr_length; + addr = kmem_alloc(addr_length, KM_NOSLEEP); + if (addr == NULL) { + rw_exit(&dsp->ds_lock); + merror(q, mp, ENOSR); return (B_FALSE); } - proto_physaddr_ack(dsp, mp, dlp->dl_addr_type); + /* + * Copy out the address before we drop the lock; we don't + * want to call dlphysaddrack() while holding ds_lock. + */ + bcopy((dlp->dl_addr_type == DL_CURR_PHYS_ADDR) ? + dsp->ds_curr_addr : dsp->ds_fact_addr, addr, addr_length); + + rw_exit(&dsp->ds_lock); + dlphysaddrack(q, mp, addr, (t_uscalar_t)addr_length); + kmem_free(addr, addr_length); return (B_TRUE); +failed: + rw_exit(&dsp->ds_lock); + dlerrorack(q, mp, DL_PHYS_ADDR_REQ, dl_err, 0); + return (B_FALSE); } /* @@ -757,29 +953,60 @@ proto_physaddr_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) static boolean_t proto_setphysaddr_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) { - dl_set_phys_addr_req_t *dlp = (dl_set_phys_addr_req_t *)udlp; - int err; + dl_set_phys_addr_req_t *dlp = (dl_set_phys_addr_req_t *)udlp; + int err = 0; + t_uscalar_t dl_err; + queue_t *q = dsp->ds_wq; - ASSERT(PERIM_EXCL(dsp->ds_wq)); + rw_enter(&dsp->ds_lock, RW_WRITER); if (dsp->ds_dlstate == DL_UNATTACHED || DL_ACK_PENDING(dsp->ds_dlstate)) { - dlerrorack(dsp->ds_wq, mp, DL_SET_PHYS_ADDR_REQ, DL_OUTSTATE, - 0); - return (B_FALSE); + dl_err = DL_OUTSTATE; + goto failed; } if (MBLKL(mp) < sizeof (dl_set_phys_addr_req_t) || !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) || dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) { - dlerrorack(dsp->ds_wq, mp, DL_SET_PHYS_ADDR_REQ, DL_BADPRIM, - 0); - return (B_FALSE); + dl_err = DL_BADPRIM; + goto failed; + } + + if (dsp->ds_passivestate == DLD_UNINITIALIZED && + !dls_active_set(dsp->ds_dc)) { + dl_err = DL_SYSERR; + err = EBUSY; + goto failed; } err = mac_unicst_set(dsp->ds_mh, mp->b_rptr + dlp->dl_addr_offset); - proto_setphysaddr_ack(dsp, mp, err); - return (err == 0); + if (err != 0) { + switch (err) { + case EINVAL: + dl_err = DL_BADADDR; + err = 0; + break; + + default: + dl_err = DL_SYSERR; + break; + } + if (dsp->ds_passivestate == DLD_UNINITIALIZED) + dls_active_clear(dsp->ds_dc); + + goto failed; + } + if (dsp->ds_passivestate == DLD_UNINITIALIZED) + dsp->ds_passivestate = DLD_ACTIVE; + + rw_exit(&dsp->ds_lock); + dlokack(q, mp, DL_SET_PHYS_ADDR_REQ); + return (B_TRUE); +failed: + rw_exit(&dsp->ds_lock); + dlerrorack(q, mp, DL_SET_PHYS_ADDR_REQ, dl_err, (t_uscalar_t)err); + return (B_FALSE); } /* @@ -788,36 +1015,44 @@ proto_setphysaddr_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) static boolean_t proto_udqos_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) { - dl_udqos_req_t *dlp = (dl_udqos_req_t *)udlp; - dl_qos_cl_sel1_t *selp; - int off, len; - - ASSERT(PERIM_EXCL(dsp->ds_wq)); + dl_udqos_req_t *dlp = (dl_udqos_req_t *)udlp; + dl_qos_cl_sel1_t *selp; + int off, len; + t_uscalar_t dl_err; + queue_t *q = dsp->ds_wq; off = dlp->dl_qos_offset; len = dlp->dl_qos_length; if (MBLKL(mp) < sizeof (dl_udqos_req_t) || !MBLKIN(mp, off, len)) { - dlerrorack(dsp->ds_wq, mp, DL_UDQOS_REQ, DL_BADPRIM, 0); - return (B_FALSE); + dl_err = DL_BADPRIM; + goto failed; } selp = (dl_qos_cl_sel1_t *)(mp->b_rptr + off); if (selp->dl_qos_type != DL_QOS_CL_SEL1) { - dlerrorack(dsp->ds_wq, mp, DL_UDQOS_REQ, DL_BADQOSTYPE, 0); - return (B_FALSE); + dl_err = DL_BADQOSTYPE; + goto failed; } + rw_enter(&dsp->ds_lock, RW_WRITER); + if (dsp->ds_vid == VLAN_ID_NONE || selp->dl_priority > (1 << VLAN_PRI_SIZE) - 1 || selp->dl_priority < 0) { - dlerrorack(dsp->ds_wq, mp, DL_UDQOS_REQ, DL_BADQOSPARAM, 0); - return (B_FALSE); + dl_err = DL_BADQOSPARAM; + goto failed; } dsp->ds_pri = selp->dl_priority; - proto_udqos_ack(dsp, mp); + + rw_exit(&dsp->ds_lock); + dlokack(q, mp, DL_UDQOS_REQ); return (B_TRUE); +failed: + rw_exit(&dsp->ds_lock); + dlerrorack(q, mp, DL_UDQOS_REQ, dl_err, 0); + return (B_FALSE); } /* @@ -827,18 +1062,25 @@ proto_udqos_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) static boolean_t proto_capability_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) { - dl_capability_req_t *dlp = (dl_capability_req_t *)udlp; + dl_capability_req_t *dlp = (dl_capability_req_t *)udlp; + dl_capability_sub_t *sp; + size_t size, len; + offset_t off, end; + t_uscalar_t dl_err; + queue_t *q = dsp->ds_wq; + boolean_t upgraded; - if (dsp->ds_dlstate == DL_UNATTACHED || - DL_ACK_PENDING(dsp->ds_dlstate)) { - dlerrorack(dsp->ds_wq, mp, DL_CAPABILITY_REQ, DL_OUTSTATE, - 0); - return (B_FALSE); - } + rw_enter(&dsp->ds_lock, RW_READER); if (MBLKL(mp) < sizeof (dl_capability_req_t)) { - dlerrorack(dsp->ds_wq, mp, DL_CAPABILITY_REQ, DL_BADPRIM, 0); - return (B_FALSE); + dl_err = DL_BADPRIM; + goto failed; + } + + if (dsp->ds_dlstate == DL_UNATTACHED || + DL_ACK_PENDING(dsp->ds_dlstate)) { + dl_err = DL_OUTSTATE; + goto failed; } /* @@ -847,17 +1089,128 @@ proto_capability_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) * support. Otherwise we enable the set of capabilities requested. */ if (dlp->dl_sub_length == 0) { - proto_capability_ack(dsp, mp); - return (B_TRUE); + /* callee drops lock */ + return (proto_capability_advertise(dsp, mp)); } if (!MBLKIN(mp, dlp->dl_sub_offset, dlp->dl_sub_length)) { - dlerrorack(dsp->ds_wq, mp, DL_CAPABILITY_REQ, DL_BADPRIM, 0); - return (B_FALSE); + dl_err = DL_BADPRIM; + goto failed; } - proto_capability_enable(dsp, mp); + dlp->dl_primitive = DL_CAPABILITY_ACK; + + off = dlp->dl_sub_offset; + len = dlp->dl_sub_length; + + /* + * Walk the list of capabilities to be enabled. + */ + upgraded = B_FALSE; + for (end = off + len; off < end; ) { + sp = (dl_capability_sub_t *)(mp->b_rptr + off); + size = sizeof (dl_capability_sub_t) + sp->dl_length; + + if (off + size > end || + !IS_P2ALIGNED(off, sizeof (uint32_t))) { + dl_err = DL_BADPRIM; + goto failed; + } + + switch (sp->dl_cap) { + /* + * TCP/IP checksum offload to hardware. + */ + case DL_CAPAB_HCKSUM: { + dl_capab_hcksum_t *hcksump; + dl_capab_hcksum_t hcksum; + + ASSERT(dsp->ds_mip->mi_cksum != 0); + + hcksump = (dl_capab_hcksum_t *)&sp[1]; + /* + * Copy for alignment. + */ + bcopy(hcksump, &hcksum, sizeof (dl_capab_hcksum_t)); + dlcapabsetqid(&(hcksum.hcksum_mid), dsp->ds_rq); + bcopy(&hcksum, hcksump, sizeof (dl_capab_hcksum_t)); + break; + } + + /* + * IP polling interface. + */ + case DL_CAPAB_POLL: { + dl_capab_poll_t *pollp; + dl_capab_poll_t poll; + + pollp = (dl_capab_poll_t *)&sp[1]; + /* + * Copy for alignment. + */ + bcopy(pollp, &poll, sizeof (dl_capab_poll_t)); + + /* + * We need to become writer before enabling and/or + * disabling the polling interface. If we couldn' + * upgrade, check state again after re-acquiring the + * lock to make sure we can proceed. + */ + if (!upgraded && !rw_tryupgrade(&dsp->ds_lock)) { + rw_exit(&dsp->ds_lock); + rw_enter(&dsp->ds_lock, RW_WRITER); + + if (dsp->ds_dlstate == DL_UNATTACHED || + DL_ACK_PENDING(dsp->ds_dlstate)) { + dl_err = DL_OUTSTATE; + goto failed; + } + } + upgraded = B_TRUE; + + switch (poll.poll_flags) { + default: + /*FALLTHRU*/ + case POLL_DISABLE: + proto_poll_disable(dsp); + break; + + case POLL_ENABLE: + ASSERT(!(dld_opt & DLD_OPT_NO_POLL)); + + /* + * Make sure polling is disabled. + */ + proto_poll_disable(dsp); + + /* + * Now attempt enable it. + */ + if (!proto_poll_enable(dsp, &poll)) + break; + + bzero(&poll, sizeof (dl_capab_poll_t)); + poll.poll_flags = POLL_ENABLE; + break; + } + + dlcapabsetqid(&(poll.poll_mid), dsp->ds_rq); + bcopy(&poll, pollp, sizeof (dl_capab_poll_t)); + break; + } + default: + break; + } + + off += size; + } + rw_exit(&dsp->ds_lock); + qreply(q, mp); return (B_TRUE); +failed: + rw_exit(&dsp->ds_lock); + dlerrorack(q, mp, DL_CAPABILITY_REQ, dl_err, 0); + return (B_FALSE); } /* @@ -866,8 +1219,10 @@ proto_capability_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) static boolean_t proto_notify_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) { - dl_notify_req_t *dlp = (dl_notify_req_t *)udlp; - uint_t notifications = + dl_notify_req_t *dlp = (dl_notify_req_t *)udlp; + t_uscalar_t dl_err; + queue_t *q = dsp->ds_wq; + uint_t note = DL_NOTE_PROMISC_ON_PHYS | DL_NOTE_PROMISC_OFF_PHYS | DL_NOTE_PHYS_ADDR | @@ -875,24 +1230,47 @@ proto_notify_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) DL_NOTE_LINK_DOWN | DL_NOTE_CAPAB_RENEG; - if (dsp->ds_dlstate == DL_UNATTACHED || - DL_ACK_PENDING(dsp->ds_dlstate)) { - dlerrorack(dsp->ds_wq, mp, DL_NOTIFY_REQ, DL_OUTSTATE, - 0); - return (B_FALSE); + if (MBLKL(mp) < sizeof (dl_notify_req_t)) { + dl_err = DL_BADPRIM; + goto failed; } - if (MBLKL(mp) < sizeof (dl_notify_req_t)) { - dlerrorack(dsp->ds_wq, mp, DL_NOTIFY_REQ, DL_BADPRIM, 0); - return (B_FALSE); + rw_enter(&dsp->ds_lock, RW_WRITER); + if (dsp->ds_dlstate == DL_UNATTACHED || + DL_ACK_PENDING(dsp->ds_dlstate)) { + dl_err = DL_OUTSTATE; + goto failed; } if (dsp->ds_mip->mi_stat[MAC_STAT_IFSPEED]) - notifications |= DL_NOTE_SPEED; + note |= DL_NOTE_SPEED; - proto_notify_ack(dsp, mp, dlp->dl_notifications & notifications, - notifications); + /* + * Cache the notifications that are being enabled. + */ + dsp->ds_notifications = dlp->dl_notifications & note; + rw_exit(&dsp->ds_lock); + /* + * The ACK carries all notifications regardless of which set is + * being enabled. + */ + dlnotifyack(q, mp, note); + + /* + * Solicit DL_NOTIFY_IND messages for each enabled notification. + */ + rw_enter(&dsp->ds_lock, RW_READER); + if (dsp->ds_notifications != 0) { + rw_exit(&dsp->ds_lock); + dld_str_notify_ind(dsp); + } else { + rw_exit(&dsp->ds_lock); + } return (B_TRUE); +failed: + rw_exit(&dsp->ds_lock); + dlerrorack(q, mp, DL_NOTIFY_REQ, dl_err, 0); + return (B_FALSE); } /* @@ -904,40 +1282,39 @@ proto_unitdata_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) queue_t *q = dsp->ds_wq; dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)udlp; off_t off; - size_t len; - size_t size; + size_t len, size; const uint8_t *addr; uint16_t sap; uint_t addr_length; - mblk_t *bp; - mblk_t *cont; - uint32_t start; - uint32_t stuff; - uint32_t end; - uint32_t value; - uint32_t flags; + mblk_t *bp, *cont; + uint32_t start, stuff, end, value, flags; + t_uscalar_t dl_err; - if (dsp->ds_dlstate != DL_IDLE) { - dlerrorack(q, mp, DL_UNITDATA_REQ, DL_OUTSTATE, 0); - return (B_FALSE); - } + rw_enter(&dsp->ds_lock, RW_READER); if (MBLKL(mp) < sizeof (dl_unitdata_req_t) || mp->b_cont == NULL) { - dlerrorack(q, mp, DL_UNITDATA_REQ, DL_BADPRIM, 0); - return (B_FALSE); + dl_err = DL_BADPRIM; + goto failed; + } + + if (dsp->ds_dlstate != DL_IDLE) { + dl_err = DL_OUTSTATE; + goto failed; } + addr_length = dsp->ds_mip->mi_addr_length; off = dlp->dl_dest_addr_offset; len = dlp->dl_dest_addr_length; if (!MBLKIN(mp, off, len) || !IS_P2ALIGNED(off, sizeof (uint16_t))) { - dlerrorack(q, mp, DL_UNITDATA_REQ, DL_BADPRIM, 0); - return (B_FALSE); + dl_err = DL_BADPRIM; + goto failed; } - addr_length = dsp->ds_mip->mi_addr_length; - if (len != addr_length + sizeof (uint16_t)) - goto badaddr; + if (len != addr_length + sizeof (uint16_t)) { + dl_err = DL_BADADDR; + goto failed; + } addr = mp->b_rptr + off; sap = *(uint16_t *)(mp->b_rptr + off + addr_length); @@ -960,8 +1337,10 @@ proto_unitdata_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) /* * Build a packet header. */ - if ((bp = dls_header(dsp->ds_dc, addr, sap, dsp->ds_pri)) == NULL) - goto badaddr; + if ((bp = dls_header(dsp->ds_dc, addr, sap, dsp->ds_pri)) == NULL) { + dl_err = DL_BADADDR; + goto failed; + } /* * We no longer need the M_PROTO header, so free it. @@ -982,33 +1361,16 @@ proto_unitdata_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) ASSERT(bp->b_cont == NULL); bp->b_cont = cont; - /* - * If something is already queued then we must queue to avoid - * re-ordering. - */ - if (q->q_first != NULL) { - (void) putq(q, bp); - return (B_TRUE); - } - - /* - * Attempt to transmit the packet. - */ - if ((mp = dls_tx(dsp->ds_dc, bp)) != NULL) { - noenable(q); - while ((bp = mp) != NULL) { - mp = mp->b_next; - bp->b_next = NULL; - (void) putq(q, bp); - } - } + str_mdata_fastpath_put(dsp, bp); + rw_exit(&dsp->ds_lock); return (B_TRUE); - -badaddr: - dlerrorack(q, mp, DL_UNITDATA_REQ, DL_BADADDR, 0); +failed: + rw_exit(&dsp->ds_lock); + dlerrorack(q, mp, DL_UNITDATA_REQ, dl_err, 0); return (B_FALSE); baddata: + rw_exit(&dsp->ds_lock); dluderrorind(q, mp, (void *)addr, len, DL_BADDATA, 0); return (B_FALSE); } @@ -1020,27 +1382,34 @@ baddata: static boolean_t proto_passive_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) { - ASSERT(PERIM_EXCL(dsp->ds_wq)); + t_uscalar_t dl_err; + rw_enter(&dsp->ds_lock, RW_WRITER); /* * If we've already become active by issuing an active primitive, * then it's too late to try to become passive. */ if (dsp->ds_passivestate == DLD_ACTIVE) { - dlerrorack(dsp->ds_wq, mp, DL_PASSIVE_REQ, DL_OUTSTATE, 0); - return (B_FALSE); + dl_err = DL_OUTSTATE; + goto failed; } if (MBLKL(mp) < sizeof (dl_passive_req_t)) { - dlerrorack(dsp->ds_wq, mp, DL_PASSIVE_REQ, DL_BADPRIM, 0); - return (B_FALSE); + dl_err = DL_BADPRIM; + goto failed; } dsp->ds_passivestate = DLD_PASSIVE; + rw_exit(&dsp->ds_lock); dlokack(dsp->ds_wq, mp, DL_PASSIVE_REQ); return (B_TRUE); +failed: + rw_exit(&dsp->ds_lock); + dlerrorack(dsp->ds_wq, mp, DL_PASSIVE_REQ, dl_err, 0); + return (B_FALSE); } + /* * Catch-all handler. */ @@ -1051,440 +1420,13 @@ proto_req(dld_str_t *dsp, union DL_primitives *dlp, mblk_t *mp) return (B_FALSE); } -typedef struct dl_info_ack_wrapper { - dl_info_ack_t dl_info; - uint8_t dl_addr[MAXADDRLEN + sizeof (uint16_t)]; - uint8_t dl_brdcst_addr[MAXADDRLEN]; - dl_qos_cl_range1_t dl_qos_range1; - dl_qos_cl_sel1_t dl_qos_sel1; -} dl_info_ack_wrapper_t; - -#define NEG(x) -(x) - -/* - * DL_INFO_ACK - */ -static void -proto_info_ack(dld_str_t *dsp, mblk_t *mp) -{ - dl_info_ack_wrapper_t *dlwp; - dl_info_ack_t *dlp; - dl_qos_cl_sel1_t *selp; - dl_qos_cl_range1_t *rangep; - uint8_t *addr; - uint8_t *brdcst_addr; - dld_node_t *dnp; - uint_t addr_length; - uint_t sap_length; - - /* - * Swap the request message for one large enough to contain the - * wrapper structure defined above. - */ - if ((mp = mexchange(dsp->ds_wq, mp, sizeof (dl_info_ack_wrapper_t), - M_PCPROTO, 0)) == NULL) - return; - - bzero(mp->b_rptr, sizeof (dl_info_ack_wrapper_t)); - dlwp = (dl_info_ack_wrapper_t *)mp->b_rptr; - - dlp = &(dlwp->dl_info); - ASSERT(dlp == (dl_info_ack_t *)mp->b_rptr); - - dlp->dl_primitive = DL_INFO_ACK; - - /* - * Set up the sub-structure pointers. - */ - addr = dlwp->dl_addr; - brdcst_addr = dlwp->dl_brdcst_addr; - rangep = &(dlwp->dl_qos_range1); - selp = &(dlwp->dl_qos_sel1); - - /* - * This driver supports only version 2 connectionless DLPI provider - * nodes. - */ - dlp->dl_service_mode = DL_CLDLS; - dlp->dl_version = DL_VERSION_2; - - /* - * Set the style of the provider from the dld_node_t structure - * representing the dev_t that was opened. - */ - dnp = dsp->ds_dnp; - dlp->dl_provider_style = dnp->dn_style; - ASSERT(dlp->dl_provider_style == DL_STYLE1 || - dlp->dl_provider_style == DL_STYLE2); - - /* - * Set the current DLPI state. - */ - dlp->dl_current_state = dsp->ds_dlstate; - - /* - * Gratuitously set the media type. This is because the Cisco VPN 3000 - * module assumes that the media type is known prior to DL_ATTACH_REQ - * being completed. - */ - dlp->dl_mac_type = DL_ETHER; - - /* - * If the stream is not at least attached then we're done. - */ - if (dsp->ds_dlstate == DL_UNATTACHED || - dsp->ds_dlstate == DL_ATTACH_PENDING || - dsp->ds_dlstate == DL_DETACH_PENDING) - goto done; - - /* - * Set the media type (properly this time). - */ - dlp->dl_mac_type = dsp->ds_mip->mi_media; - - /* - * Set the DLSAP length. We only support 16 bit values and they - * appear after the MAC address portion of DLSAP addresses. - */ - sap_length = sizeof (uint16_t); - dlp->dl_sap_length = NEG(sap_length); - - /* - * Set the minimum and maximum payload sizes. - */ - dlp->dl_min_sdu = dsp->ds_mip->mi_sdu_min; - dlp->dl_max_sdu = dsp->ds_mip->mi_sdu_max; - - addr_length = dsp->ds_mip->mi_addr_length; - ASSERT(addr_length != 0); - - /* - * Copy in the media broadcast address. - */ - dlp->dl_brdcst_addr_offset = (uintptr_t)brdcst_addr - (uintptr_t)dlp; - bcopy(dsp->ds_mip->mi_brdcst_addr, brdcst_addr, addr_length); - dlp->dl_brdcst_addr_length = addr_length; - - /* - * We only support QoS information for VLAN interfaces. - */ - if (dsp->ds_vid != VLAN_ID_NONE) { - dlp->dl_qos_range_offset = (uintptr_t)rangep - (uintptr_t)dlp; - dlp->dl_qos_range_length = sizeof (dl_qos_cl_range1_t); - - rangep->dl_qos_type = DL_QOS_CL_RANGE1; - rangep->dl_trans_delay.dl_target_value = DL_UNKNOWN; - rangep->dl_trans_delay.dl_accept_value = DL_UNKNOWN; - rangep->dl_protection.dl_min = DL_UNKNOWN; - rangep->dl_protection.dl_max = DL_UNKNOWN; - rangep->dl_residual_error = DL_UNKNOWN; - - /* - * Specify the supported range of priorities. - */ - rangep->dl_priority.dl_min = 0; - rangep->dl_priority.dl_max = (1 << VLAN_PRI_SIZE) - 1; - - dlp->dl_qos_offset = (uintptr_t)selp - (uintptr_t)dlp; - dlp->dl_qos_length = sizeof (dl_qos_cl_sel1_t); - - selp->dl_qos_type = DL_QOS_CL_SEL1; - selp->dl_trans_delay = DL_UNKNOWN; - selp->dl_protection = DL_UNKNOWN; - selp->dl_residual_error = DL_UNKNOWN; - - /* - * Specify the current priority (which can be changed by - * the DL_UDQOS_REQ primitive). - */ - selp->dl_priority = dsp->ds_pri; - } else { - /* - * Shorten the buffer to lose the unused QoS information - * structures. This is to work around a bug in the Cisco VPN - * 3000 module. - */ - mp->b_wptr = (uint8_t *)rangep; - } - - dlp->dl_addr_length = addr_length + sizeof (uint16_t); - if (dsp->ds_dlstate == DL_IDLE) { - /* - * The stream is bound. Therefore we can formulate a valid - * DLSAP address. - */ - dlp->dl_addr_offset = (uintptr_t)addr - (uintptr_t)dlp; - bcopy(dsp->ds_curr_addr, addr, addr_length); - *(uint16_t *)(addr + addr_length) = dsp->ds_sap; - } - -done: - ASSERT(IMPLY(dlp->dl_qos_offset != 0, dlp->dl_qos_length != 0)); - ASSERT(IMPLY(dlp->dl_qos_range_offset != 0, - dlp->dl_qos_range_length != 0)); - ASSERT(IMPLY(dlp->dl_addr_offset != 0, dlp->dl_addr_length != 0)); - ASSERT(IMPLY(dlp->dl_brdcst_addr_offset != 0, - dlp->dl_brdcst_addr_length != 0)); - - qreply(dsp->ds_wq, mp); -} - -/* - * DL_OK_ACK/DL_ERROR_ACK - */ -static void -proto_attach_ack(dld_str_t *dsp, mblk_t *mp, int err) -{ - int dl_err; - - if (err != 0) - goto failed; - - dsp->ds_dlstate = DL_UNBOUND; - dlokack(dsp->ds_wq, mp, DL_ATTACH_REQ); - return; - -failed: - switch (err) { - case ENOENT: - dl_err = DL_BADPPA; - err = 0; - break; - - default: - dl_err = DL_SYSERR; - break; - } - - dsp->ds_dlstate = DL_UNATTACHED; - dlerrorack(dsp->ds_wq, mp, DL_ATTACH_REQ, dl_err, err); -} - -/* - * DL_OK_ACK - */ -static void -proto_detach_ack(dld_str_t *dsp, mblk_t *mp) -{ - dsp->ds_dlstate = DL_UNATTACHED; - dlokack(dsp->ds_wq, mp, DL_DETACH_REQ); -} - -/* - * DL_BIND_ACK/DL_ERROR_ACK - */ -static void -proto_bind_ack(dld_str_t *dsp, mblk_t *mp, int err) -{ - uint8_t addr[MAXADDRLEN]; - uint_t addr_length; - int dl_err; - - if (err != 0) - goto failed; - - /* - * Copy in MAC address. - */ - addr_length = dsp->ds_mip->mi_addr_length; - bcopy(dsp->ds_curr_addr, addr, addr_length); - - /* - * Copy in the DLSAP. - */ - *(uint16_t *)(addr + addr_length) = dsp->ds_sap; - addr_length += sizeof (uint16_t); - - dsp->ds_dlstate = DL_IDLE; - dlbindack(dsp->ds_wq, mp, dsp->ds_sap, (void *)addr, addr_length, 0, - 0); - return; - -failed: - switch (err) { - case EINVAL: - dl_err = DL_BADADDR; - err = 0; - break; - - default: - dl_err = DL_SYSERR; - break; - } - - dsp->ds_dlstate = DL_UNBOUND; - dlerrorack(dsp->ds_wq, mp, DL_BIND_REQ, dl_err, err); -} - -/* - * DL_OK_ACK - */ -static void -proto_unbind_ack(dld_str_t *dsp, mblk_t *mp) -{ - dsp->ds_dlstate = DL_UNBOUND; - dlokack(dsp->ds_wq, mp, DL_UNBIND_REQ); -} - -/* - * DL_OK_ACK/DL_ERROR_ACK - */ -static void -proto_promiscon_ack(dld_str_t *dsp, mblk_t *mp, int err) -{ - if (err != 0) - goto failed; - - dlokack(dsp->ds_wq, mp, DL_PROMISCON_REQ); - return; - -failed: - dlerrorack(dsp->ds_wq, mp, DL_PROMISCON_REQ, DL_SYSERR, err); -} - -/* - * DL_OK_ACK/DL_ERROR_ACK - */ -static void -proto_promiscoff_ack(dld_str_t *dsp, mblk_t *mp, int err) -{ - if (err != 0) - goto failed; - - dlokack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ); - return; - -failed: - dlerrorack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ, DL_SYSERR, err); -} - -/* - * DL_OK_ACK/DL_ERROR_ACK - */ -static void -proto_enabmulti_ack(dld_str_t *dsp, mblk_t *mp, int err) -{ - int dl_err; - - if (err != 0) - goto failed; - - dlokack(dsp->ds_wq, mp, DL_ENABMULTI_REQ); - return; - -failed: - switch (err) { - case EINVAL: - dl_err = DL_BADADDR; - err = 0; - break; - - case ENOSPC: - dl_err = DL_TOOMANY; - err = 0; - break; - - default: - dl_err = DL_SYSERR; - break; - } - - dlerrorack(dsp->ds_wq, mp, DL_ENABMULTI_REQ, dl_err, err); -} - -/* - * DL_OK_ACK/DL_ERROR_ACK - */ -static void -proto_disabmulti_ack(dld_str_t *dsp, mblk_t *mp, int err) -{ - int dl_err; - - if (err != 0) - goto failed; - - dlokack(dsp->ds_wq, mp, DL_DISABMULTI_REQ); - return; - -failed: - switch (err) { - case EINVAL: - dl_err = DL_BADADDR; - err = 0; - break; - - case ENOENT: - dl_err = DL_NOTENAB; - err = 0; - break; - - default: - dl_err = DL_SYSERR; - break; - } - - dlerrorack(dsp->ds_wq, mp, DL_DISABMULTI_REQ, dl_err, err); -} - -/* - * DL_PHYS_ADDR_ACK - */ -static void -proto_physaddr_ack(dld_str_t *dsp, mblk_t *mp, t_uscalar_t type) -{ - uint_t addr_length; - - /* - * Copy in the address. - */ - addr_length = dsp->ds_mip->mi_addr_length; - dlphysaddrack(dsp->ds_wq, mp, (type == DL_CURR_PHYS_ADDR) ? - dsp->ds_curr_addr : dsp->ds_fact_addr, addr_length); -} - -/* - * DL_OK_ACK/DL_ERROR_ACK - */ -static void -proto_setphysaddr_ack(dld_str_t *dsp, mblk_t *mp, int err) -{ - int dl_err; - - if (err != 0) - goto failed; - - dlokack(dsp->ds_wq, mp, DL_SET_PHYS_ADDR_REQ); - return; - -failed: - switch (err) { - case EINVAL: - dl_err = DL_BADADDR; - err = 0; - break; - - default: - dl_err = DL_SYSERR; - break; - } - - dlerrorack(dsp->ds_wq, mp, DL_SET_PHYS_ADDR_REQ, dl_err, err); -} - -/* - * DL_OK_ACK - */ -static void -proto_udqos_ack(dld_str_t *dsp, mblk_t *mp) -{ - dlokack(dsp->ds_wq, mp, DL_UDQOS_REQ); -} - static void proto_poll_disable(dld_str_t *dsp) { mac_handle_t mh; + ASSERT(RW_WRITE_HELD(&dsp->ds_lock)); + if (!dsp->ds_polling) return; @@ -1516,6 +1458,7 @@ proto_poll_enable(dld_str_t *dsp, dl_capab_poll_t *pollp) { mac_handle_t mh; + ASSERT(RW_WRITE_HELD(&dsp->ds_lock)); ASSERT(!dsp->ds_polling); /* @@ -1551,8 +1494,8 @@ proto_poll_enable(dld_str_t *dsp, dl_capab_poll_t *pollp) /* * DL_CAPABILITY_ACK/DL_ERROR_ACK */ -static void -proto_capability_ack(dld_str_t *dsp, mblk_t *mp) +static boolean_t +proto_capability_advertise(dld_str_t *dsp, mblk_t *mp) { dl_capability_ack_t *dlap; dl_capability_sub_t *dlsp; @@ -1563,6 +1506,10 @@ proto_capability_ack(dld_str_t *dsp, mblk_t *mp) uint8_t *ptr; uint32_t cksum; boolean_t poll_cap; + queue_t *q = dsp->ds_wq; + mblk_t *mp1; + + ASSERT(RW_READ_HELD(&dsp->ds_lock)); /* * Initially assume no capabilities. @@ -1600,19 +1547,20 @@ proto_capability_ack(dld_str_t *dsp, mblk_t *mp) } /* - * If there are no capabilities to advertise, send a DL_ERROR_ACK. + * If there are no capabilities to advertise or if we + * can't allocate a response, send a DL_ERROR_ACK. */ - if (subsize == 0) { - dlerrorack(dsp->ds_wq, mp, DL_CAPABILITY_REQ, DL_NOTSUPPORTED, - 0); - return; + if (subsize == 0 || (mp1 = reallocb(mp, + sizeof (dl_capability_ack_t) + subsize, 0)) == NULL) { + rw_exit(&dsp->ds_lock); + dlerrorack(q, mp, DL_CAPABILITY_REQ, DL_NOTSUPPORTED, 0); + return (B_FALSE); } - if ((mp = mexchange(dsp->ds_wq, mp, - sizeof (dl_capability_ack_t) + subsize, M_PROTO, 0)) == NULL) - return; - - bzero(mp->b_rptr, sizeof (dl_capability_ack_t)); + mp = mp1; + DB_TYPE(mp) = M_PROTO; + mp->b_wptr = mp->b_rptr + sizeof (dl_capability_ack_t) + subsize; + bzero(mp->b_rptr, MBLKL(mp)); dlap = (dl_capability_ack_t *)mp->b_rptr; dlap->dl_primitive = DL_CAPABILITY_ACK; dlap->dl_sub_offset = sizeof (dl_capability_ack_t); @@ -1624,27 +1572,58 @@ proto_capability_ack(dld_str_t *dsp, mblk_t *mp) */ if (poll_cap) { /* - * Attempt to disable just in case this is a re-negotiation. + * Attempt to disable just in case this is a re-negotiation; + * we need to become writer before doing so. */ - proto_poll_disable(dsp); + if (!rw_tryupgrade(&dsp->ds_lock)) { + rw_exit(&dsp->ds_lock); + rw_enter(&dsp->ds_lock, RW_WRITER); + } - dlsp = (dl_capability_sub_t *)ptr; + /* + * Check if polling state has changed after we re-acquired + * the lock above, so that we don't mis-advertise it. + */ + poll_cap = ((dsp->ds_mip->mi_poll & DL_CAPAB_POLL) && + !(dld_opt & DLD_OPT_NO_POLL) && + (dsp->ds_vid == VLAN_ID_NONE)); - dlsp->dl_cap = DL_CAPAB_POLL; - dlsp->dl_length = sizeof (dl_capab_poll_t); - ptr += sizeof (dl_capability_sub_t); + if (!poll_cap) { + int poll_capab_size; + + rw_downgrade(&dsp->ds_lock); + + poll_capab_size = sizeof (dl_capability_sub_t) + + sizeof (dl_capab_poll_t); + + mp->b_wptr -= poll_capab_size; + subsize -= poll_capab_size; + dlap->dl_sub_length = subsize; + } else { + proto_poll_disable(dsp); + + rw_downgrade(&dsp->ds_lock); - bzero(&poll, sizeof (dl_capab_poll_t)); - poll.poll_version = POLL_VERSION_1; - poll.poll_flags = POLL_CAPABLE; - poll.poll_tx_handle = (uintptr_t)dsp->ds_dc; - poll.poll_tx = (uintptr_t)dls_tx; + dlsp = (dl_capability_sub_t *)ptr; - dlcapabsetqid(&(poll.poll_mid), dsp->ds_rq); - bcopy(&poll, ptr, sizeof (dl_capab_poll_t)); - ptr += sizeof (dl_capab_poll_t); + dlsp->dl_cap = DL_CAPAB_POLL; + dlsp->dl_length = sizeof (dl_capab_poll_t); + ptr += sizeof (dl_capability_sub_t); + + bzero(&poll, sizeof (dl_capab_poll_t)); + poll.poll_version = POLL_VERSION_1; + poll.poll_flags = POLL_CAPABLE; + poll.poll_tx_handle = (uintptr_t)dsp; + poll.poll_tx = (uintptr_t)str_mdata_fastpath_put; + + dlcapabsetqid(&(poll.poll_mid), dsp->ds_rq); + bcopy(&poll, ptr, sizeof (dl_capab_poll_t)); + ptr += sizeof (dl_capab_poll_t); + } } + ASSERT(RW_READ_HELD(&dsp->ds_lock)); + /* * TCP/IP checksum offload. */ @@ -1684,137 +1663,8 @@ proto_capability_ack(dld_str_t *dsp, mblk_t *mp) } ASSERT(ptr == mp->b_rptr + sizeof (dl_capability_ack_t) + subsize); - qreply(dsp->ds_wq, mp); -} - -/* - * DL_CAPABILITY_ACK/DL_ERROR_ACK - */ -static void -proto_capability_enable(dld_str_t *dsp, mblk_t *mp) -{ - dl_capability_req_t *dlp = (dl_capability_req_t *)mp->b_rptr; - dl_capability_sub_t *sp; - size_t size; - offset_t off; - size_t len; - offset_t end; - - dlp->dl_primitive = DL_CAPABILITY_ACK; - - off = dlp->dl_sub_offset; - len = dlp->dl_sub_length; - - /* - * Walk the list of capabilities to be enabled. - */ - for (end = off + len; off < end; ) { - sp = (dl_capability_sub_t *)(mp->b_rptr + off); - size = sizeof (dl_capability_sub_t) + sp->dl_length; - - if (off + size > end || - !IS_P2ALIGNED(off, sizeof (uint32_t))) { - dlerrorack(dsp->ds_wq, mp, DL_CAPABILITY_REQ, - DL_BADPRIM, 0); - return; - } - - switch (sp->dl_cap) { - - /* - * TCP/IP checksum offload to hardware. - */ - case DL_CAPAB_HCKSUM: { - dl_capab_hcksum_t *hcksump; - dl_capab_hcksum_t hcksum; - - ASSERT(dsp->ds_mip->mi_cksum != 0); - - hcksump = (dl_capab_hcksum_t *)&sp[1]; - - /* - * Copy for alignment. - */ - bcopy(hcksump, &hcksum, sizeof (dl_capab_hcksum_t)); - dlcapabsetqid(&(hcksum.hcksum_mid), dsp->ds_rq); - bcopy(&hcksum, hcksump, sizeof (dl_capab_hcksum_t)); - break; - } - - /* - * IP polling interface. - */ - case DL_CAPAB_POLL: { - dl_capab_poll_t *pollp; - dl_capab_poll_t poll; - - pollp = (dl_capab_poll_t *)&sp[1]; - - /* - * Copy for alignment. - */ - bcopy(pollp, &poll, sizeof (dl_capab_poll_t)); - - switch (poll.poll_flags) { - default: - /*FALLTHRU*/ - case POLL_DISABLE: - proto_poll_disable(dsp); - break; - case POLL_ENABLE: - ASSERT(!(dld_opt & DLD_OPT_NO_POLL)); - - /* - * Make sure polling is disabled. - */ - proto_poll_disable(dsp); - - /* - * Now attempt enable it. - */ - if (!proto_poll_enable(dsp, &poll)) - break; - - bzero(&poll, sizeof (dl_capab_poll_t)); - poll.poll_flags = POLL_ENABLE; - break; - } - - dlcapabsetqid(&(poll.poll_mid), dsp->ds_rq); - bcopy(&poll, pollp, sizeof (dl_capab_poll_t)); - break; - } - default: - break; - } - - off += size; - } - - qreply(dsp->ds_wq, mp); -} - -/* - * DL_NOTIFY_ACK - */ -static void -proto_notify_ack(dld_str_t *dsp, mblk_t *mp, uint_t enable_set, uint_t ack_set) -{ - /* - * Cache the notifications that are being enabled. - */ - dsp->ds_notifications = enable_set; - - /* - * The ACK carries all notifications regardless of which set is - * being enabled. - */ - dlnotifyack(dsp->ds_wq, mp, ack_set); - - /* - * Solicit DL_NOTIFY_IND messages for each enabled notification. - */ - if (dsp->ds_notifications != 0) - dld_str_notify_ind(dsp); + rw_exit(&dsp->ds_lock); + qreply(q, mp); + return (B_TRUE); } diff --git a/usr/src/uts/common/io/dld/dld_str.c b/usr/src/uts/common/io/dld/dld_str.c index 96f68cc139..0e697c39f1 100644 --- a/usr/src/uts/common/io/dld/dld_str.c +++ b/usr/src/uts/common/io/dld/dld_str.c @@ -30,31 +30,19 @@ * Data-Link Driver */ -#include <sys/types.h> -#include <sys/stream.h> #include <sys/stropts.h> #include <sys/strsun.h> #include <sys/strsubr.h> #include <sys/atomic.h> -#include <sys/sdt.h> -#include <sys/mac.h> -#include <sys/dls.h> +#include <sys/mkdev.h> +#include <sys/vlan.h> #include <sys/dld.h> #include <sys/dld_impl.h> -#include <sys/taskq.h> -#include <sys/vlan.h> +#include <sys/dls_impl.h> +#include <inet/common.h> static int str_constructor(void *, void *, int); static void str_destructor(void *, void *); -static void str_m_put(dld_str_t *, mblk_t *); -static void str_m_srv(dld_str_t *, mblk_t *); -static void str_mdata_fastpath_put(dld_str_t *, mblk_t *); -static void str_mdata_raw_put(dld_str_t *, mblk_t *); -static void str_mdata_srv(dld_str_t *, mblk_t *); -static void str_mproto_put(dld_str_t *, mblk_t *); -static void str_mpcproto_put(dld_str_t *, mblk_t *); -static void str_mioctl_put(dld_str_t *, mblk_t *); -static void str_mflush_put(dld_str_t *, mblk_t *); static mblk_t *str_unitdata_ind(dld_str_t *, mblk_t *); static void str_notify_promisc_on_phys(dld_str_t *); static void str_notify_promisc_off_phys(dld_str_t *); @@ -64,69 +52,420 @@ static void str_notify_link_down(dld_str_t *); static void str_notify_capab_reneg(dld_str_t *); static void str_notify_speed(dld_str_t *, uint32_t); static void str_notify(void *, mac_notify_type_t); -static void str_putbq(queue_t *q, mblk_t *mp); + +static void ioc_raw(dld_str_t *, mblk_t *); +static void ioc_fast(dld_str_t *, mblk_t *); +static void ioc(dld_str_t *, mblk_t *); +static void dld_ioc(dld_str_t *, mblk_t *); +static minor_t dld_minor_hold(boolean_t); +static void dld_minor_rele(minor_t); static uint32_t str_count; static kmem_cache_t *str_cachep; +static vmem_t *minor_arenap; +static uint32_t minor_count; + +#define MINOR_TO_PTR(minor) ((void *)(uintptr_t)(minor)) +#define PTR_TO_MINOR(ptr) ((minor_t)(uintptr_t)(ptr)) + +/* + * Some notes on entry points, flow-control, queueing and locking: + * + * This driver exports the traditional STREAMS put entry point as well as + * the non-STREAMS fast-path transmit routine which is provided to IP via + * the DL_CAPAB_POLL negotiation. The put procedure handles all control + * and data operations, while the fast-path routine deals only with M_DATA + * fast-path packets. Regardless of the entry point, all outbound packets + * will end up in str_mdata_fastpath_put(), where they will be delivered to + * the MAC driver. + * + * The transmit logic operates in two modes: a "not busy" mode where the + * packets will be delivered to the MAC for a send attempt, or "busy" mode + * where they will be enqueued in the internal queue because of flow-control. + * Flow-control happens when the MAC driver indicates the packets couldn't + * be transmitted due to lack of resources (e.g. running out of descriptors). + * In such case, the driver will place a dummy message on its write-side + * STREAMS queue so that the queue is marked as "full". Any subsequent + * packets arriving at the driver will be enqueued in the internal queue, + * which is drained in the context of the service thread that gets scheduled + * whenever the driver is in the "busy" mode. When all packets have been + * successfully delivered by MAC and the internal queue is empty, it will + * transition to the "not busy" mode by removing the dummy message from the + * write-side STREAMS queue; in effect this will trigger backenabling. + * The sizes of q_hiwat and q_lowat are set to 1 and 0, respectively, due + * to the above reasons. + * + * The driver implements an internal transmit queue independent of STREAMS. + * This allows for flexibility and provides a fast enqueue/dequeue mechanism + * compared to the putq() and get() STREAMS interfaces. The only putq() and + * getq() operations done by the driver are those related to placing and + * removing the dummy message to/from the write-side STREAMS queue for flow- + * control purposes. + * + * Locking is done independent of STREAMS due to the driver being fully MT. + * Threads entering the driver (either from put or service entry points) + * will most likely be readers, with the exception of a few writer cases + * such those handling DLPI attach/detach/bind/unbind/etc. or any of the + * DLD-related ioctl requests. The DLPI detach case is special, because + * it involves freeing resources and therefore must be single-threaded. + * Unfortunately the readers/writers lock can't be used to protect against + * it, because the lock is dropped prior to the driver calling places where + * putnext() may be invoked, and such places may depend on those resources + * to exist. Because of this, the driver always completes the DLPI detach + * process when there are no other threads running in the driver. This is + * done by keeping track of the number of threads, such that the the last + * thread leaving the driver will finish the pending DLPI detach operation. + */ + +/* + * dld_max_q_count is the queue depth threshold used to limit the number of + * outstanding packets or bytes allowed in the queue; once this limit is + * reached the driver will free any incoming ones until the queue depth + * drops below the threshold. + * + * This buffering is provided to accomodate clients which do not employ + * their own buffering scheme, and to handle occasional packet bursts. + * Clients which handle their own buffering will receive positive feedback + * from this driver as soon as it transitions into the "busy" state, i.e. + * when the queue is initially filled up; they will get backenabled once + * the queue is empty. + * + * The value chosen here is rather arbitrary; in future some intelligent + * heuristics may be involved which could take into account the hardware's + * transmit ring size, etc. + */ +uint_t dld_max_q_count = (16 * 1024 *1024); + +static dev_info_t * +dld_finddevinfo(dev_t dev) +{ + minor_t minor = getminor(dev); + char *drvname = ddi_major_to_name(getmajor(dev)); + char name[MAXNAMELEN]; + dls_vlan_t *dvp = NULL; + dev_info_t *dip = NULL; + + if (drvname == NULL || minor == 0 || minor > DLD_MAX_PPA + 1) + return (NULL); + + (void) snprintf(name, MAXNAMELEN, "%s%d", drvname, (int)minor - 1); + if (dls_vlan_hold(name, &dvp, B_FALSE) != 0) + return (NULL); + + dip = mac_devinfo_get(dvp->dv_dlp->dl_mh); + dls_vlan_rele(dvp); + return (dip); +} + +/* + * devo_getinfo: getinfo(9e) + */ +/*ARGSUSED*/ +int +dld_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resp) +{ + dev_info_t *devinfo; + minor_t minor = getminor((dev_t)arg); + int rc = DDI_FAILURE; + + switch (cmd) { + case DDI_INFO_DEVT2DEVINFO: + if ((devinfo = dld_finddevinfo((dev_t)arg)) != NULL) { + *(dev_info_t **)resp = devinfo; + rc = DDI_SUCCESS; + } + break; + case DDI_INFO_DEVT2INSTANCE: + if (minor > 0 && minor <= DLD_MAX_PPA + 1) { + *(int *)resp = (int)minor - 1; + rc = DDI_SUCCESS; + } + break; + } + return (rc); +} + +/* + * qi_qopen: open(9e) + */ +/*ARGSUSED*/ +int +dld_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp) +{ + dld_str_t *dsp; + major_t major; + minor_t minor; + int err; + + if (sflag == MODOPEN) + return (ENOTSUP); + + /* + * This is a cloning driver and therefore each queue should only + * ever get opened once. + */ + if (rq->q_ptr != NULL) + return (EBUSY); + + major = getmajor(*devp); + minor = getminor(*devp); + if (minor > DLD_MAX_MINOR) + return (ENODEV); + + /* + * Create a new dld_str_t for the stream. This will grab a new minor + * number that will be handed back in the cloned dev_t. Creation may + * fail if we can't allocate the dummy mblk used for flow-control. + */ + dsp = dld_str_create(rq, DLD_DLPI, major, + ((minor == 0) ? DL_STYLE2 : DL_STYLE1)); + if (dsp == NULL) + return (ENOSR); + + ASSERT(dsp->ds_dlstate == DL_UNATTACHED); + if (minor != 0) { + /* + * Style 1 open + */ -typedef struct str_msg_info { - uint8_t smi_type; - const char *smi_txt; - void (*smi_put)(dld_str_t *, mblk_t *); - void (*smi_srv)(dld_str_t *, mblk_t *); -} str_msg_info_t; + if ((err = dld_str_attach(dsp, (t_uscalar_t)minor - 1)) != 0) + goto failed; + ASSERT(dsp->ds_dlstate == DL_UNBOUND); + } + + /* + * Enable the queue srv(9e) routine. + */ + qprocson(rq); + + /* + * Construct a cloned dev_t to hand back. + */ + *devp = makedevice(getmajor(*devp), dsp->ds_minor); + return (0); + +failed: + dld_str_destroy(dsp); + return (err); +} + +/* + * qi_qclose: close(9e) + */ +int +dld_close(queue_t *rq) +{ + dld_str_t *dsp = rq->q_ptr; + + /* + * Disable the queue srv(9e) routine. + */ + qprocsoff(rq); + + /* + * At this point we can not be entered by any threads via STREAMS + * or the direct call interface, which is available only to IP. + * After the interface is unplumbed, IP wouldn't have any reference + * to this instance, and therefore we are now effectively single + * threaded and don't require any lock protection. Flush all + * pending packets which are sitting in the transmit queue. + */ + ASSERT(dsp->ds_thr == 0); + dld_tx_flush(dsp); + + /* + * This stream was open to a provider node. Check to see + * if it has been cleanly shut down. + */ + if (dsp->ds_dlstate != DL_UNATTACHED) { + /* + * The stream is either open to a style 1 provider or + * this is not clean shutdown. Detach from the PPA. + * (This is still ok even in the style 1 case). + */ + dld_str_detach(dsp); + } + + dld_str_destroy(dsp); + return (0); +} /* - * Normal priority message jump table. + * qi_qputp: put(9e) */ -str_msg_info_t str_mi[] = { - { M_DATA, "M_DATA", str_m_put, str_m_srv }, - { M_PROTO, "M_PROTO", str_mproto_put, str_m_srv }, - { 0x02, "undefined", str_m_put, str_m_srv }, - { 0x03, "undefined", str_m_put, str_m_srv }, - { 0x04, "undefined", str_m_put, str_m_srv }, - { 0x05, "undefined", str_m_put, str_m_srv }, - { 0x06, "undefined", str_m_put, str_m_srv }, - { 0x07, "undefined", str_m_put, str_m_srv }, - { M_BREAK, "M_BREAK", str_m_put, str_m_srv }, - { M_PASSFP, "M_PASSFP", str_m_put, str_m_srv }, - { M_EVENT, "M_EVENT", str_m_put, str_m_srv }, - { M_SIG, "M_SIG", str_m_put, str_m_srv }, - { M_DELAY, "M_DELAY", str_m_put, str_m_srv }, - { M_CTL, "M_CTL", str_m_put, str_m_srv }, - { M_IOCTL, "M_IOCTL", str_mioctl_put, str_m_srv }, - { M_SETOPTS, "M_SETOPTS", str_m_put, str_m_srv }, - { M_RSE, "M_RSE", str_m_put, str_m_srv } -}; - -#define STR_MI_COUNT (sizeof (str_mi) / sizeof (str_mi[0])) +void +dld_wput(queue_t *wq, mblk_t *mp) +{ + dld_str_t *dsp = (dld_str_t *)wq->q_ptr; + + DLD_ENTER(dsp); + + switch (DB_TYPE(mp)) { + case M_DATA: + rw_enter(&dsp->ds_lock, RW_READER); + if (dsp->ds_dlstate != DL_IDLE || + dsp->ds_mode == DLD_UNITDATA) { + freemsg(mp); + } else if (dsp->ds_mode == DLD_FASTPATH) { + str_mdata_fastpath_put(dsp, mp); + } else if (dsp->ds_mode == DLD_RAW) { + str_mdata_raw_put(dsp, mp); + } + rw_exit(&dsp->ds_lock); + break; + case M_PROTO: + case M_PCPROTO: + dld_proto(dsp, mp); + break; + case M_IOCTL: + dld_ioc(dsp, mp); + break; + case M_FLUSH: + if (*mp->b_rptr & FLUSHW) { + dld_tx_flush(dsp); + *mp->b_rptr &= ~FLUSHW; + } + + if (*mp->b_rptr & FLUSHR) { + qreply(wq, mp); + } else { + freemsg(mp); + } + break; + default: + freemsg(mp); + break; + } + + DLD_EXIT(dsp); +} /* - * High priority message jump table. + * qi_srvp: srv(9e) */ -str_msg_info_t str_pmi[] = { - { 0x80, "undefined", str_m_put, str_m_srv }, - { M_IOCACK, "M_IOCACK", str_m_put, str_m_srv }, - { M_IOCNAK, "M_IOCNAK", str_m_put, str_m_srv }, - { M_PCPROTO, "M_PCPROTO", str_mpcproto_put, str_m_srv }, - { M_PCSIG, "M_PCSIG", str_m_put, str_m_srv }, - { M_READ, "M_READ", str_m_put, str_m_srv }, - { M_FLUSH, "M_FLUSH", str_mflush_put, str_m_srv }, - { M_STOP, "M_STOP", str_m_put, str_m_srv }, - { M_START, "M_START", str_m_put, str_m_srv }, - { M_HANGUP, "M_HANGUP", str_m_put, str_m_srv }, - { M_ERROR, "M_ERROR", str_m_put, str_m_srv }, - { M_COPYIN, "M_COPYIN", str_m_put, str_m_srv }, - { M_COPYOUT, "M_COPYOUT", str_m_put, str_m_srv }, - { M_IOCDATA, "M_IOCDATA", str_m_put, str_m_srv }, - { M_PCRSE, "M_PCRSE", str_m_put, str_m_srv }, - { M_STOPI, "M_STOPI", str_m_put, str_m_srv }, - { M_STARTI, "M_STARTI", str_m_put, str_m_srv }, - { M_PCEVENT, "M_PCEVENT", str_m_put, str_m_srv }, - { M_UNHANGUP, "M_UNHANGUP", str_m_put, str_m_srv } -}; - -#define STR_PMI_COUNT (sizeof (str_pmi) / sizeof (str_pmi[0])) +void +dld_wsrv(queue_t *wq) +{ + mblk_t *mp; + dld_str_t *dsp = wq->q_ptr; + + DLD_ENTER(dsp); + rw_enter(&dsp->ds_lock, RW_READER); + /* + * Grab all packets (chained via b_next) off our transmit queue + * and try to send them all to the MAC layer. Since the queue + * is independent of streams, we are able to dequeue all messages + * at once without looping through getq() and manually chaining + * them. Note that the queue size parameters (byte and message + * counts) are cleared as well, but we postpone the backenabling + * until after the MAC transmit since some packets may end up + * back at our transmit queue. + */ + mutex_enter(&dsp->ds_tx_list_lock); + if ((mp = dsp->ds_tx_list_head) == NULL) { + ASSERT(!dsp->ds_tx_qbusy); + ASSERT(dsp->ds_tx_flow_mp != NULL); + ASSERT(dsp->ds_tx_list_head == NULL); + ASSERT(dsp->ds_tx_list_tail == NULL); + ASSERT(dsp->ds_tx_cnt == 0); + ASSERT(dsp->ds_tx_msgcnt == 0); + mutex_exit(&dsp->ds_tx_list_lock); + goto done; + } + dsp->ds_tx_list_head = dsp->ds_tx_list_tail = NULL; + dsp->ds_tx_cnt = dsp->ds_tx_msgcnt = 0; + mutex_exit(&dsp->ds_tx_list_lock); + + /* + * Discard packets unless we are attached and bound; note that + * the driver mode (fastpath/raw/unitdata) is irrelevant here, + * because regardless of the mode all transmit will end up in + * str_mdata_fastpath_put() where the packets may be queued. + */ + ASSERT(DB_TYPE(mp) == M_DATA); + if (dsp->ds_dlstate != DL_IDLE) { + freemsgchain(mp); + goto done; + } + + /* + * Attempt to transmit one or more packets. If the MAC can't + * send them all, re-queue the packet(s) at the beginning of + * the transmit queue to avoid any re-ordering. + */ + if ((mp = dls_tx(dsp->ds_dc, mp)) != NULL) + dld_tx_enqueue(dsp, mp, B_TRUE); + + /* + * Grab the list lock again and check if the transmit queue is + * really empty; if so, lift up flow-control and backenable any + * writer queues. If the queue is not empty, schedule service + * thread to drain it. + */ + mutex_enter(&dsp->ds_tx_list_lock); + if (dsp->ds_tx_list_head == NULL) { + dsp->ds_tx_flow_mp = getq(wq); + ASSERT(dsp->ds_tx_flow_mp != NULL); + dsp->ds_tx_qbusy = B_FALSE; + } + mutex_exit(&dsp->ds_tx_list_lock); +done: + rw_exit(&dsp->ds_lock); + DLD_EXIT(dsp); +} + +void +dld_init_ops(struct dev_ops *ops, const char *name) +{ + struct streamtab *stream; + struct qinit *rq, *wq; + struct module_info *modinfo; + + modinfo = kmem_zalloc(sizeof (struct module_info), KM_SLEEP); + modinfo->mi_idname = kmem_zalloc(FMNAMESZ, KM_SLEEP); + (void) snprintf(modinfo->mi_idname, FMNAMESZ, "%s", name); + modinfo->mi_minpsz = 0; + modinfo->mi_maxpsz = 64*1024; + modinfo->mi_hiwat = 1; + modinfo->mi_lowat = 0; + + rq = kmem_zalloc(sizeof (struct qinit), KM_SLEEP); + rq->qi_qopen = dld_open; + rq->qi_qclose = dld_close; + rq->qi_minfo = modinfo; + + wq = kmem_zalloc(sizeof (struct qinit), KM_SLEEP); + wq->qi_putp = (pfi_t)dld_wput; + wq->qi_srvp = (pfi_t)dld_wsrv; + wq->qi_minfo = modinfo; + + stream = kmem_zalloc(sizeof (struct streamtab), KM_SLEEP); + stream->st_rdinit = rq; + stream->st_wrinit = wq; + ops->devo_cb_ops->cb_str = stream; + + ops->devo_getinfo = &dld_getinfo; +} + +void +dld_fini_ops(struct dev_ops *ops) +{ + struct streamtab *stream; + struct qinit *rq, *wq; + struct module_info *modinfo; + + stream = ops->devo_cb_ops->cb_str; + rq = stream->st_rdinit; + wq = stream->st_wrinit; + modinfo = rq->qi_minfo; + ASSERT(wq->qi_minfo == modinfo); + + kmem_free(stream, sizeof (struct streamtab)); + kmem_free(wq, sizeof (struct qinit)); + kmem_free(rq, sizeof (struct qinit)); + kmem_free(modinfo->mi_idname, FMNAMESZ); + kmem_free(modinfo, sizeof (struct module_info)); +} /* * Initialize this module's data structures. @@ -140,6 +479,16 @@ dld_str_init(void) str_cachep = kmem_cache_create("dld_str_cache", sizeof (dld_str_t), 0, str_constructor, str_destructor, NULL, NULL, NULL, 0); ASSERT(str_cachep != NULL); + + /* + * Allocate a vmem arena to manage minor numbers. The range of the + * arena will be from DLD_MAX_MINOR + 1 to MAXMIN (maximum legal + * minor number). + */ + minor_arenap = vmem_create("dld_minor_arena", + MINOR_TO_PTR(DLD_MAX_MINOR + 1), MAXMIN, 1, NULL, NULL, NULL, 0, + VM_SLEEP | VMC_IDENTIFIER); + ASSERT(minor_arenap != NULL); } /* @@ -155,10 +504,16 @@ dld_str_fini(void) return (EBUSY); /* + * Check to see if there are any minor numbers still in use. + */ + if (minor_count != 0) + return (EBUSY); + + /* * Destroy object cache. */ kmem_cache_destroy(str_cachep); - + vmem_destroy(minor_arenap); return (0); } @@ -166,15 +521,28 @@ dld_str_fini(void) * Create a new dld_str_t object. */ dld_str_t * -dld_str_create(queue_t *rq) +dld_str_create(queue_t *rq, uint_t type, major_t major, t_uscalar_t style) { dld_str_t *dsp; /* * Allocate an object from the cache. */ - dsp = kmem_cache_alloc(str_cachep, KM_SLEEP); atomic_add_32(&str_count, 1); + dsp = kmem_cache_alloc(str_cachep, KM_SLEEP); + + /* + * Allocate the dummy mblk for flow-control. + */ + dsp->ds_tx_flow_mp = allocb(1, BPRI_HI); + if (dsp->ds_tx_flow_mp == NULL) { + kmem_cache_free(str_cachep, dsp); + atomic_add_32(&str_count, -1); + return (NULL); + } + dsp->ds_type = type; + dsp->ds_major = major; + dsp->ds_style = style; /* * Initialize the queue pointers. @@ -184,6 +552,12 @@ dld_str_create(queue_t *rq) dsp->ds_wq = WR(rq); rq->q_ptr = WR(rq)->q_ptr = (void *)dsp; + /* + * We want explicit control over our write-side STREAMS queue + * where the dummy mblk gets added/removed for flow-control. + */ + noenable(WR(rq)); + return (dsp); } @@ -206,6 +580,18 @@ dld_str_destroy(dld_str_t *dsp) rq->q_ptr = wq->q_ptr = NULL; dsp->ds_rq = dsp->ds_wq = NULL; + ASSERT(!RW_LOCK_HELD(&dsp->ds_lock)); + ASSERT(MUTEX_NOT_HELD(&dsp->ds_tx_list_lock)); + ASSERT(dsp->ds_tx_list_head == NULL); + ASSERT(dsp->ds_tx_list_tail == NULL); + ASSERT(dsp->ds_tx_cnt == 0); + ASSERT(dsp->ds_tx_msgcnt == 0); + ASSERT(!dsp->ds_tx_qbusy); + + ASSERT(MUTEX_NOT_HELD(&dsp->ds_thr_lock)); + ASSERT(dsp->ds_thr == 0); + ASSERT(dsp->ds_detach_req == NULL); + /* * Reinitialize all the flags. */ @@ -214,6 +600,13 @@ dld_str_destroy(dld_str_t *dsp) dsp->ds_mode = DLD_UNITDATA; /* + * Free the dummy mblk if exists. + */ + if (dsp->ds_tx_flow_mp != NULL) { + freeb(dsp->ds_tx_flow_mp); + dsp->ds_tx_flow_mp = NULL; + } + /* * Free the object back to the cache. */ kmem_cache_free(str_cachep, dsp); @@ -232,39 +625,20 @@ str_constructor(void *buf, void *cdrarg, int kmflags) bzero(buf, sizeof (dld_str_t)); /* - * Take a copy of the global message handler jump tables. - */ - ASSERT(dsp->ds_mi == NULL); - if ((dsp->ds_mi = kmem_zalloc(sizeof (str_mi), kmflags)) == NULL) - return (-1); - - bcopy(str_mi, dsp->ds_mi, sizeof (str_mi)); - - ASSERT(dsp->ds_pmi == NULL); - if ((dsp->ds_pmi = kmem_zalloc(sizeof (str_pmi), kmflags)) == NULL) { - kmem_free(dsp->ds_mi, sizeof (str_mi)); - dsp->ds_mi = NULL; - return (-1); - } - - bcopy(str_pmi, dsp->ds_pmi, sizeof (str_pmi)); - - /* * Allocate a new minor number. */ - if ((dsp->ds_minor = dld_minor_hold(kmflags == KM_SLEEP)) == 0) { - kmem_free(dsp->ds_mi, sizeof (str_mi)); - dsp->ds_mi = NULL; - kmem_free(dsp->ds_pmi, sizeof (str_pmi)); - dsp->ds_pmi = NULL; + if ((dsp->ds_minor = dld_minor_hold(kmflags == KM_SLEEP)) == 0) return (-1); - } /* * Initialize the DLPI state machine. */ dsp->ds_dlstate = DL_UNATTACHED; + mutex_init(&dsp->ds_thr_lock, NULL, MUTEX_DRIVER, NULL); + rw_init(&dsp->ds_lock, NULL, RW_DRIVER, NULL); + mutex_init(&dsp->ds_tx_list_lock, NULL, MUTEX_DRIVER, NULL); + return (0); } @@ -299,170 +673,53 @@ str_destructor(void *buf, void *cdrarg) ASSERT(!dsp->ds_polling); /* - * Make sure M_DATA message handling is disabled. - */ - ASSERT(dsp->ds_mi[M_DATA].smi_put == str_m_put); - ASSERT(dsp->ds_mi[M_DATA].smi_srv == str_m_srv); - - /* * Release the minor number. */ dld_minor_rele(dsp->ds_minor); - /* - * Clear down the jump tables. - */ - kmem_free(dsp->ds_mi, sizeof (str_mi)); - dsp->ds_mi = NULL; - - kmem_free(dsp->ds_pmi, sizeof (str_pmi)); - dsp->ds_pmi = NULL; -} - -/* - * Called from put(9e) to process a streams message. - */ -void -dld_str_put(dld_str_t *dsp, mblk_t *mp) -{ - uint8_t type; - str_msg_info_t *smip; - - /* - * Look up the message handler from the appropriate jump table. - */ - if ((type = DB_TYPE(mp)) & QPCTL) { - /* - * Clear the priority bit to index into the jump table. - */ - type &= ~QPCTL; - - /* - * Check the message is not out of range for the jump table. - */ - if (type >= STR_PMI_COUNT) - goto unknown; - - /* - * Get the handler from the jump table. - */ - smip = &(dsp->ds_pmi[type]); - - /* - * OR the priorty bit back in to restore the original message - * type. - */ - type |= QPCTL; - } else { - /* - * Check the message is not out of range for the jump table. - */ - if (type >= STR_MI_COUNT) - goto unknown; - - /* - * Get the handler from the jump table. - */ - smip = &(dsp->ds_mi[type]); - } + ASSERT(!RW_LOCK_HELD(&dsp->ds_lock)); + rw_destroy(&dsp->ds_lock); - ASSERT(smip->smi_type == type); - smip->smi_put(dsp, mp); - return; + ASSERT(MUTEX_NOT_HELD(&dsp->ds_tx_list_lock)); + mutex_destroy(&dsp->ds_tx_list_lock); + ASSERT(dsp->ds_tx_flow_mp == NULL); -unknown: - str_m_put(dsp, mp); -} - -/* - * Called from srv(9e) to process a streams message. - */ -void -dld_str_srv(dld_str_t *dsp, mblk_t *mp) -{ - uint8_t type; - str_msg_info_t *smip; - - /* - * Look up the message handler from the appropriate jump table. - */ - if ((type = DB_TYPE(mp)) & QPCTL) { - /* - * Clear the priority bit to index into the jump table. - */ - type &= ~QPCTL; - - /* - * Check the message is not out of range for the jump table. - */ - if (type >= STR_PMI_COUNT) - goto unknown; - - /* - * Get the handler from the jump table. - */ - smip = &(dsp->ds_pmi[type]); - - /* - * OR the priorty bit back in to restore the original message - * type. - */ - type |= QPCTL; - } else { - /* - * Check the message is not out of range for the jump table. - */ - if (type >= STR_MI_COUNT) - goto unknown; - - /* - * Get the handler from the jump table. - */ - ASSERT(type < STR_MI_COUNT); - smip = &(dsp->ds_mi[type]); - } - - ASSERT(smip->smi_type == type); - smip->smi_srv(dsp, mp); - return; - -unknown: - str_m_srv(dsp, mp); + ASSERT(MUTEX_NOT_HELD(&dsp->ds_thr_lock)); + mutex_destroy(&dsp->ds_thr_lock); + ASSERT(dsp->ds_detach_req == NULL); } /* * M_DATA put (IP fast-path mode) */ -static void +void str_mdata_fastpath_put(dld_str_t *dsp, mblk_t *mp) { - queue_t *q = dsp->ds_wq; - /* - * If something is already queued then we must queue to avoid - * re-ordering. + * We get here either as a result of putnext() from above or + * because IP has called us directly. If we are in the busy + * mode enqueue the packet(s) and return. Otherwise hand them + * over to the MAC driver for transmission; any remaining one(s) + * which didn't get sent will be queued. + * + * Note here that we don't grab the list lock prior to checking + * the busy flag. This is okay, because a missed transition + * will not cause any packet reordering for any particular TCP + * connection (which is single-threaded). The enqueue routine + * will atomically set the busy flag and schedule the service + * thread to run; the flag is only cleared by the service thread + * when there is no more packet to be transmitted. */ - if (q->q_first != NULL) { - (void) putq(q, mp); - return; - } - - /* - * Attempt to transmit the packet. - */ - if ((mp = dls_tx(dsp->ds_dc, mp)) != NULL) { - (void) putbq(q, mp); - qenable(q); - } + if (dsp->ds_tx_qbusy || (mp = dls_tx(dsp->ds_dc, mp)) != NULL) + dld_tx_enqueue(dsp, mp, B_FALSE); } /* * M_DATA put (raw mode) */ -static void +void str_mdata_raw_put(dld_str_t *dsp, mblk_t *mp) { - queue_t *q = dsp->ds_wq; struct ether_header *ehp; mblk_t *bp; size_t size; @@ -496,7 +753,7 @@ str_mdata_raw_put(dld_str_t *dsp, mblk_t *mp) * know the first fragment was M_DATA otherwise we could not * have got here). */ - for (bp = mp->b_next; bp != NULL; bp = bp->b_cont) { + for (bp = mp->b_cont; bp != NULL; bp = bp->b_cont) { if (DB_TYPE(bp) != M_DATA) goto discard; size += MBLKL(bp); @@ -505,22 +762,7 @@ str_mdata_raw_put(dld_str_t *dsp, mblk_t *mp) if (size > dsp->ds_mip->mi_sdu_max + hdrlen) goto discard; - /* - * If something is already queued then we must queue to avoid - * re-ordering. - */ - if (q->q_first != NULL) { - (void) putq(q, bp); - return; - } - - /* - * Attempt to transmit the packet. - */ - if ((mp = dls_tx(dsp->ds_dc, mp)) != NULL) { - (void) putbq(q, mp); - qenable(q); - } + str_mdata_fastpath_put(dsp, mp); return; discard: @@ -528,107 +770,35 @@ discard: } /* - * M_DATA srv - */ -static void -str_mdata_srv(dld_str_t *dsp, mblk_t *mp) -{ - queue_t *q = dsp->ds_wq; - - /* - * Attempt to transmit the packet. - */ - if ((mp = dls_tx(dsp->ds_dc, mp)) == NULL) - return; - - (void) str_putbq(q, mp); - qenable(q); -} - -/* - * M_PROTO put - */ -static void -str_mproto_put(dld_str_t *dsp, mblk_t *mp) -{ - dld_proto(dsp, mp); -} - -/* - * M_PCPROTO put - */ -static void -str_mpcproto_put(dld_str_t *dsp, mblk_t *mp) -{ - dld_proto(dsp, mp); -} - -/* - * M_IOCTL put - */ -static void -str_mioctl_put(dld_str_t *dsp, mblk_t *mp) -{ - dld_ioc(dsp, mp); -} - -/* - * M_FLUSH put - */ -/*ARGSUSED*/ -static void -str_mflush_put(dld_str_t *dsp, mblk_t *mp) -{ - queue_t *q = dsp->ds_wq; - - if (*mp->b_rptr & FLUSHW) { - flushq(q, FLUSHALL); - *mp->b_rptr &= ~FLUSHW; - } - - if (*mp->b_rptr & FLUSHR) - qreply(q, mp); - else - freemsg(mp); -} - -/* - * M_* put. - */ -/*ARGSUSED*/ -static void -str_m_put(dld_str_t *dsp, mblk_t *mp) -{ - freemsg(mp); -} - -/* - * M_* put. - */ -/*ARGSUSED*/ -static void -str_m_srv(dld_str_t *dsp, mblk_t *mp) -{ - freemsgchain(mp); -} - -/* * Process DL_ATTACH_REQ (style 2) or open(2) (style 1). */ int -dld_str_attach(dld_str_t *dsp, dld_ppa_t *dpp) +dld_str_attach(dld_str_t *dsp, t_uscalar_t ppa) { int err; + const char *drvname; + char name[MAXNAMELEN]; dls_channel_t dc; uint_t addr_length; ASSERT(dsp->ds_dc == NULL); + if ((drvname = ddi_major_to_name(dsp->ds_major)) == NULL) + return (EINVAL); + + (void) snprintf(name, MAXNAMELEN, "%s%u", drvname, ppa); + + if (strcmp(drvname, "aggr") != 0 && + qassociate(dsp->ds_wq, DLS_PPA2INST(ppa)) != 0) + return (EINVAL); + /* * Open a channel. */ - if ((err = dls_open(dpp->dp_name, &dc)) != 0) + if ((err = dls_open(name, &dc)) != 0) { + (void) qassociate(dsp->ds_wq, -1); return (err); + } /* * Cache the MAC interface handle, a pointer to the immutable MAC @@ -659,6 +829,8 @@ dld_str_attach(dld_str_t *dsp, dld_ppa_t *dpp) dsp->ds_mnh = mac_notify_add(dsp->ds_mh, str_notify, (void *)dsp); dsp->ds_dc = dc; + dsp->ds_dlstate = DL_UNBOUND; + return (0); } @@ -669,15 +841,17 @@ dld_str_attach(dld_str_t *dsp, dld_ppa_t *dpp) void dld_str_detach(dld_str_t *dsp) { + ASSERT(dsp->ds_thr == 0); + /* * Remove the notify function. */ mac_notify_remove(dsp->ds_mh, dsp->ds_mnh); /* - * Make sure the M_DATA handler is reset. + * Re-initialize the DLPI state machine. */ - dld_str_tx_drop(dsp); + dsp->ds_dlstate = DL_UNATTACHED; /* * Clear the polling and promisc flags. @@ -691,46 +865,8 @@ dld_str_detach(dld_str_t *dsp) dls_close(dsp->ds_dc); dsp->ds_dc = NULL; dsp->ds_mh = NULL; -} - -/* - * Enable raw mode for this stream. This mode is mutually exclusive with - * fast-path and/or polling. - */ -void -dld_str_tx_raw(dld_str_t *dsp) -{ - /* - * Enable M_DATA message handling. - */ - dsp->ds_mi[M_DATA].smi_put = str_mdata_raw_put; - dsp->ds_mi[M_DATA].smi_srv = str_mdata_srv; -} -/* - * Enable fast-path for this stream. - */ -void -dld_str_tx_fastpath(dld_str_t *dsp) -{ - /* - * Enable M_DATA message handling. - */ - dsp->ds_mi[M_DATA].smi_put = str_mdata_fastpath_put; - dsp->ds_mi[M_DATA].smi_srv = str_mdata_srv; -} - -/* - * Disable fast-path or raw mode. - */ -void -dld_str_tx_drop(dld_str_t *dsp) -{ - /* - * Disable M_DATA message handling. - */ - dsp->ds_mi[M_DATA].smi_put = str_m_put; - dsp->ds_mi[M_DATA].smi_srv = str_m_srv; + (void) qassociate(dsp->ds_wq, -1); } /* @@ -1150,7 +1286,6 @@ str_notify(void *arg, mac_notify_type_t type) switch (type) { case MAC_NOTE_TX: - enableok(q); qenable(q); break; @@ -1236,36 +1371,308 @@ str_notify(void *arg, mac_notify_type_t type) } /* - * Put a chain of packets back on the queue. + * Enqueue one or more messages to the transmit queue. + * Caller specifies the insertion position (head/tail). */ -static void -str_putbq(queue_t *q, mblk_t *mp) +void +dld_tx_enqueue(dld_str_t *dsp, mblk_t *mp, boolean_t head_insert) { - mblk_t *bp = NULL; - mblk_t *nextp; + mblk_t *tail; + queue_t *q = dsp->ds_wq; + uint_t cnt, msgcnt; + uint_t tot_cnt, tot_msgcnt; + + ASSERT(DB_TYPE(mp) == M_DATA); + /* Calculate total size and count of the packet(s) */ + for (tail = mp, cnt = msgdsize(mp), msgcnt = 1; + tail->b_next != NULL; tail = tail->b_next) { + ASSERT(DB_TYPE(tail) == M_DATA); + cnt += msgdsize(tail); + msgcnt++; + } + + mutex_enter(&dsp->ds_tx_list_lock); + /* + * If the queue depth would exceed the allowed threshold, drop + * new packet(s) and drain those already in the queue. + */ + tot_cnt = dsp->ds_tx_cnt + cnt; + tot_msgcnt = dsp->ds_tx_msgcnt + msgcnt; + + if (!head_insert && + (tot_cnt >= dld_max_q_count || tot_msgcnt >= dld_max_q_count)) { + ASSERT(dsp->ds_tx_qbusy); + mutex_exit(&dsp->ds_tx_list_lock); + freemsgchain(mp); + goto done; + } + + /* Update the queue size parameters */ + dsp->ds_tx_cnt = tot_cnt; + dsp->ds_tx_msgcnt = tot_msgcnt; /* - * Reverse the order of the chain. + * If the transmit queue is currently empty and we are + * about to deposit the packet(s) there, switch mode to + * "busy" and raise flow-control condition. */ - while (mp != NULL) { - nextp = mp->b_next; + if (!dsp->ds_tx_qbusy) { + dsp->ds_tx_qbusy = B_TRUE; + ASSERT(dsp->ds_tx_flow_mp != NULL); + (void) putq(q, dsp->ds_tx_flow_mp); + dsp->ds_tx_flow_mp = NULL; + } + + if (!head_insert) { + /* Tail insertion */ + if (dsp->ds_tx_list_head == NULL) + dsp->ds_tx_list_head = mp; + else + dsp->ds_tx_list_tail->b_next = mp; + dsp->ds_tx_list_tail = tail; + } else { + /* Head insertion */ + tail->b_next = dsp->ds_tx_list_head; + if (dsp->ds_tx_list_head == NULL) + dsp->ds_tx_list_tail = tail; + dsp->ds_tx_list_head = mp; + } + mutex_exit(&dsp->ds_tx_list_lock); +done: + /* Schedule service thread to drain the transmit queue */ + qenable(q); +} + +void +dld_tx_flush(dld_str_t *dsp) +{ + mutex_enter(&dsp->ds_tx_list_lock); + if (dsp->ds_tx_list_head != NULL) { + freemsgchain(dsp->ds_tx_list_head); + dsp->ds_tx_list_head = dsp->ds_tx_list_tail = NULL; + dsp->ds_tx_cnt = dsp->ds_tx_msgcnt = 0; + if (dsp->ds_tx_qbusy) { + dsp->ds_tx_flow_mp = getq(dsp->ds_wq); + ASSERT(dsp->ds_tx_flow_mp != NULL); + dsp->ds_tx_qbusy = B_FALSE; + } + } + mutex_exit(&dsp->ds_tx_list_lock); +} + +/* + * Process an M_IOCTL message. + */ +static void +dld_ioc(dld_str_t *dsp, mblk_t *mp) +{ + uint_t cmd; - mp->b_next = bp; - bp = mp; + cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd; + ASSERT(dsp->ds_type == DLD_DLPI); - mp = nextp; + switch (cmd) { + case DLIOCRAW: + ioc_raw(dsp, mp); + break; + case DLIOCHDRINFO: + ioc_fast(dsp, mp); + break; + default: + ioc(dsp, mp); + } +} + +/* + * DLIOCRAW + */ +static void +ioc_raw(dld_str_t *dsp, mblk_t *mp) +{ + queue_t *q = dsp->ds_wq; + + rw_enter(&dsp->ds_lock, RW_WRITER); + if (dsp->ds_polling) { + rw_exit(&dsp->ds_lock); + miocnak(q, mp, 0, EPROTO); + return; + } + + if (dsp->ds_mode != DLD_RAW && dsp->ds_dlstate == DL_IDLE) { + /* + * Set the receive callback. + */ + dls_rx_set(dsp->ds_dc, dld_str_rx_raw, (void *)dsp); + + /* + * Note that raw mode is enabled. + */ + dsp->ds_mode = DLD_RAW; + } + + rw_exit(&dsp->ds_lock); + miocack(q, mp, 0, 0); +} + +/* + * DLIOCHDRINFO + */ +static void +ioc_fast(dld_str_t *dsp, mblk_t *mp) +{ + dl_unitdata_req_t *dlp; + off_t off; + size_t len; + const uint8_t *addr; + uint16_t sap; + mblk_t *nmp; + mblk_t *hmp; + uint_t addr_length; + queue_t *q = dsp->ds_wq; + int err; + dls_channel_t dc; + + if (dld_opt & DLD_OPT_NO_FASTPATH) { + err = ENOTSUP; + goto failed; + } + + nmp = mp->b_cont; + if (nmp == NULL || MBLKL(nmp) < sizeof (dl_unitdata_req_t) || + (dlp = (dl_unitdata_req_t *)nmp->b_rptr, + dlp->dl_primitive != DL_UNITDATA_REQ)) { + err = EINVAL; + goto failed; + } + + off = dlp->dl_dest_addr_offset; + len = dlp->dl_dest_addr_length; + + if (!MBLKIN(nmp, off, len)) { + err = EINVAL; + goto failed; + } + + rw_enter(&dsp->ds_lock, RW_READER); + if (dsp->ds_dlstate != DL_IDLE) { + rw_exit(&dsp->ds_lock); + err = ENOTSUP; + goto failed; + } + + addr_length = dsp->ds_mip->mi_addr_length; + if (len != addr_length + sizeof (uint16_t)) { + rw_exit(&dsp->ds_lock); + err = EINVAL; + goto failed; + } + + addr = nmp->b_rptr + off; + sap = *(uint16_t *)(nmp->b_rptr + off + addr_length); + dc = dsp->ds_dc; + + if ((hmp = dls_header(dc, addr, sap, dsp->ds_pri)) == NULL) { + rw_exit(&dsp->ds_lock); + err = ENOMEM; + goto failed; } /* - * Walk the reversed chain and put each message back on the - * queue. + * This is a performance optimization. We originally entered + * as reader and only become writer upon transitioning into + * the DLD_FASTPATH mode for the first time. Otherwise we + * stay as reader and return the fast-path header to IP. */ - while (bp != NULL) { - nextp = bp->b_next; - bp->b_next = NULL; + if (dsp->ds_mode != DLD_FASTPATH) { + if (!rw_tryupgrade(&dsp->ds_lock)) { + rw_exit(&dsp->ds_lock); + rw_enter(&dsp->ds_lock, RW_WRITER); - (void) putbq(q, bp); + /* + * State may have changed before we re-acquired + * the writer lock in case the upgrade failed. + */ + if (dsp->ds_dlstate != DL_IDLE) { + rw_exit(&dsp->ds_lock); + err = ENOTSUP; + goto failed; + } + } + + /* + * Set the receive callback (unless polling is enabled). + */ + if (!dsp->ds_polling) + dls_rx_set(dc, dld_str_rx_fastpath, (void *)dsp); - bp = nextp; + /* + * Note that fast-path mode is enabled. + */ + dsp->ds_mode = DLD_FASTPATH; } + rw_exit(&dsp->ds_lock); + + freemsg(nmp->b_cont); + nmp->b_cont = hmp; + + miocack(q, mp, MBLKL(nmp) + MBLKL(hmp), 0); + return; +failed: + miocnak(q, mp, 0, err); +} + +/* + * Catch-all handler. + */ +static void +ioc(dld_str_t *dsp, mblk_t *mp) +{ + queue_t *q = dsp->ds_wq; + mac_handle_t mh; + + rw_enter(&dsp->ds_lock, RW_READER); + if (dsp->ds_dlstate == DL_UNATTACHED) { + rw_exit(&dsp->ds_lock); + miocnak(q, mp, 0, EINVAL); + return; + } + mh = dsp->ds_mh; + ASSERT(mh != NULL); + rw_exit(&dsp->ds_lock); + mac_ioctl(mh, q, mp); +} + +/* + * Allocate a new minor number. + */ +static minor_t +dld_minor_hold(boolean_t sleep) +{ + minor_t minor; + + /* + * Grab a value from the arena. + */ + atomic_add_32(&minor_count, 1); + if ((minor = PTR_TO_MINOR(vmem_alloc(minor_arenap, 1, + (sleep) ? VM_SLEEP : VM_NOSLEEP))) == 0) { + atomic_add_32(&minor_count, -1); + return (0); + } + + return (minor); +} + +/* + * Release a previously allocated minor number. + */ +static void +dld_minor_rele(minor_t minor) +{ + /* + * Return the value to the arena. + */ + vmem_free(minor_arenap, MINOR_TO_PTR(minor), 1); + + atomic_add_32(&minor_count, -1); } diff --git a/usr/src/uts/common/io/dls/dls.c b/usr/src/uts/common/io/dls/dls.c index f9484c648c..d7f9d876fb 100644 --- a/usr/src/uts/common/io/dls/dls.c +++ b/usr/src/uts/common/io/dls/dls.c @@ -35,7 +35,6 @@ #include <sys/strsun.h> #include <sys/sysmacros.h> #include <sys/atomic.h> -#include <sys/ght.h> #include <sys/dlpi.h> #include <sys/vlan.h> #include <sys/ethernet.h> @@ -295,9 +294,9 @@ dls_fini(void) */ int -dls_create(const char *name, const char *dev, uint_t port, uint16_t vid) +dls_create(const char *name, const char *dev, uint_t port) { - return (dls_vlan_create(name, dev, port, vid)); + return (dls_vlan_create(name, dev, port, 0)); } int @@ -316,8 +315,9 @@ dls_open(const char *name, dls_channel_t *dcp) /* * Get a reference to the named dls_vlan_t. + * Tagged vlans get created automatically. */ - if ((err = dls_vlan_hold(name, &dvp)) != 0) + if ((err = dls_vlan_hold(name, &dvp, B_TRUE)) != 0) return (err); /* @@ -433,7 +433,8 @@ dls_close(dls_channel_t dc) /* * Release our reference to the dls_vlan_t allowing that to be - * destroyed if there are no more dls_impl_t. + * destroyed if there are no more dls_impl_t. An unreferenced tagged + * vlan gets destroyed automatically. */ dls_vlan_rele(dvp); } diff --git a/usr/src/uts/common/io/dls/dls_link.c b/usr/src/uts/common/io/dls/dls_link.c index f061a625cd..edb04a6b67 100644 --- a/usr/src/uts/common/io/dls/dls_link.c +++ b/usr/src/uts/common/io/dls/dls_link.c @@ -36,7 +36,7 @@ #include <sys/strsubr.h> #include <sys/sysmacros.h> #include <sys/atomic.h> -#include <sys/ght.h> +#include <sys/modhash.h> #include <sys/dlpi.h> #include <sys/ethernet.h> #include <sys/byteorder.h> @@ -49,7 +49,9 @@ #include <sys/dls_impl.h> static kmem_cache_t *i_dls_link_cachep; -static ght_t i_dls_link_hash; +static mod_hash_t *i_dls_link_hash; +static uint_t i_dls_link_count; +static krwlock_t i_dls_link_lock; #define LINK_HASHSZ 67 /* prime */ #define IMPL_HASHSZ 67 /* prime */ @@ -58,7 +60,8 @@ static ght_t i_dls_link_hash; * Construct a hash key encompassing both DLSAP value and VLAN idenitifier. */ #define MAKE_KEY(_sap, _vid) \ - GHT_SCALAR_TO_KEY(((_sap) << VLAN_ID_SIZE) | (_vid) & VLAN_ID_MASK) + ((mod_hash_key_t)(uintptr_t) \ + (((_sap) << VLAN_ID_SIZE) | (_vid) & VLAN_ID_MASK)) /* * Extract the DLSAP value from the hash key. @@ -76,16 +79,16 @@ i_dls_link_constructor(void *buf, void *arg, int kmflag) { dls_link_t *dlp = buf; char name[MAXNAMELEN]; - int err; bzero(buf, sizeof (dls_link_t)); - (void) sprintf(name, "dls_link_t_%p_impl_hash", buf); - err = ght_scalar_create(name, IMPL_HASHSZ, &(dlp->dl_impl_hash)); - ASSERT(err == 0); + (void) sprintf(name, "dls_link_t_%p_hash", buf); + dlp->dl_impl_hash = mod_hash_create_idhash(name, IMPL_HASHSZ, + mod_hash_null_valdtor); mutex_init(&dlp->dl_lock, NULL, MUTEX_DEFAULT, NULL); mutex_init(&dlp->dl_promisc_lock, NULL, MUTEX_DEFAULT, NULL); + rw_init(&dlp->dl_impl_lock, NULL, RW_DEFAULT, NULL); return (0); } @@ -94,18 +97,17 @@ static void i_dls_link_destructor(void *buf, void *arg) { dls_link_t *dlp = buf; - int err; ASSERT(dlp->dl_ref == 0); - ASSERT(dlp->dl_hte == NULL); ASSERT(dlp->dl_mh == NULL); ASSERT(dlp->dl_unknowns == 0); - err = ght_destroy(dlp->dl_impl_hash); - ASSERT(err == 0); + mod_hash_destroy_idhash(dlp->dl_impl_hash); + dlp->dl_impl_hash = NULL; mutex_destroy(&dlp->dl_lock); mutex_destroy(&dlp->dl_promisc_lock); + rw_destroy(&dlp->dl_impl_lock); } #define ETHER_MATCH(_pkt_a, _pkt_b) \ @@ -219,21 +221,50 @@ done: } static void +i_dls_head_hold(dls_head_t *dhp) +{ + atomic_inc_32(&dhp->dh_ref); +} + +static void +i_dls_head_rele(dls_head_t *dhp) +{ + atomic_dec_32(&dhp->dh_ref); +} + +static dls_head_t * +i_dls_head_alloc(mod_hash_key_t key) +{ + dls_head_t *dhp; + + dhp = kmem_zalloc(sizeof (dls_head_t), KM_SLEEP); + dhp->dh_key = key; + return (dhp); +} + +static void +i_dls_head_free(dls_head_t *dhp) +{ + ASSERT(dhp->dh_ref == 0); + kmem_free(dhp, sizeof (dls_head_t)); +} + +static void i_dls_link_ether_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp) { dls_link_t *dlp = arg; - ght_t hash = dlp->dl_impl_hash; + mod_hash_t *hash = dlp->dl_impl_hash; mblk_t *nextp; uint_t header_length; uint8_t *daddr; uint16_t type_length; uint16_t vid; uint16_t sap; - ghte_t hte; + dls_head_t *dhp; dls_impl_t *dip; dls_impl_t *ndip; mblk_t *nmp; - ght_key_t key; + mod_hash_key_t key; uint_t npacket; boolean_t accepted; @@ -270,25 +301,19 @@ i_dls_link_ether_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp) * Search the has table for dls_impl_t eligible to receive * a packet chain for this DLSAP/VLAN combination. */ - ght_lock(hash, GHT_READ); - if (ght_find(hash, key, &hte) != 0) { - ght_unlock(hash); + rw_enter(&dlp->dl_impl_lock, RW_READER); + if (mod_hash_find(hash, key, (mod_hash_val_t *)&dhp) != 0) { + rw_exit(&dlp->dl_impl_lock); freemsgchain(mp); goto loop; } - - /* - * Place a hold the chain of dls_impl_t to make sure none are - * removed from under our feet. - */ - ght_hold(hte); - ght_unlock(hash); + i_dls_head_hold(dhp); + rw_exit(&dlp->dl_impl_lock); /* * Find the first dls_impl_t that will accept the sub-chain. */ - for (dip = (dls_impl_t *)GHT_VAL(hte); dip != NULL; - dip = dip->di_nextp) + for (dip = dhp->dh_list; dip != NULL; dip = dip->di_nextp) if (dls_accept(dip, daddr)) break; @@ -297,7 +322,7 @@ i_dls_link_ether_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp) * sub-chain then throw it away. */ if (dip == NULL) { - ght_rele(hte); + i_dls_head_rele(dhp); freemsgchain(mp); goto loop; } @@ -346,7 +371,7 @@ i_dls_link_ether_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp) * Release the hold on the dls_impl_t chain now that we have * finished walking it. */ - ght_rele(hte); + i_dls_head_rele(dhp); loop: /* @@ -368,18 +393,18 @@ i_dls_link_ether_rx_promisc(void *arg, mac_resource_handle_t mrh, mblk_t *mp) { dls_link_t *dlp = arg; - ght_t hash = dlp->dl_impl_hash; + mod_hash_t *hash = dlp->dl_impl_hash; mblk_t *nextp; uint_t header_length; uint8_t *daddr; uint16_t type_length; uint16_t vid; uint16_t sap; - ghte_t hte; + dls_head_t *dhp; dls_impl_t *dip; dls_impl_t *ndip; mblk_t *nmp; - ght_key_t key; + mod_hash_key_t key; uint_t npacket; boolean_t accepted; @@ -409,24 +434,18 @@ i_dls_link_ether_rx_promisc(void *arg, mac_resource_handle_t mrh, * Search the has table for dls_impl_t eligible to receive * a packet chain for this DLSAP/VLAN combination. */ - ght_lock(hash, GHT_READ); - if (ght_find(hash, key, &hte) != 0) { - ght_unlock(hash); + rw_enter(&dlp->dl_impl_lock, RW_READER); + if (mod_hash_find(hash, key, (mod_hash_val_t *)&dhp) != 0) { + rw_exit(&dlp->dl_impl_lock); goto non_promisc; } - - /* - * Place a hold the chain of dls_impl_t to make sure none are - * removed from under our feet. - */ - ght_hold(hte); - ght_unlock(hash); + i_dls_head_hold(dhp); + rw_exit(&dlp->dl_impl_lock); /* * Find dls_impl_t that will accept the sub-chain. */ - for (dip = (dls_impl_t *)GHT_VAL(hte); dip != NULL; - dip = dip->di_nextp) { + for (dip = dhp->dh_list; dip != NULL; dip = dip->di_nextp) { if (!dls_accept(dip, daddr)) continue; @@ -449,7 +468,7 @@ i_dls_link_ether_rx_promisc(void *arg, mac_resource_handle_t mrh, * Release the hold on the dls_impl_t chain now that we have * finished walking it. */ - ght_rele(hte); + i_dls_head_rele(dhp); non_promisc: /* @@ -469,25 +488,19 @@ non_promisc: * Search the has table for dls_impl_t eligible to receive * a packet chain for this DLSAP/VLAN combination. */ - ght_lock(hash, GHT_READ); - if (ght_find(hash, key, &hte) != 0) { - ght_unlock(hash); + rw_enter(&dlp->dl_impl_lock, RW_READER); + if (mod_hash_find(hash, key, (mod_hash_val_t *)&dhp) != 0) { + rw_exit(&dlp->dl_impl_lock); freemsgchain(mp); goto loop; } - - /* - * Place a hold the chain of dls_impl_t to make sure none are - * removed from under our feet. - */ - ght_hold(hte); - ght_unlock(hash); + i_dls_head_hold(dhp); + rw_exit(&dlp->dl_impl_lock); /* * Find the first dls_impl_t that will accept the sub-chain. */ - for (dip = (dls_impl_t *)GHT_VAL(hte); dip != NULL; - dip = dip->di_nextp) + for (dip = dhp->dh_list; dip != NULL; dip = dip->di_nextp) if (dls_accept(dip, daddr)) break; @@ -496,7 +509,7 @@ non_promisc: * sub-chain then throw it away. */ if (dip == NULL) { - ght_rele(hte); + i_dls_head_rele(dhp); freemsgchain(mp); goto loop; } @@ -545,7 +558,7 @@ non_promisc: * Release the hold on the dls_impl_t chain now that we have * finished walking it. */ - ght_rele(hte); + i_dls_head_rele(dhp); loop: /* @@ -566,18 +579,18 @@ static void i_dls_link_ether_loopback(void *arg, mblk_t *mp) { dls_link_t *dlp = arg; - ght_t hash = dlp->dl_impl_hash; + mod_hash_t *hash = dlp->dl_impl_hash; mblk_t *nextp; uint_t header_length; uint8_t *daddr; uint16_t type_length; uint16_t vid; uint16_t sap; - ghte_t hte; + dls_head_t *dhp; dls_impl_t *dip; dls_impl_t *ndip; mblk_t *nmp; - ght_key_t key; + mod_hash_key_t key; uint_t npacket; /* @@ -608,24 +621,18 @@ i_dls_link_ether_loopback(void *arg, mblk_t *mp) * Search the has table for dls_impl_t eligible to receive * a packet chain for this DLSAP/VLAN combination. */ - ght_lock(hash, GHT_READ); - if (ght_find(hash, key, &hte) != 0) { - ght_unlock(hash); + rw_enter(&dlp->dl_impl_lock, RW_READER); + if (mod_hash_find(hash, key, (mod_hash_val_t *)&dhp) != 0) { + rw_exit(&dlp->dl_impl_lock); goto promisc; } - - /* - * Place a hold the chain of dls_impl_t to make sure none are - * removed from under our feet. - */ - ght_hold(hte); - ght_unlock(hash); + i_dls_head_hold(dhp); + rw_exit(&dlp->dl_impl_lock); /* * Find dls_impl_t that will accept the sub-chain. */ - for (dip = (dls_impl_t *)GHT_VAL(hte); dip != NULL; - dip = dip->di_nextp) { + for (dip = dhp->dh_list; dip != NULL; dip = dip->di_nextp) { if (!dls_accept_loopback(dip, daddr)) continue; @@ -643,7 +650,7 @@ i_dls_link_ether_loopback(void *arg, mblk_t *mp) * Release the hold on the dls_impl_t chain now that we have * finished walking it. */ - ght_rele(hte); + i_dls_head_rele(dhp); promisc: /* @@ -656,25 +663,19 @@ promisc: * Search the has table for dls_impl_t eligible to receive * a packet chain for this DLSAP/VLAN combination. */ - ght_lock(hash, GHT_READ); - if (ght_find(hash, key, &hte) != 0) { - ght_unlock(hash); + rw_enter(&dlp->dl_impl_lock, RW_READER); + if (mod_hash_find(hash, key, (mod_hash_val_t *)&dhp) != 0) { + rw_exit(&dlp->dl_impl_lock); freemsgchain(mp); goto loop; } - - /* - * Place a hold the chain of dls_impl_t to make sure none are - * removed from under our feet. - */ - ght_hold(hte); - ght_unlock(hash); + i_dls_head_hold(dhp); + rw_exit(&dlp->dl_impl_lock); /* * Find the first dls_impl_t that will accept the sub-chain. */ - for (dip = (dls_impl_t *)GHT_VAL(hte); dip != NULL; - dip = dip->di_nextp) + for (dip = dhp->dh_list; dip != NULL; dip = dip->di_nextp) if (dls_accept_loopback(dip, daddr)) break; @@ -683,7 +684,7 @@ promisc: * sub-chain then throw it away. */ if (dip == NULL) { - ght_rele(hte); + i_dls_head_rele(dhp); freemsgchain(mp); goto loop; } @@ -728,7 +729,7 @@ promisc: * Release the hold on the dls_impl_t chain now that we have * finished walking it. */ - ght_rele(hte); + i_dls_head_rele(dhp); loop: /* @@ -738,37 +739,25 @@ loop: } } -static boolean_t -i_dls_link_walk(void *arg, ghte_t hte) +/*ARGSUSED*/ +static uint_t +i_dls_link_walk(mod_hash_key_t key, mod_hash_val_t *val, void *arg) { boolean_t *promiscp = arg; - ght_key_t key = GHT_KEY(hte); uint32_t sap = KEY_SAP(key); if (sap == DLS_SAP_PROMISC) { *promiscp = B_TRUE; - return (B_FALSE); /* terminate walk */ + return (MH_WALK_TERMINATE); } - return (B_TRUE); + return (MH_WALK_CONTINUE); } static int i_dls_link_create(const char *dev, uint_t port, dls_link_t **dlpp) { dls_link_t *dlp; - int err; - mac_handle_t mh; - - /* - * Check that the MAC exists, and (for now) that it's - * of type DL_ETHER. - */ - if ((err = mac_open(dev, port, &mh)) != 0) - return (err); - - ASSERT(mac_info(mh)->mi_media == DL_ETHER); - mac_close(mh); /* * Allocate a new dls_link_t structure. @@ -783,11 +772,6 @@ i_dls_link_create(const char *dev, uint_t port, dls_link_t **dlpp) dlp->dl_port = port; /* - * Set the initial packet receive function. - */ - ASSERT(ght_count(dlp->dl_impl_hash) == 0); - - /* * Set the packet loopback function for use when the MAC is in * promiscuous mode, and initialize promiscuous bookeeping fields. */ @@ -808,14 +792,14 @@ i_dls_link_destroy(dls_link_t *dlp) ASSERT(dlp->dl_macref == 0); ASSERT(dlp->dl_mh == NULL); ASSERT(dlp->dl_mip == NULL); + ASSERT(dlp->dl_impl_count == 0); + ASSERT(dlp->dl_mrh == NULL); /* * Free the structure back to the cache. */ - dlp->dl_mrh = NULL; dlp->dl_unknowns = 0; kmem_cache_free(i_dls_link_cachep, dlp); - } /* @@ -825,8 +809,6 @@ i_dls_link_destroy(dls_link_t *dlp) void dls_link_init(void) { - int err; - /* * Create a kmem_cache of dls_link_t structures. */ @@ -836,28 +818,31 @@ dls_link_init(void) ASSERT(i_dls_link_cachep != NULL); /* - * Create a global hash tables to be keyed by a name. + * Create a dls_link_t hash table and associated lock. */ - err = ght_str_create("dls_link_hash", LINK_HASHSZ, &i_dls_link_hash); - ASSERT(err == 0); + i_dls_link_hash = mod_hash_create_extended("dls_link_hash", + IMPL_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, + mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); + rw_init(&i_dls_link_lock, NULL, RW_DEFAULT, NULL); + i_dls_link_count = 0; } int dls_link_fini(void) { - int err; + if (i_dls_link_count > 0) + return (EBUSY); /* - * Destroy the hash table. This will return EBUSY if there are - * still entries present. + * Destroy the kmem_cache. */ - if ((err = ght_destroy(i_dls_link_hash)) != 0) - return (err); + kmem_cache_destroy(i_dls_link_cachep); /* - * Destroy the kmem_cache. + * Destroy the hash table and associated lock. */ - kmem_cache_destroy(i_dls_link_cachep); + mod_hash_destroy_hash(i_dls_link_hash); + rw_destroy(&i_dls_link_lock); return (0); } @@ -871,13 +856,6 @@ dls_link_hold(const char *dev, uint_t port, dls_link_t **dlpp) char name[MAXNAMELEN]; dls_link_t *dlp; int err; - ghte_t hte; - ghte_t nhte; - - /* - * Allocate a new hash table entry. - */ - nhte = ght_alloc(i_dls_link_hash, KM_SLEEP); /* * Construct a copy of the name used to identify any existing @@ -887,51 +865,51 @@ dls_link_hold(const char *dev, uint_t port, dls_link_t **dlpp) /* * Look up a dls_link_t corresponding to the given mac_handle_t - * in the global hash table. + * in the global hash table. We need to hold i_dls_link_lock in + * order to atomically find and insert a dls_link_t into the + * hash table. */ - ght_lock(i_dls_link_hash, GHT_WRITE); - if ((err = ght_find(i_dls_link_hash, GHT_PTR_TO_KEY(name), - &hte)) == 0) { - dlp = (dls_link_t *)GHT_VAL(hte); - ght_free(nhte); + rw_enter(&i_dls_link_lock, RW_WRITER); + if ((err = mod_hash_find(i_dls_link_hash, (mod_hash_key_t)name, + (mod_hash_val_t *)&dlp)) == 0) goto done; - } - ASSERT(err == ENOENT); + + ASSERT(err == MH_ERR_NOTFOUND); /* * We didn't find anything so we need to create one. */ if ((err = i_dls_link_create(dev, port, &dlp)) != 0) { - ght_free(nhte); - ght_unlock(i_dls_link_hash); + rw_exit(&i_dls_link_lock); return (err); } - GHT_KEY(nhte) = GHT_PTR_TO_KEY(dlp->dl_name); - GHT_VAL(nhte) = GHT_PTR_TO_VAL(dlp); - dlp->dl_hte = nhte; /* - * Insert the entry. + * Insert the dls_link_t. */ - err = ght_insert(nhte); + err = mod_hash_insert(i_dls_link_hash, (mod_hash_key_t)dlp->dl_name, + (mod_hash_val_t)dlp); ASSERT(err == 0); + i_dls_link_count++; + ASSERT(i_dls_link_count != 0); + done: /* * Bump the reference count and hand back the reference. */ dlp->dl_ref++; *dlpp = dlp; - ght_unlock(i_dls_link_hash); - return (err); + rw_exit(&i_dls_link_lock); + return (0); } void dls_link_rele(dls_link_t *dlp) { - ghte_t hte; + mod_hash_val_t val; - ght_lock(i_dls_link_hash, GHT_WRITE); + rw_enter(&i_dls_link_lock, RW_WRITER); /* * Check if there are any more references. @@ -943,22 +921,18 @@ dls_link_rele(dls_link_t *dlp) goto done; } - hte = dlp->dl_hte; - dlp->dl_hte = NULL; - - /* - * Remove the hash table entry. - */ - ght_remove(hte); - ght_free(hte); + (void) mod_hash_remove(i_dls_link_hash, + (mod_hash_key_t)dlp->dl_name, &val); + ASSERT(dlp == (dls_link_t *)val); /* * Destroy the dls_link_t. */ i_dls_link_destroy(dlp); - + ASSERT(i_dls_link_count > 0); + i_dls_link_count--; done: - ght_unlock(i_dls_link_hash); + rw_exit(&i_dls_link_lock); } int @@ -1006,17 +980,13 @@ void dls_link_add(dls_link_t *dlp, uint32_t sap, dls_impl_t *dip) { dls_vlan_t *dvp = dip->di_dvp; - ght_t hash = dlp->dl_impl_hash; - ghte_t hte; - ghte_t nhte; - ght_key_t key; - dls_impl_t **pp; + mod_hash_t *hash = dlp->dl_impl_hash; + mod_hash_key_t key; + dls_head_t *dhp; dls_impl_t *p; mac_rx_t rx; int err; - uint_t impl_count; - - ASSERT(dip->di_nextp == NULL); + boolean_t promisc = B_FALSE; /* * For ethernet media, sap values less than or equal to @@ -1035,128 +1005,84 @@ dls_link_add(dls_link_t *dlp, uint32_t sap, dls_impl_t *dip) * We need dl_lock here because we want to be able to walk * the hash table *and* set the mac rx func atomically. if * these two operations are separate, someone else could - * insert/remove dls_impl_t from the ght after we drop the - * ght lock and this could cause our chosen rx func to be - * incorrect. note that we cannot call mac_rx_set when - * holding the ght lock because this can cause deadlock. + * insert/remove dls_impl_t from the hash table after we + * drop the hash lock and this could cause our chosen rx + * func to be incorrect. note that we cannot call mac_rx_add + * when holding the hash lock because this can cause deadlock. */ mutex_enter(&dlp->dl_lock); - /* - * Allocate a new entry. - */ - nhte = ght_alloc(hash, KM_SLEEP); /* - * Search the table for any existing entry with this key. + * Search the table for a list head with this key. */ - ght_lock(hash, GHT_WRITE); - if ((err = ght_find(hash, key, &hte)) != 0) { - ASSERT(err == ENOENT); + rw_enter(&dlp->dl_impl_lock, RW_WRITER); - GHT_KEY(nhte) = key; - GHT_VAL(nhte) = GHT_PTR_TO_VAL(dip); + if ((err = mod_hash_find(hash, key, (mod_hash_val_t *)&dhp)) != 0) { + ASSERT(err == MH_ERR_NOTFOUND); - /* - * Insert it in the table to be the head of a new list. - */ - err = ght_insert(nhte); + dhp = i_dls_head_alloc(key); + err = mod_hash_insert(hash, key, (mod_hash_val_t)dhp); ASSERT(err == 0); - - /* - * Cache a reference to the hash table entry. - */ - ASSERT(dip->di_hte == NULL); - dip->di_hte = nhte; - - goto done; } /* - * Free the unused hash table entry. + * Add the dls_impl_t to the head of the list. */ - ght_free(nhte); + ASSERT(dip->di_nextp == NULL); + p = dhp->dh_list; + dip->di_nextp = p; + dhp->dh_list = dip; /* - * Add the dls_impl_t to the end of the list. We can't add to the head - * because the hash table internals already have a reference to the - * head of the list. + * Save a pointer to the list head. */ - for (pp = (dls_impl_t **)&(GHT_VAL(hte)); (p = *pp) != NULL; - pp = &(p->di_nextp)) - ASSERT(p != dip); - - *pp = dip; + dip->di_headp = dhp; + dlp->dl_impl_count++; /* - * Cache a reference to the hash table entry. + * Walk the bound dls_impl_t to see if there are any + * in promiscuous 'all sap' mode. */ - ASSERT(dip->di_hte == NULL); - dip->di_hte = hte; + mod_hash_walk(hash, i_dls_link_walk, (void *)&promisc); + rw_exit(&dlp->dl_impl_lock); -done: /* - * If there are no dls_impl_t then we can just drop all received - * packets on the floor. + * If there are then we need to use a receive routine + * which will route packets to those dls_impl_t as well + * as ones bound to the DLSAP of the packet. */ - impl_count = ght_count(hash); - if (impl_count == 0) { - ght_unlock(hash); - } else { - boolean_t promisc = B_FALSE; + if (promisc) + rx = i_dls_link_ether_rx_promisc; + else + rx = i_dls_link_ether_rx; - /* - * Walk the bound dls_impl_t to see if there are any - * in promiscuous 'all sap' mode. - */ - ght_walk(hash, i_dls_link_walk, (void *)&promisc); - - /* - * If there are then we need to use a receive routine - * which will route packets to those dls_impl_t as well - * as ones bound to the DLSAP of the packet. - */ - if (promisc) - rx = i_dls_link_ether_rx_promisc; - else - rx = i_dls_link_ether_rx; - - ght_unlock(hash); - - /* Replace the existing receive function if there is one. */ - if (dlp->dl_mrh != NULL) - mac_rx_remove(dlp->dl_mh, dlp->dl_mrh); - dlp->dl_mrh = mac_rx_add(dlp->dl_mh, rx, (void *)dlp); - } + /* Replace the existing receive function if there is one. */ + if (dlp->dl_mrh != NULL) + mac_rx_remove(dlp->dl_mh, dlp->dl_mrh); + dlp->dl_mrh = mac_rx_add(dlp->dl_mh, rx, (void *)dlp); mutex_exit(&dlp->dl_lock); } void dls_link_remove(dls_link_t *dlp, dls_impl_t *dip) { - ght_t hash = dlp->dl_impl_hash; - ghte_t hte; + mod_hash_t *hash = dlp->dl_impl_hash; dls_impl_t **pp; dls_impl_t *p; + dls_head_t *dhp; mac_rx_t rx; /* * We need dl_lock here because we want to be able to walk * the hash table *and* set the mac rx func atomically. if * these two operations are separate, someone else could - * insert/remove dls_impl_t from the ght after we drop the - * ght lock and this could cause our chosen rx func to be - * incorrect. note that we cannot call mac_rx_add when - * holding the ght lock because this can cause deadlock. + * insert/remove dls_impl_t from the hash table after we + * drop the hash lock and this could cause our chosen rx + * func to be incorrect. note that we cannot call mac_rx_add + * when holding the hash lock because this can cause deadlock. */ mutex_enter(&dlp->dl_lock); - - ght_lock(hash, GHT_WRITE); - - /* - * Get the cached hash table entry reference. - */ - hte = dip->di_hte; - ASSERT(hte != NULL); + rw_enter(&dlp->dl_impl_lock, RW_WRITER); /* * Poll the hash table entry until all references have been dropped. @@ -1166,35 +1092,39 @@ dls_link_remove(dls_link_t *dlp, dls_impl_t *dip) * This is only a hint to quicken the decrease of the refcnt so * the assignment need not be protected by any lock. */ + dhp = dip->di_headp; dip->di_removing = B_TRUE; - while (ght_ref(hte) != 0) { - ght_unlock(hash); + while (dhp->dh_ref != 0) { + rw_exit(&dlp->dl_impl_lock); mutex_exit(&dlp->dl_lock); delay(drv_usectohz(1000)); /* 1ms delay */ mutex_enter(&dlp->dl_lock); - ght_lock(hash, GHT_WRITE); + rw_enter(&dlp->dl_impl_lock, RW_WRITER); } /* * Walk the list and remove the dls_impl_t. */ - for (pp = (dls_impl_t **)&(GHT_VAL(hte)); (p = *pp) != NULL; - pp = &(p->di_nextp)) { + for (pp = &dhp->dh_list; (p = *pp) != NULL; pp = &(p->di_nextp)) { if (p == dip) break; } ASSERT(p != NULL); - *pp = p->di_nextp; p->di_nextp = NULL; - dip->di_hte = NULL; - if (GHT_VAL(hte) == NULL) { + ASSERT(dlp->dl_impl_count > 0); + dlp->dl_impl_count--; + + if (dhp->dh_list == NULL) { + mod_hash_val_t val = NULL; + /* * The list is empty so remove the hash table entry. */ - ght_remove(hte); - ght_free(hte); + (void) mod_hash_remove(hash, dhp->dh_key, &val); + ASSERT(dhp == (dls_head_t *)val); + i_dls_head_free(dhp); } dip->di_removing = B_FALSE; @@ -1202,8 +1132,8 @@ dls_link_remove(dls_link_t *dlp, dls_impl_t *dip) * If there are no dls_impl_t then there's no need to register a * receive function with the mac. */ - if (ght_count(hash) == 0) { - ght_unlock(hash); + if (dlp->dl_impl_count == 0) { + rw_exit(&dlp->dl_impl_lock); mac_rx_remove(dlp->dl_mh, dlp->dl_mrh); dlp->dl_mrh = NULL; } else { @@ -1213,7 +1143,8 @@ dls_link_remove(dls_link_t *dlp, dls_impl_t *dip) * Walk the bound dls_impl_t to see if there are any * in promiscuous 'all sap' mode. */ - ght_walk(hash, i_dls_link_walk, (void *)&promisc); + mod_hash_walk(hash, i_dls_link_walk, (void *)&promisc); + rw_exit(&dlp->dl_impl_lock); /* * If there are then we need to use a receive routine @@ -1225,8 +1156,6 @@ dls_link_remove(dls_link_t *dlp, dls_impl_t *dip) else rx = i_dls_link_ether_rx; - ght_unlock(hash); - mac_rx_remove(dlp->dl_mh, dlp->dl_mrh); dlp->dl_mrh = mac_rx_add(dlp->dl_mh, rx, (void *)dlp); } diff --git a/usr/src/uts/common/io/dls/dls_mod.c b/usr/src/uts/common/io/dls/dls_mod.c index a9d007211f..9567d785ba 100644 --- a/usr/src/uts/common/io/dls/dls_mod.c +++ b/usr/src/uts/common/io/dls/dls_mod.c @@ -32,7 +32,6 @@ #include <sys/types.h> #include <sys/modctl.h> -#include <sys/ght.h> #include <sys/mac.h> #include <sys/dls.h> diff --git a/usr/src/uts/common/io/dls/dls_stat.c b/usr/src/uts/common/io/dls/dls_stat.c index 987628b74a..d0025c7fb9 100644 --- a/usr/src/uts/common/io/dls/dls_stat.c +++ b/usr/src/uts/common/io/dls/dls_stat.c @@ -33,7 +33,6 @@ #include <sys/types.h> #include <sys/sysmacros.h> #include <sys/atomic.h> -#include <sys/ght.h> #include <sys/kstat.h> #include <sys/vlan.h> #include <sys/mac.h> diff --git a/usr/src/uts/common/io/dls/dls_vlan.c b/usr/src/uts/common/io/dls/dls_vlan.c index e37f9c9f32..872dc29522 100644 --- a/usr/src/uts/common/io/dls/dls_vlan.c +++ b/usr/src/uts/common/io/dls/dls_vlan.c @@ -33,7 +33,7 @@ #include <sys/types.h> #include <sys/sysmacros.h> #include <sys/atomic.h> -#include <sys/ght.h> +#include <sys/modhash.h> #include <sys/kstat.h> #include <sys/vlan.h> #include <sys/mac.h> @@ -42,7 +42,9 @@ #include <sys/dls_impl.h> static kmem_cache_t *i_dls_vlan_cachep; -static ght_t i_dls_vlan_hash; +static mod_hash_t *i_dls_vlan_hash; +static krwlock_t i_dls_vlan_lock; +static uint_t i_dls_vlan_count; #define VLAN_HASHSZ 67 /* prime */ @@ -75,8 +77,6 @@ i_dls_vlan_destructor(void *buf, void *arg) void dls_vlan_init(void) { - int err; - /* * Create a kmem_cache of dls_vlan_t structures. */ @@ -88,20 +88,24 @@ dls_vlan_init(void) /* * Create a hash table, keyed by name, of dls_vlan_t. */ - err = ght_str_create("dls_vlan_hash", VLAN_HASHSZ, &i_dls_vlan_hash); - ASSERT(err == 0); + i_dls_vlan_hash = mod_hash_create_extended("dls_vlan_hash", + VLAN_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, + mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); + rw_init(&i_dls_vlan_lock, NULL, RW_DEFAULT, NULL); + i_dls_vlan_count = 0; } int dls_vlan_fini(void) { - int err; + if (i_dls_vlan_count > 0) + return (EBUSY); /* - * If the hash table is not empty then this call will return EBUSY. + * Destroy the hash table */ - if ((err = ght_destroy(i_dls_vlan_hash)) != 0) - return (err); + mod_hash_destroy_hash(i_dls_vlan_hash); + rw_destroy(&i_dls_vlan_lock); /* * Destroy the kmem_cache. @@ -120,7 +124,6 @@ dls_vlan_create(const char *name, const char *dev, uint_t port, uint16_t vid) dls_link_t *dlp; dls_vlan_t *dvp; int err; - ghte_t hte; uint_t len; /* @@ -143,17 +146,6 @@ dls_vlan_create(const char *name, const char *dev, uint_t port, uint16_t vid) return (err); /* - * If we're creating a tagged VLAN, grab a reference to the MAC. - * Strictly speaking, this is only needed for aggregations (so that - * they can't be deleted when there are configured VLAN's), but it - * doesn't hurt for other MAC's either. - */ - if (vid != 0 && (err = dls_mac_hold(dlp)) != 0) { - dls_link_rele(dlp); - return (err); - } - - /* * Allocate a new dls_vlan_t. */ dvp = kmem_cache_alloc(i_dls_vlan_cachep, KM_SLEEP); @@ -162,33 +154,21 @@ dls_vlan_create(const char *name, const char *dev, uint_t port, uint16_t vid) dvp->dv_dlp = dlp; /* - * Allocate a new hash table entry. - */ - hte = ght_alloc(i_dls_vlan_hash, KM_SLEEP); - - GHT_KEY(hte) = GHT_PTR_TO_KEY(dvp->dv_name); - GHT_VAL(hte) = GHT_PTR_TO_VAL(dvp); - - /* * Insert the entry into the table. */ - ght_lock(i_dls_vlan_hash, GHT_WRITE); - if ((err = ght_insert(hte)) != 0) { - ght_free(hte); + rw_enter(&i_dls_vlan_lock, RW_WRITER); + + if ((err = mod_hash_insert(i_dls_vlan_hash, + (mod_hash_key_t)dvp->dv_name, (mod_hash_val_t)dvp)) != 0) { kmem_cache_free(i_dls_vlan_cachep, dvp); - if (vid != 0) - dls_mac_rele(dlp); dls_link_rele(dlp); + err = EEXIST; goto done; } - - /* - * Create kstats. - */ - dls_stat_create(dvp); + i_dls_vlan_count++; done: - ght_unlock(i_dls_vlan_hash); + rw_exit(&i_dls_vlan_lock); return (err); } @@ -196,50 +176,46 @@ int dls_vlan_destroy(const char *name) { int err; - ghte_t hte; dls_vlan_t *dvp; dls_link_t *dlp; + mod_hash_val_t val; /* * Find the dls_vlan_t in the global hash table. */ - ght_lock(i_dls_vlan_hash, GHT_WRITE); - if ((err = ght_find(i_dls_vlan_hash, GHT_PTR_TO_KEY(name), &hte)) != 0) + rw_enter(&i_dls_vlan_lock, RW_WRITER); + + err = mod_hash_find(i_dls_vlan_hash, (mod_hash_key_t)name, + (mod_hash_val_t *)&dvp); + if (err != 0) { + err = ENOENT; goto done; + } /* - * Check to see if it is referenced by any dls_t. + * Check to see if it is referenced by any dls_impl_t. */ - dvp = (dls_vlan_t *)GHT_VAL(hte); if (dvp->dv_ref != 0) { err = EBUSY; goto done; } /* - * Destroy kstats before releasing dls_link_t and before destroying - * the dls_vlan_t to ensure ks_update is safe. - */ - dls_stat_destroy(dvp); - - /* * Remove and destroy the hash table entry. */ - ght_remove(hte); - ght_free(hte); + err = mod_hash_remove(i_dls_vlan_hash, (mod_hash_key_t)name, + (mod_hash_val_t *)&val); + ASSERT(err == 0); + ASSERT(dvp == (dls_vlan_t *)val); - dlp = dvp->dv_dlp; + ASSERT(i_dls_vlan_count > 0); + i_dls_vlan_count--; /* - * If we're destroying a tagged VLAN, release the hold we acquired - * in dls_vlan_create(). - */ - if (dvp->dv_id != 0) - dls_mac_rele(dlp); - - /* - * Free the dls_vlan_t back to the cache. + * Save a reference to dv_dlp before freeing the dls_vlan_t back + * to the cache. */ + dlp = dvp->dv_dlp; kmem_cache_free(i_dls_vlan_cachep, dvp); /* @@ -248,23 +224,76 @@ dls_vlan_destroy(const char *name) */ dls_link_rele(dlp); done: - ght_unlock(i_dls_vlan_hash); + rw_exit(&i_dls_vlan_lock); return (err); } int -dls_vlan_hold(const char *name, dls_vlan_t **dvpp) +dls_vlan_hold(const char *name, dls_vlan_t **dvpp, boolean_t create_vlan) { int err; - ghte_t hte; dls_vlan_t *dvp; dls_link_t *dlp; + boolean_t vlan_created = B_FALSE; + +again: + rw_enter(&i_dls_vlan_lock, RW_WRITER); + + err = mod_hash_find(i_dls_vlan_hash, (mod_hash_key_t)name, + (mod_hash_val_t *)&dvp); + if (err != 0) { + char drv[MAXNAMELEN]; + uint_t index, port, len; + uint16_t vid; + + ASSERT(err == MH_ERR_NOTFOUND); + + vlan_created = B_FALSE; + if (!create_vlan) { + err = ENOENT; + goto done; + } + + /* + * Only create tagged vlans on demand. + * Note that if we get here, 'name' must be a sane + * value because it must have been derived from + * ddi_major_to_name(). + */ + if (ddi_parse(name, drv, &index) != DDI_SUCCESS || + (vid = DLS_PPA2VID(index)) == VLAN_ID_NONE || + vid > VLAN_ID_MAX) { + err = EINVAL; + goto done; + } + + if (strcmp(drv, "aggr") == 0) { + port = (uint_t)DLS_PPA2INST(index); + (void) strlcpy(drv, "aggr0", MAXNAMELEN); + } else { + port = 0; + len = strlen(drv); + ASSERT(len < MAXNAMELEN); + (void) snprintf(drv + len, MAXNAMELEN - len, "%d", + DLS_PPA2INST(index)); + } + rw_exit(&i_dls_vlan_lock); + + if ((err = dls_vlan_create(name, drv, port, vid)) != 0) { + rw_enter(&i_dls_vlan_lock, RW_WRITER); + goto done; + } + + /* + * At this point someone else could do a dls_vlan_hold and + * dls_vlan_rele on this new vlan and causes it to be + * destroyed. This will at worst cause us to spin a few + * times. + */ + vlan_created = B_TRUE; + goto again; + } - ght_lock(i_dls_vlan_hash, GHT_WRITE); - if ((err = ght_find(i_dls_vlan_hash, GHT_PTR_TO_KEY(name), &hte)) != 0) - goto done; - - dvp = (dls_vlan_t *)GHT_VAL(hte); dlp = dvp->dv_dlp; if ((err = dls_mac_hold(dlp)) != 0) @@ -275,10 +304,20 @@ dls_vlan_hold(const char *name, dls_vlan_t **dvpp) goto done; } - dvp->dv_ref++; + if (dvp->dv_ref++ == 0) + dls_stat_create(dvp); + *dvpp = dvp; done: - ght_unlock(i_dls_vlan_hash); + rw_exit(&i_dls_vlan_lock); + + /* + * We could be destroying a vlan created by another thread. This + * is ok because this other thread will just loop back up and + * recreate the vlan. + */ + if (err != 0 && vlan_created) + (void) dls_vlan_destroy(name); return (err); } @@ -286,12 +325,62 @@ void dls_vlan_rele(dls_vlan_t *dvp) { dls_link_t *dlp; + char name[IFNAMSIZ]; + boolean_t destroy_vlan = B_FALSE; - ght_lock(i_dls_vlan_hash, GHT_WRITE); + rw_enter(&i_dls_vlan_lock, RW_WRITER); dlp = dvp->dv_dlp; mac_stop(dlp->dl_mh); dls_mac_rele(dlp); - --dvp->dv_ref; - ght_unlock(i_dls_vlan_hash); + if (--dvp->dv_ref == 0) { + dls_stat_destroy(dvp); + /* + * Tagged vlans get destroyed when dv_ref drops + * to 0. We need to copy dv_name here because + * dvp could disappear after we drop i_dls_vlan_lock. + */ + if (dvp->dv_id != 0) { + (void) strlcpy(name, dvp->dv_name, IFNAMSIZ); + destroy_vlan = B_TRUE; + } + } + rw_exit(&i_dls_vlan_lock); + if (destroy_vlan) + (void) dls_vlan_destroy(name); +} + +typedef struct dls_vlan_walk_state { + int (*fn)(dls_vlan_t *, void *); + void *arg; + int rc; +} dls_vlan_walk_state_t; + +/*ARGSUSED*/ +static uint_t +dls_vlan_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) +{ + dls_vlan_walk_state_t *statep = arg; + dls_vlan_t *dvp; + + dvp = (dls_vlan_t *)val; + statep->rc = statep->fn(dvp, statep->arg); + + return ((statep->rc == 0) ? MH_WALK_CONTINUE : MH_WALK_TERMINATE); +} + +int +dls_vlan_walk(int (*fn)(dls_vlan_t *, void *), void *arg) +{ + dls_vlan_walk_state_t state; + + rw_enter(&i_dls_vlan_lock, RW_READER); + + state.fn = fn; + state.arg = arg; + state.rc = 0; + mod_hash_walk(i_dls_vlan_hash, dls_vlan_walker, (void *)&state); + + rw_exit(&i_dls_vlan_lock); + return (state.rc); } diff --git a/usr/src/uts/common/io/mac/mac.c b/usr/src/uts/common/io/mac/mac.c index ca69bb9be5..288bb79298 100644 --- a/usr/src/uts/common/io/mac/mac.c +++ b/usr/src/uts/common/io/mac/mac.c @@ -37,14 +37,18 @@ #include <sys/strsun.h> #include <sys/strsubr.h> #include <sys/dlpi.h> +#include <sys/modhash.h> #include <sys/mac.h> #include <sys/mac_impl.h> -#include <sys/dld_impl.h> +#include <sys/dls.h> +#include <sys/dld.h> #define IMPL_HASHSZ 67 /* prime */ static kmem_cache_t *i_mac_impl_cachep; -static ght_t i_mac_impl_hash; +static mod_hash_t *i_mac_impl_hash; +krwlock_t i_mac_impl_lock; +uint_t i_mac_impl_count; /* * Private functions. @@ -110,7 +114,6 @@ i_mac_destructor(void *buf, void *arg) mac_impl_t *mip = buf; ASSERT(mip->mi_mp == NULL); - ASSERT(mip->mi_hte == NULL); ASSERT(mip->mi_ref == 0); ASSERT(mip->mi_active == 0); ASSERT(mip->mi_link == LINK_STATE_UNKNOWN); @@ -130,13 +133,12 @@ i_mac_destructor(void *buf, void *arg) mutex_destroy(&mip->mi_activelink_lock); } -int +static int i_mac_create(mac_t *mp) { dev_info_t *dip; mac_impl_t *mip; - int err; - ghte_t hte; + int err = 0; dip = mp->m_dip; ASSERT(dip != NULL); @@ -163,24 +165,16 @@ i_mac_create(mac_t *mp) mp->m_impl = (void *)mip; /* - * Allocate a hash table entry. - */ - hte = ght_alloc(i_mac_impl_hash, KM_SLEEP); - - GHT_KEY(hte) = GHT_PTR_TO_KEY(mip->mi_name); - GHT_VAL(hte) = GHT_PTR_TO_VAL(mip); - - /* * Insert the hash table entry. */ - ght_lock(i_mac_impl_hash, GHT_WRITE); - if ((err = ght_insert(hte)) != 0) { - ght_free(hte); + rw_enter(&i_mac_impl_lock, RW_WRITER); + if (mod_hash_insert(i_mac_impl_hash, + (mod_hash_key_t)mip->mi_name, (mod_hash_val_t)mip) != 0) { kmem_cache_free(i_mac_impl_cachep, mip); + err = EEXIST; goto done; } - - mip->mi_hte = hte; + i_mac_impl_count++; /* * Copy the fixed 'factory' MAC address from the immutable info. @@ -210,7 +204,7 @@ i_mac_create(mac_t *mp) mac_stat_create(mip); done: - ght_unlock(i_mac_impl_hash); + rw_exit(&i_mac_impl_lock); return (err); } @@ -218,10 +212,10 @@ static void i_mac_destroy(mac_t *mp) { mac_impl_t *mip = mp->m_impl; - ghte_t hte; mac_multicst_addr_t *p, *nextp; + mod_hash_val_t val; - ght_lock(i_mac_impl_hash, GHT_WRITE); + rw_enter(&i_mac_impl_lock, RW_WRITER); ASSERT(mip->mi_ref == 0); ASSERT(!mip->mi_activelink); @@ -234,10 +228,12 @@ i_mac_destroy(mac_t *mp) /* * Remove and destroy the hash table entry. */ - hte = mip->mi_hte; - ght_remove(hte); - ght_free(hte); - mip->mi_hte = NULL; + (void) mod_hash_remove(i_mac_impl_hash, + (mod_hash_key_t)mip->mi_name, &val); + ASSERT(mip == (mac_impl_t *)val); + + ASSERT(i_mac_impl_count > 0); + i_mac_impl_count--; /* * Free the list of multicast addresses. @@ -261,7 +257,7 @@ i_mac_destroy(mac_t *mp) */ kmem_cache_free(i_mac_impl_cachep, mip); - ght_unlock(i_mac_impl_hash); + rw_exit(&i_mac_impl_lock); } static void @@ -292,24 +288,26 @@ i_mac_notify(mac_impl_t *mip, mac_notify_type_t type) void mac_init(void) { - int err; - i_mac_impl_cachep = kmem_cache_create("mac_impl_cache", sizeof (mac_impl_t), 0, i_mac_constructor, i_mac_destructor, NULL, NULL, NULL, 0); ASSERT(i_mac_impl_cachep != NULL); - err = ght_str_create("mac_impl_hash", IMPL_HASHSZ, &i_mac_impl_hash); - ASSERT(err == 0); + i_mac_impl_hash = mod_hash_create_extended("mac_impl_hash", + IMPL_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, + mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); + rw_init(&i_mac_impl_lock, NULL, RW_DEFAULT, NULL); + i_mac_impl_count = 0; } int mac_fini(void) { - int err; + if (i_mac_impl_count > 0) + return (EBUSY); - if ((err = ght_destroy(i_mac_impl_hash)) != 0) - return (err); + mod_hash_destroy_hash(i_mac_impl_hash); + rw_destroy(&i_mac_impl_lock); kmem_cache_destroy(i_mac_impl_cachep); return (0); @@ -328,7 +326,6 @@ mac_open(const char *dev, uint_t port, mac_handle_t *mhp) major_t major; dev_info_t *dip; mac_impl_t *mip; - ghte_t hte; int err; /* @@ -352,7 +349,11 @@ mac_open(const char *dev, uint_t port, mac_handle_t *mhp) /* * Hold the given instance to prevent it from being detached. - * (This will also attach it if it is not currently attached). + * This will also attach the instance if it is not currently attached. + * Currently we ensure that mac_register() (called by the driver's + * attach entry point) and all code paths under it cannot possibly + * call mac_open() because this would lead to a recursive attach + * panic. */ if ((dip = ddi_hold_devi_by_instance(major, instance, 0)) == NULL) return (EINVAL); @@ -366,26 +367,31 @@ mac_open(const char *dev, uint_t port, mac_handle_t *mhp) * Look up its entry in the global hash table. */ again: - ght_lock(i_mac_impl_hash, GHT_WRITE); - if ((err = ght_find(i_mac_impl_hash, GHT_PTR_TO_KEY(name), &hte)) != 0) + rw_enter(&i_mac_impl_lock, RW_WRITER); + err = mod_hash_find(i_mac_impl_hash, (mod_hash_key_t)name, + (mod_hash_val_t *)&mip); + if (err != 0) { + err = ENOENT; goto failed; - - mip = (mac_impl_t *)GHT_VAL(hte); - ASSERT(mip->mi_mp->m_dip == dip); + } if (mip->mi_destroying) { - ght_unlock(i_mac_impl_hash); + rw_exit(&i_mac_impl_lock); goto again; } + /* + * We currently only support the DL_ETHER media type. + */ + ASSERT(mip->mi_mp->m_info.mi_media == DL_ETHER); mip->mi_ref++; - ght_unlock(i_mac_impl_hash); + rw_exit(&i_mac_impl_lock); *mhp = (mac_handle_t)mip; return (0); failed: - ght_unlock(i_mac_impl_hash); + rw_exit(&i_mac_impl_lock); ddi_release_devi(dip); return (err); } @@ -396,14 +402,14 @@ mac_close(mac_handle_t mh) mac_impl_t *mip = (mac_impl_t *)mh; dev_info_t *dip = mip->mi_mp->m_dip; - ght_lock(i_mac_impl_hash, GHT_WRITE); + rw_enter(&i_mac_impl_lock, RW_WRITER); ASSERT(mip->mi_ref != 0); if (--mip->mi_ref == 0) { ASSERT(!mip->mi_activelink); } ddi_release_devi(dip); - ght_unlock(i_mac_impl_hash); + rw_exit(&i_mac_impl_lock); } const mac_info_t * @@ -418,6 +424,12 @@ mac_info(mac_handle_t mh) return (&(mp->m_info)); } +dev_info_t * +mac_devinfo_get(mac_handle_t mh) +{ + return (((mac_impl_t *)mh)->mi_mp->m_dip); +} + uint64_t mac_stat_get(mac_handle_t mh, enum mac_stat stat) { @@ -1009,19 +1021,19 @@ mac_resource_set(mac_handle_t mh, mac_resource_add_t add, void *arg) int mac_register(mac_t *mp) { - int err; - char name[MAXNAMELEN], aggr_name[MAXNAMELEN]; + int err, instance; + char name[MAXNAMELEN], devname[MAXNAMELEN]; + const char *drvname; struct devnames *dnp; + minor_t minor; -#ifdef DEBUG - if (strcmp(mp->m_ident, MAC_IDENT) != 0) - cmn_err(CE_WARN, "%s%d/%d: possible mac interface mismatch", - ddi_driver_name(mp->m_dip), - ddi_get_instance(mp->m_dip), - mp->m_port); -#endif /* DEBUG */ + drvname = ddi_driver_name(mp->m_dip); + instance = ddi_get_instance(mp->m_dip); - ASSERT(!(mp->m_info.mi_addr_length & 1)); + if (strcmp(mp->m_ident, MAC_IDENT) != 0) { + cmn_err(CE_WARN, "%s%d/%d: possible mac interface mismatch", + drvname, instance, mp->m_port); + } /* * Create a new mac_impl_t to pair with the mac_t. @@ -1029,71 +1041,80 @@ mac_register(mac_t *mp) if ((err = i_mac_create(mp)) != 0) return (err); - /* - * Create a DDI_NT_MAC minor node such that libdevinfo(3lib) can be - * used to search for mac interfaces. - */ - (void) sprintf(name, "%d", mp->m_port); - if (ddi_create_minor_node(mp->m_dip, name, S_IFCHR, mp->m_port, - DDI_NT_MAC, 0) != DDI_SUCCESS) { - i_mac_destroy(mp); - return (EEXIST); - } + err = EEXIST; + if (ddi_create_minor_node(mp->m_dip, (char *)drvname, S_IFCHR, 0, + DDI_NT_NET, CLONE_DEV) != DDI_SUCCESS) + goto fail1; - /* - * Right now only the "aggr" driver creates nodes at mac_register - * time, but it is expected that in the future with some - * enhancement of devfs, all the drivers can create nodes here. - */ - if (strcmp(ddi_driver_name(mp->m_dip), "aggr") == 0) { - (void) snprintf(aggr_name, MAXNAMELEN, "aggr%u", mp->m_port); - err = dld_ppa_create(aggr_name, AGGR_DEV, mp->m_port, 0); - if (err != 0) { - ASSERT(err != EEXIST); - ddi_remove_minor_node(mp->m_dip, name); - i_mac_destroy(mp); - return (err); - } + (void) snprintf(devname, MAXNAMELEN, "%s%d", drvname, instance); + + if (strcmp(drvname, "aggr") == 0) { + (void) snprintf(name, MAXNAMELEN, "aggr%u", mp->m_port); + minor = (minor_t)mp->m_port + 1; + } else { + (void) strlcpy(name, devname, MAXNAMELEN); + minor = (minor_t)instance + 1; } + if (ddi_create_minor_node(mp->m_dip, name, S_IFCHR, minor, + DDI_NT_NET, 0) != DDI_SUCCESS) + goto fail2; + + if ((err = dls_create(name, devname, mp->m_port)) != 0) + goto fail3; + /* set the gldv3 flag in dn_flags */ dnp = &devnamesp[ddi_driver_major(mp->m_dip)]; LOCK_DEV_OPS(&dnp->dn_lock); dnp->dn_flags |= DN_GLDV3_DRIVER; UNLOCK_DEV_OPS(&dnp->dn_lock); - cmn_err(CE_NOTE, "!%s%d/%d registered", - ddi_driver_name(mp->m_dip), - ddi_get_instance(mp->m_dip), - mp->m_port); - + cmn_err(CE_NOTE, "!%s%d/%d registered", drvname, instance, mp->m_port); return (0); + +fail3: + ddi_remove_minor_node(mp->m_dip, name); +fail2: + ddi_remove_minor_node(mp->m_dip, (char *)drvname); +fail1: + i_mac_destroy(mp); + return (err); } int mac_unregister(mac_t *mp) { - int err; + int err, instance; char name[MAXNAMELEN]; + const char *drvname; mac_impl_t *mip = mp->m_impl; + drvname = ddi_driver_name(mp->m_dip); + instance = ddi_get_instance(mp->m_dip); + /* * See if there are any other references to this mac_t (e.g., VLAN's). * If not, set mi_destroying to prevent any new VLAN's from being * created before we can perform the i_mac_destroy() below. */ - ght_lock(i_mac_impl_hash, GHT_WRITE); + rw_enter(&i_mac_impl_lock, RW_WRITER); if (mip->mi_ref > 0) { - ght_unlock(i_mac_impl_hash); + rw_exit(&i_mac_impl_lock); return (EBUSY); } mip->mi_destroying = B_TRUE; - ght_unlock(i_mac_impl_hash); + rw_exit(&i_mac_impl_lock); - if (strcmp(ddi_driver_name(mp->m_dip), "aggr") == 0) { + if (strcmp(drvname, "aggr") == 0) (void) snprintf(name, MAXNAMELEN, "aggr%u", mp->m_port); - if ((err = dld_ppa_destroy(name)) != 0) - return (err); + else + (void) snprintf(name, MAXNAMELEN, "%s%d", drvname, instance); + + if ((err = dls_destroy(name)) != 0) { + rw_enter(&i_mac_impl_lock, RW_WRITER); + mip->mi_destroying = B_FALSE; + rw_exit(&i_mac_impl_lock); + return (err); } /* @@ -1102,16 +1123,13 @@ mac_unregister(mac_t *mp) i_mac_destroy(mp); /* - * Remove the minor node. + * Remove both style 1 and style 2 minor nodes */ - (void) sprintf(name, "%d", mp->m_port); + ddi_remove_minor_node(mp->m_dip, (char *)drvname); ddi_remove_minor_node(mp->m_dip, name); - cmn_err(CE_NOTE, "!%s%d/%d unregistered", - ddi_driver_name(mp->m_dip), - ddi_get_instance(mp->m_dip), + cmn_err(CE_NOTE, "!%s%d/%d unregistered", drvname, instance, mp->m_port); - return (0); } @@ -1378,3 +1396,63 @@ mac_active_clear(mac_handle_t mh) mip->mi_activelink = B_FALSE; mutex_exit(&mip->mi_activelink_lock); } + +/* + * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is + * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find + * the first mac_impl_t with a matching driver name; then we copy its mac_info_t + * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t + * cannot disappear while we are accessing it. + */ +typedef struct i_mac_info_state_s { + const char *mi_name; + mac_info_t *mi_infop; +} i_mac_info_state_t; + +/*ARGSUSED*/ +static uint_t +i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) +{ + i_mac_info_state_t *statep = arg; + mac_impl_t *mip = (mac_impl_t *)val; + + if (mip->mi_destroying) + return (MH_WALK_CONTINUE); + + if (strcmp(statep->mi_name, + ddi_driver_name(mip->mi_mp->m_dip)) != 0) + return (MH_WALK_CONTINUE); + + statep->mi_infop = &mip->mi_mp->m_info; + return (MH_WALK_TERMINATE); +} + +boolean_t +mac_info_get(const char *name, mac_info_t *minfop) +{ + i_mac_info_state_t state; + + rw_enter(&i_mac_impl_lock, RW_READER); + state.mi_name = name; + state.mi_infop = NULL; + mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state); + if (state.mi_infop == NULL) { + rw_exit(&i_mac_impl_lock); + return (B_FALSE); + } + *minfop = *state.mi_infop; + rw_exit(&i_mac_impl_lock); + return (B_TRUE); +} + +void +mac_init_ops(struct dev_ops *ops, const char *name) +{ + dld_init_ops(ops, name); +} + +void +mac_fini_ops(struct dev_ops *ops) +{ + dld_fini_ops(ops); +} diff --git a/usr/src/uts/common/io/strplumb.c b/usr/src/uts/common/io/strplumb.c index 4e735f2dce..3bacfdc4be 100644 --- a/usr/src/uts/common/io/strplumb.c +++ b/usr/src/uts/common/io/strplumb.c @@ -360,50 +360,6 @@ done: return (err); } -static int -create_gldv3_linkobj(ldi_ident_t li, char *driver, int instance) -{ - ldi_handle_t lh; - int err; - struct strioctl iocb; - int rval; - dld_ioc_create_t dic; - - /* - * gld v3 driver. open the DLD control node. - */ - if ((err = ldi_open_by_name(DLD_CONTROL_DEV, FREAD|FWRITE, CRED(), &lh, - li)) != 0) { - printf("strplumb: open CTLDEV failed: %d\n", err); - return (ENXIO); - } - - (void) snprintf(dic.dic_name, sizeof (dic.dic_name) - 1, "%s%d", - driver, instance); - (void) snprintf(dic.dic_dev, sizeof (dic.dic_dev) - 1, "%s%d", - driver, instance); - dic.dic_port = 0; - dic.dic_vid = 0; - - iocb.ic_cmd = DLDIOCCREATE; - iocb.ic_timout = 15; - iocb.ic_len = sizeof (dic); - iocb.ic_dp = (char *)&dic; - - /* - * Try to create a data-link interface with the same name as the - * device. - */ - if ((err = ldi_ioctl(lh, I_STR, (intptr_t)&iocb, FKIOCTL, CRED(), - &rval)) != 0) { - cmn_err(CE_WARN, "strplumb: DLDIOCCREATE failed: %d\n", err); - return (ENXIO); - } - - (void) ldi_close(lh, FREAD|FWRITE, CRED()); - return (0); -} - /* * Can be set in /etc/system in the case of local booting. See comment below. */ @@ -420,13 +376,12 @@ int ndev_unit = 0; * This can be overridden by setting "ndev_name" in /etc/system. */ static int -resolve_boot_path(ldi_ident_t li) +resolve_boot_path(void) { char *devpath = NULL; dev_info_t *dip; const char *driver; int instance; - int err; if (strncmp(rootfs.bo_fstype, "nfs", 3) == 0) devpath = rootfs.bo_name; @@ -466,29 +421,12 @@ resolve_boot_path(ldi_ident_t li) instance = ndev_unit; } - /* legcy driver, use clone to open */ - if (!GLDV3_DRV(ddi_name_to_major((char *)driver))) { - (void) snprintf(rootfs.bo_devname, BO_MAXOBJNAME, - "/devices/pseudo/clone@0:%s", driver); - (void) snprintf(rootfs.bo_ifname, BO_MAXOBJNAME, "%s%d", - driver, instance); - rootfs.bo_ppa = instance; - return (0); - } - - /* GLDv3: create link object so open with succeed later */ - err = create_gldv3_linkobj(li, (char *)driver, instance); - if (err != 0) { - return (err); - } - (void) snprintf(rootfs.bo_devname, BO_MAXOBJNAME, - "/devices/pseudo/dld@0:%s", driver); + "/devices/pseudo/clone@0:%s", driver); (void) snprintf(rootfs.bo_ifname, BO_MAXOBJNAME, "%s%d", driver, instance); rootfs.bo_ppa = instance; - - return (err); + return (0); } static int @@ -697,7 +635,7 @@ strplumb(void) if ((err = strplumb_tcpq(li)) != 0) goto done; - if ((err = resolve_boot_path(li)) != 0) + if ((err = resolve_boot_path()) != 0) goto done; DBG1("rootfs.bo_devname: %s\n", rootfs.bo_devname); diff --git a/usr/src/uts/common/os/ght.c b/usr/src/uts/common/os/ght.c deleted file mode 100644 index 7c33a8e125..0000000000 --- a/usr/src/uts/common/os/ght.c +++ /dev/null @@ -1,527 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Generic Hash Table Module - */ - -#include <sys/types.h> -#include <sys/sysmacros.h> -#include <sys/kmem.h> -#include <sys/sunddi.h> -#include <sys/modctl.h> -#include <sys/atomic.h> -#include <sys/ght.h> - -/* - * Revelations of the hash table and element structures. - * - * ght_t -> ght_impl_t * - * ghte_t -> ghte_impl_t * - */ -typedef struct ght_impl ght_impl_t; -typedef struct ghte_impl ghte_impl_t; - -struct ghte_impl { - ght_key_t ghtei_key; - ght_val_t ghtei_val; - ghte_impl_t **ghtei_prevp; - ghte_impl_t *ghtei_next; - ght_impl_t *ghtei_table; - boolean_t ghtei_active; - uint_t ghtei_ref; -}; - -struct ght_impl { - char ghti_name[MAXNAMELEN]; - uint_t ghti_nbuckets; - uint_t ghti_entries; - ghte_impl_t **ghti_bucket; - krwlock_t ghti_lock; - kmem_cache_t *ghti_cache; - uintptr_t (*ghti_hash)(ght_key_t); - int (*ghti_keycmp)(ght_key_t, ght_key_t); -}; - -static uintptr_t i_ght_str_hash(ght_key_t); -static int i_ght_str_keycmp(ght_key_t, ght_key_t); -static uintptr_t i_ght_scalar_hash(ght_key_t); -static int i_ght_scalar_keycmp(ght_key_t, ght_key_t); -static int i_ght_ctor(void *, void *, int); -static void i_ght_dtor(void *, void *); -static int i_ght_create(char *, uint_t, uintptr_t (*)(ght_key_t), - int (*)(ght_key_t, ght_key_t), ght_impl_t **); - -#define GHT_LINKINFO "Generic Hash Table v%I%" - -static struct modlmisc modlmisc = { - &mod_miscops, - GHT_LINKINFO -}; - -static struct modlinkage modlinkage = { - MODREV_1, - &modlmisc, - NULL -}; - -int -_init(void) -{ - int err; - - if ((err = mod_install(&modlinkage)) != 0) - return (err); - - return (0); -} - -int -_fini(void) -{ - int err; - - if ((err = mod_remove(&modlinkage)) != 0) - return (err); - - return (0); -} - -int -_info(struct modinfo *modinfop) -{ - return (mod_info(&modlinkage, modinfop)); -} - -/* - * Hash function for text string keys - */ -static uintptr_t -i_ght_str_hash(ght_key_t key) -{ - char *k = (char *)key; - uintptr_t hash; - - ASSERT(k != NULL); - hash = *k++; - while (*k != '\0') { - uint_t g; - - hash = (hash << 4) + *k++; - if ((g = (hash & 0xf0000000)) == 0) - continue; - - hash ^= (g >> 24) ^ g; - } - - return (hash); -} - -/* - * Comparitor for text string keys - */ -static int -i_ght_str_keycmp(ght_key_t key1, ght_key_t key2) -{ - return (strcmp((char *)key1, (char *)key2)); -} - -/* - * Hash function for scalar keys - */ -static uintptr_t -i_ght_scalar_hash(ght_key_t key) -{ - return ((uintptr_t)key); -} - -/* - * Comparitor for scalar keys - */ -static int -i_ght_scalar_keycmp(ght_key_t key1, ght_key_t key2) -{ - uintptr_t k1 = (uintptr_t)key1; - uintptr_t k2 = (uintptr_t)key2; - - return ((k1 == k2) ? 0 : ((k1 > k2) ? 1 : -1)); -} - -/* - * Cache constructor for hash table entries - */ -/*ARGSUSED*/ -static int -i_ght_ctor(void *buf, void *arg, int kmflags) -{ - ghte_impl_t *ghteip = buf; - - bzero(buf, sizeof (ghte_impl_t)); - - ghteip->ghtei_table = (ght_impl_t *)arg; - - return (0); -} - -/* - * Cache destructor for hash table entries - */ -static void -i_ght_dtor(void *buf, void *arg) -{ - ghte_impl_t *ghteip = buf; - - ASSERT(!(ghteip->ghtei_active)); - ASSERT((void *)ghteip->ghtei_table == arg); - ASSERT(ghteip->ghtei_next == NULL); -} - -/* - * Create a hash table - */ -static int -i_ght_create(char *name, uint_t nbuckets, uintptr_t (*hash)(ght_key_t), - int (*keycmp)(ght_key_t, ght_key_t), ght_impl_t **ghtipp) -{ - int len; - size_t size; - ght_impl_t *ghtip; - - ASSERT(name != NULL); - ASSERT(hash != NULL); - ASSERT(keycmp != NULL); - ASSERT(ghtipp != NULL); - - if ((len = strlen(name)) >= MAXNAMELEN) - return (EINVAL); - - size = sizeof (ght_impl_t) + (nbuckets * sizeof (ghte_impl_t)); - ghtip = kmem_zalloc(size, KM_SLEEP); - - (void) strlcpy(ghtip->ghti_name, name, MAXNAMELEN); - ghtip->ghti_name[len] = '\0'; - ghtip->ghti_bucket = (ghte_impl_t **)&ghtip[1]; - ghtip->ghti_nbuckets = nbuckets; - ghtip->ghti_entries = 0; - ghtip->ghti_hash = hash; - ghtip->ghti_keycmp = keycmp; - - rw_init(&ghtip->ghti_lock, NULL, RW_DRIVER, NULL); - ghtip->ghti_cache = kmem_cache_create(name, sizeof (ghte_impl_t), 0, - i_ght_ctor, i_ght_dtor, NULL, (void *)ghtip, NULL, 0); - - *ghtipp = ghtip; - return (0); -} - -/* - * External functions. - */ - -/* - * Lock a table. - */ -void -ght_lock(ght_t ght, int flag) -{ - ght_impl_t *ghtip = (ght_impl_t *)ght; - - ASSERT(flag == GHT_READ || flag == GHT_WRITE); - rw_enter(&(ghtip->ghti_lock), (flag == GHT_READ) ? RW_READER : - RW_WRITER); -} - -/* - * Unlock a table. - */ -void -ght_unlock(ght_t ght) -{ - ght_impl_t *ghtip = (ght_impl_t *)ght; - - rw_exit(&(ghtip->ghti_lock)); -} - -/* - * Create a string keyed table. - */ -int -ght_str_create(char *name, uint_t nbuckets, ght_t *ghtp) -{ - ght_impl_t *ghtip; - int err; - - if ((err = i_ght_create(name, nbuckets, i_ght_str_hash, - i_ght_str_keycmp, &ghtip)) != 0) - return (err); - - *ghtp = (ght_t)ghtip; - return (0); -} - -/* - * Create a scalar keyed table. - */ -int -ght_scalar_create(char *name, uint_t nbuckets, ght_t *ghtp) -{ - ght_impl_t *ghtip; - int err; - - if ((err = i_ght_create(name, nbuckets, i_ght_scalar_hash, - i_ght_scalar_keycmp, &ghtip)) != 0) - return (err); - - *ghtp = (ght_t)ghtip; - return (0); -} - -/* - * Destroy a table. - */ -int -ght_destroy(ght_t ght) -{ - ght_impl_t *ghtip = (ght_impl_t *)ght; - size_t size; - - ASSERT(ghtip != NULL); - - if (ghtip->ghti_entries != 0) - return (EBUSY); - - kmem_cache_destroy(ghtip->ghti_cache); - rw_destroy(&ghtip->ghti_lock); - - size = sizeof (ght_impl_t) + - (ghtip->ghti_nbuckets * sizeof (ghte_impl_t)); - kmem_free(ghtip, size); - - return (0); -} - -/* - * Return the number of entries in a table. - */ -uint_t -ght_count(ght_t ght) -{ - ght_impl_t *ghtip = (ght_impl_t *)ght; - - return (ghtip->ghti_entries); -} - -/* - * Allocate a new entry for a table. - */ -ghte_t -ght_alloc(ght_t ght, int kmflags) -{ - ght_impl_t *ghtip = (ght_impl_t *)ght; - ghte_impl_t *ghteip; - - if ((ghteip = kmem_cache_alloc(ghtip->ghti_cache, kmflags)) == NULL) - return (NULL); - - return ((ghte_t)ghteip); -} - -/* - * Free a table entry (after it has been removed). - */ -void -ght_free(ghte_t ghte) -{ - ghte_impl_t *ghteip = (ghte_impl_t *)ghte; - ght_impl_t *ghtip = ghteip->ghtei_table; - - ASSERT(!(ghteip->ghtei_active)); - ASSERT(ghteip->ghtei_ref == 0); - - kmem_cache_free(ghtip->ghti_cache, ghteip); -} - -/* - * Insert an entry into a table. - */ -int -ght_insert(ghte_t ghte) -{ - ghte_impl_t *ghteip = (ghte_impl_t *)ghte; - ght_impl_t *ghtip = ghteip->ghtei_table; - ghte_impl_t **pp; - ghte_impl_t *p; - uint_t n; - - ASSERT(ghteip != NULL); - ASSERT(!(ghteip->ghtei_active)); - ASSERT(rw_write_held(&(ghtip->ghti_lock))); - - n = ghtip->ghti_hash(ghteip->ghtei_key) % ghtip->ghti_nbuckets; - for (pp = &(ghtip->ghti_bucket[n]); (p = *pp) != NULL; - pp = &(p->ghtei_next)) { - if (ghtip->ghti_keycmp(ghteip->ghtei_key, p->ghtei_key) == 0) - return (EEXIST); - } - - ghteip->ghtei_next = p; - ghteip->ghtei_prevp = pp; - *pp = ghteip; - - ghteip->ghtei_active = B_TRUE; - ghtip->ghti_entries++; - return (0); -} - -/* - * Look-up an enrty in a table. - */ -int -ght_find(ght_t ght, ght_key_t key, ghte_t *ghtep) -{ - ght_impl_t *ghtip = (ght_impl_t *)ght; - ghte_impl_t *p; - uint_t n; - - ASSERT(ghtip != NULL); - ASSERT(rw_read_held(&(ghtip->ghti_lock)) || - rw_write_held(&(ghtip->ghti_lock))); - - n = ghtip->ghti_hash(key) % ghtip->ghti_nbuckets; - for (p = ghtip->ghti_bucket[n]; p != NULL; p = p->ghtei_next) { - ASSERT(p->ghtei_active); - if (ghtip->ghti_keycmp(key, p->ghtei_key) == 0) - break; - } - if (p == NULL) - return (ENOENT); - - *ghtep = (ghte_t)p; - return (0); -} - -/* - * Increment the reference count on a hash table entry. - */ -void -ght_hold(ghte_t ghte) -{ - ghte_impl_t *ghteip = (ghte_impl_t *)ghte; - ght_impl_t *ghtip = ghteip->ghtei_table; - - ASSERT(ghteip->ghtei_active); - ASSERT(rw_read_held(&(ghtip->ghti_lock)) || - rw_write_held(&(ghtip->ghti_lock))); - - atomic_add_32(&(ghteip->ghtei_ref), 1); -} - -/* - * Decrement the reference count on a hash table entry. - */ -void -ght_rele(ghte_t ghte) -{ - ghte_impl_t *ghteip = (ghte_impl_t *)ghte; - - ASSERT(ghteip->ghtei_active); - ASSERT(ghteip->ghtei_ref != 0); - - atomic_add_32(&(ghteip->ghtei_ref), -1); -} - -/* - * Return the reference count on a hash table entry. - */ -uint_t -ght_ref(ghte_t ghte) -{ - ghte_impl_t *ghteip = (ghte_impl_t *)ghte; - ght_impl_t *ghtip = ghteip->ghtei_table; - - ASSERT(ghteip->ghtei_active); - ASSERT(rw_read_held(&(ghtip->ghti_lock)) || - rw_write_held(&(ghtip->ghti_lock))); - - return (ghteip->ghtei_ref); -} - -/* - * Remove an entry from its table. - */ -void -ght_remove(ghte_t ghte) -{ - ghte_impl_t *ghteip = (ghte_impl_t *)ghte; - ght_impl_t *ghtip = ghteip->ghtei_table; - ghte_impl_t **pp; - ghte_impl_t *p; - - ASSERT(ghteip != NULL); - ASSERT(ghteip->ghtei_active); - ASSERT(rw_write_held(&(ghtip->ghti_lock))); - - pp = ghteip->ghtei_prevp; - p = ghteip->ghtei_next; - - *pp = p; - if (p != NULL) { - ASSERT(p->ghtei_prevp == &(ghteip->ghtei_next)); - p->ghtei_prevp = pp; - } - - ghteip->ghtei_prevp = NULL; - ghteip->ghtei_next = NULL; - - ghteip->ghtei_active = B_FALSE; - --ghtip->ghti_entries; -} - -/* - * Walk table entries calling fn() for each one. - */ -void -ght_walk(ght_t ght, boolean_t (*fn)(void *, ghte_t), void *arg) -{ - ght_impl_t *ghtip = (ght_impl_t *)ght; - uint_t n; - ghte_impl_t *p; - - ASSERT(ghtip != NULL); - ASSERT(rw_read_held(&(ghtip->ghti_lock)) || - rw_write_held(&(ghtip->ghti_lock))); - ASSERT(fn != NULL); - - for (n = 0; n < ghtip->ghti_nbuckets; n++) { - for (p = ghtip->ghti_bucket[n]; p != NULL; p = p->ghtei_next) { - ASSERT(p->ghtei_active); - if (!(fn(arg, (ghte_t)p))) - return; - } - } -} diff --git a/usr/src/uts/common/sys/Makefile b/usr/src/uts/common/sys/Makefile index 25f7f90f15..259ceadd6d 100644 --- a/usr/src/uts/common/sys/Makefile +++ b/usr/src/uts/common/sys/Makefile @@ -236,7 +236,6 @@ CHKHDRS= \ fx.h \ fxpriocntl.h \ gfs.h \ - ght.h \ gld.h \ gldpriv.h \ hdio.h \ diff --git a/usr/src/uts/common/sys/aggr.h b/usr/src/uts/common/sys/aggr.h index aaf6fe8231..d41899a3de 100644 --- a/usr/src/uts/common/sys/aggr.h +++ b/usr/src/uts/common/sys/aggr.h @@ -117,7 +117,6 @@ typedef struct laioc_port { typedef struct laioc_create { uint32_t lc_key; uint32_t lc_nports; - caddr_t lc_ports; /* ptr to lacio_port_t */ uint32_t lc_policy; uchar_t lc_mac[ETHERADDRL]; boolean_t lc_mac_fixed; @@ -130,7 +129,6 @@ typedef struct laioc_create { typedef struct laioc_create32 { uint32_t lc_key; uint32_t lc_nports; - caddr32_t lc_ports; uint32_t lc_policy; uchar_t lc_mac[ETHERADDRL]; boolean_t lc_mac_fixed; @@ -187,7 +185,6 @@ typedef struct laioc_info_group { } laioc_info_group_t; typedef struct laioc_info { - uint32_t li_bufsize; uint32_t li_ngroups; uint32_t li_group_key; /* 0 returns all */ } laioc_info_t; @@ -198,15 +195,13 @@ typedef struct laioc_info { typedef struct laioc_add_rem { uint32_t la_key; uint32_t la_nports; - caddr_t la_ports; -} laioc_add_t; +} laioc_add_rem_t; #ifdef _SYSCALL32 typedef struct laioc_add_rem32 { uint32_t la_key; uint32_t la_nports; - caddr32_t la_ports; } laioc_add_rem32_t; #endif /* _SYSCALL32 */ diff --git a/usr/src/uts/common/sys/aggr_impl.h b/usr/src/uts/common/sys/aggr_impl.h index 7fca234c8d..8c66b3dffe 100644 --- a/usr/src/uts/common/sys/aggr_impl.h +++ b/usr/src/uts/common/sys/aggr_impl.h @@ -31,7 +31,6 @@ #include <sys/types.h> #include <sys/mac.h> -#include <sys/ght.h> #include <sys/aggr_lacp.h> #ifdef __cplusplus @@ -40,7 +39,7 @@ extern "C" { #ifdef _KERNEL -#define AGGR_MINOR_CTL 0 /* control interface minor */ +#define AGGR_MINOR_CTL 1 /* control interface minor */ /* flags for aggr_grp_modify() */ #define AGGR_MODIFY_POLICY 0x01 @@ -109,7 +108,6 @@ typedef struct aggr_grp_s { uint32_t lg_refs; /* refcount */ uint16_t lg_nports; /* number of MAC ports */ uint8_t lg_addr[ETHERADDRL]; /* group MAC address */ - ghte_t lg_hte; uint16_t lg_addr_fixed : 1, /* fixed MAC address? */ lg_started : 1, /* group started? */ @@ -162,10 +160,7 @@ typedef struct aggr_grp_s { } extern dev_info_t *aggr_dip; - -extern int aggr_open(dev_t *, int, int, cred_t *); -extern int aggr_close(dev_t, int, int, cred_t *); -extern int aggr_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); +extern void aggr_ioctl(queue_t *, mblk_t *); typedef int (*aggr_grp_info_new_grp_fn_t)(void *, uint32_t, uchar_t *, boolean_t, uint32_t, uint32_t, aggr_lacp_mode_t, aggr_lacp_timer_t); @@ -193,6 +188,7 @@ extern int aggr_grp_modify(uint32_t, aggr_grp_t *, uint8_t, uint32_t, boolean_t, const uchar_t *, aggr_lacp_mode_t, aggr_lacp_timer_t); extern void aggr_grp_multicst_port(aggr_port_t *, boolean_t); extern void aggr_grp_walk(aggr_grp_walker_fn_t, void *); +extern uint_t aggr_grp_count(void); extern void aggr_port_init(void); extern int aggr_port_fini(void); diff --git a/usr/src/uts/common/sys/dld.h b/usr/src/uts/common/sys/dld.h index 369bb54398..2fe60769e6 100644 --- a/usr/src/uts/common/sys/dld.h +++ b/usr/src/uts/common/sys/dld.h @@ -37,7 +37,6 @@ #include <sys/stream.h> #include <sys/mac.h> #include <sys/dls.h> -#include <sys/ght.h> #include <net/if.h> #ifdef __cplusplus @@ -49,18 +48,15 @@ extern "C" { */ #define DLD_INFO "Data-Link Driver v%I%" +#define DLD_MAX_PPA 999 +#define DLD_MAX_MINOR (DLD_MAX_PPA + 1) + /* * Options: To enable an option set the property name to a non-zero value * in kernel/drv/dld.conf. */ /* - * Prevent creation of DLPI style 1 provider nodes (thus forcing stacks such - * as TCP/IP to use style 2 nodes). - */ -#define DLD_PROP_NO_STYLE1 "no-style-1" - -/* * Prevent use of the IP fast-path (direct M_DATA transmit). */ #define DLD_PROP_NO_FASTPATH "no-fastpath" @@ -93,30 +89,37 @@ extern "C" { */ #define DLDIOC ('D' << 24 | 'L' << 16 | 'D' << 8) -#define DLDIOCCREATE (DLDIOC | 0x01) - -typedef struct dld_ioc_create { - char dic_name[IFNAMSIZ]; - char dic_dev[MAXNAMELEN]; - uint_t dic_port; - uint16_t dic_vid; -} dld_ioc_create_t; - -#define DLDIOCDESTROY (DLDIOC | 0x02) - -typedef struct dld_ioc_destroy { - char did_name[IFNAMSIZ]; -} dld_ioc_destroy_t; - #define DLDIOCATTR (DLDIOC | 0x03) typedef struct dld_ioc_attr { char dia_name[IFNAMSIZ]; char dia_dev[MAXNAMELEN]; + uint_t dia_max_sdu; uint_t dia_port; uint16_t dia_vid; } dld_ioc_attr_t; +#define DLDIOCVLAN (DLDIOC | 0x04) + +typedef struct dld_ioc_vlan { + uint_t div_count; +} dld_ioc_vlan_t; + +typedef struct dld_vlan_info { + char dvi_name[IFNAMSIZ]; + uint16_t dvi_vid; +} dld_vlan_info_t; + +#ifdef _KERNEL +int dld_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); +int dld_open(queue_t *, dev_t *, int, int, cred_t *); +int dld_close(queue_t *); +void dld_wput(queue_t *, mblk_t *); +void dld_wsrv(queue_t *); +void dld_init_ops(struct dev_ops *, const char *); +void dld_fini_ops(struct dev_ops *); +#endif + #ifdef __cplusplus } #endif diff --git a/usr/src/uts/common/sys/dld_impl.h b/usr/src/uts/common/sys/dld_impl.h index eae8e262eb..cafc32433a 100644 --- a/usr/src/uts/common/sys/dld_impl.h +++ b/usr/src/uts/common/sys/dld_impl.h @@ -41,85 +41,6 @@ extern "C" { #endif -/* - * dld_ppa_t object definition. - */ -typedef struct dld_node dld_node_t; - -typedef struct dld_ppa { - /* - * Name of the data-link. - */ - char dp_name[IFNAMSIZ]; - - /* - * The device and port of the MAC interface. - */ - char dp_dev[MAXNAMELEN]; - uint_t dp_port; - - /* - * The VLAN identifier of the data-link interface. - */ - uint_t dp_vid; - - /* - * Style 1 and style 2 provider nodes that reference the object. - */ - dld_node_t *dp_style1; - dld_node_t *dp_style2; - - /* - * Style 2 PPA index number of the object. - */ - t_scalar_t dp_index; -} dld_ppa_t; - -/* - * dld_node_t object definition. - */ -struct dld_node { - /* - * Name of the node, this will be the name of the dev_t in the - * file system. - */ - char dn_name[IFNAMSIZ]; - - /* - * DL_STYLE1 or DL_STYLE2. - */ - t_uscalar_t dn_style; - - /* - * Minor number of the dev_t. - */ - minor_t dn_minor; - - /* - * Global hash table entries that reference the object. - */ - ghte_t dn_byminor_hte; - ghte_t dn_byname_hte; - - /* - * Number of dld_ppa_t objects referencing the object. - */ - uint32_t dn_ref; - - /* - * For style 1 nodes there is only a single dld_ppa_t object reference. - * This field is used for that purpose. - */ - dld_ppa_t *dn_dpp; - - /* - * For style 2 nodes there may be many dld_ppa_t references, keyed - * by a PPA index number. The following hash table stores the - * references and the subsequent methods are used to manage the table. - */ - ght_t dn_hash; -}; - #define DLD_CONTROL 0x00000001 #define DLD_DLPI 0x00000002 @@ -142,6 +63,11 @@ typedef struct dld_str dld_str_t; */ struct dld_str { /* + * Major number of the device + */ + major_t ds_major; + + /* * Ephemeral minor number for the object. */ minor_t ds_minor; @@ -153,6 +79,11 @@ struct dld_str { queue_t *ds_wq; /* + * Lock to protect this structure. + */ + krwlock_t ds_lock; + + /* * Stream is open to DLD_CONTROL (control node) or * DLD_DLPI (DLS provider) node. */ @@ -163,14 +94,14 @@ struct dld_str { */ /* - * dld_node_t of the node that was opened. + * Current DLPI state. */ - dld_node_t *ds_dnp; + t_uscalar_t ds_dlstate; /* - * Current DLPI state. + * DLPI style */ - t_uscalar_t ds_dlstate; + t_uscalar_t ds_style; /* * Currently bound DLSAP. @@ -241,10 +172,29 @@ struct dld_str { dld_passivestate_t ds_passivestate; /* - * Message handler jump tables. + * Dummy mblk used for flow-control. + */ + mblk_t *ds_tx_flow_mp; + + /* + * Internal transmit queue and its parameters. + */ + kmutex_t ds_tx_list_lock; + mblk_t *ds_tx_list_head; + mblk_t *ds_tx_list_tail; + uint_t ds_tx_cnt; + uint_t ds_tx_msgcnt; + boolean_t ds_tx_qbusy; + + /* + * Number of threads currently in dld. If there is a pending + * DL_DETACH_REQ, the request is placed in the ds_detach_req + * and the operation will be finished when the driver goes + * single-threaded. */ - struct str_msg_info *ds_mi; - struct str_msg_info *ds_pmi; + kmutex_t ds_thr_lock; + uint_t ds_thr; + mblk_t *ds_detach_req; } dld_str; /* @@ -253,78 +203,37 @@ struct dld_str { extern void dld_str_init(void); extern int dld_str_fini(void); -extern dld_str_t *dld_str_create(queue_t *); +extern dld_str_t *dld_str_create(queue_t *, uint_t, major_t, + t_uscalar_t); extern void dld_str_destroy(dld_str_t *); -extern int dld_str_attach(dld_str_t *, dld_ppa_t *); +extern int dld_str_attach(dld_str_t *, t_uscalar_t); extern void dld_str_detach(dld_str_t *); -extern void dld_str_tx_raw(dld_str_t *); -extern void dld_str_tx_fastpath(dld_str_t *); -extern void dld_str_tx_drop(dld_str_t *); extern void dld_str_rx_raw(void *, mac_resource_handle_t, mblk_t *, size_t); extern void dld_str_rx_fastpath(void *, mac_resource_handle_t, mblk_t *, size_t); extern void dld_str_rx_unitdata(void *, mac_resource_handle_t, mblk_t *, size_t); -extern void dld_str_put(dld_str_t *, mblk_t *); -extern void dld_str_srv(dld_str_t *, mblk_t *); +extern void dld_tx_flush(dld_str_t *); +extern void dld_tx_enqueue(dld_str_t *, mblk_t *, boolean_t); extern void dld_str_notify_ind(dld_str_t *); +extern void str_mdata_fastpath_put(dld_str_t *, mblk_t *); +extern void str_mdata_raw_put(dld_str_t *, mblk_t *); + /* * dld_proto.c */ extern void dld_proto(dld_str_t *, mblk_t *); - -/* - * dld_ppa.c module. - */ -extern void dld_ppa_init(void); -extern int dld_ppa_fini(void); -extern int dld_ppa_create(const char *, const char *, uint_t, - uint16_t); -extern int dld_ppa_destroy(const char *); -extern int dld_ppa_attr(const char *, char *, uint_t *, - uint16_t *); - -/* - * dld_node.c module. - */ -extern void dld_node_init(void); -extern int dld_node_fini(void); -extern dld_node_t *dld_node_hold(const char *, t_uscalar_t); -extern void dld_node_rele(dld_node_t *); -extern dld_node_t *dld_node_find(minor_t); -extern int dld_node_ppa_add(dld_node_t *, t_scalar_t, - dld_ppa_t *); -extern int dld_node_ppa_remove(dld_node_t *, t_scalar_t); -extern dld_ppa_t *dld_node_ppa_find(dld_node_t *, t_scalar_t); - -/* - * dld_minor.c module. - */ -extern void dld_minor_init(void); -extern int dld_minor_fini(void); -extern minor_t dld_minor_hold(boolean_t); -extern void dld_minor_rele(minor_t); - -/* - * dld_ioc.c module. - */ -extern void dld_ioc(dld_str_t *, mblk_t *); - -/* - * dld_drv.c module. - */ -extern dev_info_t *dld_dip; +extern void dld_finish_pending_ops(dld_str_t *); /* * Options: there should be a separate bit defined here for each * DLD_PROP... defined in dld.h. */ -#define DLD_OPT_NO_STYLE1 0x00000001 -#define DLD_OPT_NO_FASTPATH 0x00000002 -#define DLD_OPT_NO_POLL 0x00000004 -#define DLD_OPT_NO_ZEROCOPY 0x00000008 +#define DLD_OPT_NO_FASTPATH 0x00000001 +#define DLD_OPT_NO_POLL 0x00000002 +#define DLD_OPT_NO_ZEROCOPY 0x00000004 extern uint32_t dld_opt; @@ -335,6 +244,28 @@ extern uint32_t dld_opt; #define IMPLY(p, c) (!(p) || (c)) #define AGGR_DEV "aggr0" +#define DLD_ENTER(dsp) { \ + mutex_enter(&dsp->ds_thr_lock); \ + ++dsp->ds_thr; \ + ASSERT(dsp->ds_thr != 0); \ + mutex_exit(&dsp->ds_thr_lock); \ +} + +#define DLD_EXIT(dsp) { \ + mutex_enter(&dsp->ds_thr_lock); \ + ASSERT(dsp->ds_thr > 0); \ + if (--dsp->ds_thr == 0 && dsp->ds_detach_req != NULL) \ + dld_finish_pending_ops(dsp); \ + else \ + mutex_exit(&dsp->ds_thr_lock); \ +} + +#ifdef DEBUG +#define DLD_DBG cmn_err +#else +#define DLD_DBG if (0) cmn_err +#endif + #ifdef __cplusplus } #endif diff --git a/usr/src/uts/common/sys/dls.h b/usr/src/uts/common/sys/dls.h index 695b185a21..a9423be978 100644 --- a/usr/src/uts/common/sys/dls.h +++ b/usr/src/uts/common/sys/dls.h @@ -31,7 +31,6 @@ #include <sys/types.h> #include <sys/stream.h> -#include <sys/ght.h> #include <sys/mac.h> /* @@ -66,9 +65,15 @@ extern "C" { ((sap) == 0) || \ ((sap) <= ETHERMTU && (type) == DL_ETHER)) +/* + * Macros for converting ppas to instance #s and to Vlan IDs. + */ +#define DLS_PPA2INST(ppa) ((int)((ppa) % 1000)) +#define DLS_PPA2VID(ppa) ((uint16_t)((ppa) / 1000)) + #ifdef _KERNEL -extern int dls_create(const char *, const char *, uint_t, uint16_t); +extern int dls_create(const char *, const char *, uint_t); extern int dls_destroy(const char *); typedef struct dls_t *dls_channel_t; diff --git a/usr/src/uts/common/sys/dls_impl.h b/usr/src/uts/common/sys/dls_impl.h index 117e113e83..70de658cc4 100644 --- a/usr/src/uts/common/sys/dls_impl.h +++ b/usr/src/uts/common/sys/dls_impl.h @@ -32,7 +32,7 @@ #include <sys/stream.h> #include <sys/dls.h> #include <sys/mac.h> -#include <sys/ght.h> +#include <sys/modhash.h> #include <sys/kstat.h> #include <net/if.h> @@ -57,10 +57,11 @@ struct dls_link_s { const mac_info_t *dl_mip; mac_rx_handle_t dl_mrh; mac_txloop_handle_t dl_mth; - ghte_t dl_hte; uint_t dl_ref; uint_t dl_macref; - ght_t dl_impl_hash; + mod_hash_t *dl_impl_hash; + krwlock_t dl_impl_lock; + uint_t dl_impl_count; mac_txloop_t dl_loopback; kmutex_t dl_promisc_lock; uint_t dl_npromisc; @@ -71,7 +72,6 @@ struct dls_link_s { typedef struct dls_vlan_s { char dv_name[IFNAMSIZ]; - ghte_t dv_hte; uint_t dv_ref; dls_link_t *dv_dlp; uint16_t dv_id; @@ -79,6 +79,7 @@ typedef struct dls_vlan_s { } dls_vlan_t; typedef struct dls_impl_s dls_impl_t; +typedef struct dls_head_s dls_head_t; typedef mblk_t *(*dls_priv_header_t)(dls_impl_t *, const uint8_t *, uint16_t, uint_t); @@ -87,13 +88,13 @@ typedef void (*dls_priv_header_info_t)(dls_impl_t *, struct dls_impl_s { dls_impl_t *di_nextp; + dls_head_t *di_headp; dls_vlan_t *di_dvp; mac_handle_t di_mh; mac_notify_handle_t di_mnh; const mac_info_t *di_mip; krwlock_t di_lock; uint16_t di_sap; - ghte_t di_hte; uint_t di_promisc; dls_multicst_addr_t *di_dmap; dls_rx_t di_rx; @@ -107,6 +108,12 @@ struct dls_impl_s { dls_priv_header_info_t di_header_info; }; +struct dls_head_s { + dls_impl_t *dh_list; + uint_t dh_ref; + mod_hash_key_t dh_key; +}; + extern void dls_link_init(void); extern int dls_link_fini(void); extern int dls_link_hold(const char *, uint_t, dls_link_t **); @@ -124,8 +131,9 @@ extern int dls_vlan_fini(void); extern int dls_vlan_create(const char *, const char *, uint_t, uint16_t); extern int dls_vlan_destroy(const char *); -extern int dls_vlan_hold(const char *, dls_vlan_t **); +extern int dls_vlan_hold(const char *, dls_vlan_t **, boolean_t); extern void dls_vlan_rele(dls_vlan_t *); +extern int dls_vlan_walk(int (*)(dls_vlan_t *, void *), void *); extern void dls_init(void); extern int dls_fini(void); diff --git a/usr/src/uts/common/sys/ght.h b/usr/src/uts/common/sys/ght.h deleted file mode 100644 index 15d5754bf5..0000000000 --- a/usr/src/uts/common/sys/ght.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _SYS_GHT_H -#define _SYS_GHT_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef _KERNEL - -#include <sys/types.h> - -typedef struct __ght_key *ght_key_t; -typedef struct __ght_val *ght_val_t; - -#define GHT_SCALAR_TO_KEY(scalar) ((ght_key_t)(uintptr_t)(scalar)) -#define GHT_PTR_TO_KEY(ptr) ((ght_key_t)(ptr)) - -#define GHT_SCALAR_TO_VAL(scalar) ((ght_val_t)(uintptr_t)(scalar)) -#define GHT_PTR_TO_VAL(ptr) ((ght_val_t)(ptr)) - -typedef struct __ght *ght_t; -typedef struct __ghte *ghte_t; - -struct ghte_reveal { - ght_key_t key; - ght_val_t val; -}; - -#define GHT_KEY(ghte) ((struct ghte_reveal *)ghte)->key -#define GHT_VAL(ghte) ((struct ghte_reveal *)ghte)->val - -extern int ght_str_create(char *, uint_t, ght_t *); -extern int ght_scalar_create(char *, uint_t, ght_t *); -extern int ght_destroy(ght_t); -extern uint_t ght_count(ght_t); - -extern ghte_t ght_alloc(ght_t, int); -extern void ght_free(ghte_t); - -#define GHT_READ 0 -#define GHT_WRITE 1 - -extern void ght_lock(ght_t, int); -extern void ght_unlock(ght_t); - -extern int ght_insert(ghte_t); -extern int ght_find(ght_t, ght_key_t, ghte_t *); -extern void ght_remove(ghte_t); - -extern void ght_hold(ghte_t); -extern void ght_rele(ghte_t); -extern uint_t ght_ref(ghte_t); - -extern void ght_walk(ght_t, boolean_t (*)(void *, ghte_t), void *); - -#endif /* _KERNEL */ - -#ifdef __cplusplus -} -#endif - -#endif /* _SYS_GHT_H */ diff --git a/usr/src/uts/common/sys/mac.h b/usr/src/uts/common/sys/mac.h index 39c970b942..59e493f9bd 100644 --- a/usr/src/uts/common/sys/mac.h +++ b/usr/src/uts/common/sys/mac.h @@ -374,6 +374,7 @@ typedef mac_resource_handle_t (*mac_resource_add_t)(void *, mac_resource_t *); extern int mac_open(const char *, uint_t, mac_handle_t *); extern void mac_close(mac_handle_t); extern const mac_info_t *mac_info(mac_handle_t); +extern boolean_t mac_info_get(const char *, mac_info_t *); extern uint64_t mac_stat_get(mac_handle_t, enum mac_stat); extern int mac_start(mac_handle_t); extern void mac_stop(mac_handle_t); @@ -406,6 +407,7 @@ extern boolean_t mac_active_set(mac_handle_t); extern void mac_active_clear(mac_handle_t); extern void mac_resource_set(mac_handle_t, mac_resource_add_t, void *); +extern dev_info_t *mac_devinfo_get(mac_handle_t); /* * Driver interface functions. @@ -425,6 +427,8 @@ extern void mac_unicst_refresh(mac_t *, mac_unicst_t, void *); extern void mac_promisc_refresh(mac_t *, mac_promisc_t, void *); +extern void mac_init_ops(struct dev_ops *, const char *); +extern void mac_fini_ops(struct dev_ops *); #endif /* _KERNEL */ diff --git a/usr/src/uts/common/sys/mac_impl.h b/usr/src/uts/common/sys/mac_impl.h index a66d3693e4..0091402a28 100644 --- a/usr/src/uts/common/sys/mac_impl.h +++ b/usr/src/uts/common/sys/mac_impl.h @@ -30,7 +30,6 @@ #pragma ident "%Z%%M% %I% %E% SMI" #include <sys/mac.h> -#include <sys/ght.h> #ifdef __cplusplus extern "C" { @@ -79,7 +78,6 @@ struct mac_impl_s { uint_t mi_port; char mi_name[MAXNAMELEN]; - ghte_t mi_hte; uint32_t mi_ref; boolean_t mi_destroying; diff --git a/usr/src/uts/intel/Makefile.intel b/usr/src/uts/intel/Makefile.intel index 96c2637ff0..c9125719cc 100644 --- a/usr/src/uts/intel/Makefile.intel +++ b/usr/src/uts/intel/Makefile.intel @@ -444,7 +444,6 @@ MISC_KMODS += diaudio MISC_KMODS += dls MISC_KMODS += fssnap_if MISC_KMODS += gda -MISC_KMODS += ght MISC_KMODS += gld MISC_KMODS += hidparser MISC_KMODS += hpcsvc diff --git a/usr/src/uts/intel/aggr/Makefile b/usr/src/uts/intel/aggr/Makefile index 814c36da48..9852de4c84 100644 --- a/usr/src/uts/intel/aggr/Makefile +++ b/usr/src/uts/intel/aggr/Makefile @@ -56,7 +56,7 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) # Overrides # CFLAGS += $(CCVERBOSE) -LDFLAGS += -dy -Nmisc/ght -Nmisc/mac +LDFLAGS += -dy -Ndrv/dld -Nmisc/mac # # Default build targets. diff --git a/usr/src/uts/intel/bge/Makefile b/usr/src/uts/intel/bge/Makefile index 94c2586c0b..da9c8fd16a 100644 --- a/usr/src/uts/intel/bge/Makefile +++ b/usr/src/uts/intel/bge/Makefile @@ -60,7 +60,7 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) # # -# Driver depends on GLD & IP +# Driver depends on MAC & IP # LDFLAGS += -dy -N misc/mac -N drv/ip diff --git a/usr/src/uts/intel/dld/Makefile b/usr/src/uts/intel/dld/Makefile index 6dd9842f4c..00cb2f7fc9 100644 --- a/usr/src/uts/intel/dld/Makefile +++ b/usr/src/uts/intel/dld/Makefile @@ -56,7 +56,7 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) # Overrides # CFLAGS += $(CCVERBOSE) -LDFLAGS += -dy -N misc/dls -N misc/mac -N misc/ght +LDFLAGS += -dy -N misc/dls -N misc/mac # # Default build targets. diff --git a/usr/src/uts/intel/dls/Makefile b/usr/src/uts/intel/dls/Makefile index 741283f80f..c5acd953ce 100644 --- a/usr/src/uts/intel/dls/Makefile +++ b/usr/src/uts/intel/dls/Makefile @@ -54,7 +54,7 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE) # Overrides. # CFLAGS += $(CCVERBOSE) -LDFLAGS += -dy -N misc/ght -N misc/mac +LDFLAGS += -dy -N misc/mac # # Default build targets. diff --git a/usr/src/uts/intel/ght/Makefile b/usr/src/uts/intel/ght/Makefile deleted file mode 100644 index e0d462df78..0000000000 --- a/usr/src/uts/intel/ght/Makefile +++ /dev/null @@ -1,82 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -# -# Path to the base of the uts directory tree (usually /usr/src/uts). -# -UTSBASE = ../.. - -# -# Define the module and object file sets. -# -MODULE = ght -OBJECTS = $(GHT_OBJS:%=$(OBJS_DIR)/%) -LINTS = $(GHT_OBJS:%.o=$(LINTS_DIR)/%.ln) -ROOTMODULE = $(ROOT_MISC_DIR)/$(MODULE) - -# -# Include common rules. -# -include $(UTSBASE)/intel/Makefile.intel - -# -# Define targets -# -ALL_TARGET = $(BINARY) -LINT_TARGET = $(MODULE).lint -INSTALL_TARGET = $(BINARY) $(ROOTMODULE) - -# -# Overrides. -# -CFLAGS += $(CCVERBOSE) - -# -# Default build targets. -# -.KEEP_STATE: - -def: $(DEF_DEPS) - -all: $(ALL_DEPS) - -clean: $(CLEAN_DEPS) - -clobber: $(CLOBBER_DEPS) - -lint: $(LINT_DEPS) - -modlintlib: $(MODLINTLIB_DEPS) - -clean.lint: $(CLEAN_LINT_DEPS) - -install: $(INSTALL_DEPS) - -# -# Include common targets. -# -include $(UTSBASE)/intel/Makefile.targ diff --git a/usr/src/uts/intel/ia32/ml/modstubs.s b/usr/src/uts/intel/ia32/ml/modstubs.s index 5d80c622fa..e0b0a92ee9 100644 --- a/usr/src/uts/intel/ia32/ml/modstubs.s +++ b/usr/src/uts/intel/ia32/ml/modstubs.s @@ -1129,10 +1129,22 @@ fcnname/**/_info: \ END_MODULE(sha1); #endif -#ifndef DLD_MODULE +/* + * The following stubs are used by the mac module. + * Since dls and dld already depend on mac, these + * stubs are needed to avoid circular dependencies. + */ +#ifndef DLS_MODULE + MODULE(dls,misc); + STUB(dls, dls_create, nomod_einval); + STUB(dls, dls_destroy, nomod_einval); + END_MODULE(dls); +#endif + +#ifndef DLD_MODULE MODULE(dld,drv); - STUB(dld, dld_ppa_create, nomod_einval); - STUB(dld, dld_ppa_destroy, nomod_einval); + STUB(dld, dld_init_ops, nomod_void); + STUB(dld, dld_fini_ops, nomod_void); END_MODULE(dld); #endif diff --git a/usr/src/uts/intel/mac/Makefile b/usr/src/uts/intel/mac/Makefile index f751b380cd..8e34b910a9 100644 --- a/usr/src/uts/intel/mac/Makefile +++ b/usr/src/uts/intel/mac/Makefile @@ -59,7 +59,7 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE) # Overrides. # CFLAGS += $(CCVERBOSE) -LDFLAGS += -dy -N misc/ght +LDFLAGS += -dy # # Default build targets. diff --git a/usr/src/uts/sparc/Makefile.sparc b/usr/src/uts/sparc/Makefile.sparc index 2c43f6ac46..f2ddfb16ae 100644 --- a/usr/src/uts/sparc/Makefile.sparc +++ b/usr/src/uts/sparc/Makefile.sparc @@ -339,7 +339,7 @@ MISC_KMODS += ibmf MISC_KMODS += ibtl MISC_KMODS += ctf MISC_KMODS += zmod -MISC_KMODS += mac dls ght +MISC_KMODS += mac dls # # Software Cryptographic Providers (/kernel/crypto): diff --git a/usr/src/uts/sparc/aggr/Makefile b/usr/src/uts/sparc/aggr/Makefile index f175b433cf..80e15198cc 100644 --- a/usr/src/uts/sparc/aggr/Makefile +++ b/usr/src/uts/sparc/aggr/Makefile @@ -56,7 +56,7 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) # Overrides # CFLAGS += $(CCVERBOSE) -LDFLAGS += -dy -N misc/ght -Nmisc/mac +LDFLAGS += -dy -Ndrv/dld -Nmisc/mac # # Default build targets. diff --git a/usr/src/uts/sparc/dld/Makefile b/usr/src/uts/sparc/dld/Makefile index e8a29b5a5d..5e9c4a352f 100644 --- a/usr/src/uts/sparc/dld/Makefile +++ b/usr/src/uts/sparc/dld/Makefile @@ -58,7 +58,7 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) CFLAGS += $(CCVERBOSE) $(RELEASE_BUILD)CFLAGS += -xinline=auto -xcrossfile $(RELEASE_BUILD)COPTIMIZE = -xO5 -LDFLAGS += -dy -N misc/dls -N misc/mac -N misc/ght +LDFLAGS += -dy -N misc/dls -N misc/mac # # Default build targets. diff --git a/usr/src/uts/sparc/dls/Makefile b/usr/src/uts/sparc/dls/Makefile index 71d4ae3cab..7a11f43724 100644 --- a/usr/src/uts/sparc/dls/Makefile +++ b/usr/src/uts/sparc/dls/Makefile @@ -56,7 +56,7 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE) CFLAGS += $(CCVERBOSE) $(RELEASE_BUILD)CFLAGS += -xinline=auto -xcrossfile $(RELEASE_BUILD)COPTIMIZE = -xO5 -LDFLAGS += -dy -N misc/ght -N misc/mac +LDFLAGS += -dy -N misc/mac # # Default build targets. diff --git a/usr/src/uts/sparc/ght/Makefile b/usr/src/uts/sparc/ght/Makefile deleted file mode 100644 index bd95b494f4..0000000000 --- a/usr/src/uts/sparc/ght/Makefile +++ /dev/null @@ -1,84 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -# -# Path to the base of the uts directory tree (usually /usr/src/uts). -# -UTSBASE = ../.. - -# -# Define the module and object file sets. -# -MODULE = ght -OBJECTS = $(GHT_OBJS:%=$(OBJS_DIR)/%) -LINTS = $(GHT_OBJS:%.o=$(LINTS_DIR)/%.ln) -ROOTMODULE = $(ROOT_MISC_DIR)/$(MODULE) - -# -# Include common rules. -# -include $(UTSBASE)/sparc/Makefile.sparc - -# -# Define targets -# -ALL_TARGET = $(BINARY) -LINT_TARGET = $(MODULE).lint -INSTALL_TARGET = $(BINARY) $(ROOTMODULE) - -# -# Overrides. -# -CFLAGS += $(CCVERBOSE) -$(RELEASE_BUILD)CFLAGS += -xinline=auto -$(RELEASE_BUILD)COPTIMIZE = -xO5 - -# -# Default build targets. -# -.KEEP_STATE: - -def: $(DEF_DEPS) - -all: $(ALL_DEPS) - -clean: $(CLEAN_DEPS) - -clobber: $(CLOBBER_DEPS) - -lint: $(LINT_DEPS) - -modlintlib: $(MODLINTLIB_DEPS) - -clean.lint: $(CLEAN_LINT_DEPS) - -install: $(INSTALL_DEPS) - -# -# Include common targets. -# -include $(UTSBASE)/sparc/Makefile.targ diff --git a/usr/src/uts/sparc/mac/Makefile b/usr/src/uts/sparc/mac/Makefile index a3c6814f0a..ecf5b2cfa2 100644 --- a/usr/src/uts/sparc/mac/Makefile +++ b/usr/src/uts/sparc/mac/Makefile @@ -62,7 +62,7 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE) CFLAGS += $(CCVERBOSE) $(RELEASE_BUILD)CFLAGS += -xinline=auto -xcrossfile $(RELEASE_BUILD)COPTIMIZE = -xO5 -LDFLAGS += -dy -N misc/ght +LDFLAGS += -dy # # Default build targets. diff --git a/usr/src/uts/sparc/ml/modstubs.s b/usr/src/uts/sparc/ml/modstubs.s index 304a320d31..9594335f33 100644 --- a/usr/src/uts/sparc/ml/modstubs.s +++ b/usr/src/uts/sparc/ml/modstubs.s @@ -1082,10 +1082,22 @@ stubs_base: END_MODULE(sha1); #endif -#ifndef DLD_MODULE +/* + * The following stubs are used by the mac module. + * Since dls and dld already depend on mac, these + * stubs are needed to avoid circular dependencies. + */ +#ifndef DLS_MODULE + MODULE(dls,misc); + STUB(dls, dls_create, nomod_einval); + STUB(dls, dls_destroy, nomod_einval); + END_MODULE(dls); +#endif + +#ifndef DLD_MODULE MODULE(dld,drv); - STUB(dld, dld_ppa_create, nomod_einval); - STUB(dld, dld_ppa_destroy, nomod_einval); + STUB(dld, dld_init_ops, nomod_void); + STUB(dld, dld_fini_ops, nomod_void); END_MODULE(dld); #endif |