Mercurial > illumos > s390-betelgeuse
changeset 10847:f171925d2a2f
Branch merge
line wrap: on
line diff
--- a/usr/src/Targetdirs Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/Targetdirs Mon Jul 20 13:07:46 2009 -0400 @@ -224,8 +224,8 @@ /etc/dbus-1 \ /etc/dbus-1/system.d \ /etc/saf \ - /etc/sma \ - /etc/sma/snmp \ + /etc/net-snmp \ + /etc/net-snmp/snmp \ /lib \ /lib/crypto \ /lib/inet \
--- a/usr/src/cmd/devfsadm/devfsadm.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/devfsadm/devfsadm.c Mon Jul 20 13:07:46 2009 -0400 @@ -228,17 +228,12 @@ {"dsk", "rdsk", "term", NULL}; /* Devname globals */ -static int devname_debug_msg = 1; -static nvlist_t *devname_maps = NULL; -static int devname_first_call = 1; -static int load_devname_nsmaps = FALSE; static int lookup_door_fd = -1; static char *lookup_door_path; static void load_dev_acl(void); static void update_drvconf(major_t); static void check_reconfig_state(void); -static void devname_setup_nsmaps(void); static int s_stat(const char *, struct stat *); static int is_blank(char *); @@ -745,7 +740,7 @@ devlinktab_file = DEVLINKTAB_FILE; while ((opt = getopt(argc, argv, - "a:Cc:deIi:l:mnp:PR:r:sSt:vV:x:")) != EOF) { + "a:Cc:deIi:l:np:PR:r:sSt:vV:x:")) != EOF) { if (opt == 'I' || opt == 'P' || opt == 'S') { if (public_mode) usage(); @@ -798,9 +793,6 @@ /* specify an alternate module load path */ module_dirs = s_strdup(optarg); break; - case 'm': - load_devname_nsmaps = TRUE; - break; case 'n': /* prevent driver loading and deferred attach */ load_attach_drv = FALSE; @@ -909,12 +901,6 @@ devfsadm_exit(0); /*NOTREACHED*/ } - - if (load_devname_nsmaps == TRUE) { - devname_setup_nsmaps(); - devfsadm_exit(0); - /*NOTREACHED*/ - } } @@ -1339,8 +1325,6 @@ /* pass down the door name to kernel for door_ki_open */ if (devname_kcall(MODDEVNAME_LOOKUPDOOR, (void *)door_file) != 0) err_print(DEVNAME_CONTACT_FAILED, strerror(errno)); - else - devname_setup_nsmaps(); vprint(CHATTY_MID, "%spausing\n", fcn); for (;;) { @@ -8430,25 +8414,8 @@ devname_kcall(int subcmd, void *args) { int error = 0; - char *nvlbuf = NULL; - size_t nvlsize; switch (subcmd) { - case MODDEVNAME_NSMAPS: - error = nvlist_pack((nvlist_t *)args, &nvlbuf, &nvlsize, 0, 0); - if (error) { - err_print("packing MODDEVNAME_NSMAPS failed\n"); - break; - } - error = modctl(MODDEVNAME, subcmd, nvlbuf, nvlsize); - if (error) { - vprint(INFO_MID, "modctl(MODDEVNAME, " - "MODDEVNAME_NSMAPS) failed - %s\n", - strerror(errno)); - } - free(nvlbuf); - nvlist_free(args); - break; case MODDEVNAME_LOOKUPDOOR: error = modctl(MODDEVNAME, subcmd, (uintptr_t)args); if (error) { @@ -8464,93 +8431,6 @@ return (error); } -static void -devname_setup_nsmaps(void) -{ - int error = 0; - - if (devname_first_call) { - devname_first_call = 0; - } - - error = di_devname_get_mapinfo(DEVNAME_MASTER_MAP, &devname_maps); - - if (error) { - vprint(DEVNAME_MID, "devname_setup_nsmaps: non-existing/empty" - "%s\n", DEVNAME_MASTER_MAP); - } else { - di_devname_print_mapinfo(devname_maps); - - /* pass down the existing map names to kernel */ - (void) devname_kcall(MODDEVNAME_NSMAPS, (void *)devname_maps); - } -} - -static void -devname_ns_services(uint8_t cmd, char *key, char *map) -{ - nvlist_t *nvl = NULL; - int32_t error = 0; - sdev_door_res_t res; - - vprint(DEVNAME_MID, "devname_ns_services: cmd %d key %s map %s\n", - cmd, key, map); - - switch (cmd) { - case DEVFSADMD_NS_LOOKUP: - vprint(DEVNAME_MID, "calling di_devname_get_mapent\n"); - error = di_devname_get_mapent(key, map, &nvl); - if (nvl == NULL) { - error = DEVFSADM_NS_FAILED; - goto done; - } - - if (error) { - nvlist_free(nvl); - goto done; - } - - if (devname_debug_msg) - di_devname_print_mapinfo(nvl); - - vprint(DEVNAME_MID, "calling di_devname_action_on_key for %d\n", - cmd); - error = di_devname_action_on_key(nvl, cmd, key, (void *)&res); - nvlist_free(nvl); - break; - case DEVFSADMD_NS_READDIR: - vprint(DEVNAME_MID, "calling di_devname_get_mapinfo for cmd %d" - "\n", cmd); - error = di_devname_get_mapinfo(map, &nvl); - if (nvl == NULL) { - error = DEVFSADM_NS_FAILED; - goto done; - } - - if (error) { - nvlist_free(nvl); - goto done; - } - - if (devname_debug_msg) - di_devname_print_mapinfo(nvl); - - vprint(DEVNAME_MID, "calling di_devname_action_on_key\n"); - error = di_devname_action_on_key(nvl, cmd, key, (void *)&res); - nvlist_free(nvl); - break; - default: - error = DEVFSADM_RUN_NOTSUP; - break; - } - -done: - vprint(DEVNAME_MID, "error %d\n", error); - res.devfsadm_error = error; - (void) door_return((char *)&res, sizeof (struct sdev_door_res), - NULL, 0); -} - /* ARGSUSED */ static void devname_lookup_handler(void *cookie, char *argp, size_t arg_size, @@ -8560,7 +8440,6 @@ door_cred_t dcred; struct dca_impl dci; uint8_t cmd; - char *ns_map, *ns_name; sdev_door_res_t res; sdev_door_arg_t *args; @@ -8582,19 +8461,6 @@ vprint(DEVNAME_MID, "devname_lookup_handler: cmd %d\n", cmd); switch (cmd) { - case DEVFSADMD_NS_LOOKUP: - case DEVFSADMD_NS_READDIR: - ns_name = s_strdup(args->ns_hdl.ns_name); - ns_map = s_strdup(args->ns_hdl.ns_map); - - vprint(DEVNAME_MID, " ns_name %s ns_map %s\n", ns_name, ns_map); - if (ns_name == NULL || ns_map == NULL) { - error = DEVFSADM_RUN_INVALID; - goto done; - } - - devname_ns_services(cmd, ns_name, ns_map); - return; case DEVFSADMD_RUN_ALL: /* * run "devfsadm"
--- a/usr/src/cmd/devfsadm/devfsadm.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/devfsadm/devfsadm.h Mon Jul 20 13:07:46 2009 -0400 @@ -19,15 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _DEVFSADM_H #define _DEVFSADM_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <libdevinfo.h> #include <sys/devinfo_impl.h> @@ -96,9 +94,6 @@ #define DEVFSADM_SERVICE_DOOR "/etc/sysevent/devfsadm_event_channel" #define DEVNAME_LOOKUP_DOOR ".devname_lookup_door" -/* /dev device name binding rule locations */ -#define DEVNAME_MASTER_MAP "/etc/dev/devname_master" - /* File of reserved devnames */ #define ENUMERATE_RESERVED "/etc/dev/reserved_devnames"
--- a/usr/src/cmd/devfsadm/devfsadm_impl.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/devfsadm/devfsadm_impl.h Mon Jul 20 13:07:46 2009 -0400 @@ -18,7 +18,7 @@ * * CDDL HEADER END * - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -71,7 +71,7 @@ #include <sys/sysevent/dev.h> #include <libzonecfg.h> #include <device_info.h> -#include <sys/fs/sdev_node.h> +#include <sys/fs/sdev_impl.h> #include <sys/syscall.h> #include <rpcsvc/ypclnt.h> #include <sys/sysevent/eventdefs.h>
--- a/usr/src/cmd/drd/drd.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/drd/drd.c Mon Jul 20 13:07:46 2009 -0400 @@ -20,12 +20,10 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * sun4v DR daemon */ @@ -384,11 +382,19 @@ break; case DRCTL_MEM_CONFIG_REQUEST: + (*drd_backend->mem_config_request)(rsrcs, nrsrc); + break; + case DRCTL_MEM_CONFIG_NOTIFY: + (*drd_backend->mem_config_notify)(rsrcs, nrsrc); + break; + case DRCTL_MEM_UNCONFIG_REQUEST: + (*drd_backend->mem_unconfig_request)(rsrcs, nrsrc); + break; + case DRCTL_MEM_UNCONFIG_NOTIFY: - drd_err("memory DR operations not supported yet"); - DRD_DOOR_RETURN_ERR(); + (*drd_backend->mem_unconfig_notify)(rsrcs, nrsrc); break; case DRCTL_IO_CONFIG_REQUEST:
--- a/usr/src/cmd/drd/drd.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/drd/drd.h Mon Jul 20 13:07:46 2009 -0400 @@ -20,15 +20,13 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _DRD_H #define _DRD_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -65,6 +63,10 @@ int (*io_config_notify)(drctl_rsrc_t *rsrc, int nrsrc); int (*io_unconfig_request)(drctl_rsrc_t *rsrc, int nrsrc); int (*io_unconfig_notify)(drctl_rsrc_t *rsrc, int nrsrc); + int (*mem_config_request)(drctl_rsrc_t *rsrcs, int nrsrc); + int (*mem_config_notify)(drctl_rsrc_t *rsrcs, int nrsrc); + int (*mem_unconfig_request)(drctl_rsrc_t *rsrcs, int nrsrc); + int (*mem_unconfig_notify)(drctl_rsrc_t *rsrcs, int nrsrc); } drd_backend_t; extern drd_backend_t drd_rcm_backend;
--- a/usr/src/cmd/drd/drd_rcm.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/drd/drd_rcm.c Mon Jul 20 13:07:46 2009 -0400 @@ -20,12 +20,10 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * RCM backend for the DR Daemon */ @@ -37,6 +35,7 @@ #include <libnvpair.h> #include <librcm.h> #include <locale.h> +#include <assert.h> #include "drd.h" @@ -53,6 +52,10 @@ static int drd_rcm_io_config_notify(drctl_rsrc_t *rsrc, int nrsrc); static int drd_rcm_io_unconfig_request(drctl_rsrc_t *rsrc, int nrsrc); static int drd_rcm_io_unconfig_notify(drctl_rsrc_t *rsrc, int nrsrc); +static int drd_rcm_mem_config_request(drctl_rsrc_t *rsrcs, int nrsrc); +static int drd_rcm_mem_config_notify(drctl_rsrc_t *rsrcs, int nrsrc); +static int drd_rcm_mem_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc); +static int drd_rcm_mem_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc); drd_backend_t drd_rcm_backend = { drd_rcm_init, /* init */ @@ -64,9 +67,17 @@ drd_rcm_io_config_request, /* io_config_request */ drd_rcm_io_config_notify, /* io_config_notify */ drd_rcm_io_unconfig_request, /* io_unconfig_request */ - drd_rcm_io_unconfig_notify /* io_unconfig_notify */ + drd_rcm_io_unconfig_notify, /* io_unconfig_notify */ + drd_rcm_mem_config_request, /* mem_config_request */ + drd_rcm_mem_config_notify, /* mem_config_notify */ + drd_rcm_mem_unconfig_request, /* mem_unconfig_request */ + drd_rcm_mem_unconfig_notify /* mem_unconfig_notify */ }; +typedef int (*rcm_op_t)(rcm_handle_t *, char *, uint_t, nvlist_t *, + rcm_info_t **); + +#define RCM_MEM_ALL "SUNW_memory" #define RCM_CPU_ALL "SUNW_cpu" #define RCM_CPU RCM_CPU_ALL"/cpu" #define RCM_CPU_MAX_LEN (32) @@ -423,7 +434,7 @@ if (rv != RCM_SUCCESS) { drd_dbg("RCM call failed: %d", rv); /* - * Since the capcity change was blocked, we + * Since the capacity change was blocked, we * mark all CPUs as blocked. It is up to the * user to reframe the query so that it can * succeed. @@ -1198,3 +1209,225 @@ return (table); } + +static void +dump_mem_rsrc_list(char *prefix, drctl_rsrc_t *rsrcs, int nrsrc) +{ + int idx; + char *errstr; + + /* just return if not debugging */ + if (drd_debug == 0) + return; + + if (prefix) + drd_dbg("%s", prefix); + + for (idx = 0; idx < nrsrc; idx++) { + + /* get a pointer to the error string */ + errstr = (char *)(uintptr_t)rsrcs[idx].offset; + + drd_dbg(" mem[%d]: addr=0x%llx, size=0x%llx" + " status=%d, errstr='%s'", idx, + rsrcs[idx].res_mem_addr, rsrcs[idx].res_mem_size, + rsrcs[idx].status, (errstr != NULL) ? errstr : ""); + } +} + +static int +drd_rcm_mem_op(rcm_op_t op, uint64_t change) +{ + int rv = -1; + int pgsize; + long oldpages; + long newpages; + nvlist_t *nvl = NULL; + rcm_info_t *rinfo; + + /* allocate an nvlist for the RCM call */ + if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) + goto done; + + if ((pgsize = sysconf(_SC_PAGE_SIZE)) == -1 || + (newpages = sysconf(_SC_PHYS_PAGES)) == -1) + goto done; + + /* + * If this is a notify add, the capacity change + * was positive and the current page count reflects + * the new capacity level. + * + * If this is a request del, the capacity change + * is negative and the current page count will + * reflect the old capacity level. + */ + assert(change % pgsize == 0); + if (change > 0) { + oldpages = newpages - (long)(change / pgsize); + } else { + assert(newpages >= change / pgsize); + oldpages = newpages; + newpages = oldpages + (long)(change / pgsize); + } + + drd_dbg("oldpages=%lld newpages=%lld delta=%lld", + oldpages, newpages, newpages - oldpages); + + /* setup the nvlist for the RCM call */ + if (nvlist_add_string(nvl, "state", "capacity") != 0 || + nvlist_add_int32(nvl, "page_size", pgsize) != 0 || + nvlist_add_int32(nvl, "old_pages", oldpages) != 0 || + nvlist_add_int32(nvl, "new_pages", newpages) != 0) { + goto done; + } + + rv = (*op)(rcm_hdl, RCM_MEM_ALL, 0, nvl, &rinfo); + rv = (rv == RCM_SUCCESS) ? 0 : -1; + +done: + s_nvfree(nvl); + + return (rv); +} + +/* + * RCM clients can interpose only on removal of resources. + */ +static int +drd_rcm_mem_config_request(drctl_rsrc_t *rsrcs, int nrsrc) +{ + int idx; + + drd_dbg("drd_rcm_mem_config_request..."); + + if ((rsrcs == NULL) || (nrsrc == 0)) + return (0); + dump_mem_rsrc_list(NULL, rsrcs, nrsrc); + + /* + * There is no RCM operation to request the addition + * of resources. So, by definition, the operation for + * all the memory is allowed. + */ + for (idx = 0; idx < nrsrc; idx++) + rsrcs[idx].status = DRCTL_STATUS_ALLOW; + + dump_mem_rsrc_list("returning:", rsrcs, nrsrc); + + return (0); +} + +static int +drd_rcm_mem_config_notify(drctl_rsrc_t *rsrcs, int nrsrc) +{ + int idx; + int rv = -1; + uint64_t change = 0; + + drd_dbg("drd_rcm_mem_config_notify..."); + + if ((rsrcs == NULL) || (nrsrc == 0)) { + drd_err("mem_config_notify: mem list empty"); + goto done; + } + dump_mem_rsrc_list(NULL, rsrcs, nrsrc); + + for (idx = 0; idx < nrsrc; idx++) { + if (rsrcs[idx].status == DRCTL_STATUS_CONFIG_SUCCESS) + change += rsrcs[idx].res_mem_size; + drd_dbg(" idx=%d addr=0x%llx size=0x%llx", + idx, rsrcs[idx].res_mem_addr, rsrcs[idx].res_mem_size); + } + + rv = drd_rcm_mem_op(rcm_notify_capacity_change, change); +done: + return (rv); +} + +static int +drd_rcm_mem_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc) +{ + int rv = -1; + int idx; + uint64_t change = 0; + + drd_dbg("drd_rcm_del_mem_request..."); + + if ((rsrcs == NULL) || (nrsrc == 0)) { + drd_err("mem_unconfig_request: mem list empty"); + goto done; + } + dump_mem_rsrc_list(NULL, rsrcs, nrsrc); + + for (idx = 0; idx < nrsrc; idx++) { + drd_dbg(" idx=%d addr=0x%llx size=0x%llx", + idx, rsrcs[idx].res_mem_addr, rsrcs[idx].res_mem_size); + change += rsrcs[idx].res_mem_size; + } + + rv = drd_rcm_mem_op(rcm_request_capacity_change, -change); + + if (rv != RCM_SUCCESS) { + drd_dbg("RCM call failed: %d", rv); + /* + * Since the capacity change was blocked, we + * mark all mblocks as blocked. It is up to the + * user to reframe the query so that it can + * succeed. + */ + for (idx = 0; idx < nrsrc; idx++) { + rsrcs[idx].status = DRCTL_STATUS_DENY; + } + + /* tack on message to first resource */ + rsrcs[0].offset = (uintptr_t)strdup("unable to remove " + "specified amount of memory"); + drd_dbg(" unable to remove specified amount of memory"); + } else { + for (idx = 0; idx < nrsrc; idx++) + rsrcs[idx].status = DRCTL_STATUS_ALLOW; + rv = 0; + } + +done: + + dump_mem_rsrc_list("returning:", rsrcs, nrsrc); + return (rv); +} + +static int +drd_rcm_mem_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc) +{ + int idx; + int rv = -1; + uint64_t change = 0; + + drd_dbg("drd_rcm_mem_unconfig_notify..."); + + if ((rsrcs == NULL) || (nrsrc == 0)) { + drd_err("unconfig_mem_notify: mem list empty"); + goto done; + } + dump_mem_rsrc_list(NULL, rsrcs, nrsrc); + + /* + * Filter out the memory that was configured. + * + * We need to notify RCM about a memory capacity change + * only if the memory unconfigure request wasn't successful + * because if both the RCM capacity delete request and the + * memory unconfigure succeed, this notify would give a + * memory capacity identical to the delete request. + */ + for (idx = 0; idx < nrsrc; idx++) { + if (rsrcs[idx].status != DRCTL_STATUS_CONFIG_SUCCESS) + change += rsrcs[idx].res_mem_size; + drd_dbg(" idx=%d addr=0x%llx size=0x%llx", + idx, rsrcs[idx].res_mem_addr, rsrcs[idx].res_mem_size); + } + + rv = drd_rcm_mem_op(rcm_notify_capacity_change, change); +done: + return (rv); +}
--- a/usr/src/cmd/fm/dicts/PCI.dict Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/fm/dicts/PCI.dict Mon Jul 20 13:07:46 2009 -0400 @@ -1,5 +1,5 @@ # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # CDDL HEADER START @@ -21,8 +21,6 @@ # # CDDL HEADER END # -#ident "%Z%%M% %I% %E% SMI" -# # DO NOT EDIT -- this file is generated by the Event Registry. # @@ -44,3 +42,5 @@ fault.io.pci.device-interr-corr=13 fault.io.pci.bus-linkerr-deg fault.io.pci.device-interr-deg=14 fault.io.pci.device-interr-deg=15 +fault.io.pci.fw_corrupt=16 +fault.io.pci.fw_mismatch=17
--- a/usr/src/cmd/fm/dicts/PCI.po Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/fm/dicts/PCI.po Mon Jul 20 13:07:46 2009 -0400 @@ -1,5 +1,5 @@ # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # CDDL HEADER START @@ -21,8 +21,6 @@ # # CDDL HEADER END # -#ident "%Z%%M% %I% %E% SMI" -# # DO NOT EDIT -- this file is generated by the Event Registry. # # @@ -281,3 +279,35 @@ msgstr "Degraded services provided by the device instances associated with this fault\n" msgid "PCI-8000-G3.action" msgstr "Schedule a repair procedure to replace the affected device. Use fmadm faulty to identify the device or contact Sun for support.\n" +# +# code: PCI-8000-HR +# keys: fault.io.pci.fw_corrupt +# +msgid "PCI-8000-HR.type" +msgstr "Fault" +msgid "PCI-8000-HR.severity" +msgstr "Major" +msgid "PCI-8000-HR.description" +msgstr "A firmware corruption was detected for a PCI device.\n Refer to %s for more information." +msgid "PCI-8000-HR.response" +msgstr "One or more device instances may be disabled.\n" +msgid "PCI-8000-HR.impact" +msgstr "Degraded services provided by the device instances associated with this fault.\n" +msgid "PCI-8000-HR.action" +msgstr "Use fmadm faulty to identify the device and then update the firmware to the latest version or schedule a repair procedure to replace the affected device. Contact Sun support for further information.\n" +# +# code: PCI-8000-J4 +# keys: fault.io.pci.fw_mismatch +# +msgid "PCI-8000-J4.type" +msgstr "Fault" +msgid "PCI-8000-J4.severity" +msgstr "Major" +msgid "PCI-8000-J4.description" +msgstr "A firmware version mismatch was detected for a PCI device.\n Refer to %s for more information." +msgid "PCI-8000-J4.response" +msgstr "One or more device instances may be disabled.\n" +msgid "PCI-8000-J4.impact" +msgstr "Degraded services provided by the device instances associated with this fault.\n" +msgid "PCI-8000-J4.action" +msgstr "Use fmadm faulty to identify the device and then update the firmware to the latest version. Contact Sun support for further information.\n"
--- a/usr/src/cmd/fm/dicts/PCIEX.dict Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/fm/dicts/PCIEX.dict Mon Jul 20 13:07:46 2009 -0400 @@ -1,5 +1,5 @@ # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # CDDL HEADER START @@ -21,8 +21,6 @@ # # CDDL HEADER END # -#ident "%Z%%M% %I% %E% SMI" -# # DO NOT EDIT -- this file is generated by the Event Registry. # @@ -50,3 +48,5 @@ fault.io.pci.bus-linkerr-unaf fault.io.pciex.device-interr-unaf=19 fault.io.pciex.device-interr-unaf=20 fault.io.pciex.device-interr-deg=21 +fault.io.pciex.fw_corrupt=22 +fault.io.pciex.fw_mismatch=23
--- a/usr/src/cmd/fm/dicts/PCIEX.po Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/fm/dicts/PCIEX.po Mon Jul 20 13:07:46 2009 -0400 @@ -1,5 +1,5 @@ # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # CDDL HEADER START @@ -21,8 +21,6 @@ # # CDDL HEADER END # -#ident "%Z%%M% %I% %E% SMI" -# # DO NOT EDIT -- this file is generated by the Event Registry. # # @@ -120,7 +118,7 @@ msgid "PCIEX-8000-5Y.impact" msgstr "Loss of services provided by the device instances associated with this fault\n" msgid "PCIEX-8000-5Y.action" -msgstr "Ensure that the latest drivers and patches are installed. Otherwise schedule a repair procedure to replace the affected device(s). Use fmadm faulty to identify the devices or contact Sun for support.\n" +msgstr "Ensure that the latest drivers and patches are installed. Otherwise schedule a repair procedure to replace the affected device(s). Use fmadm faulty to identify the devices or contact Sun for support." # # code: PCIEX-8000-6D # keys: fault.io.pci.device-invreq fault.io.pciex.device-interr @@ -377,3 +375,35 @@ msgstr "Degraded services provided by the device instances associated with this fault\n" msgid "PCIEX-8000-ND.action" msgstr "Schedule a repair procedure to replace the affected device. Use fmadm faulty to identify the device or contact Sun for support.\n" +# +# code: PCIEX-8000-PY +# keys: fault.io.pciex.fw_corrupt +# +msgid "PCIEX-8000-PY.type" +msgstr "Fault" +msgid "PCIEX-8000-PY.severity" +msgstr "Major" +msgid "PCIEX-8000-PY.description" +msgstr "A firmware corruption was detected for a PCIEX device.\n Refer to %s for more information." +msgid "PCIEX-8000-PY.response" +msgstr "One or more device instances may be disabled.\n" +msgid "PCIEX-8000-PY.impact" +msgstr "Degraded services provided by the device instances associated with this fault.\n" +msgid "PCIEX-8000-PY.action" +msgstr "Use fmadm faulty to identify the device and then update the firmware to the latest version or schedule a repair procedure to replace the affected device. Contact Sun support for further information.\n" +# +# code: PCIEX-8000-Q3 +# keys: fault.io.pciex.fw_mismatch +# +msgid "PCIEX-8000-Q3.type" +msgstr "Fault" +msgid "PCIEX-8000-Q3.severity" +msgstr "Major" +msgid "PCIEX-8000-Q3.description" +msgstr "A firmware version mismatch was detected for a PCIEX device.\n Refer to %s for more information." +msgid "PCIEX-8000-Q3.response" +msgstr "One or more device instances may be disabled.\n" +msgid "PCIEX-8000-Q3.impact" +msgstr "Degraded services provided by the device instances associated with this fault.\n" +msgid "PCIEX-8000-Q3.action" +msgstr "Use fmadm faulty to identify the device and then update the firmware to the latest version. Contact Sun support for further information.\n"
--- a/usr/src/cmd/fm/eversholt/files/common/pci.esc Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/fm/eversholt/files/common/pci.esc Mon Jul 20 13:07:46 2009 -0400 @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #pragma dictionary "PCI" #include <fm/topo_hc.h> @@ -98,6 +96,10 @@ event fault.io.pci.device-noresp@PCIFN, FITrate=PCI_DEV_FIT; +event fault.io.pci.fw_corrupt@PCIFN, FITrate=PCI_DEV_FIT, retire=0; + +event fault.io.pci.fw_mismatch@PCIFN, FITrate=PCI_DEV_FIT, retire=0; + /* * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * A faulty hostbridge may cause: @@ -328,6 +330,8 @@ event ereport.io.pcix.oor@PCIFN{within(5s)}; event ereport.io.pcix.unex-sc@PCIFN{within(5s)}; +event ereport.io.device.fw_corrupt@PCIFN{within(5s)}; +event ereport.io.device.fw_mismatch@PCIFN{within(5s)}; event ereport.io.service.lost@PCIFN{within(5s)}; event ereport.io.service.degraded@PCIFN{within(5s)}; event ereport.io.service.unaffected@PCIFN{within(5s)}; @@ -359,6 +363,20 @@ error.io.pcix.tx-oor@PCI_NOT_HB, error.io.pcix.rx-unex-sc@PCI_NOT_HB; +prop fault.io.pci.fw_corrupt@PCIFN {IS_LEAF} (1)-> + ereport.io.device.fw_corrupt@PCIFN; + +prop fault.io.pci.fw_corrupt@PCIFN {IS_LEAF} (0)-> + ereport.io.service.lost@PCIFN, + ereport.io.service.degraded@PCIFN; + +prop fault.io.pci.fw_mismatch@PCIFN {IS_LEAF} (1)-> + ereport.io.device.fw_mismatch@PCIFN; + +prop fault.io.pci.fw_mismatch@PCIFN {IS_LEAF} (0)-> + ereport.io.service.lost@PCIFN, + ereport.io.service.degraded@PCIFN; + prop fault.io.pci.device-invreq@pcibus/pcidev[fromdev]/pcifn {FD_IS_LEAF} (0)-> error.io.pci.badreq-drw-u@PCI_NOT_HB, error.io.pci.badreq-pw-u@PCI_NOT_HB;
--- a/usr/src/cmd/fm/eversholt/files/common/pciex.esc Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/fm/eversholt/files/common/pciex.esc Mon Jul 20 13:07:46 2009 -0400 @@ -110,6 +110,9 @@ /* * define faults */ +event fault.io.pciex.fw_corrupt@PCIEXFN, FITrate=PCIEX_DEV_FIT, retire=0; +event fault.io.pciex.fw_mismatch@PCIEXFN, FITrate=PCIEX_DEV_FIT, retire=0; + event fault.io.pciex.device-interr@PCIEXFN, FITrate=PCIEX_DEV_FIT; event fault.io.pciex.device-interr-deg@PCIEXFN, FITrate=PCIEX_DEV_FIT, retire=0; @@ -409,6 +412,8 @@ event ereport.io.pciex.dl.rto@PCIEXFN/PCIEXFN{within(5s)}; event ereport.io.pciex.dl.rnr@PCIEXFN/PCIEXFN{within(5s)}; event ereport.io.pciex.pl.re@PCIEXFN/PCIEXFN{within(5s)}; +event ereport.io.device.fw_corrupt@PCIEXFN{within(5s)}; +event ereport.io.device.fw_mismatch@PCIEXFN{within(5s)}; prop fault.io.pciex.device-noresp@PCIEXFN { IS_LF(PCIEXFN) } (1)-> error.io.pciex.flt-nr-u@PCIEXFN; @@ -512,6 +517,20 @@ error.io.pciex.flt-mtlp-u@PCIEXFN, error.io.pciex.fatlink@PCIEXFN; +prop fault.io.pciex.fw_corrupt@PCIEXFN { IS_LF(PCIEXFN) } (1)-> + ereport.io.device.fw_corrupt@PCIEXFN; + +prop fault.io.pciex.fw_corrupt@PCIEXFN { IS_LF(PCIEXFN) } (0)-> + ereport.io.service.lost@PCIEXFN, + ereport.io.service.degraded@PCIEXFN; + +prop fault.io.pciex.fw_mismatch@PCIEXFN { IS_LF(PCIEXFN) } (1)-> + ereport.io.device.fw_mismatch@PCIEXFN; + +prop fault.io.pciex.fw_mismatch@PCIEXFN { IS_LF(PCIEXFN) } (0)-> + ereport.io.service.lost@PCIEXFN, + ereport.io.service.degraded@PCIEXFN; + /* * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * A faulty PCI Express downstream switch port may cause
--- a/usr/src/cmd/fm/modules/common/snmp-trapgen/Makefile Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/fm/modules/common/snmp-trapgen/Makefile Mon Jul 20 13:07:46 2009 -0400 @@ -28,10 +28,10 @@ MODULE = snmp-trapgen CLASS = common SRCS = snmp.c -SMASNMPCONFS = fmd-trapgen.conf +NETSNMPCONFS = fmd-trapgen.conf -ROOTSMASNMPDIR = $(ROOT)/etc/sma/snmp -ROOTSMASNMPCONFS = $(SMASNMPCONFS:%=$(ROOTSMASNMPDIR)/%) +ROOTNETSNMPDIR = $(ROOT)/etc/net-snmp/snmp +ROOTNETSNMPCONFS = $(NETSNMPCONFS:%=$(ROOTNETSNMPDIR)/%) include ../../Makefile.plugin @@ -42,9 +42,9 @@ LINTFLAGS += -L$(ROOT)/usr/lib/fm LDLIBS += $(SNMPLIBS) -lfmd_msg -$(ROOTSMASNMPCONFS) := FILEMODE = 0600 +$(ROOTNETSNMPCONFS) := FILEMODE = 0600 -$(ROOTSMASNMPDIR)/%: % +$(ROOTNETSNMPDIR)/%: % $(INS.file) -install: $(ROOTSMASNMPCONFS) +install: $(ROOTNETSNMPCONFS)
--- a/usr/src/cmd/fm/modules/common/snmp-trapgen/fmd-trapgen.conf Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/fm/modules/common/snmp-trapgen/fmd-trapgen.conf Mon Jul 20 13:07:46 2009 -0400 @@ -20,15 +20,14 @@ # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" # # # Supplemental configuration for the snmp-trapgen FMA module. Normal # configuration of this module should be made via trap sink directives -# in /etc/sma/snmp/snmpd.conf, not in this file. See snmpd(4) and +# in /etc/net-snmp/snmp/snmpd.conf, not in this file. See snmpd(4) and # snmp_config(4). #
--- a/usr/src/cmd/fs.d/dev/mount.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/fs.d/dev/mount.c Mon Jul 20 13:07:46 2009 -0400 @@ -20,12 +20,10 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <limits.h> #include <stdio.h> @@ -38,7 +36,7 @@ #include <sys/stat.h> #include <sys/mount.h> #include <sys/mntent.h> -#include <sys/fs/sdev_node.h> +#include <sys/fs/sdev_impl.h> #define READFLAG_RO 1
--- a/usr/src/cmd/idmap/idmap/idmap.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/idmap/idmap/idmap.c Mon Jul 20 13:07:46 2009 -0400 @@ -34,7 +34,6 @@ #include <sys/varargs.h> #include "idmap_engine.h" #include "idmap_priv.h" -#include "idmap_impl.h" /* Initialization values for pids/rids: */
--- a/usr/src/cmd/idmap/idmapd/Makefile Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/idmap/idmapd/Makefile Mon Jul 20 13:07:46 2009 -0400 @@ -25,8 +25,21 @@ PROG = idmapd MANIFEST = idmap.xml -SERVEROBJS = idmapd.o init.o dbutils.o rpc_svc.o server.o adutils.o\ - idmap_config.o nldaputils.o +SERVEROBJS = \ + directory_provider_builtin.o \ + directory_provider_nsswitch.o \ + directory_provider_ad.o \ + directory_server.o \ + adutils.o \ + dbutils.o \ + idmap_config.o \ + idmapd.o \ + init.o \ + nldaputils.o \ + rpc_svc.o \ + server.o \ + wksids.o + SERVERSRCS = $(SERVEROBJS:%.o=%.c) OBJS = $(SERVEROBJS) SRCS = $(SERVERSRCS) @@ -42,8 +55,17 @@ include ../../Makefile.cmd +TEXT_DOMAIN = SUNW_OST_OSLIB +XGETTEXT = $(GNUXGETTEXT) +XGETFLAGS = --foreign-user --strict -n -E --width=72 \ + --omit-header --keyword=directoryError:2 \ + --language=C --force-po + +C99MODE = $(C99_ENABLE) POFILE = $(PROG)_all.po +RPC_MSGOUT_OPT = -DRPC_MSGOUT=idmap_rpc_msgout + ROOTMANIFESTDIR = $(ROOTSVCSYSTEM) $(ROOTMANIFEST) := FILEMODE= 444 @@ -55,7 +77,18 @@ $(POFILE) := CPPFLAGS += $(INCS) CFLAGS += -v -LDLIBS += -lsecdb -lsocket -lnsl -lidmap -lscf -lsldap -lldap -luuid -ladutils +LDLIBS += -lsecdb \ + -lsocket \ + -lnsl \ + -lidmap \ + -lscf \ + -lsldap \ + -lldap \ + -luuid \ + -ladutils \ + -lumem + +rpc_svc.o := CFLAGS += $(RPC_MSGOUT_OPT) $(PROG) := MAPFILES = $(MAPFILE.INT) $(MAPFILE.NGB) $(PROG) := LDFLAGS += $(MAPFILES:%=-M%) @@ -65,7 +98,7 @@ OWNER = root GROUP = sys -lint_SRCS := CPPFLAGS += $(INCS) -D_REENTRANT +lint_SRCS := CPPFLAGS += $(INCS) -D_REENTRANT $(RPC_MSGOUT_OPT) lint := LDLIBS += $(SQLITELINT) .KEEP_STATE:
--- a/usr/src/cmd/idmap/idmapd/adutils.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/idmap/idmapd/adutils.c Mon Jul 20 13:07:46 2009 -0400 @@ -20,7 +20,7 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -235,7 +235,7 @@ char *sid, rid_t rid, int sid_type, char *unixname) { char *domain; - int err1, err2; + int err1; assert(dn != NULL); @@ -252,8 +252,7 @@ if (q->edomain != NULL) { /* Check that this is the domain that we were looking for */ - if (u8_strcmp(q->edomain, domain, 0, U8_STRCMP_CI_LOWER, - U8_UNICODE_LATEST, &err2) != 0 || err2 != 0) + if (!domain_eq(q->edomain, domain)) goto out; }
--- a/usr/src/cmd/idmap/idmapd/dbutils.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/idmap/idmapd/dbutils.c Mon Jul 20 13:07:46 2009 -0400 @@ -74,8 +74,6 @@ #define IS_EPHEMERAL(pid) (pid > INT32_MAX && pid != SENTINEL_PID) -#define LOCALRID_MIN 1000 - typedef enum init_db_option { FAIL_IF_CORRUPT = 0, @@ -83,21 +81,6 @@ } init_db_option_t; /* - * Data structure to store well-known SIDs and - * associated mappings (if any) - */ -typedef struct wksids_table { - const char *sidprefix; - uint32_t rid; - const char *domain; - const char *winname; - int is_wuser; - uid_t pid; - int is_user; - int direction; -} wksids_table_t; - -/* * Thread specific data to hold the database handles so that the * databases are not opened and closed for every request. It also * contains the sqlite busy handler structure. @@ -131,12 +114,6 @@ static pthread_key_t idmap_tsd_key; -static const wksids_table_t *find_wksid_by_pid(uid_t pid, int is_user); -static const wksids_table_t *find_wksid_by_sid(const char *sid, int rid, - int type); -static const wksids_table_t *find_wksid_by_name(const char *name, - const char *domain, int type); - void idmap_tsd_destroy(void *key) { @@ -1203,179 +1180,6 @@ rule->direction = direction; } - -/* - * Table for well-known SIDs. - * - * Background: - * - * Some of the well-known principals are stored under: - * cn=WellKnown Security Principals, cn=Configuration, dc=<forestRootDomain> - * They belong to objectClass "foreignSecurityPrincipal". They don't have - * "samAccountName" nor "userPrincipalName" attributes. Their names are - * available in "cn" and "name" attributes. Some of these principals have a - * second entry under CN=ForeignSecurityPrincipals,dc=<forestRootDomain> and - * these duplicate entries have the stringified SID in the "name" and "cn" - * attributes instead of the actual name. - * - * Those of the form S-1-5-32-X are Builtin groups and are stored in the - * cn=builtin container (except, Power Users which is not stored in AD) - * - * These principals are and will remain constant. Therefore doing AD lookups - * provides no benefit. Also, using hard-coded table (and thus avoiding AD - * lookup) improves performance and avoids additional complexity in the - * adutils.c code. Moreover these SIDs can be used when no Active Directory - * is available (such as the CIFS server's "workgroup" mode). - * - * Notes: - * 1. Currently we don't support localization of well-known SID names, - * unlike Windows. - * - * 2. Other well-known SIDs i.e. S-1-5-<domain>-<w-k RID> are not stored - * here. AD does have normal user/group objects for these objects and - * can be looked up using the existing AD lookup code. - * - * 3. See comments above lookup_wksids_sid2pid() for more information - * on how we lookup the wksids table. - * - * 4. If this table contains two entries for a particular Windows name, - * so as to offer both UID and GID mappings, the preferred mapping (the - * one that matches Windows usage) must be listed first. That is the - * entry that will be used when the caller specifies IDMAP_POSIXID - * ("don't care") as the target. - * - * Entries here come from KB243330, MS-LSAT, and - * http://technet.microsoft.com/en-us/library/cc755854.aspx - * http://technet.microsoft.com/en-us/library/cc755925.aspx - * http://msdn.microsoft.com/en-us/library/cc980032(PROT.10).aspx - */ -static wksids_table_t wksids[] = { - /* S-1-0 Null Authority */ - {"S-1-0", 0, "", "Nobody", 1, SENTINEL_PID, -1, 1}, - - /* S-1-1 World Authority */ - {"S-1-1", 0, "", "Everyone", 0, SENTINEL_PID, -1, -1}, - - /* S-1-2 Local Authority */ - {"S-1-2", 0, "", "Local", 0, SENTINEL_PID, -1, -1}, - {"S-1-2", 1, "", "Console Logon", 0, SENTINEL_PID, -1, -1}, - - /* S-1-3 Creator Authority */ - {"S-1-3", 0, "", "Creator Owner", 1, IDMAP_WK_CREATOR_OWNER_UID, 1, 0}, - {"S-1-3", 1, "", "Creator Group", 0, IDMAP_WK_CREATOR_GROUP_GID, 0, 0}, - {"S-1-3", 2, "", "Creator Owner Server", 1, SENTINEL_PID, -1, -1}, - {"S-1-3", 3, "", "Creator Group Server", 0, SENTINEL_PID, -1, 1}, - {"S-1-3", 4, "", "Owner Rights", 0, SENTINEL_PID, -1, -1}, - - /* S-1-4 Non-unique Authority */ - - /* S-1-5 NT Authority */ - {"S-1-5", 1, "", "Dialup", 0, SENTINEL_PID, -1, -1}, - {"S-1-5", 2, "", "Network", 0, SENTINEL_PID, -1, -1}, - {"S-1-5", 3, "", "Batch", 0, SENTINEL_PID, -1, -1}, - {"S-1-5", 4, "", "Interactive", 0, SENTINEL_PID, -1, -1}, - /* S-1-5-5-X-Y Logon Session */ - {"S-1-5", 6, "", "Service", 0, SENTINEL_PID, -1, -1}, - {"S-1-5", 7, "", "Anonymous Logon", 0, GID_NOBODY, 0, 0}, - {"S-1-5", 7, "", "Anonymous Logon", 0, UID_NOBODY, 1, 0}, - {"S-1-5", 8, "", "Proxy", 0, SENTINEL_PID, -1, -1}, - {"S-1-5", 9, "", "Enterprise Domain Controllers", 0, - SENTINEL_PID, -1, -1}, - {"S-1-5", 10, "", "Self", 0, SENTINEL_PID, -1, -1}, - {"S-1-5", 11, "", "Authenticated Users", 0, SENTINEL_PID, -1, -1}, - {"S-1-5", 12, "", "Restricted", 0, SENTINEL_PID, -1, -1}, - {"S-1-5", 13, "", "Terminal Server Users", 0, SENTINEL_PID, -1, -1}, - {"S-1-5", 14, "", "Remote Interactive Logon", 0, SENTINEL_PID, -1, -1}, - {"S-1-5", 15, "", "This Organization", 0, SENTINEL_PID, -1, -1}, - {"S-1-5", 17, "", "IUSR", 0, SENTINEL_PID, -1, -1}, - {"S-1-5", 18, "", "Local System", 0, IDMAP_WK_LOCAL_SYSTEM_GID, 0, 0}, - {"S-1-5", 19, "", "Local Service", 0, SENTINEL_PID, -1, -1}, - {"S-1-5", 20, "", "Network Service", 0, SENTINEL_PID, -1, -1}, - - /* S-1-5-21-<domain> Machine-local definitions */ - {NULL, 498, NULL, "Enterprise Read-only Domain Controllers", 0, - SENTINEL_PID, -1, -1}, - {NULL, 500, NULL, "Administrator", 1, SENTINEL_PID, 1, -1}, - {NULL, 501, NULL, "Guest", 1, SENTINEL_PID, 1, -1}, - {NULL, 502, NULL, "KRBTGT", 1, SENTINEL_PID, 1, -1}, - {NULL, 512, NULL, "Domain Admins", 0, SENTINEL_PID, -1, -1}, - {NULL, 513, NULL, "Domain Users", 0, SENTINEL_PID, -1, -1}, - {NULL, 514, NULL, "Domain Guests", 0, SENTINEL_PID, -1, -1}, - {NULL, 515, NULL, "Domain Computers", 0, SENTINEL_PID, -1, -1}, - {NULL, 516, NULL, "Domain Controllers", 0, SENTINEL_PID, -1, -1}, - {NULL, 517, NULL, "Cert Publishers", 0, SENTINEL_PID, -1, -1}, - {NULL, 518, NULL, "Schema Admins", 0, SENTINEL_PID, -1, -1}, - {NULL, 519, NULL, "Enterprise Admins", 0, SENTINEL_PID, -1, -1}, - {NULL, 520, NULL, "Global Policy Creator Owners", 0, - SENTINEL_PID, -1, -1}, - {NULL, 533, NULL, "RAS and IAS Servers", 0, SENTINEL_PID, -1, -1}, - - /* S-1-5-32 BUILTIN */ - {"S-1-5-32", 544, "BUILTIN", "Administrators", 0, SENTINEL_PID, -1, -1}, - {"S-1-5-32", 545, "BUILTIN", "Users", 0, SENTINEL_PID, -1, -1}, - {"S-1-5-32", 546, "BUILTIN", "Guests", 0, SENTINEL_PID, -1, -1}, - {"S-1-5-32", 547, "BUILTIN", "Power Users", 0, SENTINEL_PID, -1, -1}, - {"S-1-5-32", 548, "BUILTIN", "Account Operators", 0, - SENTINEL_PID, -1, -1}, - {"S-1-5-32", 549, "BUILTIN", "Server Operators", 0, - SENTINEL_PID, -1, -1}, - {"S-1-5-32", 550, "BUILTIN", "Print Operators", 0, - SENTINEL_PID, -1, -1}, - {"S-1-5-32", 551, "BUILTIN", "Backup Operators", 0, - SENTINEL_PID, -1, -1}, - {"S-1-5-32", 552, "BUILTIN", "Replicator", 0, SENTINEL_PID, -1, -1}, - {"S-1-5-32", 554, "BUILTIN", "Pre-Windows 2000 Compatible Access", 0, - SENTINEL_PID, -1, -1}, - {"S-1-5-32", 555, "BUILTIN", "Remote Desktop Users", 0, - SENTINEL_PID, -1, -1}, - {"S-1-5-32", 556, "BUILTIN", "Network Configuration Operators", 0, - SENTINEL_PID, -1, -1}, - {"S-1-5-32", 557, "BUILTIN", "Incoming Forest Trust Builders", 0, - SENTINEL_PID, -1, -1}, - {"S-1-5-32", 558, "BUILTIN", "Performance Monitor Users", 0, - SENTINEL_PID, -1, -1}, - {"S-1-5-32", 559, "BUILTIN", "Performance Log Users", 0, - SENTINEL_PID, -1, -1}, - {"S-1-5-32", 560, "BUILTIN", "Windows Authorization Access Group", 0, - SENTINEL_PID, -1, -1}, - {"S-1-5-32", 561, "BUILTIN", "Terminal Server License Servers", 0, - SENTINEL_PID, -1, -1}, - {"S-1-5-32", 562, "BUILTIN", "Distributed COM Users", 0, - SENTINEL_PID, -1, -1}, - {"S-1-5-32", 568, "BUILTIN", "IIS_IUSRS", 0, SENTINEL_PID, -1, -1}, - {"S-1-5-32", 569, "BUILTIN", "Cryptographic Operators", 0, - SENTINEL_PID, -1, -1}, - {"S-1-5-32", 573, "BUILTIN", "Event Log Readers", 0, - SENTINEL_PID, -1, -1}, - {"S-1-5-32", 574, "BUILTIN", "Certificate Service DCOM Access", 0, - SENTINEL_PID, -1, -1}, - - {"S-1-5", 33, "", "Write Restricted", 0, SENTINEL_PID, -1, -1}, - - /* S-1-5-64 NT Authority */ - {"S-1-5-64", 10, "", "NTLM Authentication", 0, SENTINEL_PID, -1, -1}, - {"S-1-5-64", 14, "", "SChannel Authentication", 0, - SENTINEL_PID, -1, -1}, - {"S-1-5-64", 21, "", "Digest Authentication", 0, SENTINEL_PID, -1, -1}, - - /* S-1-5-80-a-b-c-d NT Service */ - - {"S-1-5", 1000, "", "Other Organization", 0, SENTINEL_PID, -1, -1}, - - /* S-1-7 Internet$ */ - - /* - * S-1-16 Mandatory Label - * S-1-16-0 Untrusted Mandatory Level - * S-1-16-4096 Low Mandatory Level - * S-1-16-8192 Medium Mandatory Level - * S-1-16-8448 Medium Plus Mandatory Level - * S-1-16-12288 High Mandatory Level - * S-1-16-16384 System Mandatory Level - * S-1-16-20480 Protected Process Mandatory Level - */ -}; - /* * Lookup well-known SIDs table either by winname or by SID. * @@ -2634,8 +2438,8 @@ return (IDMAP_ERR_NOMAPPING); /* Skip 1000 UIDs */ - if (is_user && req->id1.idmap_id_u.uid > - (INT32_MAX - LOCALRID_MIN)) + if (is_user && + req->id1.idmap_id_u.uid + LOCALRID_UID_MIN > LOCALRID_UID_MAX) return (IDMAP_ERR_NOMAPPING); RDLOCK_CONFIG(); @@ -2652,8 +2456,8 @@ } UNLOCK_CONFIG(); res->id.idmap_id_u.sid.rid = - (is_user) ? req->id1.idmap_id_u.uid + LOCALRID_MIN : - req->id1.idmap_id_u.gid + INT32_MAX + 1; + (is_user) ? req->id1.idmap_id_u.uid + LOCALRID_UID_MIN : + req->id1.idmap_id_u.gid + LOCALRID_GID_MIN; res->direction = IDMAP_DIRECTION_BI; if (res->id.idtype == IDMAP_SID) res->id.idtype = is_user ? IDMAP_USID : IDMAP_GSID; @@ -2702,24 +2506,24 @@ switch (res->id.idtype) { case IDMAP_UID: - if (rid > INT32_MAX || rid < LOCALRID_MIN) + if (rid < LOCALRID_UID_MIN || rid > LOCALRID_UID_MAX) return (IDMAP_ERR_ARG); - res->id.idmap_id_u.uid = rid - LOCALRID_MIN; + res->id.idmap_id_u.uid = rid - LOCALRID_UID_MIN; break; case IDMAP_GID: - if (rid <= INT32_MAX) + if (rid < LOCALRID_GID_MIN) return (IDMAP_ERR_ARG); - res->id.idmap_id_u.gid = rid - INT32_MAX - 1; + res->id.idmap_id_u.gid = rid - LOCALRID_GID_MIN; break; case IDMAP_POSIXID: - if (rid > INT32_MAX) { - res->id.idmap_id_u.gid = rid - INT32_MAX - 1; + if (rid >= LOCALRID_GID_MIN) { + res->id.idmap_id_u.gid = rid - LOCALRID_GID_MIN; res->id.idtype = IDMAP_GID; - } else if (rid < LOCALRID_MIN) { - return (IDMAP_ERR_ARG); + } else if (rid >= LOCALRID_UID_MIN) { + res->id.idmap_id_u.uid = rid - LOCALRID_UID_MIN; + res->id.idtype = IDMAP_UID; } else { - res->id.idmap_id_u.uid = rid - LOCALRID_MIN; - res->id.idtype = IDMAP_UID; + return (IDMAP_ERR_ARG); } break; default: @@ -4851,161 +4655,3 @@ result.ids.ids_val = res; return (ad_lookup_batch(state, &batch, &result)); } - -/* - * Find a wksid entry for the specified Windows name and domain, of the - * specified type. - * - * Ignore entries intended only for U2W use. - */ -static -const -wksids_table_t * -find_wksid_by_name(const char *name, const char *domain, int type) -{ - int i; - char *myhostname; - int len; - - RDLOCK_CONFIG(); - len = strlen(_idmapdstate.hostname) + 1; - myhostname = alloca(len); - (void) memcpy(myhostname, _idmapdstate.hostname, len); - UNLOCK_CONFIG(); - - for (i = 0; i < NELEM(wksids); i++) { - /* Check to see if this entry yields the desired type */ - switch (type) { - case IDMAP_UID: - if (wksids[i].is_user == 0) - continue; - break; - case IDMAP_GID: - if (wksids[i].is_user == 1) - continue; - break; - case IDMAP_POSIXID: - break; - default: - assert(FALSE); - } - - if (strcasecmp(wksids[i].winname, name) != 0) - continue; - - if (!EMPTY_STRING(domain)) { - const char *dom; - - if (wksids[i].domain != NULL) { - dom = wksids[i].domain; - } else { - dom = myhostname; - } - if (strcasecmp(dom, domain) != 0) { - /* this is not our domain */ - continue; - } - } - - /* - * We have a Windows name, so ignore entries that are only - * usable for mapping UNIX->Windows. (Note: the current - * table does not have any such entries.) - */ - if (wksids[i].direction == IDMAP_DIRECTION_U2W) - continue; - - return (&wksids[i]); - } - - return (NULL); -} - -/* - * Find a wksid entry for the specified SID, of the specified type. - * - * Ignore entries intended only for U2W use. - */ -static -const -wksids_table_t * -find_wksid_by_sid(const char *sid, int rid, int type) -{ - int i; - char *mymachinesid; - int len; - - RDLOCK_CONFIG(); - len = strlen(_idmapdstate.cfg->pgcfg.machine_sid) + 1; - mymachinesid = alloca(len); - (void) memcpy(mymachinesid, _idmapdstate.cfg->pgcfg.machine_sid, len); - UNLOCK_CONFIG(); - - for (i = 0; i < NELEM(wksids); i++) { - int sidcmp; - - /* Check to see if this entry yields the desired type */ - switch (type) { - case IDMAP_UID: - if (wksids[i].is_user == 0) - continue; - break; - case IDMAP_GID: - if (wksids[i].is_user == 1) - continue; - break; - case IDMAP_POSIXID: - break; - default: - assert(FALSE); - } - - if (wksids[i].sidprefix != NULL) { - sidcmp = strcasecmp(wksids[i].sidprefix, sid); - } else { - sidcmp = strcasecmp(mymachinesid, sid); - } - - if (sidcmp != 0) - continue; - if (wksids[i].rid != rid) - continue; - - /* - * We have a SID, so ignore entries that are only usable - * for mapping UNIX->Windows. (Note: the current table - * does not have any such entries.) - */ - if (wksids[i].direction == IDMAP_DIRECTION_U2W) - continue; - - return (&wksids[i]); - } - - return (NULL); -} - -/* - * Find a wksid entry for the specified pid, of the specified type. - * Ignore entries that do not specify U2W mappings. - */ -static -const -wksids_table_t * -find_wksid_by_pid(uid_t pid, int is_user) -{ - int i; - - if (pid == SENTINEL_PID) - return (NULL); - - for (i = 0; i < NELEM(wksids); i++) { - if (wksids[i].pid == pid && - wksids[i].is_user == is_user && - (wksids[i].direction == IDMAP_DIRECTION_BI || - wksids[i].direction == IDMAP_DIRECTION_U2W)) { - return (&wksids[i]); - } - } - return (NULL); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/idmap/idmapd/directory_provider_ad.c Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,590 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Retrieve directory information for Active Directory users. + */ + +#include <ldap.h> +#include <lber.h> +#include <pwd.h> +#include <malloc.h> +#include <string.h> +#include <stdlib.h> +#include <netdb.h> +#include <libadutils.h> +#include <note.h> +#include <assert.h> +#include "directory.h" +#include "directory_private.h" +#include "idmapd.h" +#include <rpcsvc/idmap_prot.h> +#include "directory_server_impl.h" +#include "miscutils.h" + +/* + * Information required by the function that handles the callback from LDAP + * when responses are received. + */ +struct cbinfo { + const char * const *attrs; + int nattrs; + directory_entry_rpc *entry; + const char *domain; +}; + +static void directory_provider_ad_cb(LDAP *ld, LDAPMessage **ldapres, int rc, + int qid, void *argp); +static void directory_provider_ad_cb1(LDAP *ld, LDAPMessage *msg, + struct cbinfo *cbinfo); +static directory_error_t bv_list_dav(directory_values_rpc *lvals, + struct berval **bv); +static directory_error_t directory_provider_ad_lookup( + directory_entry_rpc *pent, const char * const * attrs, int nattrs, + const char *domain, const char *filter); +static directory_error_t get_domain(LDAP *ld, LDAPMessage *ldapres, + char **domain); +static directory_error_t directory_provider_ad_utils_error(char *func, int rc); + +#if defined(DUMP_VALUES) +static void dump_bv_list(const char *attr, struct berval **bv); +#endif + +#define MAX_EXTRA_ATTRS 1 /* sAMAccountName */ + +/* + * Add an entry to a NULL-terminated list, if it's not already there. + * Assumes that the list has been allocated large enough for all additions, + * and prefilled with NULL. + */ +static +void +maybe_add_to_list(const char **list, const char *s) +{ + for (; *list != NULL; list++) { + if (strcaseeq(*list, s)) + return; + } + *list = s; +} + +/* + * Copy a counted attribute list to a NULL-terminated one. + * In the process, examine the requested attributes and augment + * the list as required to support any synthesized attributes + * requested. + */ +static +const char ** +copy_and_augment_attr_list(char **req_list, int req_list_len) +{ + const char **new_list; + int i; + + new_list = + calloc(req_list_len + MAX_EXTRA_ATTRS + 1, sizeof (*new_list)); + if (new_list == NULL) + return (NULL); + + (void) memcpy(new_list, req_list, req_list_len * sizeof (char *)); + + for (i = 0; i < req_list_len; i++) { + const char *a = req_list[i]; + /* + * Note that you must update MAX_EXTRA_ATTRS above if you + * add to this list. + */ + if (strcaseeq(a, "x-sun-canonicalName")) { + maybe_add_to_list(new_list, "sAMAccountName"); + continue; + } + /* None needed for x-sun-provider */ + } + + return (new_list); +} + +/* + * Retrieve information by name. + * Called indirectly through the Directory_provider_static structure. + */ +static +directory_error_t +directory_provider_ad_get( + directory_entry_rpc *del, + idmap_utf8str_list *ids, + char *types, + idmap_utf8str_list *attrs) +{ + int i; + const char **attrs2; + directory_error_t de = NULL; + + /* + * If we don't have any AD servers handy, we can't find anything. + */ + if (_idmapdstate.num_ads < 1) { + return (NULL); + } + + RDLOCK_CONFIG() + + /* 6835280 spurious lint error if the strlen is in the declaration */ + int len = strlen(_idmapdstate.cfg->pgcfg.default_domain); + char default_domain[len + 1]; + (void) strcpy(default_domain, _idmapdstate.cfg->pgcfg.default_domain); + + UNLOCK_CONFIG(); + + /* + * Turn our counted-array argument into a NULL-terminated array. + * At the same time, add in any attributes that we need to support + * any requested synthesized attributes. + */ + attrs2 = copy_and_augment_attr_list(attrs->idmap_utf8str_list_val, + attrs->idmap_utf8str_list_len); + if (attrs2 == NULL) + goto nomem; + + for (i = 0; i < ids->idmap_utf8str_list_len; i++) { + char *vw[3]; + int type; + + /* + * Extract the type for this particular ID. + * Advance to the next type, if it's there, else keep + * using this type until we run out of IDs. + */ + type = *types; + if (*(types+1) != '\0') + types++; + + /* + * If this entry has already been handled, one way or another, + * skip it. + */ + if (del[i].status != DIRECTORY_NOT_FOUND) + continue; + + char *id = ids->idmap_utf8str_list_val[i]; + + /* + * Allow for expanding every character to \xx, plus some + * space for the query syntax. + */ + int id_len = strlen(id); + char filter[1000 + id_len*3]; + + if (type == DIRECTORY_ID_SID[0]) { + /* + * Mildly surprisingly, AD appears to allow searching + * based on text SIDs. Must be a special case on the + * server end. + */ + ldap_build_filter(filter, sizeof (filter), + "(objectSid=%v)", NULL, NULL, NULL, id, NULL); + + de = directory_provider_ad_lookup(&del[i], attrs2, + attrs->idmap_utf8str_list_len, NULL, filter); + if (de != NULL) { + directory_entry_set_error(&del[i], de); + de = NULL; + } + } else { + int id_len = strlen(id); + char name[id_len + 1]; + char domain[id_len + 1]; + + split_name(name, domain, id); + + vw[0] = name; + + if (streq(domain, "")) { + vw[1] = default_domain; + } else { + vw[1] = domain; + } + + if (type == DIRECTORY_ID_USER[0]) + vw[2] = "user"; + else if (type == DIRECTORY_ID_GROUP[0]) + vw[2] = "group"; + else + vw[2] = "*"; + + /* + * Try samAccountName. + * Note that here we rely on checking the returned + * distinguishedName to make sure that we found an + * entry from the right domain, because there's no + * attribute we can straightforwardly filter for to + * match domain. + * + * Eventually we should perhaps also try + * userPrincipalName. + */ + ldap_build_filter(filter, sizeof (filter), + "(&(samAccountName=%v1)(objectClass=%v3))", + NULL, NULL, NULL, NULL, vw); + + de = directory_provider_ad_lookup(&del[i], attrs2, + attrs->idmap_utf8str_list_len, vw[1], filter); + if (de != NULL) { + directory_entry_set_error(&del[i], de); + de = NULL; + } + } + } + + de = NULL; + + goto out; + +nomem: + de = directory_error("ENOMEM.AD", + "Out of memory during AD lookup", NULL); +out: + free(attrs2); + return (de); +} + +/* + * Note that attrs is NULL terminated, and that nattrs is the number + * of attributes requested by the user... which might be fewer than are + * in attrs because of attributes that we need for our own processing. + */ +static +directory_error_t +directory_provider_ad_lookup( + directory_entry_rpc *pent, + const char * const * attrs, + int nattrs, + const char *domain, + const char *filter) +{ + adutils_ad_t *ad; + adutils_rc batchrc; + struct cbinfo cbinfo; + adutils_query_state_t *qs; + int rc; + + /* + * NEEDSWORK: Should eventually handle other forests. + * NEEDSWORK: Should eventually handle non-GC attributes. + */ + ad = _idmapdstate.ads[0]; + + /* Stash away information for the callback function. */ + cbinfo.attrs = attrs; + cbinfo.nattrs = nattrs; + cbinfo.entry = pent; + cbinfo.domain = domain; + + rc = adutils_lookup_batch_start(ad, 1, directory_provider_ad_cb, + &cbinfo, &qs); + if (rc != ADUTILS_SUCCESS) { + return (directory_provider_ad_utils_error( + "adutils_lookup_batch_start", rc)); + } + + rc = adutils_lookup_batch_add(qs, filter, attrs, domain, + NULL, &batchrc); + if (rc != ADUTILS_SUCCESS) { + adutils_lookup_batch_release(&qs); + return (directory_provider_ad_utils_error( + "adutils_lookup_batch_add", rc)); + } + + rc = adutils_lookup_batch_end(&qs); + if (rc != ADUTILS_SUCCESS) { + return (directory_provider_ad_utils_error( + "adutils_lookup_batch_end", rc)); + } + + if (batchrc != ADUTILS_SUCCESS) { + /* + * NEEDSWORK: We're consistently getting -9997 here. + * What does it mean? + */ + return (NULL); + } + + return (NULL); +} + +/* + * Callback from the LDAP functions when they get responses. + * We don't really need (nor want) asynchronous handling, but it's + * what libadutils gives us. + */ +static +void +directory_provider_ad_cb( + LDAP *ld, + LDAPMessage **ldapres, + int rc, + int qid, + void *argp) +{ + NOTE(ARGUNUSED(rc, qid)) + struct cbinfo *cbinfo = (struct cbinfo *)argp; + LDAPMessage *msg = *ldapres; + + for (msg = ldap_first_entry(ld, msg); + msg != NULL; + msg = ldap_next_entry(ld, msg)) { + directory_provider_ad_cb1(ld, msg, cbinfo); + } +} + +/* + * Process a single entry returned by an LDAP callback. + * Note that this performs a function roughly equivalent to the + * directory*Populate() functions in the other providers. + * Given an LDAP response, populate the directory entry for return to + * the caller. This one differs primarily in that we're working directly + * with LDAP, so we don't have to do any attribute translation. + */ +static +void +directory_provider_ad_cb1( + LDAP *ld, + LDAPMessage *msg, + struct cbinfo *cbinfo) +{ + int nattrs = cbinfo->nattrs; + const char * const *attrs = cbinfo->attrs; + directory_entry_rpc *pent = cbinfo->entry; + + int i; + directory_values_rpc *llvals; + directory_error_t de; + char *domain = NULL; + + /* + * We don't have a way to filter for entries from the right domain + * in the LDAP query, so we check for it here. Searches based on + * samAccountName might yield results from the wrong domain. + */ + de = get_domain(ld, msg, &domain); + if (de != NULL) + goto err; + + if (cbinfo->domain != NULL && !domain_eq(cbinfo->domain, domain)) + goto out; + + /* + * If we've already found a match, error. + */ + if (pent->status != DIRECTORY_NOT_FOUND) { + de = directory_error("Duplicate.AD", + "Multiple matching entries found", NULL); + goto err; + } + + llvals = calloc(nattrs, sizeof (directory_values_rpc)); + if (llvals == NULL) + goto nomem; + + pent->directory_entry_rpc_u.attrs.attrs_val = llvals; + pent->directory_entry_rpc_u.attrs.attrs_len = nattrs; + pent->status = DIRECTORY_FOUND; + + for (i = 0; i < nattrs; i++) { + struct berval **bv; + const char *a = attrs[i]; + directory_values_rpc *val = &llvals[i]; + + bv = ldap_get_values_len(ld, msg, a); +#if defined(DUMP_VALUES) + dump_bv_list(attrs[i], bv); +#endif + if (bv != NULL) { + de = bv_list_dav(val, bv); + ldap_value_free_len(bv); + if (de != NULL) + goto err; + } else if (strcaseeq(a, "x-sun-canonicalName")) { + bv = ldap_get_values_len(ld, msg, "sAMAccountName"); + if (bv != NULL) { + int n = ldap_count_values_len(bv); + if (n > 0) { + char *tmp; + (void) asprintf(&tmp, "%.*s@%s", + bv[0]->bv_len, bv[0]->bv_val, + domain); + if (tmp == NULL) + goto nomem; + const char *ctmp = tmp; + de = str_list_dav(val, &ctmp, 1); + free(tmp); + if (de != NULL) + goto err; + } + } + } else if (strcaseeq(a, "x-sun-provider")) { + const char *provider = "LDAP-AD"; + de = str_list_dav(val, &provider, 1); + } + } + + goto out; + +nomem: + de = directory_error("ENOMEM.users", + "No memory allocating return value for user lookup", NULL); + +err: + directory_entry_set_error(pent, de); + de = NULL; + +out: + free(domain); +} + +/* + * Given a struct berval, populate a directory attribute value (which is a + * list of values). + * Note that here we populate the DAV with the exact bytes that LDAP returns. + * Back over in the client it appends a \0 so that strings are null + * terminated. + */ +static +directory_error_t +bv_list_dav(directory_values_rpc *lvals, struct berval **bv) +{ + directory_value_rpc *dav; + int n; + int i; + + n = ldap_count_values_len(bv); + + dav = calloc(n, sizeof (directory_value_rpc)); + if (dav == NULL) + goto nomem; + + lvals->directory_values_rpc_u.values.values_val = dav; + lvals->directory_values_rpc_u.values.values_len = n; + lvals->found = TRUE; + + for (i = 0; i < n; i++) { + dav[i].directory_value_rpc_val = + memdup(bv[i]->bv_val, bv[i]->bv_len); + if (dav[i].directory_value_rpc_val == NULL) + goto nomem; + dav[i].directory_value_rpc_len = bv[i]->bv_len; + } + + return (NULL); + +nomem: + return (directory_error("ENOMEM.bv_list_dav", + "Insufficient memory copying values")); +} + +#if defined(DUMP_VALUES) +static +void +dump_bv_list(const char *attr, struct berval **bv) +{ + int i; + + if (bv == NULL) { + (void) fprintf(stderr, "%s: (empty)\n", attr); + return; + } + for (i = 0; bv[i] != NULL; i++) { + (void) fprintf(stderr, "%s[%d] =\n", attr, i); + dump(stderr, " ", bv[i]->bv_val, bv[i]->bv_len); + } +} +#endif /* DUMP_VALUES */ + +/* + * Return the domain associated with the specified entry. + */ +static +directory_error_t +get_domain( + LDAP *ld, + LDAPMessage *msg, + char **domain) +{ + *domain = NULL; + + char *dn = ldap_get_dn(ld, msg); + if (dn == NULL) { + char buf[100]; /* big enough for any int */ + char *m; + char *s; + int err = ldap_get_lderrno(ld, &m, &s); + (void) snprintf(buf, sizeof (buf), "%d", err); + + return directory_error("AD.get_domain.ldap_get_dn", + "ldap_get_dn: %1 (%2)\n" + "matched: %3\n" + "error: %4", + ldap_err2string(err), buf, + m == NULL ? "(null)" : m, + s == NULL ? "(null)" : s, + NULL); + } + + *domain = adutils_dn2dns(dn); + if (*domain == NULL) { + directory_error_t de; + + de = directory_error("Unknown.get_domain.adutils_dn2dns", + "get_domain: Unexpected error from adutils_dn2dns(%1)", + dn, NULL); + free(dn); + return (de); + } + free(dn); + + return (NULL); +} + +/* + * Given an error report from libadutils, generate a directory_error_t. + */ +static +directory_error_t +directory_provider_ad_utils_error(char *func, int rc) +{ + char rcstr[100]; /* plenty for any int */ + char code[100]; /* plenty for any int */ + (void) snprintf(rcstr, sizeof (rcstr), "%d", rc); + (void) snprintf(code, sizeof (code), "ADUTILS.%d", rc); + + return (directory_error(code, + "Error %2 from adutils function %1", func, rcstr, NULL)); +} + +struct directory_provider_static directory_provider_ad = { + "AD", + directory_provider_ad_get, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/idmap/idmapd/directory_provider_builtin.c Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,319 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Retrieve directory information for built-in users and groups + */ + +#include <stdio.h> +#include <limits.h> +#include <sys/idmap.h> +#include <sys/param.h> +#include <string.h> +#include <stdlib.h> +#include <netdb.h> +#include <note.h> +#include "idmapd.h" +#include "directory.h" +#include "directory_private.h" +#include <rpcsvc/idmap_prot.h> +#include "directory_server_impl.h" +#include "miscutils.h" +#include "sidutil.h" + +static directory_error_t sid_dav(directory_values_rpc *lvals, + const wksids_table_t *wksid); +static directory_error_t directory_provider_builtin_populate( + directory_entry_rpc *pent, const wksids_table_t *wksid, + idmap_utf8str_list *attrs); + +/* + * Retrieve information by name. + * Called indirectly through the directory_provider_static structure. + */ +static +directory_error_t +directory_provider_builtin_get( + directory_entry_rpc *del, + idmap_utf8str_list *ids, + idmap_utf8str types, + idmap_utf8str_list *attrs) +{ + int i; + + for (i = 0; i < ids->idmap_utf8str_list_len; i++) { + const wksids_table_t *wksid; + directory_error_t de; + int type; + + /* + * Extract the type for this particular ID. + * Advance to the next type, if it's there, else keep + * using this type until we run out of IDs. + */ + type = *types; + if (*(types+1) != '\0') + types++; + + /* + * If this entry has already been handled, one way or another, + * skip it. + */ + if (del[i].status != DIRECTORY_NOT_FOUND) + continue; + + char *id = ids->idmap_utf8str_list_val[i]; + + /* + * End-to-end error injection point. + * NEEDSWORK: should probably eliminate this for production + */ + if (streq(id, " DEBUG BUILTIN ERROR ")) { + directory_entry_set_error(&del[i], + directory_error("Directory_provider_builtin.debug", + "Directory_provider_builtin: artificial error", + NULL)); + continue; + } + + if (type == DIRECTORY_ID_SID[0]) + wksid = find_wk_by_sid(id); + else { + int idmap_id_type; + if (type == DIRECTORY_ID_NAME[0]) + idmap_id_type = IDMAP_POSIXID; + else if (type == DIRECTORY_ID_USER[0]) + idmap_id_type = IDMAP_UID; + else if (type == DIRECTORY_ID_GROUP[0]) + idmap_id_type = IDMAP_GID; + else { + directory_entry_set_error(&del[i], + directory_error("invalid_arg.id_type", + "Invalid ID type \"%1\"", + types, NULL)); + continue; + } + + int id_len = strlen(id); + char name[id_len + 1]; + char domain[id_len + 1]; + + split_name(name, domain, id); + + wksid = find_wksid_by_name(name, domain, idmap_id_type); + } + + if (wksid == NULL) + continue; + + de = directory_provider_builtin_populate(&del[i], wksid, attrs); + if (de != NULL) { + directory_entry_set_error(&del[i], de); + de = NULL; + } + } + + return (NULL); +} + +/* + * Given a well-known name entry and a list of attributes that were + * requested, populate the structure to return to the caller. + */ +static +directory_error_t +directory_provider_builtin_populate( + directory_entry_rpc *pent, + const wksids_table_t *wksid, + idmap_utf8str_list *attrs) +{ + int j; + directory_values_rpc *llvals; + int nattrs; + + nattrs = attrs->idmap_utf8str_list_len; + + llvals = calloc(nattrs, sizeof (directory_values_rpc)); + if (llvals == NULL) + goto nomem; + + pent->status = DIRECTORY_FOUND; + pent->directory_entry_rpc_u.attrs.attrs_val = llvals; + pent->directory_entry_rpc_u.attrs.attrs_len = nattrs; + + for (j = 0; j < nattrs; j++) { + directory_values_rpc *val; + char *a; + directory_error_t de; + + /* + * We're going to refer to these a lot, so make a shorthand + * copy. + */ + a = attrs->idmap_utf8str_list_val[j]; + val = &llvals[j]; + + /* + * Start by assuming no errors and that we don't have + * the information. + */ + val->found = FALSE; + de = NULL; + + if (strcaseeq(a, "uid")) { + de = str_list_dav(val, &wksid->winname, 1); + } else if (strcaseeq(a, "uidNumber")) { + if (wksid->pid != SENTINEL_PID && wksid->is_user) { + de = uint_list_dav(val, &wksid->pid, 1); + } + } else if (strcaseeq(a, "gidNumber")) { + if (wksid->pid != SENTINEL_PID && !wksid->is_user) { + de = uint_list_dav(val, &wksid->pid, 1); + } + } else if (strcaseeq(a, "displayName") || strcaseeq(a, "cn")) { + de = str_list_dav(val, &wksid->winname, 1); + } else if (strcaseeq(a, "distinguishedName")) { + char *container; + if (wksid->domain == NULL) { + container = "Users"; + } else { + container = "Builtin"; + } + RDLOCK_CONFIG(); + char *dn; + (void) asprintf(&dn, + "CN=%s,CN=%s,DC=%s", + wksid->winname, container, _idmapdstate.hostname); + UNLOCK_CONFIG(); + const char *cdn = dn; + de = str_list_dav(val, &cdn, 1); + free(dn); + } else if (strcaseeq(a, "objectClass")) { + if (wksid->is_wuser) { + static const char *objectClasses[] = { + "top", + "person", + "organizationalPerson", + "user", + }; + de = str_list_dav(val, objectClasses, + NELEM(objectClasses)); + } else { + static const char *objectClasses[] = { + "top", + "group", + }; + de = str_list_dav(val, objectClasses, + NELEM(objectClasses)); + } + } else if (strcaseeq(a, "objectSid")) { + de = sid_dav(val, wksid); + } else if (strcaseeq(a, "x-sun-canonicalName")) { + char *canon; + + if (wksid->domain == NULL) { + RDLOCK_CONFIG(); + (void) asprintf(&canon, "%s@%s", + wksid->winname, _idmapdstate.hostname); + UNLOCK_CONFIG(); + } else if (streq(wksid->domain, "")) { + canon = strdup(wksid->winname); + } else { + (void) asprintf(&canon, "%s@%s", + wksid->winname, wksid->domain); + } + + if (canon == NULL) + goto nomem; + const char *ccanon = canon; + de = str_list_dav(val, &ccanon, 1); + free(canon); + } else if (strcaseeq(a, "x-sun-provider")) { + const char *provider = "Builtin"; + de = str_list_dav(val, &provider, 1); + } + if (de != NULL) + return (de); + } + + return (NULL); + +nomem: + return (directory_error("ENOMEM.users", + "No memory allocating return value for user lookup", NULL)); +} + +/* + * Given a well-known name structure, generate a binary-format SID. + * It's a bit perverse that we must take a text-format SID and turn it into + * a binary-format SID, only to have the caller probably turn it back into + * text format, but SIDs are carried across LDAP in binary format. + */ +static +directory_error_t +sid_dav(directory_values_rpc *lvals, const wksids_table_t *wksid) +{ + char *text_sid; + sid_t *sid; + directory_error_t de; + + if (wksid->sidprefix == NULL) { + RDLOCK_CONFIG(); + (void) asprintf(&text_sid, "%s-%d", + _idmapdstate.cfg->pgcfg.machine_sid, + wksid->rid); + UNLOCK_CONFIG(); + } else { + (void) asprintf(&text_sid, "%s-%d", + wksid->sidprefix, wksid->rid); + } + + if (text_sid == NULL) + goto nomem; + + sid = sid_fromstr(text_sid); + free(text_sid); + + if (sid == NULL) + goto nomem; + + sid_to_le(sid); + + de = bin_list_dav(lvals, sid, 1, sid_len(sid)); + + sid_free(sid); + + return (de); + +nomem: + return (directory_error("ENOMEM.sid_dav", + "No memory allocating SID for user lookup", NULL)); +} + +struct directory_provider_static directory_provider_builtin = { + "builtin", + directory_provider_builtin_get, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/idmap/idmapd/directory_provider_nsswitch.c Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,472 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Retrieve directory information for standard UNIX users/groups. + * (NB: not just from files, but all nsswitch sources.) + */ + +#include <pwd.h> +#include <grp.h> +#include <malloc.h> +#include <string.h> +#include <stdlib.h> +#include <netdb.h> +#include <note.h> +#include <errno.h> +#include "idmapd.h" +#include "directory.h" +#include "directory_private.h" +#include <rpcsvc/idmap_prot.h> +#include "directory_server_impl.h" +#include "miscutils.h" +#include "sidutil.h" + +static directory_error_t machine_sid_dav(directory_values_rpc *lvals, + unsigned int rid); +static directory_error_t directory_provider_nsswitch_populate( + directory_entry_rpc *pent, struct passwd *pwd, struct group *grp, + idmap_utf8str_list *attrs); + +/* + * Retrieve information by name. + * Called indirectly through the directory_provider_static structure. + */ +static +directory_error_t +directory_provider_nsswitch_get( + directory_entry_rpc *del, + idmap_utf8str_list *ids, + idmap_utf8str types, + idmap_utf8str_list *attrs) +{ + int i; + + RDLOCK_CONFIG(); + + /* 6835280 spurious lint error if the strlen is in the declaration */ + int host_name_len = strlen(_idmapdstate.hostname); + char my_host_name[host_name_len + 1]; + (void) strcpy(my_host_name, _idmapdstate.hostname); + + /* We use len later, so this is not merely a workaround for 6835280 */ + int machine_sid_len = strlen(_idmapdstate.cfg->pgcfg.machine_sid); + char my_machine_sid[machine_sid_len + 1]; + (void) strcpy(my_machine_sid, _idmapdstate.cfg->pgcfg.machine_sid); + + UNLOCK_CONFIG(); + + for (i = 0; i < ids->idmap_utf8str_list_len; i++) { + struct passwd *pwd = NULL; + struct group *grp = NULL; + directory_error_t de; + int type; + + /* + * Extract the type for this particular ID. + * Advance to the next type, if it's there, else keep + * using this type until we run out of IDs. + */ + type = *types; + if (*(types+1) != '\0') + types++; + + /* + * If this entry has already been handled, one way or another, + * skip it. + */ + if (del[i].status != DIRECTORY_NOT_FOUND) + continue; + + char *id = ids->idmap_utf8str_list_val[i]; + + if (type == DIRECTORY_ID_SID[0]) { + /* + * Is it our SID? + * Check whether the first part matches, then a "-", + * then a single RID. + */ + if (strncasecmp(id, my_machine_sid, machine_sid_len) != + 0) + continue; + if (id[machine_sid_len] != '-') + continue; + char *p; + uint32_t rid = + strtoul(id + machine_sid_len + 1, &p, 10); + if (*p != '\0') + continue; + + if (rid < LOCALRID_UID_MIN) { + /* Builtin, not handled here */ + continue; + } + + if (rid <= LOCALRID_UID_MAX) { + /* User */ + errno = 0; + pwd = getpwuid(rid - LOCALRID_UID_MIN); + if (pwd == NULL) { + if (errno == 0) /* Not found */ + continue; + char buf[40]; + int err = errno; + (void) snprintf(buf, sizeof (buf), + "%d", err); + directory_entry_set_error(&del[i], + directory_error("errno.getpwuid", + "getpwuid: %2 (%1)", + buf, strerror(err), NULL)); + continue; + } + } else if (rid >= LOCALRID_GID_MIN && + rid <= LOCALRID_GID_MAX) { + /* Group */ + errno = 0; + grp = getgrgid(rid - LOCALRID_GID_MIN); + if (grp == NULL) { + if (errno == 0) /* Not found */ + continue; + char buf[40]; + int err = errno; + (void) snprintf(buf, sizeof (buf), + "%d", err); + directory_entry_set_error(&del[i], + directory_error("errno.getgrgid", + "getgrgid: %2 (%1)", + buf, strerror(err), NULL)); + continue; + } + } else + continue; + + } else { + int id_len = strlen(id); + char name[id_len + 1]; + char domain[id_len + 1]; + + split_name(name, domain, id); + + if (domain[0] != '\0') { + if (!domain_eq(domain, my_host_name)) + continue; + } + + /* + * If the caller has requested user or group + * information specifically, we only set one of + * pwd or grp. + * If the caller has requested either type, we try + * both in the hopes of getting one. + * Note that directory_provider_nsswitch_populate + * considers it to be an error if both are set. + */ + if (type != DIRECTORY_ID_GROUP[0]) { + /* prep for not found / error case */ + errno = 0; + + pwd = getpwnam(name); + if (pwd == NULL && errno != 0) { + char buf[40]; + int err = errno; + (void) snprintf(buf, sizeof (buf), + "%d", err); + directory_entry_set_error(&del[i], + directory_error("errno.getpwnam", + "getpwnam: %2 (%1)", + buf, strerror(err), NULL)); + continue; + } + } + + if (type != DIRECTORY_ID_USER[0]) { + /* prep for not found / error case */ + errno = 0; + + grp = getgrnam(name); + if (grp == NULL && errno != 0) { + char buf[40]; + int err = errno; + (void) snprintf(buf, sizeof (buf), + "%d", err); + directory_entry_set_error(&del[i], + directory_error("errno.getgrnam", + "getgrnam: %2 (%1)", + buf, strerror(err), NULL)); + continue; + } + } + } + + /* + * Didn't find it, don't populate the structure. + * Another provider might populate it. + */ + if (pwd == NULL && grp == NULL) + continue; + + de = directory_provider_nsswitch_populate(&del[i], pwd, grp, + attrs); + if (de != NULL) { + directory_entry_set_error(&del[i], de); + de = NULL; + continue; + } + } + + return (NULL); +} + +/* + * Given a pwd structure or a grp structure, and a list of attributes that + * were requested, populate the structure to return to the caller. + */ +static +directory_error_t +directory_provider_nsswitch_populate( + directory_entry_rpc *pent, + struct passwd *pwd, + struct group *grp, + idmap_utf8str_list *attrs) +{ + int j; + directory_values_rpc *llvals; + int nattrs; + + /* + * If it wasn't for this case, everything would be a lot simpler. + * UNIX allows users and groups with the same name. Windows doesn't. + */ + if (pwd != NULL && grp != NULL) { + return directory_error("Ambiguous.Name", + "Ambiguous name, is both a user and a group", + NULL); + } + + nattrs = attrs->idmap_utf8str_list_len; + + llvals = calloc(nattrs, sizeof (directory_values_rpc)); + if (llvals == NULL) + goto nomem; + + pent->directory_entry_rpc_u.attrs.attrs_val = llvals; + pent->directory_entry_rpc_u.attrs.attrs_len = nattrs; + pent->status = DIRECTORY_FOUND; + + for (j = 0; j < nattrs; j++) { + directory_values_rpc *val; + char *a; + directory_error_t de; + + /* + * We're going to refer to these a lot, so make a shorthand + * copy. + */ + a = attrs->idmap_utf8str_list_val[j]; + val = &llvals[j]; + + /* + * Start by assuming no errors and that we don't have + * the information + */ + val->found = FALSE; + de = NULL; + + if (pwd != NULL) { + /* + * Handle attributes for user entries. + */ + if (strcaseeq(a, "cn")) { + const char *p = pwd->pw_name; + de = str_list_dav(val, &p, 1); + } else if (strcaseeq(a, "objectClass")) { + static const char *objectClasses[] = { + "top", + "posixAccount", + }; + de = str_list_dav(val, objectClasses, + NELEM(objectClasses)); + } else if (strcaseeq(a, "gidNumber")) { + de = uint_list_dav(val, &pwd->pw_gid, 1); + } else if (strcaseeq(a, "objectSid")) { + de = machine_sid_dav(val, + pwd->pw_uid + LOCALRID_UID_MIN); + } else if (strcaseeq(a, "displayName")) { + const char *p = pwd->pw_gecos; + de = str_list_dav(val, &p, 1); + } else if (strcaseeq(a, "distinguishedName")) { + char *dn; + RDLOCK_CONFIG(); + (void) asprintf(&dn, + "uid=%s,ou=people,dc=%s", + pwd->pw_name, _idmapdstate.hostname); + UNLOCK_CONFIG(); + if (dn == NULL) + goto nomem; + const char *cdn = dn; + de = str_list_dav(val, &cdn, 1); + free(dn); + } else if (strcaseeq(a, "uid")) { + const char *p = pwd->pw_name; + de = str_list_dav(val, &p, 1); + } else if (strcaseeq(a, "uidNumber")) { + de = uint_list_dav(val, &pwd->pw_uid, 1); + } else if (strcaseeq(a, "gecos")) { + const char *p = pwd->pw_gecos; + de = str_list_dav(val, &p, 1); + } else if (strcaseeq(a, "homeDirectory")) { + const char *p = pwd->pw_dir; + de = str_list_dav(val, &p, 1); + } else if (strcaseeq(a, "loginShell")) { + const char *p = pwd->pw_shell; + de = str_list_dav(val, &p, 1); + } else if (strcaseeq(a, "x-sun-canonicalName")) { + char *canon; + RDLOCK_CONFIG(); + (void) asprintf(&canon, "%s@%s", + pwd->pw_name, _idmapdstate.hostname); + UNLOCK_CONFIG(); + if (canon == NULL) + goto nomem; + const char *ccanon = canon; + de = str_list_dav(val, &ccanon, 1); + free(canon); + } else if (strcaseeq(a, "x-sun-provider")) { + const char *provider = "UNIX-passwd"; + de = str_list_dav(val, &provider, 1); + } + } else if (grp != NULL) { + /* + * Handle attributes for group entries. + */ + if (strcaseeq(a, "cn")) { + const char *p = grp->gr_name; + de = str_list_dav(val, &p, 1); + } else if (strcaseeq(a, "objectClass")) { + static const char *objectClasses[] = { + "top", + "posixGroup", + }; + de = str_list_dav(val, objectClasses, + NELEM(objectClasses)); + } else if (strcaseeq(a, "gidNumber")) { + de = uint_list_dav(val, &grp->gr_gid, 1); + } else if (strcaseeq(a, "objectSid")) { + de = machine_sid_dav(val, + grp->gr_gid + LOCALRID_GID_MIN); + } else if (strcaseeq(a, "displayName")) { + const char *p = grp->gr_name; + de = str_list_dav(val, &p, 1); + } else if (strcaseeq(a, "distinguishedName")) { + char *dn; + RDLOCK_CONFIG(); + (void) asprintf(&dn, + "cn=%s,ou=group,dc=%s", + grp->gr_name, _idmapdstate.hostname); + UNLOCK_CONFIG(); + if (dn == NULL) + goto nomem; + const char *cdn = dn; + de = str_list_dav(val, &cdn, 1); + free(dn); + } else if (strcaseeq(a, "memberUid")) { + /* + * NEEDSWORK: There is probably a non-cast + * way to do this, but I don't immediately + * see it. + */ + const char * const *members = + (const char * const *)grp->gr_mem; + de = str_list_dav(val, members, 0); + } else if (strcaseeq(a, "x-sun-canonicalName")) { + char *canon; + RDLOCK_CONFIG(); + (void) asprintf(&canon, "%s@%s", + grp->gr_name, _idmapdstate.hostname); + UNLOCK_CONFIG(); + if (canon == NULL) + goto nomem; + const char *ccanon = canon; + de = str_list_dav(val, &ccanon, 1); + free(canon); + } else if (strcaseeq(a, "x-sun-provider")) { + const char *provider = "UNIX-group"; + de = str_list_dav(val, &provider, 1); + } + } + + if (de != NULL) + return (de); + } + + return (NULL); + +nomem: + return (directory_error("ENOMEM.users", + "No memory allocating return value for user lookup", NULL)); +} + +/* + * Populate a directory attribute value with a SID based on our machine SID + * and the specified RID. + * + * It's a bit perverse that we must take a text-format SID and turn it into + * a binary-format SID, only to have the caller probably turn it back into + * text format, but SIDs are carried across LDAP in binary format. + */ +static +directory_error_t +machine_sid_dav(directory_values_rpc *lvals, unsigned int rid) +{ + sid_t *sid; + directory_error_t de; + + RDLOCK_CONFIG(); + int len = strlen(_idmapdstate.cfg->pgcfg.machine_sid); + char buf[len + 100]; /* 100 is enough space for any RID */ + (void) snprintf(buf, sizeof (buf), "%s-%u", + _idmapdstate.cfg->pgcfg.machine_sid, rid); + UNLOCK_CONFIG(); + + sid = sid_fromstr(buf); + if (sid == NULL) + goto nomem; + + sid_to_le(sid); + + de = bin_list_dav(lvals, sid, 1, sid_len(sid)); + sid_free(sid); + return (de); + +nomem: + return (directory_error("ENOMEM.machine_sid_dav", + "Out of memory allocating return value for lookup", NULL)); +} + +struct directory_provider_static directory_provider_nsswitch = { + "files", + directory_provider_nsswitch_get, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/idmap/idmapd/directory_server.c Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,292 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Server-side support for directory information lookup functions. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <malloc.h> +#include <sys/types.h> +#include <netdb.h> +#include <pthread.h> +#include <unistd.h> +#include <string.h> +#include <note.h> +#include "idmapd.h" +#include "directory.h" +#include "directory_private.h" +#include <rpcsvc/idmap_prot.h> +#include "directory_library_impl.h" +#include "directory_server_impl.h" +#include "sized_array.h" +#include "miscutils.h" + +/* + * Here's a list of all of the modules that provide directory + * information. In the fullness of time this should probably be + * a plugin-able switch mechanism. + * Note that the list is in precedence order. + */ +extern struct directory_provider_static directory_provider_builtin; +extern struct directory_provider_static directory_provider_nsswitch; +extern struct directory_provider_static directory_provider_ad; +struct directory_provider_static *providers[] = { + &directory_provider_builtin, + &directory_provider_nsswitch, + &directory_provider_ad, +}; + +/* + * This is the entry point for all directory lookup service requests. + */ +bool_t +directory_get_common_1_svc( + idmap_utf8str_list ids, + idmap_utf8str types, + idmap_utf8str_list attrs, + directory_results_rpc *result, + struct svc_req *req) +{ + NOTE(ARGUNUSED(req)) + int nids; + directory_entry_rpc *entries; + directory_error_t de; + int i; + + nids = ids.idmap_utf8str_list_len; + + entries = (directory_entry_rpc *) + calloc(nids, sizeof (directory_entry_rpc)); + if (entries == NULL) + goto nomem; + result->directory_results_rpc_u.entries.entries_val = entries; + result->directory_results_rpc_u.entries.entries_len = nids; + result->failed = FALSE; + + for (i = 0; i < nids; i++) { + if (strlen(ids.idmap_utf8str_list_val[i]) > + IDMAP_MAX_NAME_LEN) { + directory_entry_set_error(&entries[i], + directory_error("invalid_arg.id.too_long", + "Identifier too long", NULL)); + } + } + + for (i = 0; i < NELEM(providers); i++) { + de = providers[i]->get(entries, &ids, types, + &attrs); + if (de != NULL) + goto err; + } + + return (TRUE); + +nomem: + de = directory_error("ENOMEM.get_common", + "Insufficient memory retrieving directory data", NULL); + +err: + xdr_free(xdr_directory_results_rpc, (char *)result); + result->failed = TRUE; + return ( + directory_error_to_rpc(&result->directory_results_rpc_u.err, de)); +} + +/* + * Split name into {domain, name}. + * Suggest allocating name and domain on the stack, same size as id, + * using variable length arrays. + */ +void +split_name(char *name, char *domain, char *id) +{ + char *p; + + if ((p = strchr(id, '@')) != NULL) { + (void) strlcpy(name, id, p - id + 1); + (void) strcpy(domain, p + 1); + } else if ((p = strchr(id, '\\')) != NULL) { + (void) strcpy(name, p + 1); + (void) strlcpy(domain, id, p - id + 1); + } else { + (void) strcpy(name, id); + (void) strcpy(domain, ""); + } +} + +/* + * Given a list of strings, return a set of directory attribute values. + * + * Mark that the attribute was found. + * + * Note that the terminating \0 is *not* included in the result, because + * that's the way that strings come from LDAP. + * (Note also that the client side stuff adds in a terminating \0.) + * + * Note that on error the array may have been partially populated and will + * need to be cleaned up by the caller. This is normally not a problem + * because the caller will need to clean up several such arrays. + */ +directory_error_t +str_list_dav(directory_values_rpc *lvals, const char * const *str_list, int n) +{ + directory_value_rpc *dav; + int i; + + if (n == 0) { + for (n = 0; str_list[n] != NULL; n++) + /* LOOP */; + } + + dav = calloc(n, sizeof (directory_value_rpc)); + if (dav == NULL) + goto nomem; + + lvals->directory_values_rpc_u.values.values_val = dav; + lvals->directory_values_rpc_u.values.values_len = n; + lvals->found = TRUE; + + for (i = 0; i < n; i++) { + int len; + + len = strlen(str_list[i]); + dav[i].directory_value_rpc_val = memdup(str_list[i], len); + if (dav[i].directory_value_rpc_val == NULL) + goto nomem; + dav[i].directory_value_rpc_len = len; + } + + return (NULL); + +nomem: + return (directory_error("ENOMEM.str_list_dav", + "Insufficient memory copying values")); +} + +/* + * Given a list of unsigned integers, return a set of string directory + * attribute values. + * + * Mark that the attribute was found. + * + * Note that the terminating \0 is *not* included in the result, because + * that's the way that strings come from LDAP. + * (Note also that the client side stuff adds in a terminating \0.) + * + * Note that on error the array may have been partially populated and will + * need to be cleaned up by the caller. This is normally not a problem + * because the caller will need to clean up several such arrays. + */ +directory_error_t +uint_list_dav(directory_values_rpc *lvals, const unsigned int *array, int n) +{ + directory_value_rpc *dav; + int i; + + dav = calloc(n, sizeof (directory_value_rpc)); + if (dav == NULL) + goto nomem; + + lvals->directory_values_rpc_u.values.values_val = dav; + lvals->directory_values_rpc_u.values.values_len = n; + lvals->found = TRUE; + + for (i = 0; i < n; i++) { + char buf[100]; /* larger than any integer */ + int len; + + (void) snprintf(buf, sizeof (buf), "%u", array[i]); + + len = strlen(buf); + dav[i].directory_value_rpc_val = memdup(buf, len); + if (dav[i].directory_value_rpc_val == NULL) + goto nomem; + dav[i].directory_value_rpc_len = len; + } + + return (NULL); + +nomem: + return (directory_error("ENOMEM.uint_list_dav", + "Insufficient memory copying values")); +} + +/* + * Given a list of fixed-length binary chunks, return a set of binary + * directory attribute values. + * + * Mark that the attribute was found. + * + * Note that on error the array may have been partially populated and will + * need to be cleaned up by the caller. This is normally not a problem + * because the caller will need to clean up several such arrays. + */ +directory_error_t +bin_list_dav(directory_values_rpc *lvals, const void *array, int n, size_t sz) +{ + directory_value_rpc *dav; + char *inbuf = (char *)array; + int i; + + dav = calloc(n, sizeof (directory_value_rpc)); + if (dav == NULL) + goto nomem; + + lvals->directory_values_rpc_u.values.values_val = dav; + lvals->directory_values_rpc_u.values.values_len = n; + lvals->found = TRUE; + + for (i = 0; i < n; i++) { + dav[i].directory_value_rpc_val = memdup(inbuf, sz); + if (dav[i].directory_value_rpc_val == NULL) + goto nomem; + dav[i].directory_value_rpc_len = sz; + inbuf += sz; + } + + return (NULL); + +nomem: + return (directory_error("ENOMEM.bin_list_dav", + "Insufficient memory copying values")); +} + +/* + * Set up to return an error on a particular directory entry. + * Note that the caller need not (and in fact must not) free + * the directory_error_t; it will be freed when the directory entry + * list is freed. + */ +void +directory_entry_set_error(directory_entry_rpc *ent, directory_error_t de) +{ + xdr_free(xdr_directory_entry_rpc, (char *)&ent); + ent->status = DIRECTORY_ERROR; + (void) directory_error_to_rpc(&ent->directory_entry_rpc_u.err, de); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/idmap/idmapd/directory_server_impl.h Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,79 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _DIRECTORY_SERVER_IMPL_H +#define _DIRECTORY_SERVER_IMPL_H + +/* + * Internal implementation details for the server side of directory lookup. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Functions to populate Directory Attribute Value lists. + */ +directory_error_t str_list_dav(directory_values_rpc *lvals, + const char * const *str_list, int n); +directory_error_t uint_list_dav(directory_values_rpc *lvals, + const unsigned int *uint_list, int n); +directory_error_t bin_list_dav(directory_values_rpc *lvals, + const void *array, int n, size_t sz); + +/* + * Split a name@domain into name, domain. Recommend allocating the + * destination buffers the same size as the input, on the stack, + * using variable length arrays. + */ +void split_name(char *name, char *domain, char *id); + +/* + * Insert a directory_error_t into a directory entry to be returned. + * Caller MUST NOT free the directory_error_t. + */ +void directory_entry_set_error(directory_entry_rpc *ent, + directory_error_t de); + +/* + * This is the structure by which a provider supplies its entry points. + * The name is not currently used. + */ +struct directory_provider_static { + char *name; + directory_error_t (*get)( + directory_entry_rpc *ret, + idmap_utf8str_list *ids, + idmap_utf8str types, + idmap_utf8str_list *attrs); +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _DIRECTORY_SERVER_IMPL_H */
--- a/usr/src/cmd/idmap/idmapd/idmap_config.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/idmap/idmapd/idmap_config.c Mon Jul 20 13:07:46 2009 -0400 @@ -696,7 +696,6 @@ int num_df1 = 0; int num_df2 = 0; boolean_t match; - int err; for (i = 0; df1[i].domain[0] != '\0'; i++) if (df1[i].trusted) @@ -714,10 +713,8 @@ match = B_FALSE; for (j = 0; df2[j].domain[0] != '\0'; j++) { if (df2[j].trusted && - u8_strcmp(df1[i].domain, df2[i].domain, 0, - U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err) - == 0 && err == 0 && - strcmp(df1[i].sid, df2[i].sid) == 0) { + domain_eq(df1[i].domain, df2[j].domain) && + strcmp(df1[i].sid, df2[j].sid) == 0) { match = B_TRUE; break; } @@ -756,10 +753,10 @@ (*new)[j].forest_name) == 0 && ad_disc_compare_ds( (*value)[i].global_catalog, - (*new)[i].global_catalog) == 0 && + (*new)[j].global_catalog) == 0 && compare_trusteddomainsinforest( (*value)[i].domains_in_forest, - (*new)[i].domains_in_forest) == 0) { + (*new)[j].domains_in_forest) == 0) { match = B_TRUE; break; } @@ -1274,7 +1271,6 @@ char *forestname; int num_trusteddomains; boolean_t new_forest; - int err; char *trusteddomain; idmap_ad_disc_ds_t *globalcatalog; idmap_trustedforest_t *trustedforests; @@ -1368,11 +1364,8 @@ /* Mark the domain as trusted */ for (l = 0; domainsinforest[l].domain[0] != '\0'; l++) { - if (u8_strcmp(trusteddomain, - domainsinforest[l].domain, 0, - U8_STRCMP_CI_LOWER, - U8_UNICODE_LATEST, &err) == 0 && - err == 0) { + if (domain_eq(trusteddomain, + domainsinforest[l].domain)) { domainsinforest[l].trusted = TRUE; break; @@ -1420,11 +1413,8 @@ /* Mark the domain as trusted */ for (l = 0; domainsinforest[l].domain[0] != '\0'; l++) { - if (u8_strcmp(trusteddomain, - domainsinforest[l].domain, 0, - U8_STRCMP_CI_LOWER, - U8_UNICODE_LATEST, &err) == 0 && - err == 0) { + if (domain_eq(trusteddomain, + domainsinforest[l].domain)) { domainsinforest[l].trusted = TRUE; break; } @@ -1434,6 +1424,8 @@ if (j > 0) { pgcfg->num_trusted_forests = j; pgcfg->trusted_forests = trustedforests; + } else { + free(trustedforests); } }
--- a/usr/src/cmd/idmap/idmapd/idmapd.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/idmap/idmapd/idmapd.c Mon Jul 20 13:07:46 2009 -0400 @@ -59,12 +59,6 @@ static void init_idmapd(); static void fini_idmapd(); - -#define _RPCSVC_CLOSEDOWN 120 - -int _rpcsvcstate = _IDLE; /* Set when a request is serviced */ -int _rpcsvccount = 0; /* Number of requests being serviced */ -mutex_t _svcstate_lock; /* lock for _rpcsvcstate, _rpcsvccount */ idmapd_state_t _idmapdstate; SVCXPRT *xprt = NULL;
--- a/usr/src/cmd/idmap/idmapd/idmapd.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/idmap/idmapd/idmapd.h Mon Jul 20 13:07:46 2009 -0400 @@ -47,15 +47,9 @@ extern "C" { #endif -/* States a server can be in wrt request */ -#define _IDLE 0 -#define _SERVED 1 - #define SENTINEL_PID UINT32_MAX #define CHECK_NULL(s) (s != NULL ? s : "null") -extern int _rpcsvcstate; /* set when a request is serviced */ -extern int _rpcsvccount; /* number of requests being serviced */ extern mutex_t _svcstate_lock; /* lock for _rpcsvcstate, _rpcsvccount */ typedef enum idmap_namemap_mode { @@ -154,6 +148,21 @@ const char *msg; } msg_table_t; +/* + * Data structure to store well-known SIDs and + * associated mappings (if any) + */ +typedef struct wksids_table { + const char *sidprefix; + uint32_t rid; + const char *domain; + const char *winname; + int is_wuser; + uid_t pid; + int is_user; + int direction; +} wksids_table_t; + #define IDMAPD_SEARCH_TIMEOUT 3 /* seconds */ #define IDMAPD_LDAP_OPEN_TIMEOUT 1 /* secs; initial, w/ exp backoff */ @@ -221,6 +230,14 @@ #define IS_REQUEST_GID(request) \ ((request).id1.idtype == IDMAP_GID) +/* + * Local RID ranges + */ +#define LOCALRID_UID_MIN 1000U +#define LOCALRID_UID_MAX ((uint32_t)INT32_MAX) +#define LOCALRID_GID_MIN (((uint32_t)INT32_MAX) + 1) +#define LOCALRID_GID_MAX UINT32_MAX + typedef idmap_retcode (*update_list_res_cb)(void *, const char **, uint64_t); typedef int (*list_svc_cb)(void *, int, char **, char **); @@ -286,6 +303,13 @@ extern void idmap_log_syslog(boolean_t); extern void idmap_log_degraded(boolean_t); +extern const wksids_table_t *find_wksid_by_pid(uid_t pid, int is_user); +extern const wksids_table_t *find_wksid_by_sid(const char *sid, int rid, + int type); +extern const wksids_table_t *find_wksid_by_name(const char *name, + const char *domain, int type); +extern const wksids_table_t *find_wk_by_sid(char *sid); + #ifdef __cplusplus } #endif
--- a/usr/src/cmd/idmap/idmapd/rpc_svc.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/idmap/idmapd/rpc_svc.c Mon Jul 20 13:07:46 2009 -0400 @@ -24,73 +24,152 @@ */ /* - * RPC service routines - * It was initially generated using rpcgen. + * Please do not edit this file. + * It was generated using rpcgen. + * Edit idmap_prot.x and rebuild this file with + * rpcgen -CMNm -o idmap_prot_svc.c.new ../../../uts/common/rpcsvc/idmap_prot.x + * then merge as required. A recent version of rpcgen is needed to + * produce this exact file; when the revised rpcgen is available in the + * build environment this file can be built automatically. */ -#include "idmapd.h" -#include <rpcsvc/idmap_prot.h> -#include <stdlib.h> +#include "../../../uts/common/rpcsvc/idmap_prot.h" +#include <stdio.h> +#include <stdlib.h> /* getenv, exit */ #include <signal.h> -#include <rpc/xdr.h> -#include <rpc/rpc.h> -#include <string.h> -#include <thread.h> -#include <synch.h> +#include <rpc/pmap_clnt.h> /* for pmap_unset */ +#include <string.h> /* strcmp */ +#include <unistd.h> /* setsid */ +#include <sys/types.h> +#include <memory.h> +#include <stropts.h> +#include <sys/resource.h> /* rlimit */ +#include <syslog.h> + +#ifndef SIG_PF +#define SIG_PF void(*)(int) +#endif + +#ifdef DEBUG +#define RPC_SVC_FG +#endif + +#define _RPCSVC_CLOSEDOWN 120 +extern int _rpcpmstart; /* Started by a port monitor ? */ + +/* States a server can be in wrt request */ +#define _IDLE 0 +#define _SERVED 1 + +/* LINTED static unused if no main */ +static int _rpcsvcstate = _IDLE; /* Set when a request is serviced */ +static int _rpcsvccount = 0; /* Number of requests being serviced */ +mutex_t _svcstate_lock; /* lock for _rpcsvcstate, _rpcsvccount */ + +#if defined(RPC_MSGOUT) +extern void RPC_MSGOUT(const char *, ...); +#else /* defined(RPC_MSGOUT) */ +static void +RPC_MSGOUT(const char *fmt, char *msg) +{ +#ifdef RPC_SVC_FG + if (_rpcpmstart) + syslog(LOG_ERR, fmt, msg); + else { + (void) fprintf(stderr, fmt, msg); + (void) putc('\n', stderr); + } +#else + syslog(LOG_ERR, fmt, msg); +#endif +} +#endif /* defined(RPC_MSGOUT) */ /* ARGSUSED */ int -_idmap_null_1(void *argp, void *result, struct svc_req *rqstp) +_idmap_null_1( + void *argp, + void *result, + struct svc_req *rqstp) { return (idmap_null_1_svc(result, rqstp)); } int -_idmap_get_mapped_ids_1(idmap_mapping_batch *argp, idmap_ids_res *result, - struct svc_req *rqstp) +_idmap_get_mapped_ids_1( + idmap_mapping_batch *argp, + idmap_ids_res *result, + struct svc_req *rqstp) { return (idmap_get_mapped_ids_1_svc(*argp, result, rqstp)); } int -_idmap_list_mappings_1(idmap_list_mappings_1_argument *argp, - idmap_mappings_res *result, struct svc_req *rqstp) +_idmap_list_mappings_1( + idmap_list_mappings_1_argument *argp, + idmap_mappings_res *result, + struct svc_req *rqstp) { - return (idmap_list_mappings_1_svc(argp->lastrowid, - argp->limit, argp->flag, result, rqstp)); + return (idmap_list_mappings_1_svc( + argp->lastrowid, + argp->limit, + argp->flag, + result, rqstp)); } int -_idmap_list_namerules_1(idmap_list_namerules_1_argument *argp, - idmap_namerules_res *result, struct svc_req *rqstp) +_idmap_list_namerules_1( + idmap_list_namerules_1_argument *argp, + idmap_namerules_res *result, + struct svc_req *rqstp) { - return (idmap_list_namerules_1_svc(argp->rule, argp->lastrowid, - argp->limit, result, rqstp)); + return (idmap_list_namerules_1_svc( + argp->rule, + argp->lastrowid, + argp->limit, + result, rqstp)); } int -_idmap_update_1(idmap_update_batch *argp, idmap_update_res *res, - struct svc_req *rqstp) +_idmap_update_1( + idmap_update_batch *argp, + idmap_update_res *result, + struct svc_req *rqstp) { - return (idmap_update_1_svc(*argp, res, rqstp)); + return (idmap_update_1_svc(*argp, result, rqstp)); } int -_idmap_get_mapped_id_by_name_1(idmap_mapping *argp, - idmap_mappings_res *result, struct svc_req *rqstp) +_idmap_get_mapped_id_by_name_1( + idmap_mapping *argp, + idmap_mappings_res *result, + struct svc_req *rqstp) { return (idmap_get_mapped_id_by_name_1_svc(*argp, result, rqstp)); } int -_idmap_get_prop_1(idmap_prop_type *argp, - idmap_prop_res *result, struct svc_req *rqstp) +_idmap_get_prop_1( + idmap_prop_type *argp, + idmap_prop_res *result, + struct svc_req *rqstp) { return (idmap_get_prop_1_svc(*argp, result, rqstp)); } - +int +_directory_get_common_1( + directory_get_common_1_argument *argp, + directory_results_rpc *result, + struct svc_req *rqstp) +{ + return (directory_get_common_1_svc( + argp->ids, + argp->types, + argp->attrs, + result, rqstp)); +} void idmap_prog_1(struct svc_req *rqstp, register SVCXPRT *transp) @@ -102,6 +181,7 @@ idmap_update_batch idmap_update_1_arg; idmap_mapping idmap_get_mapped_id_by_name_1_arg; idmap_prop_type idmap_get_prop_1_arg; + directory_get_common_1_argument directory_get_common_1_arg; } argument; union { idmap_ids_res idmap_get_mapped_ids_1_res; @@ -110,6 +190,7 @@ idmap_update_res idmap_update_1_res; idmap_mappings_res idmap_get_mapped_id_by_name_1_res; idmap_prop_res idmap_get_prop_1_res; + directory_results_rpc directory_get_common_1_res; } result; bool_t retval; xdrproc_t _xdr_argument, _xdr_result; @@ -120,61 +201,84 @@ (void) mutex_unlock(&_svcstate_lock); switch (rqstp->rq_proc) { case IDMAP_NULL: - _xdr_argument = (xdrproc_t)xdr_void; - _xdr_result = (xdrproc_t)xdr_void; + _xdr_argument = (xdrproc_t) + xdr_void; + _xdr_result = (xdrproc_t) + xdr_void; local = (bool_t (*) (char *, void *, struct svc_req *)) _idmap_null_1; break; case IDMAP_GET_MAPPED_IDS: - _xdr_argument = (xdrproc_t)xdr_idmap_mapping_batch; - _xdr_result = (xdrproc_t)xdr_idmap_ids_res; + _xdr_argument = (xdrproc_t) + xdr_idmap_mapping_batch; + _xdr_result = (xdrproc_t) + xdr_idmap_ids_res; local = (bool_t (*) (char *, void *, struct svc_req *)) _idmap_get_mapped_ids_1; break; case IDMAP_LIST_MAPPINGS: - _xdr_argument = (xdrproc_t)xdr_idmap_list_mappings_1_argument; - _xdr_result = (xdrproc_t)xdr_idmap_mappings_res; + _xdr_argument = (xdrproc_t) + xdr_idmap_list_mappings_1_argument; + _xdr_result = (xdrproc_t) + xdr_idmap_mappings_res; local = (bool_t (*) (char *, void *, struct svc_req *)) _idmap_list_mappings_1; break; case IDMAP_LIST_NAMERULES: - _xdr_argument = (xdrproc_t)xdr_idmap_list_namerules_1_argument; - _xdr_result = (xdrproc_t)xdr_idmap_namerules_res; + _xdr_argument = (xdrproc_t) + xdr_idmap_list_namerules_1_argument; + _xdr_result = (xdrproc_t) + xdr_idmap_namerules_res; local = (bool_t (*) (char *, void *, struct svc_req *)) _idmap_list_namerules_1; break; case IDMAP_UPDATE: - _xdr_argument = (xdrproc_t)xdr_idmap_update_batch; - _xdr_result = (xdrproc_t)xdr_idmap_update_res; + _xdr_argument = (xdrproc_t) + xdr_idmap_update_batch; + _xdr_result = (xdrproc_t) + xdr_idmap_update_res; local = (bool_t (*) (char *, void *, struct svc_req *)) _idmap_update_1; break; case IDMAP_GET_MAPPED_ID_BY_NAME: - _xdr_argument = (xdrproc_t)xdr_idmap_mapping; - _xdr_result = (xdrproc_t)xdr_idmap_mappings_res; + _xdr_argument = (xdrproc_t) + xdr_idmap_mapping; + _xdr_result = (xdrproc_t) + xdr_idmap_mappings_res; local = (bool_t (*) (char *, void *, struct svc_req *)) _idmap_get_mapped_id_by_name_1; break; case IDMAP_GET_PROP: - _xdr_argument = (xdrproc_t)xdr_idmap_prop_type; - _xdr_result = (xdrproc_t)xdr_idmap_prop_res; + _xdr_argument = (xdrproc_t) + xdr_idmap_prop_type; + _xdr_result = (xdrproc_t) + xdr_idmap_prop_res; local = (bool_t (*) (char *, void *, struct svc_req *)) _idmap_get_prop_1; break; + case DIRECTORY_GET_COMMON: + _xdr_argument = (xdrproc_t) + xdr_directory_get_common_1_argument; + _xdr_result = (xdrproc_t) + xdr_directory_results_rpc; + local = (bool_t (*) (char *, void *, struct svc_req *)) + _directory_get_common_1; + break; + default: svcerr_noproc(transp); (void) mutex_lock(&_svcstate_lock); _rpcsvccount--; _rpcsvcstate = _SERVED; (void) mutex_unlock(&_svcstate_lock); - return; + return; /* CSTYLED */ } (void) memset((char *)&argument, 0, sizeof (argument)); if (!svc_getargs(transp, _xdr_argument, (caddr_t)&argument)) { @@ -183,27 +287,28 @@ _rpcsvccount--; _rpcsvcstate = _SERVED; (void) mutex_unlock(&_svcstate_lock); - return; + return; /* CSTYLED */ } retval = (bool_t)(*local)((char *)&argument, (void *)&result, rqstp); - if (_xdr_result && retval > 0 && !svc_sendreply(transp, _xdr_result, - (char *)&result)) { + if (_xdr_result && retval > 0 && + !svc_sendreply(transp, _xdr_result, (char *)&result)) { svcerr_systemerr(transp); } if (!svc_freeargs(transp, _xdr_argument, (caddr_t)&argument)) { - idmapdlog(LOG_ERR, - "unable to free RPC arguments"); + RPC_MSGOUT("%s", + "unable to free arguments"); exit(1); } if (_xdr_result != NULL) { if (!idmap_prog_1_freeresult(transp, _xdr_result, (caddr_t)&result)) - idmapdlog(LOG_ERR, - "unable to free RPC results"); + RPC_MSGOUT("%s", + "unable to free results"); } (void) mutex_lock(&_svcstate_lock); _rpcsvccount--; _rpcsvcstate = _SERVED; (void) mutex_unlock(&_svcstate_lock); + return; /* CSTYLED */ }
--- a/usr/src/cmd/idmap/idmapd/server.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/idmap/idmapd/server.c Mon Jul 20 13:07:46 2009 -0400 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -44,6 +44,7 @@ #include <auth_attr.h> #include <secdb.h> #include <sys/u8_textprep.h> +#include <note.h> #define _VALIDATE_LIST_CB_DATA(col, val, siz)\ retcode = validate_list_cb_data(cb_data, argc, argv, col,\ @@ -1097,3 +1098,20 @@ (void) xdr_free(xdr_result, result); return (TRUE); } + +/* + * This function is called by rpc_svc.c when it encounters an error. + */ +NOTE(PRINTFLIKE(1)) +void +idmap_rpc_msgout(const char *fmt, ...) +{ + va_list va; + char buf[1000]; + + va_start(va, fmt); + (void) vsnprintf(buf, sizeof (buf), fmt, va); + va_end(va); + + idmapdlog(LOG_ERR, "idmap RPC: %s", buf); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/idmap/idmapd/wksids.c Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,407 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Information about well-known (builtin) names, and functions to retrieve + * information about them. + */ + +#include <assert.h> +#include <string.h> +#include "idmapd.h" +#include "miscutils.h" + +/* + * Table for well-known SIDs. + * + * Background: + * + * Some of the well-known principals are stored under: + * cn=WellKnown Security Principals, cn=Configuration, dc=<forestRootDomain> + * They belong to objectClass "foreignSecurityPrincipal". They don't have + * "samAccountName" nor "userPrincipalName" attributes. Their names are + * available in "cn" and "name" attributes. Some of these principals have a + * second entry under CN=ForeignSecurityPrincipals,dc=<forestRootDomain> and + * these duplicate entries have the stringified SID in the "name" and "cn" + * attributes instead of the actual name. + * + * Those of the form S-1-5-32-X are Builtin groups and are stored in the + * cn=builtin container (except, Power Users which is not stored in AD) + * + * These principals are and will remain constant. Therefore doing AD lookups + * provides no benefit. Also, using hard-coded table (and thus avoiding AD + * lookup) improves performance and avoids additional complexity in the + * adutils.c code. Moreover these SIDs can be used when no Active Directory + * is available (such as the CIFS server's "workgroup" mode). + * + * Notes: + * 1. Currently we don't support localization of well-known SID names, + * unlike Windows. + * + * 2. Other well-known SIDs i.e. S-1-5-<domain>-<w-k RID> are not stored + * here. AD does have normal user/group objects for these objects and + * can be looked up using the existing AD lookup code. + * + * 3. See comments above lookup_wksids_sid2pid() for more information + * on how we lookup the wksids table. + * + * 4. If this table contains two entries for a particular Windows name, + * so as to offer both UID and GID mappings, the preferred mapping (the + * one that matches Windows usage) must be listed first. That is the + * entry that will be used when the caller specifies IDMAP_POSIXID + * ("don't care") as the target. + * + * Entries here come from KB243330, MS-LSAT, and + * http://technet.microsoft.com/en-us/library/cc755854.aspx + * http://technet.microsoft.com/en-us/library/cc755925.aspx + * http://msdn.microsoft.com/en-us/library/cc980032(PROT.10).aspx + */ +static wksids_table_t wksids[] = { + /* S-1-0 Null Authority */ + {"S-1-0", 0, "", "Nobody", 1, SENTINEL_PID, -1, 1}, + + /* S-1-1 World Authority */ + {"S-1-1", 0, "", "Everyone", 0, SENTINEL_PID, -1, -1}, + + /* S-1-2 Local Authority */ + {"S-1-2", 0, "", "Local", 0, SENTINEL_PID, -1, -1}, + {"S-1-2", 1, "", "Console Logon", 0, SENTINEL_PID, -1, -1}, + + /* S-1-3 Creator Authority */ + {"S-1-3", 0, "", "Creator Owner", 1, IDMAP_WK_CREATOR_OWNER_UID, 1, 0}, + {"S-1-3", 1, "", "Creator Group", 0, IDMAP_WK_CREATOR_GROUP_GID, 0, 0}, + {"S-1-3", 2, "", "Creator Owner Server", 1, SENTINEL_PID, -1, -1}, + {"S-1-3", 3, "", "Creator Group Server", 0, SENTINEL_PID, -1, 1}, + {"S-1-3", 4, "", "Owner Rights", 0, SENTINEL_PID, -1, -1}, + + /* S-1-4 Non-unique Authority */ + + /* S-1-5 NT Authority */ + {"S-1-5", 1, "", "Dialup", 0, SENTINEL_PID, -1, -1}, + {"S-1-5", 2, "", "Network", 0, SENTINEL_PID, -1, -1}, + {"S-1-5", 3, "", "Batch", 0, SENTINEL_PID, -1, -1}, + {"S-1-5", 4, "", "Interactive", 0, SENTINEL_PID, -1, -1}, + /* S-1-5-5-X-Y Logon Session */ + {"S-1-5", 6, "", "Service", 0, SENTINEL_PID, -1, -1}, + {"S-1-5", 7, "", "Anonymous Logon", 0, GID_NOBODY, 0, 0}, + {"S-1-5", 7, "", "Anonymous Logon", 0, UID_NOBODY, 1, 0}, + {"S-1-5", 8, "", "Proxy", 0, SENTINEL_PID, -1, -1}, + {"S-1-5", 9, "", "Enterprise Domain Controllers", 0, + SENTINEL_PID, -1, -1}, + {"S-1-5", 10, "", "Self", 0, SENTINEL_PID, -1, -1}, + {"S-1-5", 11, "", "Authenticated Users", 0, SENTINEL_PID, -1, -1}, + {"S-1-5", 12, "", "Restricted", 0, SENTINEL_PID, -1, -1}, + {"S-1-5", 13, "", "Terminal Server Users", 0, SENTINEL_PID, -1, -1}, + {"S-1-5", 14, "", "Remote Interactive Logon", 0, SENTINEL_PID, -1, -1}, + {"S-1-5", 15, "", "This Organization", 0, SENTINEL_PID, -1, -1}, + {"S-1-5", 17, "", "IUSR", 0, SENTINEL_PID, -1, -1}, + {"S-1-5", 18, "", "Local System", 0, IDMAP_WK_LOCAL_SYSTEM_GID, 0, 0}, + {"S-1-5", 19, "", "Local Service", 0, SENTINEL_PID, -1, -1}, + {"S-1-5", 20, "", "Network Service", 0, SENTINEL_PID, -1, -1}, + + /* S-1-5-21-<domain> Machine-local definitions */ + {NULL, 498, NULL, "Enterprise Read-only Domain Controllers", 0, + SENTINEL_PID, -1, -1}, + {NULL, 500, NULL, "Administrator", 1, SENTINEL_PID, 1, -1}, + {NULL, 501, NULL, "Guest", 1, SENTINEL_PID, 1, -1}, + {NULL, 502, NULL, "KRBTGT", 1, SENTINEL_PID, 1, -1}, + {NULL, 512, NULL, "Domain Admins", 0, SENTINEL_PID, -1, -1}, + {NULL, 513, NULL, "Domain Users", 0, SENTINEL_PID, -1, -1}, + {NULL, 514, NULL, "Domain Guests", 0, SENTINEL_PID, -1, -1}, + {NULL, 515, NULL, "Domain Computers", 0, SENTINEL_PID, -1, -1}, + {NULL, 516, NULL, "Domain Controllers", 0, SENTINEL_PID, -1, -1}, + {NULL, 517, NULL, "Cert Publishers", 0, SENTINEL_PID, -1, -1}, + {NULL, 518, NULL, "Schema Admins", 0, SENTINEL_PID, -1, -1}, + {NULL, 519, NULL, "Enterprise Admins", 0, SENTINEL_PID, -1, -1}, + {NULL, 520, NULL, "Global Policy Creator Owners", 0, + SENTINEL_PID, -1, -1}, + {NULL, 533, NULL, "RAS and IAS Servers", 0, SENTINEL_PID, -1, -1}, + + /* S-1-5-32 BUILTIN */ + {"S-1-5-32", 544, "BUILTIN", "Administrators", 0, SENTINEL_PID, -1, -1}, + {"S-1-5-32", 545, "BUILTIN", "Users", 0, SENTINEL_PID, -1, -1}, + {"S-1-5-32", 546, "BUILTIN", "Guests", 0, SENTINEL_PID, -1, -1}, + {"S-1-5-32", 547, "BUILTIN", "Power Users", 0, SENTINEL_PID, -1, -1}, + {"S-1-5-32", 548, "BUILTIN", "Account Operators", 0, + SENTINEL_PID, -1, -1}, + {"S-1-5-32", 549, "BUILTIN", "Server Operators", 0, + SENTINEL_PID, -1, -1}, + {"S-1-5-32", 550, "BUILTIN", "Print Operators", 0, + SENTINEL_PID, -1, -1}, + {"S-1-5-32", 551, "BUILTIN", "Backup Operators", 0, + SENTINEL_PID, -1, -1}, + {"S-1-5-32", 552, "BUILTIN", "Replicator", 0, SENTINEL_PID, -1, -1}, + {"S-1-5-32", 554, "BUILTIN", "Pre-Windows 2000 Compatible Access", 0, + SENTINEL_PID, -1, -1}, + {"S-1-5-32", 555, "BUILTIN", "Remote Desktop Users", 0, + SENTINEL_PID, -1, -1}, + {"S-1-5-32", 556, "BUILTIN", "Network Configuration Operators", 0, + SENTINEL_PID, -1, -1}, + {"S-1-5-32", 557, "BUILTIN", "Incoming Forest Trust Builders", 0, + SENTINEL_PID, -1, -1}, + {"S-1-5-32", 558, "BUILTIN", "Performance Monitor Users", 0, + SENTINEL_PID, -1, -1}, + {"S-1-5-32", 559, "BUILTIN", "Performance Log Users", 0, + SENTINEL_PID, -1, -1}, + {"S-1-5-32", 560, "BUILTIN", "Windows Authorization Access Group", 0, + SENTINEL_PID, -1, -1}, + {"S-1-5-32", 561, "BUILTIN", "Terminal Server License Servers", 0, + SENTINEL_PID, -1, -1}, + {"S-1-5-32", 562, "BUILTIN", "Distributed COM Users", 0, + SENTINEL_PID, -1, -1}, + {"S-1-5-32", 568, "BUILTIN", "IIS_IUSRS", 0, SENTINEL_PID, -1, -1}, + {"S-1-5-32", 569, "BUILTIN", "Cryptographic Operators", 0, + SENTINEL_PID, -1, -1}, + {"S-1-5-32", 573, "BUILTIN", "Event Log Readers", 0, + SENTINEL_PID, -1, -1}, + {"S-1-5-32", 574, "BUILTIN", "Certificate Service DCOM Access", 0, + SENTINEL_PID, -1, -1}, + + {"S-1-5", 33, "", "Write Restricted", 0, SENTINEL_PID, -1, -1}, + + /* S-1-5-64 NT Authority */ + {"S-1-5-64", 10, "", "NTLM Authentication", 0, SENTINEL_PID, -1, -1}, + {"S-1-5-64", 14, "", "SChannel Authentication", 0, + SENTINEL_PID, -1, -1}, + {"S-1-5-64", 21, "", "Digest Authentication", 0, SENTINEL_PID, -1, -1}, + + /* S-1-5-80-a-b-c-d NT Service */ + + {"S-1-5", 1000, "", "Other Organization", 0, SENTINEL_PID, -1, -1}, + + /* S-1-7 Internet$ */ + + /* + * S-1-16 Mandatory Label + * S-1-16-0 Untrusted Mandatory Level + * S-1-16-4096 Low Mandatory Level + * S-1-16-8192 Medium Mandatory Level + * S-1-16-8448 Medium Plus Mandatory Level + * S-1-16-12288 High Mandatory Level + * S-1-16-16384 System Mandatory Level + * S-1-16-20480 Protected Process Mandatory Level + */ +}; + +/* + * Find a wksid entry for the specified Windows name and domain, of the + * specified type. + * + * Ignore entries intended only for U2W use. + */ +const +wksids_table_t * +find_wksid_by_name(const char *name, const char *domain, int type) +{ + int i; + + RDLOCK_CONFIG(); + int len = strlen(_idmapdstate.hostname); + char my_host_name[len + 1]; + (void) strcpy(my_host_name, _idmapdstate.hostname); + UNLOCK_CONFIG(); + + for (i = 0; i < NELEM(wksids); i++) { + /* Check to see if this entry yields the desired type */ + switch (type) { + case IDMAP_UID: + if (wksids[i].is_user == 0) + continue; + break; + case IDMAP_GID: + if (wksids[i].is_user == 1) + continue; + break; + case IDMAP_POSIXID: + break; + default: + assert(FALSE); + } + + if (strcasecmp(wksids[i].winname, name) != 0) + continue; + + if (!EMPTY_STRING(domain)) { + const char *dom; + + if (wksids[i].domain != NULL) { + dom = wksids[i].domain; + } else { + dom = my_host_name; + } + if (strcasecmp(dom, domain) != 0) + continue; + } + + /* + * We have a Windows name, so ignore entries that are only + * usable for mapping UNIX->Windows. (Note: the current + * table does not have any such entries.) + */ + if (wksids[i].direction == IDMAP_DIRECTION_U2W) + continue; + + return (&wksids[i]); + } + + return (NULL); +} + +/* + * Find a wksid entry for the specified SID, of the specified type. + * + * Ignore entries intended only for U2W use. + */ +const +wksids_table_t * +find_wksid_by_sid(const char *sid, int rid, int type) +{ + int i; + + RDLOCK_CONFIG(); + int len = strlen(_idmapdstate.cfg->pgcfg.machine_sid); + char my_machine_sid[len + 1]; + (void) strcpy(my_machine_sid, _idmapdstate.cfg->pgcfg.machine_sid); + UNLOCK_CONFIG(); + + for (i = 0; i < NELEM(wksids); i++) { + int sidcmp; + + /* Check to see if this entry yields the desired type */ + switch (type) { + case IDMAP_UID: + if (wksids[i].is_user == 0) + continue; + break; + case IDMAP_GID: + if (wksids[i].is_user == 1) + continue; + break; + case IDMAP_POSIXID: + break; + default: + assert(FALSE); + } + + if (wksids[i].sidprefix != NULL) { + sidcmp = strcasecmp(wksids[i].sidprefix, sid); + } else { + sidcmp = strcasecmp(my_machine_sid, sid); + } + + if (sidcmp != 0) + continue; + if (wksids[i].rid != rid) + continue; + + /* + * We have a SID, so ignore entries that are only usable + * for mapping UNIX->Windows. (Note: the current table + * does not have any such entries.) + */ + if (wksids[i].direction == IDMAP_DIRECTION_U2W) + continue; + + return (&wksids[i]); + } + + return (NULL); +} + +/* + * Find a wksid entry for the specified pid, of the specified type. + * Ignore entries that do not specify U2W mappings. + */ +const +wksids_table_t * +find_wksid_by_pid(uid_t pid, int is_user) +{ + int i; + + if (pid == SENTINEL_PID) + return (NULL); + + for (i = 0; i < NELEM(wksids); i++) { + if (wksids[i].pid == pid && + wksids[i].is_user == is_user && + (wksids[i].direction == IDMAP_DIRECTION_BI || + wksids[i].direction == IDMAP_DIRECTION_U2W)) { + return (&wksids[i]); + } + } + return (NULL); +} + +/* + * It is probably a bug that both this and find_wksid_by_sid exist, + * but for now the distinction is primarily that one takes {machinesid,rid} + * and the other takes a full SID. + */ +const +wksids_table_t * +find_wk_by_sid(char *sid) +{ + int i; + + RDLOCK_CONFIG(); + int len = strlen(_idmapdstate.cfg->pgcfg.machine_sid); + char my_machine_sid[len + 1]; + (void) strcpy(my_machine_sid, _idmapdstate.cfg->pgcfg.machine_sid); + UNLOCK_CONFIG(); + + for (i = 0; i < NELEM(wksids); i++) { + int len; + const char *prefix; + char *p; + unsigned long rid; + + if (wksids[i].sidprefix == NULL) + prefix = my_machine_sid; + else + prefix = wksids[i].sidprefix; + + len = strlen(prefix); + + /* + * Check to see whether the SID we're looking for starts + * with this prefix, then a -, then a single RID, and it's + * the right RID. + */ + if (strncasecmp(sid, prefix, len) != 0) + continue; + if (sid[len] != '-') + continue; + rid = strtoul(sid + len + 1, &p, 10); + if (*p != '\0') + continue; + + if (rid != wksids[i].rid) + continue; + + return (&wksids[i]); + } + return (NULL); +}
--- a/usr/src/cmd/init/init.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/init/init.c Mon Jul 20 13:07:46 2009 -0400 @@ -939,10 +939,10 @@ console(B_FALSE, "Requesting maintenance mode\n" "(See /lib/svc/share/README for additional information.)\n"); - (void) sigset(SIGCLD, SIG_DFL); + (void) sighold(SIGCLD); while ((su_process = efork(M_OFF, NULLPROC, NOCLEANUP)) == NO_ROOM) (void) pause(); - (void) sigset(SIGCLD, childeath); + (void) sigrelse(SIGCLD); if (su_process == NULLPROC) { int fd; @@ -1394,7 +1394,7 @@ /* * Spawn a child process to execute this command. */ - (void) sigset(SIGCLD, SIG_DFL); + (void) sighold(SIGCLD); oprocess = process; while ((process = efork(cmd->c_action, oprocess, modes)) == NO_ROOM) (void) pause(); @@ -1453,7 +1453,7 @@ st_write(); - (void) sigset(SIGCLD, childeath); + (void) sigrelse(SIGCLD); } /* @@ -1890,10 +1890,10 @@ { struct PROC_TABLE *process; - (void) sigset(SIGCLD, SIG_DFL); + (void) sighold(SIGCLD); while ((process = efork(M_OFF, NULLPROC, 0)) == NO_ROOM) (void) pause(); - (void) sigset(SIGCLD, childeath); + (void) sigrelse(SIGCLD); if (process == NULLPROC) { /* @@ -2080,7 +2080,7 @@ * until after there has been an chance to check it. */ if (process = findpslot(&cmd)) { - (void) sigset(SIGCLD, SIG_DFL); + (void) sighold(SIGCLD); (void) snprintf(svc_aux, SVC_AUX_SIZE, INITTAB_ENTRY_ID_STR_FORMAT, cmd.c_id); (void) snprintf(init_svc_fmri, SVC_FMRI_SIZE, @@ -2098,7 +2098,7 @@ (NAMED|NOCLEANUP))) == NO_ROOM; /* CSTYLED */) ; - (void) sigset(SIGCLD, childeath); + (void) sigrelse(SIGCLD); if (process == NULLPROC) { maxfiles = ulimit(UL_GDESLIM, 0); @@ -2355,22 +2355,14 @@ * to do and return, otherwise the child will be waited for. */ static void -childeath_single() +childeath_single(pid_t pid, int status) { struct PROC_TABLE *process; struct pidlist *pp; - pid_t pid; - int status; /* - * Perform wait to get the process id of the child that died and - * then scan the process table to see if we are interested in - * this process. NOTE: if a super-user sends the SIGCLD signal - * to init, the following wait will not immediately return and - * init will be inoperative until one of its child really does die. + * Scan the process table to see if we are interested in this process. */ - pid = wait(&status); - for (process = proc_table; (process < proc_table + num_proc); process++) { if ((process->p_flags & (LIVING|OCCUPIED)) == @@ -2425,11 +2417,11 @@ static void childeath(int signo) { - siginfo_t info; - - while ((waitid(P_ALL, (id_t)0, &info, WEXITED|WNOHANG|WNOWAIT) == 0) && - info.si_pid != 0) - childeath_single(); + pid_t pid; + int status; + + while ((pid = waitpid(-1, &status, WNOHANG)) > 0) + childeath_single(pid, status); } static void @@ -2448,13 +2440,8 @@ * otherwise it searches for a free slot. Regardless of how it was called, * it returns the pointer to the proc_table entry * - * The SIGCLD handler is set to default (SIG_DFL) before calling efork(). - * This relies on the somewhat obscure SVR2 SIGCLD/SIG_DFL semantic - * implied by the use of signal(3c). While the meaning of SIG_DFL for - * SIGCLD is nominally to ignore the signal, once the signal disposition - * is set to childeath(), the kernel will post a SIGCLD if a child - * exited during the period the disposition was SIG_DFL. It acts more - * like a signal block. + * The SIGCLD signal is blocked (held) before calling efork() + * and is unblocked (released) after efork() returns. * * Ideally, this should be rewritten to use modern signal semantics. */ @@ -2464,7 +2451,6 @@ pid_t childpid; struct PROC_TABLE *proc; int i; - void (*oldroutine)(); /* * Freshen up the proc_table, removing any entries for dead processes * that don't have NOCLEANUP set. Perform the necessary accounting. @@ -2494,13 +2480,13 @@ setimer(5); /* - * Wait for some children to die. Since efork() is normally - * called with SIGCLD in the default state, reset it to catch - * so that child death signals can come in. + * Wait for some children to die. Since efork() + * is always called with SIGCLD blocked, unblock + * it here so that child death signals can come in. */ - oldroutine = sigset(SIGCLD, childeath); + (void) sigrelse(SIGCLD); (void) pause(); - (void) sigset(SIGCLD, oldroutine); + (void) sighold(SIGCLD); setimer(0); } @@ -2851,7 +2837,7 @@ * '/', thus when a ' ', '\t', '\n', or '\0' is found, "ptr" will * point to the last element of the pathname. */ - for (ptr = string; *string != ' ' && *string != '\t' && + for (ptr = string; *string != ' ' && *string != '\t' && *string != '\n' && *string != '\0'; string++) { if (*string == '/') ptr = string+1; @@ -3765,7 +3751,7 @@ pid_t pid; short status; - (void) sigset(SIGCLD, SIG_DFL); + (void) sighold(SIGCLD); Gchild = 0; /* Note - Safe to do this here since no SIGCLDs */ (void) sighold(SIGPOLL); savep = p = Plhead; @@ -3795,7 +3781,7 @@ p = p->pl_next; } (void) sigrelse(SIGPOLL); - (void) sigset(SIGCLD, childeath); + (void) sigrelse(SIGCLD); } @@ -4420,8 +4406,8 @@ "Template activation failed; not starting \"%s\" in " "proper contract.\n", cline); - /* Hold SIGCHLD so we can wait if necessary. */ - (void) sighold(SIGCHLD); + /* Hold SIGCLD so we can wait if necessary. */ + (void) sighold(SIGCLD); while ((pid = fork()) < 0) { if (errno == EPERM) { @@ -4491,7 +4477,7 @@ if (old_ctid != 0) (void) ct_pr_tmpl_set_transfer(tmpl, 0); - (void) sigrelse(SIGCHLD); + (void) sigrelse(SIGCLD); return (0); }
--- a/usr/src/cmd/iscsi/iscsitgtd/mgmt_scf.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/iscsi/iscsitgtd/mgmt_scf.c Mon Jul 20 13:07:46 2009 -0400 @@ -1119,15 +1119,19 @@ } /* - * this function tries to convert configuration in files into scf - * it loads xml conf into node tree then dump them to scf with - * mgmt_config_save2scf() - * this function has 3 return values: - * CONVERT_OK: successfully converted - * CONVERT_INIT_NEW: configuration files dont exist, created a new scf entry - * CONVERT_FAIL: some error occurred in conversion and no scf entry created. - * In this case, user have to check files manually and try - * conversion again. + * Convert legacy (XML) configuration files into an equivalent SCF + * representation. + * + * Read the XML from disk, translate the XML into a tree of nodes of + * type tgt_node_t, and write the in-memory tree to SCF's persistent + * data-store using mgmt_config_save2scf(). + * + * Return Values: + * CONVERT_OK: successfully converted + * CONVERT_INIT_NEW: configuration files don't exist; created an SCF entry + * CONVERT_FAIL: some conversion error occurred; no SCF entry created. + * In this case, user has to manually check files and try + * conversion again. */ convert_ret_t mgmt_convert_conf() @@ -1146,17 +1150,21 @@ if (h == NULL) return (CONVERT_FAIL); - /* check main config in pgroup iscsitgt */ + /* + * Check if the "iscsitgt" PropertyGroup has already been added + * to the "iscsitgt" SMF Service. If so, then we have already + * converted the legacy configuration files (and there is no work + * to do). + */ if (scf_service_get_pg(h->t_service, "iscsitgt", h->t_pg) == 0) { ret = CONVERT_OK; goto done; } - /* check the conf files */ if (access(config_file, R_OK) != 0) { /* - * if there is no configuration file, initialize - * an empty scf entry + * then the Main Config file is not present; initialize + * SCF Properties to default values. */ if (mgmt_transaction_start(h, "iscsitgt", "basic") == True) { ret = CONVERT_INIT_NEW; @@ -1210,6 +1218,8 @@ r = (xmlTextReaderPtr)xmlReaderForFd(xml_fd, NULL, NULL, 0); if (r != NULL) { + int is_target_config; + n = xmlTextReaderRead(r); while (n == 1) { if (tgt_node_process(r, &node) == False) { @@ -1225,30 +1235,53 @@ main_config = node; + /* + * Initialize the Base Directory (global) variable by + * using the value specified in the XML_ELEMENT_BASEDIR + * XML tag. If a tag is not specified, use a default. + */ (void) tgt_find_value_str(node, XML_ELEMENT_BASEDIR, &target_basedir); if (target_basedir == NULL) target_basedir = strdup(DEFAULT_TARGET_BASEDIR); - /* Now convert targets' config if possible */ - if (xml_fd != -1) + if (xml_fd != -1) { (void) close(xml_fd); + xml_fd = -1; + } (void) xmlTextReaderClose(r); xmlFreeTextReader(r); xmlCleanupParser(); - r = NULL; - xml_fd = -1; - node = NULL; + /* + * If a Target Config file is present, read and translate + * its XML representation into a tree of tgt_node_t. + * Merge that tree with the tree of tgt_node_t rooted at + * 'main_config'. The merged tree will then be archived + * using an SCF representation. + */ (void) snprintf(path, MAXPATHLEN, "%s/%s", target_basedir, "config.xml"); - if ((xml_fd = open(path, O_RDONLY)) >= 0) + if ((xml_fd = open(path, O_RDONLY)) >= 0) { + is_target_config = 1; r = (xmlTextReaderPtr)xmlReaderForFd(xml_fd, NULL, NULL, 0); + } else { + is_target_config = 0; + r = NULL; + } if (r != NULL) { + /* then the Target Config file is available. */ + + node = NULL; + + /* + * Create a tree of tgt_node_t rooted at 'node' by + * processing each XML Tag in the file. + */ n = xmlTextReaderRead(r); while (n == 1) { if (tgt_node_process(r, &node) == False) { @@ -1262,8 +1295,11 @@ goto done; } - /* now combine main_config and node */ - if (node) { + /* + * Merge the tree at 'node' into the tree rooted at + * 'main_config'. + */ + if (node != NULL) { next = NULL; while ((next = tgt_node_next(node, XML_ELEMENT_TARG, next)) != NULL) { @@ -1272,59 +1308,77 @@ } tgt_node_free(node); } + } - if (mgmt_config_save2scf() != True) { - syslog(LOG_ERR, "Converting config failed"); - if (xml_fd != -1) - (void) close(xml_fd); - (void) xmlTextReaderClose(r); - xmlFreeTextReader(r); - xmlCleanupParser(); - ret = CONVERT_FAIL; - goto done; + /* + * Iterate over the in-memory tree rooted at 'main_config' + * and write a representation of the appropriate nodes to + * SCF's persistent data-store. + */ + if (mgmt_config_save2scf() != True) { + syslog(LOG_ERR, "Converting config failed"); + if (xml_fd != -1) { + (void) close(xml_fd); + xml_fd = -1; } + (void) xmlTextReaderClose(r); + xmlFreeTextReader(r); + xmlCleanupParser(); + ret = CONVERT_FAIL; + goto done; + } - /* Copy files into backup dir */ - (void) snprintf(path, sizeof (path), "%s/backup", - target_basedir); - if ((mkdir(path, 0755) == -1) && (errno != EEXIST)) { - syslog(LOG_ERR, "Creating backup dir failed"); - ret = CONVERT_FAIL; - goto done; - } - backup(config_file, NULL); + /* + * Move the configuration files into a well-known backup + * directory. This allows a user to restore their + * configuration, if they choose. + */ + (void) snprintf(path, sizeof (path), "%s/backup", + target_basedir); + if ((mkdir(path, 0755) == -1) && (errno != EEXIST)) { + syslog(LOG_ERR, "Creating backup dir failed"); + ret = CONVERT_FAIL; + goto done; + } + /* Save the Main Config file. */ + backup(config_file, NULL); + + /* Save the Target Config file, if it was present. */ + if (is_target_config != 0) { (void) snprintf(path, MAXPATHLEN, "%s/%s", target_basedir, "config.xml"); backup(path, NULL); - + } - while ((next = tgt_node_next(main_config, - XML_ELEMENT_TARG, next)) != NULL) { - if (tgt_find_value_str(next, XML_ELEMENT_INAME, - &target) == False) { - continue; - } - (void) snprintf(path, MAXPATHLEN, "%s/%s", - target_basedir, target); - if (mgmt_convert_param(path, next) - != True) { - ret = CONVERT_FAIL; - goto done; - } - free(target); + /* + * For each tgt_node_t node in 'main_config' whose value is + * an iSCSI Name as defined in the RFC (3720) standard (eg, + * "iqn.1986..."), read its XML-encoded attributes from a + * flat-file and write an equivalent representation to SCF's + * data-store. + */ + while ((next = tgt_node_next(main_config, + XML_ELEMENT_TARG, next)) != NULL) { + if (tgt_find_value_str(next, XML_ELEMENT_INAME, + &target) == False) { + continue; } - - ret = CONVERT_OK; - syslog(LOG_NOTICE, "Conversion succeeded"); + (void) snprintf(path, MAXPATHLEN, "%s/%s", + target_basedir, target); + if (mgmt_convert_param(path, next) + != True) { + ret = CONVERT_FAIL; + goto done; + } + free(target); + } - (void) xmlTextReaderClose(r); - xmlFreeTextReader(r); - xmlCleanupParser(); - } else { - syslog(LOG_ERR, "Reading targets config failed"); - ret = CONVERT_FAIL; - goto done; - } + ret = CONVERT_OK; + syslog(LOG_NOTICE, "Conversion succeeded"); + + (void) xmlTextReaderClose(r); + xmlFreeTextReader(r); + xmlCleanupParser(); } else { syslog(LOG_ERR, "Reading main config failed"); ret = CONVERT_FAIL;
--- a/usr/src/cmd/mdb/intel/modules/Makefile Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/mdb/intel/modules/Makefile Mon Jul 20 13:07:46 2009 -0400 @@ -19,11 +19,12 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # SUBDIRS = mdb_kb \ generic_cpu \ - amd_opteron + amd_opteron \ + sata include ../../Makefile.subdirs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/mdb/intel/modules/sata/Makefile Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,30 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +include $(SRC)/Makefile.master +SUBDIRS = ia32 +$(BUILD64)SUBDIRS += $(MACH64) +include ../../../Makefile.subdirs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/mdb/intel/modules/sata/amd64/Makefile Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,35 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +MODULE = sata.so +MDBTGT = kvm + +MODSRCS = sata.c + +include ../../../../../Makefile.cmd +include ../../../../../Makefile.cmd.64 +include ../../../Makefile.amd64 +include ../../../../Makefile.module + +CPPFLAGS += -I$(SRC)/cmd/mdb/common
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/mdb/intel/modules/sata/ia32/Makefile Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,34 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +MODULE = sata.so +MDBTGT = kvm + +MODSRCS = sata.c + +include ../../../../../Makefile.cmd +include ../../../Makefile.ia32 +include ../../../../Makefile.module + +CPPFLAGS += -I$(SRC)/cmd/mdb/common
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/mdb/intel/modules/sata/sata.c Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,286 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + + +#include <sys/mdb_modapi.h> +#include <mdb/mdb_ks.h> +#include <sys/modctl.h> +#include <note.h> +#include <sys/ddi_impldefs.h> +#include <sys/ddidmareq.h> +#include <sys/devops.h> +#include <time.h> +#include <sys/varargs.h> +#include <sys/sata/sata_hba.h> + +/* + * SATA trace debug walker/dcmd code + */ + +/* + * Initialize the sata_trace_dmsg_t walker by either using the given starting + * address, or reading the value of the kernel's sata_debug_rbuf pointer. + * We also allocate a sata_trace_dmsg_t for storage, and save this using the + * walk_data pointer. + */ +static int +sata_dmsg_walk_i(mdb_walk_state_t *wsp) +{ + uintptr_t rbuf_addr; + sata_trace_rbuf_t rbuf; + + if (wsp->walk_addr == NULL) { + if (mdb_readvar(&rbuf_addr, "sata_debug_rbuf") == -1) { + mdb_warn("failed to read 'sata_debug_rbuf'"); + return (WALK_ERR); + } + + if (mdb_vread(&rbuf, sizeof (sata_trace_rbuf_t), rbuf_addr) + == -1) { + mdb_warn("failed to read sata_trace_rbuf_t at %p", + rbuf_addr); + return (WALK_ERR); + } + + wsp->walk_addr = (uintptr_t)(sata_trace_dmsg_t *)rbuf.dmsgh; + } + + /* + * Save ptr to head of ring buffer to prevent looping. + */ + wsp->walk_arg = (void *)wsp->walk_addr; + wsp->walk_data = mdb_alloc(sizeof (sata_trace_dmsg_t), UM_SLEEP); + return (WALK_NEXT); +} + +/* + * At each step, read a sata_trace_dmsg_t into our private storage, and then + * invoke the callback function. We terminate when we reach a NULL next + * pointer. + */ +static int +sata_dmsg_walk_s(mdb_walk_state_t *wsp) +{ + int status; + + if (wsp->walk_addr == NULL) + return (WALK_DONE); + + if (mdb_vread(wsp->walk_data, sizeof (sata_trace_dmsg_t), + wsp->walk_addr) == -1) { + mdb_warn("failed to read sata_trace_dmsg_t at %p", + wsp->walk_addr); + return (WALK_ERR); + } + + status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, + wsp->walk_cbdata); + + wsp->walk_addr = + (uintptr_t)(((sata_trace_dmsg_t *)wsp->walk_data)->next); + + /* + * If we've looped then we're done. + */ + if (wsp->walk_addr == (uintptr_t)wsp->walk_arg) + wsp->walk_addr = NULL; + + return (status); +} + +/* + * The walker's fini function is invoked at the end of each walk. Since we + * dynamically allocated a sata_trace_dmsg_t in sata_dmsg_walk_i, we must + * free it now. + */ +static void +sata_dmsg_walk_f(mdb_walk_state_t *wsp) +{ + mdb_free(wsp->walk_data, sizeof (sata_trace_dmsg_t)); +} + +/* + * This routine is used by the sata_dmsg_dump dcmd to dump content of + * SATA trace ring buffer. + */ +int +sata_dmsg_dump(sata_trace_dmsg_t *addr, int print_pathname, uint_t *printed) +{ + sata_trace_dmsg_t dmsg, *dmsgh = addr; + struct dev_info dev; + char drivername[MODMAXNAMELEN]; + char pathname[MAXPATHLEN]; + char merge[1024]; + + while (addr != NULL) { + if (mdb_vread(&dmsg, sizeof (dmsg), (uintptr_t)addr) != + sizeof (dmsg)) { + mdb_warn("failed to read message pointer in kernel"); + return (DCMD_ERR); + } + + if (dmsg.dip != NULL) { + if ((mdb_vread(&dev, sizeof (struct dev_info), + (uintptr_t)dmsg.dip)) == -1) { + (void) mdb_snprintf(merge, sizeof (merge), + "[%Y:%03d:%03d:%03d] : %s", + dmsg.timestamp.tv_sec, + (int)dmsg.timestamp.tv_nsec/1000000, + (int)(dmsg.timestamp.tv_nsec/1000)%1000, + (int)dmsg.timestamp.tv_nsec%1000, + dmsg.buf); + } else { + (void) mdb_devinfo2driver((uintptr_t)dmsg.dip, + drivername, sizeof (drivername)); + (void) mdb_snprintf(merge, sizeof (merge), + "[%Y:%03d:%03d:%03d] %s%d: %s", + dmsg.timestamp.tv_sec, + (int)dmsg.timestamp.tv_nsec/1000000, + (int)(dmsg.timestamp.tv_nsec/1000)%1000, + (int)dmsg.timestamp.tv_nsec%1000, + drivername, + dev.devi_instance, + dmsg.buf); + + if (print_pathname == TRUE) { + (void) mdb_ddi_pathname( + (uintptr_t)dmsg.dip, pathname, + sizeof (pathname)); + mdb_printf("\n[%s]", pathname); + } + } + } else { + (void) mdb_snprintf(merge, sizeof (merge), + "[%Y:%03d:%03d:%03d] : %s", + dmsg.timestamp.tv_sec, + (int)dmsg.timestamp.tv_nsec/1000000, + (int)(dmsg.timestamp.tv_nsec/1000)%1000, + (int)dmsg.timestamp.tv_nsec%1000, + dmsg.buf); + } + + mdb_printf("%s", merge); + + if (printed != NULL) { + (*printed)++; + } + + if (((addr = dmsg.next) == NULL) || (dmsg.next == dmsgh)) { + break; + } + } + + return (DCMD_OK); +} + +/* + * 1. Process flag passed to sata_dmsg_dump dcmd. + * 2. Obtain SATA trace ring buffer pointer. + * 3. Pass SATA trace ring buffer pointer to sata_dmsg_dump() + * to dump content of SATA trace ring buffer. + */ +int +sata_rbuf_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + sata_trace_rbuf_t rbuf; + uint_t printed = 0; /* have we printed anything? */ + int print_pathname = FALSE; + int rval = DCMD_OK; + + if (argc > 1) { + return (DCMD_USAGE); + } + + if (mdb_getopts(argc, argv, + 'a', MDB_OPT_SETBITS, TRUE, &print_pathname) != argc) { + return (DCMD_USAGE); + } + + /* + * If ring buffer address not provided try to obtain + * it using sata_debug_rbuf global. + */ + if ((addr == NULL) || !(flags & DCMD_ADDRSPEC)) { + if (mdb_readvar(&addr, "sata_debug_rbuf") == -1) { + mdb_warn("Failed to read 'sata_debug_rbuf'."); + return (DCMD_ERR); + } + } + + if (mdb_vread(&rbuf, sizeof (rbuf), addr) != sizeof (rbuf)) { + mdb_warn("Failed to read ring buffer in kernel."); + return (DCMD_ERR); + } + + if (rbuf.dmsgh == NULL) { + mdb_printf("The sata trace ring buffer is empty.\n"); + return (DCMD_OK); + } + + rval = sata_dmsg_dump((sata_trace_dmsg_t *)rbuf.dmsgh, + print_pathname, &printed); + + if (rval != DCMD_OK) { + return (rval); + } + + if (printed == 0) { + mdb_warn("Failed to read sata trace ring buffer."); + return (DCMD_ERR); + } + + return (rval); +} + +/* + * MDB module linkage information: + * + * We declare a list of structures describing our dcmds, a list of structures + * describing our walkers, and a function named _mdb_init to return a pointer + * to our module information. + */ + +static const mdb_dcmd_t dcmds[] = { + { "sata_dmsg_dump", "[-a]", "Dump sata trace debug messages", + sata_rbuf_dump }, + { NULL } +}; + +static const mdb_walker_t walkers[] = { + { "sata_dmsg", + "walk ring buffer containing sata trace debug messages", + sata_dmsg_walk_i, sata_dmsg_walk_s, sata_dmsg_walk_f }, + { NULL } +}; + +static const mdb_modinfo_t modinfo = { + MDB_API_VERSION, dcmds, walkers +}; + +const mdb_modinfo_t * +_mdb_init(void) +{ + return (&modinfo); +}
--- a/usr/src/cmd/print/selector/Makefile Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/print/selector/Makefile Mon Jul 20 13:07:46 2009 -0400 @@ -19,21 +19,22 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # include ../../Makefile.cmd SBINPROG = print-service +BINPROG = desktop-print-management-applet LPBINLINKS = lp lpstat cancel enable disable LPRBINLINKS = lpr lpq lprm lpc -DESKTOPLINKS = desktop-print-management desktop-print-management-applet -DESKTOPLINKS += desktop-print-management-prefs +DESKTOPLINKS = desktop-print-management desktop-print-management-prefs BINLINKS = $(LPBINLINKS) $(LPRBINLINKS) $(DESKTOPLINKS) SBINLINKS = accept reject lpmove lpadmin ROOTUSRSBINPROG = $(SBINPROG:%=$(ROOTUSRSBIN)/%) +ROOTUSRBINPROG = $(BINPROG:%=$(ROOTBIN)/%) ROOTUSRBINLINKS = $(BINLINKS:%=$(ROOTBIN)/%) ROOTUSRSBINLINKS = $(SBINLINKS:%=$(ROOTUSRSBIN)/%) @@ -50,5 +51,5 @@ all check clean clobber lint: -install: $(ROOTUSRSBINPROG) $(ROOTUSRBINLINKS) $(ROOTUSRSBINLINKS) +install: $(ROOTUSRSBINPROG) $(ROOTUSRBINPROG) $(ROOTUSRBINLINKS) $(ROOTUSRSBINLINKS)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/print/selector/desktop-print-management-applet Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,81 @@ +#!/usr/perl5/bin/perl +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# + +my $SVC_CUPS_SCHEDULER = 'cups/scheduler'; +my $SVCPROP = '/usr/bin/svcprop'; + +sub svcprop { + local ($fmri, $property) = @_; + my $FH; + + open($FH, "$SVCPROP -C -p $property $fmri 2>/dev/null |"); + $result = <$FH>; + close($FH); + + return ($result); +} + +sub print_service { + my $service; + + $service = svcprop("$SVC_CUPS_SCHEDULER:default", "general/active"); + ($service =~ /true/) && ($service = 'cups') || ($service = 'lp'); + + return ($service); +} + +sub kill_running_applets { + # cups applet daemon + system("pkill -f '/system-config-printer/applet.py'"); + # lp applet daemon + system("pkill ospm-applet"); +} + +my $pid; + +sub handle_signal { + kill_running_applets (); +} +$SIG{USR1} = \&handle_signal; + + +$SIG{CHLD} = 'IGNORE'; +my $service; +$service = print_service(); +$pid = fork(); +if ($pid) { + waitpid($pid, 0); + exec('/usr/bin/desktop-print-management-applet'); +} +else { + if ($service eq 'lp') { + exec('/usr/lib/lp/bin/desktop-print-management-applet'); + } + else { + exec('/usr/lib/cups/bin/desktop-print-management-applet'); + } +} +
--- a/usr/src/cmd/print/selector/print-service Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/print/selector/print-service Mon Jul 20 13:07:46 2009 -0400 @@ -19,10 +19,9 @@ # # CDDL HEADER END # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" # # @@ -242,6 +241,7 @@ svcadm("enable", $SVC_CUPS_SCHEDULER, $SVC_CUPS_LPD); svccfg("cups/scheduler:default", "setprop general/active = boolean: true"); + system("pkill -USR1 -f '/desktop-print-management-applet'"); } else { print("disabling CUPS services...\n"); svcadm("disable", $SVC_CUPS_SCHEDULER, $SVC_CUPS_LPD); @@ -251,6 +251,7 @@ (-f '/etc/lp/printers.conf') && rename('/etc/lp/printers.conf', '/etc/printers.conf'); svccfg("cups/scheduler:default", "delprop general/active"); + system("pkill -USR1 -f '/desktop-print-management-applet'"); } # import the new print queue configuration (if migrating)
--- a/usr/src/cmd/psrset/psrset.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/psrset/psrset.c Mon Jul 20 13:07:46 2009 -0400 @@ -2,9 +2,8 @@ * 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. + * Common Development and Distribution License (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. @@ -20,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * psrset - create and manage processor sets */ @@ -44,7 +41,6 @@ #include <procfs.h> #include <libproc.h> #include <stdarg.h> -#include <priv.h> #if !defined(TEXT_DOMAIN) /* should be defined by cc -D */ #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */ @@ -107,14 +103,10 @@ exit(ERR_FAIL); } -static prpriv_t *orig_priv; - static struct ps_prochandle * grab_proc(id_t pid) { int ret; - prpriv_t *new_priv; - priv_set_t *eff_set, *perm_set; struct ps_prochandle *Pr; if ((Pr = Pgrab(pid, 0, &ret)) == NULL) { @@ -124,66 +116,6 @@ return (NULL); } - /* - * If target process does not have required PRIV_SYS_RES_CONFIG - * privilege, assign it temporarily to that process' effective - * and permitted sets so that it can call pset_bind(2). - */ - if ((new_priv = proc_get_priv(pid)) == NULL) { - warn(gettext("unable to get privileges for process %d: %s\n"), - pid, strerror(errno)); - errors = ERR_FAIL; - Prelease(Pr, 0); - return (NULL); - } - - if (Pcreate_agent(Pr) != 0) { - warn(gettext("cannot control process %d\n"), (int)pid); - errors = ERR_FAIL; - Prelease(Pr, 0); - free(new_priv); - return (NULL); - } - - eff_set = (priv_set_t *)&new_priv->pr_sets[new_priv->pr_setsize * - priv_getsetbyname(PRIV_EFFECTIVE)]; - perm_set = (priv_set_t *)&new_priv->pr_sets[new_priv->pr_setsize * - priv_getsetbyname(PRIV_PERMITTED)]; - if (!priv_ismember(eff_set, PRIV_SYS_RES_CONFIG)) { - /* - * Save original privileges - */ - if ((orig_priv = proc_get_priv(pid)) == NULL) { - warn(gettext("unable to get privileges for " - "process %d: %s\n"), pid, strerror(errno)); - errors = ERR_FAIL; - Pdestroy_agent(Pr); - Prelease(Pr, 0); - free(new_priv); - return (NULL); - } - (void) priv_addset(eff_set, PRIV_SYS_RES_CONFIG); - (void) priv_addset(perm_set, PRIV_SYS_RES_CONFIG); - /* - * We don't want to leave a process with elevated privileges, - * so make sure the process dies if we exit unexpectedly. - */ - if (Psetflags(Pr, PR_KLC) != 0 || - Psetpriv(Pr, new_priv) != 0) { - warn(gettext("unable to set process privileges for " - "process %d: %s\n"), pid, strerror(errno)); - (void) Punsetflags(Pr, PR_KLC); - free(new_priv); - free(orig_priv); - Pdestroy_agent(Pr); - Prelease(Pr, 0); - orig_priv = NULL; - errors = ERR_FAIL; - return (NULL); - } - } - free(new_priv); - return (Pr); } @@ -192,28 +124,6 @@ { if (Pr == NULL) return; - if (orig_priv != NULL) { - if (Psetpriv(Pr, orig_priv) != 0) { - /* - * If this fails, we can't leave a process with - * elevated privileges, so we have to release the - * process from libproc, knowing that it will - * be killed (since we set the PR_KLC flag). - */ - Pdestroy_agent(Pr); - warn(gettext("cannot relinquish privileges for " - "process %d. The process was killed\n"), - Ppsinfo(Pr)->pr_pid); - errors = ERR_FAIL; - } else { - (void) Punsetflags(Pr, PR_KLC); - Pdestroy_agent(Pr); - } - free(orig_priv); - orig_priv = NULL; - } else { - Pdestroy_agent(Pr); - } Prelease(Pr, 0); } @@ -351,29 +261,30 @@ if (old == PS_NONE) { if (new == PS_NONE) (void) printf(gettext("%s id %s: was not bound, " - "now not bound\n"), proclwp, pidstr); + "now not bound\n"), proclwp, pidstr); else (void) printf(gettext("%s id %s: was not bound, " - "now %d\n"), proclwp, pidstr, new); + "now %d\n"), proclwp, pidstr, new); } else { if (new == PS_NONE) (void) printf(gettext("%s id %s: was %d, " - "now not bound\n"), proclwp, pidstr, old); + "now not bound\n"), proclwp, pidstr, old); else (void) printf(gettext("%s id %s: was %d, " - "now %d\n"), proclwp, pidstr, old, new); + "now %d\n"), proclwp, pidstr, old, new); } } static void -bind_lwp(struct ps_prochandle *Pr, id_t pid, id_t lwpid, psetid_t pset) +bind_lwp(id_t pid, id_t lwpid, psetid_t pset) { psetid_t old_pset; - if (pr_pset_bind(Pr, pset, P_LWPID, lwpid, &old_pset) < 0) { + if (pset_bind_lwp(pset, lwpid, pid, &old_pset) != 0) { bind_err(pset, pid, lwpid, errno); errors = ERR_FAIL; - } else { + } + if (errors != ERR_FAIL) { if (qflag) query_out(pid, lwpid, old_pset); else @@ -621,22 +532,22 @@ usage(void) { (void) fprintf(stderr, gettext( - "usage: \n" - "\t%1$s -c [-F] [processor_id ...]\n" - "\t%1$s -d processor_set_id ...\n" - "\t%1$s -n processor_set_id\n" - "\t%1$s -f processor_set_id\n" - "\t%1$s -e processor_set_id command [argument(s)...]\n" - "\t%1$s -a [-F] processor_set_id processor_id ...\n" - "\t%1$s -r [-F] processor_id ...\n" - "\t%1$s -p [processorid ...]\n" - "\t%1$s -b processor_set_id pid[/lwpids] ...\n" - "\t%1$s -u pid[/lwpids] ...\n" - "\t%1$s -q [pid[/lwpids] ...]\n" - "\t%1$s -U [processor_set_id] ...\n" - "\t%1$s -Q [processor_set_id] ...\n" - "\t%1$s [-i] [processor_set_id ...]\n"), - progname); + "usage: \n" + "\t%1$s -c [-F] [processor_id ...]\n" + "\t%1$s -d processor_set_id ...\n" + "\t%1$s -n processor_set_id\n" + "\t%1$s -f processor_set_id\n" + "\t%1$s -e processor_set_id command [argument(s)...]\n" + "\t%1$s -a [-F] processor_set_id processor_id ...\n" + "\t%1$s -r [-F] processor_id ...\n" + "\t%1$s -p [processorid ...]\n" + "\t%1$s -b processor_set_id pid[/lwpids] ...\n" + "\t%1$s -u pid[/lwpids] ...\n" + "\t%1$s -q [pid[/lwpids] ...]\n" + "\t%1$s -U [processor_set_id] ...\n" + "\t%1$s -Q [processor_set_id] ...\n" + "\t%1$s [-i] [processor_set_id ...]\n"), + progname); return (ERR_USAGE); } @@ -699,7 +610,7 @@ continue; found++; if (bflag || uflag) - bind_lwp(Pr, pid, lwp->pr_lwpid, pset); + bind_lwp(pid, lwp->pr_lwpid, pset); else if (binding != PBIND_NONE) query_out(pid, lwp->pr_lwpid, binding); } @@ -960,7 +871,7 @@ pid = (id_t)strtol(*argv, &errptr, 10); if (errno != 0 || (errptr != NULL && *errptr != '\0' && - *errptr != '/')) { + *errptr != '/')) { warn(gettext("invalid process ID: %s\n"), *argv); continue;
--- a/usr/src/cmd/stmfadm/stmfadm.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/stmfadm/stmfadm.c Mon Jul 20 13:07:46 2009 -0400 @@ -126,13 +126,15 @@ #define COMPANY_ID "OUI" #define BLOCK_SIZE "BLK" #define SERIAL_NUMBER "SERIAL" +#define MGMT_URL "MGMT-URL" #define MODIFY_HELP "\n"\ "Description: Modify properties of a logical unit. \n" \ "Valid properties for -p, --lu-prop are: \n" \ -" alias - alias for logical unit (up to 255 chars)\n" \ -" wcd - write cache disabled (true, false)\n" \ -" wp - write protect (true, false)\n\n" \ +" alias - alias for logical unit (up to 255 chars)\n" \ +" mgmt-url - Management URL address\n" \ +" wcd - write cache disabled (true, false)\n" \ +" wp - write protect (true, false)\n\n" \ "-f alters the meaning of the operand to be a file name\n" \ "rather than a LU name. This allows for modification\n" \ "of a logical unit that is not yet imported into stmf\n" @@ -140,17 +142,18 @@ #define CREATE_HELP "\n"\ "Description: Create a logical unit. \n" \ "Valid properties for -p, --lu-prop are: \n" \ -" alias - alias for logical unit (up to 255 chars)\n" \ -" blk - block size in bytes in 2^n\n" \ -" guid - 32 ascii hex characters in NAA format \n" \ -" meta - separate meta data file name\n" \ -" oui - organizational unique identifier\n" \ -" 6 ascii hex characters of valid format\n" \ -" pid - product identifier (up to 16 chars)\n" \ -" serial- serial number (up to 252 chars)\n" \ -" vid - vendor identifier (up to 8 chars)\n" \ -" wp - write protect (true, false)\n" \ -" wcd - write cache disabled (true, false)\n" +" alias - alias for logical unit (up to 255 chars)\n" \ +" blk - block size in bytes in 2^n\n" \ +" guid - 32 ascii hex characters in NAA format \n" \ +" meta - separate meta data file name\n" \ +" mgmt-url - Management URL address\n" \ +" oui - organizational unique identifier\n" \ +" 6 ascii hex characters of valid format\n" \ +" pid - product identifier (up to 16 chars)\n" \ +" serial - serial number (up to 252 chars)\n" \ +" vid - vendor identifier (up to 8 chars)\n" \ +" wcd - write cache disabled (true, false)\n" \ +" wp - write protect (true, false)\n" #define ADD_VIEW_HELP "\n"\ "Description: Add a view entry to a logical unit. \n" \ "A view entry is comprised of three elements; the \n" \ @@ -991,14 +994,7 @@ switch (options->optval) { case 'p': prop = strtok_r(options->optarg, "=", &lasts); - if ((propVal = strtok_r(NULL, "=", &lasts)) - == NULL) { - (void) fprintf(stderr, "%s: %s: %s\n", - cmdName, options->optarg, - gettext("invalid property specifier" - "- prop=val\n")); - return (1); - } + propVal = strtok_r(NULL, "=", &lasts); ret = convertCharToPropId(prop, &propId); if (ret != 0) { (void) fprintf(stderr, "%s: %s: %s\n", @@ -1007,8 +1003,22 @@ prop); return (1); } - if (callModify(fname, &inGuid, propId, propVal, - prop) != 0) { + if (propVal == NULL && + propId != STMF_LU_PROP_MGMT_URL) { + (void) fprintf(stderr, "%s: %s: %s\n", + cmdName, options->optarg, + gettext("invalid property specifier" + "- prop=val\n")); + return (1); + } + if (propVal == NULL) { + ret = callModify(fname, &inGuid, propId, + "", prop); + } else { + ret = callModify(fname, &inGuid, propId, + propVal, prop); + } + if (ret != 0) { return (1); } break; @@ -1270,6 +1280,8 @@ *propId = STMF_LU_PROP_COMPANY_ID; } else if (strcasecmp(prop, META_FILE) == 0) { *propId = STMF_LU_PROP_META_FILENAME; + } else if (strcasecmp(prop, MGMT_URL) == 0) { + *propId = STMF_LU_PROP_MGMT_URL; } else { return (1); } @@ -2092,6 +2104,18 @@ ret++; } + stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_MGMT_URL, propVal, + &propValSize); + (void) printf(PROPS_FORMAT, "Management URL"); + if (stmfRet == STMF_STATUS_SUCCESS) { + (void) printf("%s\n", propVal); + } else if (stmfRet == STMF_ERROR_NO_PROP) { + (void) printf("not set\n"); + } else { + (void) printf("<error retrieving property>\n"); + ret++; + } + stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_VID, propVal, &propValSize); (void) printf(PROPS_FORMAT, "Vendor ID");
--- a/usr/src/cmd/svc/profile/generic_limited_net.xml Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/svc/profile/generic_limited_net.xml Mon Jul 20 13:07:46 2009 -0400 @@ -169,7 +169,7 @@ <instance name='default' enabled='false' /> </service> - <service name='application/management/sma' version='1' type='service'> + <service name='application/management/net-snmp' version='1' type='service'> <instance name='default' enabled='false' /> </service> <service name='application/management/seaport' version='1' type='service'>
--- a/usr/src/cmd/svc/profile/generic_open.xml Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/svc/profile/generic_open.xml Mon Jul 20 13:07:46 2009 -0400 @@ -140,7 +140,7 @@ <instance name='default' enabled='true'/> </service> - <service name='application/management/sma' version='1' type='service'> + <service name='application/management/net-snmp' version='1' type='service'> <instance name='default' enabled='true' /> </service> <service name='application/management/seaport' version='1' type='service'>
--- a/usr/src/cmd/svr4pkg/libinst/pkgdbmerg.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/svr4pkg/libinst/pkgdbmerg.c Mon Jul 20 13:07:46 2009 -0400 @@ -99,7 +99,7 @@ static int do_like_ent(VFP_T *vfpo, struct cfextra *el_ent, struct cfent *cf_ent, int ctrl); static int do_new_ent(VFP_T *vfpo, struct cfextra *el_ent, int ctrl); -static int typechg(struct cfent *el_ent, struct cfent *cf_ent, +static int typechg(struct cfent *el_ent, char *curftype, struct mergstat *mstat); static void set_change(struct cfextra *el_ent); @@ -549,6 +549,40 @@ * about this later. Note that noconflict means NO conflict * at the file level. Even rogue files count. */ + char myftype = '?'; + int n = 0; + + /* Get the existing file type on disk */ + eval_ftype(el_ent->server_path, el_ent->cf_ent.ftype, &myftype); + + /* Do the right thing if types are different */ + n = typechg(&(el_ent->cf_ent), &myftype, &(el_ent->mstat)); + switch (n) { + case TYPE_OK: + break; + + /* This is an allowable change. */ + case TYPE_WARNING: + el_ent->mstat.contchg = 1; + break; + + /* Not allowed, but leaving it as is is OK. */ + case TYPE_IGNORED: + break; + + /* Future analysis will reveal if this is OK. */ + case TYPE_REPLACE: + el_ent->mstat.replace = 1; + break; + + /* Kill it before it does any damage. */ + case TYPE_FATAL: + logerr(gettext(MSG_TYPE_ERR)); + quit(99); + + default: + break; + } el_ent->mstat.shared = 1; el_ent->mstat.rogue = 1; set_change(el_ent); @@ -725,20 +759,20 @@ * TYPE_FATAL something awful happened */ static int -typechg(struct cfent *el_ent, struct cfent *cf_ent, struct mergstat *mstat) +typechg(struct cfent *el_ent, char *curftype, struct mergstat *mstat) { int i, etype, itype, retcode; /* If they are identical, return OK */ - if (cf_ent->ftype == el_ent->ftype) + if (*curftype == el_ent->ftype) return (TYPE_OK); /* * If package database entry is ambiguous, set it to the new entity's * ftype */ - if (cf_ent->ftype == BADFTYPE) { - cf_ent->ftype = el_ent->ftype; + if (*curftype == BADFTYPE) { + *curftype = el_ent->ftype; return (TYPE_OK); /* do nothing; not really different */ } @@ -751,7 +785,7 @@ * exclusive directory, this is very dangerous. We will continue, but * we will deny the conversion. */ - if (el_ent->ftype == 'x' && cf_ent->ftype == 'd') { + if (el_ent->ftype == 'x' && *curftype == 'd') { logerr(gettext(WRN_TOEXCL), el_ent->path); return (TYPE_IGNORED); } @@ -768,7 +802,7 @@ /* Set itype to that in the package database. */ for (i = 0; types[i]; ++i) { - if (strchr(types[i], cf_ent->ftype)) { + if (strchr(types[i], *curftype)) { itype = i+1; break; } @@ -792,36 +826,36 @@ /* allow change, but warn user of possible problems */ switch (itype) { - case 1: - logerr(gettext(WRN_NOTFILE), el_ent->path); - break; + case 1: + logerr(gettext(WRN_NOTFILE), el_ent->path); + break; - case 2: - logerr(gettext(WRN_NOTSYMLN), el_ent->path); - break; + case 2: + logerr(gettext(WRN_NOTSYMLN), el_ent->path); + break; - case 3: - logerr(gettext(WRN_NOTLINK), el_ent->path); - break; + case 3: + logerr(gettext(WRN_NOTLINK), el_ent->path); + break; - case 4: - logerr(gettext(WRN_NOTDIR), el_ent->path); - break; + case 4: + logerr(gettext(WRN_NOTDIR), el_ent->path); + break; - case 5: - logerr(gettext(WRN_NOTCHAR), el_ent->path); - break; + case 5: + logerr(gettext(WRN_NOTCHAR), el_ent->path); + break; - case 6: - logerr(gettext(WRN_NOTBLOCK), el_ent->path); - break; + case 6: + logerr(gettext(WRN_NOTBLOCK), el_ent->path); + break; - case 7: - logerr(gettext(WRN_NOTPIPE), el_ent->path); - break; + case 7: + logerr(gettext(WRN_NOTPIPE), el_ent->path); + break; - default: - break; + default: + break; } return (retcode); } @@ -867,7 +901,8 @@ * can't figure it 'til later (d -> s) or fatal (a hook for later). */ if (cf_ent->ftype != el_ent->cf_ent.ftype) { - n = typechg(&(el_ent->cf_ent), cf_ent, &(el_ent->mstat)); + n = typechg(&(el_ent->cf_ent), &(cf_ent->ftype), + &(el_ent->mstat)); switch (n) { case TYPE_OK:
--- a/usr/src/cmd/zic/README Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/zic/README Mon Jul 20 13:07:46 2009 -0400 @@ -9,7 +9,7 @@ The zoneinfo files track the Olson public source provided at ftp://elsie.nci.nih.gov/pub/, therefore zoneinfo files may be added and removed as the Solaris source is updated. The current Solaris release of -the zoneinfo files is based on tzdata2009i.tar.gz. +the zoneinfo files is based on tzdata2009j.tar.gz. The /usr/share/lib/zoneinfo/GMT[+-]* timezones listed below have been removed from the release. Replace usage of the
--- a/usr/src/cmd/zic/asia Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/zic/asia Mon Jul 20 13:07:46 2009 -0400 @@ -1,5 +1,5 @@ # <pre> -# @(#)asia 8.34 +# @(#)asia 8.35 # This file is in the public domain, so clarified as of # 2009-05-17 by Arthur David Olson. @@ -165,9 +165,12 @@ # http://www.timeanddate.com/news/time/bangladesh-daylight-saving-2009.html # </a> -# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S -Rule Bang 2009 only - Jan 1 0:00 0 - -Rule Bang 2009 only - Jun 20 0:00 1:00 S +# From A. N. M. Kamrus Saadat (2009-06-15): +# Finally we've got the official mail regarding DST start time where DST start +# time is mentioned as Jun 19 2009, 23:00 from BTRC (Bangladesh +# Telecommunication Regulatory Commission). +# +# No DST end date has been announced yet. # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Dhaka 6:01:40 - LMT 1890 @@ -176,8 +179,8 @@ 5:30 - IST 1942 Sep 6:30 - BURT 1951 Sep 30 6:00 - DACT 1971 Mar 26 # Dacca Time - 6:00 - BDT 2009 # Bangladesh Time - 6:00 Bang BD%sT + 6:00 - BDT 2009 Jun 19 23:00 # Bangladesh Time + 6:00 1:00 BDST # Bhutan # Zone NAME GMTOFF RULES FORMAT [UNTIL]
--- a/usr/src/cmd/zoneadmd/zcons.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/zoneadmd/zcons.c Mon Jul 20 13:07:46 2009 -0400 @@ -108,7 +108,6 @@ #include <syslog.h> #include <sys/modctl.h> -#include <sys/fs/sdev_node.h> #include "zoneadmd.h"
--- a/usr/src/cmd/zpool/zpool_main.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/zpool/zpool_main.c Mon Jul 20 13:07:46 2009 -0400 @@ -3540,6 +3540,7 @@ (void) printf(gettext(" 14 passthrough-x aclinherit\n")); (void) printf(gettext(" 15 user/group space accounting\n")); (void) printf(gettext(" 16 stmf property support\n")); + (void) printf(gettext(" 17 Triple-parity RAID-Z\n")); (void) printf(gettext("For more information on a particular " "version, including supported releases, see:\n\n")); (void) printf("http://www.opensolaris.org/os/community/zfs/"
--- a/usr/src/cmd/zpool/zpool_vdev.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/zpool/zpool_vdev.c Mon Jul 20 13:07:46 2009 -0400 @@ -20,7 +20,7 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -67,6 +67,7 @@ #include <libdiskmgt.h> #include <libintl.h> #include <libnvpair.h> +#include <limits.h> #include <stdio.h> #include <string.h> #include <unistd.h> @@ -1093,19 +1094,34 @@ } static const char * -is_grouping(const char *type, int *mindev) +is_grouping(const char *type, int *mindev, int *maxdev) { - if (strcmp(type, "raidz") == 0 || strcmp(type, "raidz1") == 0) { + if (strncmp(type, "raidz", 5) == 0) { + const char *p = type + 5; + char *end; + long nparity; + + if (*p == '\0') { + nparity = 1; + } else if (*p == '0') { + return (NULL); /* no zero prefixes allowed */ + } else { + errno = 0; + nparity = strtol(p, &end, 10); + if (errno != 0 || nparity < 1 || nparity >= 255 || + *end != '\0') + return (NULL); + } + if (mindev != NULL) - *mindev = 2; + *mindev = nparity + 1; + if (maxdev != NULL) + *maxdev = 255; return (VDEV_TYPE_RAIDZ); } - if (strcmp(type, "raidz2") == 0) { - if (mindev != NULL) - *mindev = 3; - return (VDEV_TYPE_RAIDZ); - } + if (maxdev != NULL) + *maxdev = INT_MAX; if (strcmp(type, "mirror") == 0) { if (mindev != NULL) @@ -1144,7 +1160,7 @@ construct_spec(int argc, char **argv) { nvlist_t *nvroot, *nv, **top, **spares, **l2cache; - int t, toplevels, mindev, nspares, nlogs, nl2cache; + int t, toplevels, mindev, maxdev, nspares, nlogs, nl2cache; const char *type; uint64_t is_log; boolean_t seen_logs; @@ -1166,7 +1182,7 @@ * If it's a mirror or raidz, the subsequent arguments are * its leaves -- until we encounter the next mirror or raidz. */ - if ((type = is_grouping(argv[0], &mindev)) != NULL) { + if ((type = is_grouping(argv[0], &mindev, &maxdev)) != NULL) { nvlist_t **child = NULL; int c, children = 0; @@ -1223,7 +1239,7 @@ } for (c = 1; c < argc; c++) { - if (is_grouping(argv[c], NULL) != NULL) + if (is_grouping(argv[c], NULL, NULL) != NULL) break; children++; child = realloc(child, @@ -1243,6 +1259,13 @@ return (NULL); } + if (children > maxdev) { + (void) fprintf(stderr, gettext("invalid vdev " + "specification: %s supports no more than " + "%d devices\n"), argv[0], maxdev); + return (NULL); + } + argc -= c; argv += c;
--- a/usr/src/cmd/ztest/ztest.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/cmd/ztest/ztest.c Mon Jul 20 13:07:46 2009 -0400 @@ -479,7 +479,7 @@ zopt_raidz = MAX(1, value); break; case 'R': - zopt_raidz_parity = MIN(MAX(value, 1), 2); + zopt_raidz_parity = MIN(MAX(value, 1), 3); break; case 'd': zopt_datasets = MAX(1, value);
--- a/usr/src/common/smbsrv/smb_xdr_utils.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/common/smbsrv/smb_xdr_utils.c Mon Jul 20 13:07:46 2009 -0400 @@ -30,57 +30,6 @@ #endif /* _KERNEL */ #include <smbsrv/smb_xdr.h> #include <sys/socket.h> -#ifdef _KERNEL -/* - * xdr_vector(): - * - * XDR a fixed length array. Unlike variable-length arrays, - * the storage of fixed length arrays is static and unfreeable. - * > basep: base of the array - * > size: size of the array - * > elemsize: size of each element - * > xdr_elem: routine to XDR each element - */ -#define LASTUNSIGNED ((uint_t)0-1) -bool_t -xdr_vector(XDR *xdrs, char *basep, uint_t nelem, - uint_t elemsize, xdrproc_t xdr_elem) -{ - uint_t i; - char *elptr; - - elptr = basep; - for (i = 0; i < nelem; i++) { - if (!(*xdr_elem)(xdrs, elptr, LASTUNSIGNED)) - return (FALSE); - elptr += elemsize; - } - return (TRUE); -} - -/* - * XDR an unsigned char - */ -bool_t -xdr_u_char(XDR *xdrs, uchar_t *cp) -{ - int i; - - switch (xdrs->x_op) { - case XDR_ENCODE: - i = (*cp); - return (XDR_PUTINT32(xdrs, &i)); - case XDR_DECODE: - if (!XDR_GETINT32(xdrs, &i)) - return (FALSE); - *cp = (uchar_t)i; - return (TRUE); - case XDR_FREE: - return (TRUE); - } - return (FALSE); -} -#endif /* _KERNEL */ bool_t xdr_smb_dr_string_t(xdrs, objp) @@ -160,45 +109,44 @@ } /* - * Encode an opipe context structure into a buffer. + * Encode an smb_netuserinfo_t into a buffer. */ int -smb_opipe_context_encode(smb_opipe_context_t *ctx, uint8_t *buf, - uint32_t buflen, uint_t *pbytes_encoded) +smb_netuserinfo_encode(smb_netuserinfo_t *info, uint8_t *buf, + uint32_t buflen, uint_t *nbytes) { XDR xdrs; int rc = 0; xdrmem_create(&xdrs, (const caddr_t)buf, buflen, XDR_ENCODE); - if (!smb_opipe_context_xdr(&xdrs, ctx)) + if (!smb_netuserinfo_xdr(&xdrs, info)) rc = -1; - if (pbytes_encoded != NULL) - *pbytes_encoded = xdr_getpos(&xdrs); - + if (nbytes != NULL) + *nbytes = xdr_getpos(&xdrs); xdr_destroy(&xdrs); return (rc); } /* - * Decode an XDR buffer into an opipe context structure. + * Decode an XDR buffer into an smb_netuserinfo_t. */ int -smb_opipe_context_decode(smb_opipe_context_t *ctx, uint8_t *buf, - uint32_t buflen, uint_t *pbytes_decoded) +smb_netuserinfo_decode(smb_netuserinfo_t *info, uint8_t *buf, + uint32_t buflen, uint_t *nbytes) { XDR xdrs; int rc = 0; xdrmem_create(&xdrs, (const caddr_t)buf, buflen, XDR_DECODE); - bzero(ctx, sizeof (smb_opipe_context_t)); - if (!smb_opipe_context_xdr(&xdrs, ctx)) + bzero(info, sizeof (smb_netuserinfo_t)); + if (!smb_netuserinfo_xdr(&xdrs, info)) rc = -1; - if (pbytes_decoded != NULL) - *pbytes_decoded = xdr_getpos(&xdrs); + if (nbytes != NULL) + *nbytes = xdr_getpos(&xdrs); xdr_destroy(&xdrs); return (rc); } @@ -219,32 +167,175 @@ return (TRUE); } +/* + * XDR encode/decode for smb_netuserinfo_t. + */ bool_t -smb_opipe_context_xdr(XDR *xdrs, smb_opipe_context_t *objp) +smb_netuserinfo_xdr(XDR *xdrs, smb_netuserinfo_t *objp) { - if (!xdr_uint64_t(xdrs, &objp->oc_session_id)) + if (!xdr_uint64_t(xdrs, &objp->ui_session_id)) + return (FALSE); + if (!xdr_uint16_t(xdrs, &objp->ui_uid)) + return (FALSE); + if (!xdr_uint16_t(xdrs, &objp->ui_domain_len)) + return (FALSE); + if (!xdr_string(xdrs, &objp->ui_domain, ~0)) + return (FALSE); + if (!xdr_uint16_t(xdrs, &objp->ui_account_len)) return (FALSE); - if (!xdr_uint16_t(xdrs, &objp->oc_uid)) + if (!xdr_string(xdrs, &objp->ui_account, ~0)) + return (FALSE); + if (!xdr_uint16_t(xdrs, &objp->ui_workstation_len)) return (FALSE); - if (!xdr_uint16_t(xdrs, &objp->oc_domain_len)) + if (!xdr_string(xdrs, &objp->ui_workstation, ~0)) + return (FALSE); + if (!xdr_smb_inaddr_t(xdrs, &objp->ui_ipaddr)) return (FALSE); - if (!xdr_string(xdrs, &objp->oc_domain, ~0)) + if (!xdr_int32_t(xdrs, &objp->ui_native_os)) + return (FALSE); + if (!xdr_int64_t(xdrs, &objp->ui_logon_time)) return (FALSE); - if (!xdr_uint16_t(xdrs, &objp->oc_account_len)) + if (!xdr_uint32_t(xdrs, &objp->ui_numopens)) + return (FALSE); + if (!xdr_uint32_t(xdrs, &objp->ui_flags)) return (FALSE); - if (!xdr_string(xdrs, &objp->oc_account, ~0)) + return (TRUE); +} + +/* + * Encode an smb_netconnectinfo_t into a buffer. + */ +int +smb_netconnectinfo_encode(smb_netconnectinfo_t *info, uint8_t *buf, + uint32_t buflen, uint_t *nbytes) +{ + XDR xdrs; + int rc = 0; + + xdrmem_create(&xdrs, (const caddr_t)buf, buflen, XDR_ENCODE); + + if (!smb_netconnectinfo_xdr(&xdrs, info)) + rc = -1; + + if (nbytes != NULL) + *nbytes = xdr_getpos(&xdrs); + xdr_destroy(&xdrs); + return (rc); +} + +/* + * Decode an XDR buffer into an smb_netconnectinfo_t. + */ +int +smb_netconnectinfo_decode(smb_netconnectinfo_t *info, uint8_t *buf, + uint32_t buflen, uint_t *nbytes) +{ + XDR xdrs; + int rc = 0; + + xdrmem_create(&xdrs, (const caddr_t)buf, buflen, XDR_DECODE); + + bzero(info, sizeof (smb_netconnectinfo_t)); + if (!smb_netconnectinfo_xdr(&xdrs, info)) + rc = -1; + + if (nbytes != NULL) + *nbytes = xdr_getpos(&xdrs); + xdr_destroy(&xdrs); + return (rc); +} + +/* + * XDR encode/decode for smb_netconnectinfo_t. + */ +bool_t +smb_netconnectinfo_xdr(XDR *xdrs, smb_netconnectinfo_t *objp) +{ + if (!xdr_uint32_t(xdrs, &objp->ci_id)) return (FALSE); - if (!xdr_uint16_t(xdrs, &objp->oc_workstation_len)) + if (!xdr_uint32_t(xdrs, &objp->ci_type)) + return (FALSE); + if (!xdr_uint32_t(xdrs, &objp->ci_numopens)) + return (FALSE); + if (!xdr_uint32_t(xdrs, &objp->ci_numusers)) return (FALSE); - if (!xdr_string(xdrs, &objp->oc_workstation, ~0)) + if (!xdr_uint32_t(xdrs, &objp->ci_time)) + return (FALSE); + if (!xdr_uint32_t(xdrs, &objp->ci_namelen)) + return (FALSE); + if (!xdr_uint32_t(xdrs, &objp->ci_sharelen)) + return (FALSE); + if (!xdr_string(xdrs, &objp->ci_username, MAXNAMELEN)) return (FALSE); - if (!xdr_smb_inaddr_t(xdrs, &objp->oc_ipaddr)) - return (FALSE); - if (!xdr_int32_t(xdrs, &objp->oc_native_os)) + if (!xdr_string(xdrs, &objp->ci_share, MAXNAMELEN)) return (FALSE); - if (!xdr_int64_t(xdrs, &objp->oc_logon_time)) + return (TRUE); +} + +/* + * Encode an smb_netfileinfo_t into a buffer. + */ +int +smb_netfileinfo_encode(smb_netfileinfo_t *info, uint8_t *buf, + uint32_t buflen, uint_t *nbytes) +{ + XDR xdrs; + int rc = 0; + + xdrmem_create(&xdrs, (const caddr_t)buf, buflen, XDR_ENCODE); + + if (!smb_netfileinfo_xdr(&xdrs, info)) + rc = -1; + + if (nbytes != NULL) + *nbytes = xdr_getpos(&xdrs); + xdr_destroy(&xdrs); + return (rc); +} + +/* + * Decode an XDR buffer into an smb_netfileinfo_t. + */ +int +smb_netfileinfo_decode(smb_netfileinfo_t *info, uint8_t *buf, + uint32_t buflen, uint_t *nbytes) +{ + XDR xdrs; + int rc = 0; + + xdrmem_create(&xdrs, (const caddr_t)buf, buflen, XDR_DECODE); + + bzero(info, sizeof (smb_netfileinfo_t)); + if (!smb_netfileinfo_xdr(&xdrs, info)) + rc = -1; + + if (nbytes != NULL) + *nbytes = xdr_getpos(&xdrs); + xdr_destroy(&xdrs); + return (rc); +} + +/* + * XDR encode/decode for smb_netfileinfo_t. + */ +bool_t +smb_netfileinfo_xdr(XDR *xdrs, smb_netfileinfo_t *objp) +{ + if (!xdr_uint16_t(xdrs, &objp->fi_fid)) return (FALSE); - if (!xdr_uint32_t(xdrs, &objp->oc_flags)) + if (!xdr_uint32_t(xdrs, &objp->fi_uniqid)) + return (FALSE); + if (!xdr_uint32_t(xdrs, &objp->fi_permissions)) + return (FALSE); + if (!xdr_uint32_t(xdrs, &objp->fi_numlocks)) + return (FALSE); + if (!xdr_uint32_t(xdrs, &objp->fi_pathlen)) + return (FALSE); + if (!xdr_uint32_t(xdrs, &objp->fi_namelen)) + return (FALSE); + if (!xdr_string(xdrs, &objp->fi_path, MAXPATHLEN)) + return (FALSE); + if (!xdr_string(xdrs, &objp->fi_username, MAXNAMELEN)) return (FALSE); return (TRUE); }
--- a/usr/src/grub/capability Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/grub/capability Mon Jul 20 13:07:46 2009 -0400 @@ -40,7 +40,7 @@ # This file and the associated version are Solaris specific and are # not a part of the open source distribution of GRUB. # -VERSION=9 +VERSION=10 dboot xVM zfs
--- a/usr/src/grub/grub-0.97/stage2/zfs-include/zfs.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/grub/grub-0.97/stage2/zfs-include/zfs.h Mon Jul 20 13:07:46 2009 -0400 @@ -27,7 +27,7 @@ /* * On-disk version number. */ -#define SPA_VERSION 16ULL +#define SPA_VERSION 17ULL /* * The following are configuration names used in the nvlist describing a pool's
--- a/usr/src/lib/fm/libfmd_snmp/Makefile Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/fm/libfmd_snmp/Makefile Mon Jul 20 13:07:46 2009 -0400 @@ -19,10 +19,9 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" # include ../../Makefile.lib @@ -36,11 +35,11 @@ MIBFILES = SUN-FM-MIB.mib -ROOTSMAMIBDIR = $(ROOT)/etc/sma/snmp/mibs -ROOTMIBS = $(MIBFILES:%=$(ROOTSMAMIBDIR)/%) +ROOTNETSNMPMIBDIR = $(ROOT)/etc/net-snmp/snmp/mibs +ROOTMIBS = $(MIBFILES:%=$(ROOTNETSNMPMIBDIR)/%) $(ROOTMIBS) := FILEMODE = 0644 -$(ROOTSMAMIBDIR) := DIRMODE = 0755 +$(ROOTNETSNMPMIBDIR) := DIRMODE = 0755 all := TARGET = all clean := TARGET = clean @@ -56,17 +55,17 @@ install_h: $(ROOTFMHDRS) -install_mibs: $(ROOTSMAMIBDIR) $(ROOTMIBS) +install_mibs: $(ROOTNETSNMPMIBDIR) $(ROOTMIBS) check: $(CHECKHDRS) $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) -$(ROOTSMAMIBDIR): +$(ROOTNETSNMPMIBDIR): $(INS.dir) -$(ROOTSMAMIBDIR)/%: mibs/% +$(ROOTNETSNMPMIBDIR)/%: mibs/% $(INS.file) FRC:
--- a/usr/src/lib/fm/topo/modules/i86pc/chip/chip_amd.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/fm/topo/modules/i86pc/chip/chip_amd.c Mon Jul 20 13:07:46 2009 -0400 @@ -137,9 +137,9 @@ * This "generic" topology is adequate for all of family 0xf and * for revisions A, B and C of family 0x10 (for the list of models * in each revision, refer to usr/src/uts/i86pc/os/cpuid_subr.c). - * We cover all family 0x10 models, till model 6. + * We cover all family 0x10 models, till model 8. */ - if (family > 0x10 || (family == 0x10 && model > 6)) + if (family > 0x10 || (family == 0x10 && model > 8)) return (1); if (topo_node_range_create(mod, mcnode, CHAN_NODE_NAME, 0,
--- a/usr/src/lib/libadutils/common/addisc.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libadutils/common/addisc.c Mon Jul 20 13:07:46 2009 -0400 @@ -314,7 +314,6 @@ int num_td1; int num_td2; boolean_t match; - int err; for (i = 0; td1[i].domain[0] != '\0'; i++) continue; @@ -330,9 +329,7 @@ for (i = 0; i < num_td1; i++) { match = B_FALSE; for (j = 0; j < num_td2; j++) { - if (u8_strcmp(td1[i].domain, td2[j].domain, 0, - U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err) == 0 && - err == 0) { + if (domain_eq(td1[i].domain, td2[j].domain)) { match = B_TRUE; break; } @@ -373,7 +370,6 @@ int num_df1; int num_df2; boolean_t match; - int err; for (i = 0; df1[i].domain[0] != '\0'; i++) continue; @@ -389,9 +385,7 @@ for (i = 0; i < num_df1; i++) { match = B_FALSE; for (j = 0; j < num_df2; j++) { - if (u8_strcmp(df1[i].domain, df2[j].domain, 0, - U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err) == 0 && - err == 0 && + if (domain_eq(df1[i].domain, df2[j].domain) && strcmp(df1[i].sid, df2[j].sid) == 0) { match = B_TRUE; break; @@ -1077,7 +1071,7 @@ if (ndomains < nresults) { ad_disc_domainsinforest_t *tmp; - tmp = realloc(domains, (ndomains+1) * sizeof (*domains)); + tmp = realloc(domains, (ndomains + 1) * sizeof (*domains)); if (tmp == NULL) goto err; domains = tmp; @@ -1241,8 +1235,8 @@ /* Eat any trailing dot */ len = strlen(dname); - if (len > 0 && dname[len-1] == '.') - dname[len-1] = '\0'; + if (len > 0 && dname[len - 1] == '.') + dname[len - 1] = '\0'; update_item(&ctx->domain_name, dname, AD_STATE_AUTO, ttl);
--- a/usr/src/lib/libadutils/common/adutils.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libadutils/common/adutils.c Mon Jul 20 13:07:46 2009 -0400 @@ -863,12 +863,10 @@ adutils_lookup_check_domain(adutils_query_state_t *qs, const char *domain) { adutils_ad_t *ad = qs->qadh->owner; - int i, err; + int i; for (i = 0; i < ad->num_known_domains; i++) { - if (u8_strcmp(domain, ad->known_domains[i].name, 0, - U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err) == 0 && - err == 0) + if (domain_eq(domain, ad->known_domains[i].name)) return (1); } @@ -1116,7 +1114,7 @@ char *attr = NULL, *dn = NULL, *domain = NULL; adutils_entry_t *ep; adutils_attr_t *ap; - int i, j, b, err = 0, ret = -2; + int i, j, b, ret = -2; *entry = NULL; @@ -1128,8 +1126,7 @@ return (-2); } if (q->edomain != NULL) { - if (u8_strcmp(q->edomain, domain, 0, U8_STRCMP_CI_LOWER, - U8_UNICODE_LATEST, &err) != 0 || err != 0) { + if (!domain_eq(q->edomain, domain)) { ldap_memfree(dn); free(domain); return (-1); @@ -1560,7 +1557,7 @@ */ adutils_rc adutils_lookup_batch_add(adutils_query_state_t *state, - const char *filter, const char **attrs, const char *edomain, + const char *filter, const char * const *attrs, const char *edomain, adutils_result_t **result, adutils_rc *rc) { adutils_rc retcode = ADUTILS_SUCCESS; @@ -1675,3 +1672,12 @@ return (rc); return (brc); } + +boolean_t +domain_eq(const char *a, const char *b) +{ + int err; + + return (u8_strcmp(a, b, 0, U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err) + == 0 && err == 0); +}
--- a/usr/src/lib/libadutils/common/libadutils.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libadutils/common/libadutils.h Mon Jul 20 13:07:46 2009 -0400 @@ -164,7 +164,7 @@ void *ldap_res_search_argp, adutils_query_state_t **state); extern adutils_rc adutils_lookup_batch_add(adutils_query_state_t *state, - const char *filter, const char **attrs, + const char *filter, const char * const *attrs, const char *edomain, adutils_result_t **result, adutils_rc *rc); extern adutils_rc adutils_lookup_batch_end( @@ -181,6 +181,8 @@ const char *sid); extern void adutils_set_logger(adutils_logger logger); +extern boolean_t domain_eq(const char *a, const char *b); + #ifdef __cplusplus } #endif
--- a/usr/src/lib/libadutils/common/mapfile-vers Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libadutils/common/mapfile-vers Mon Jul 20 13:07:46 2009 -0400 @@ -80,6 +80,7 @@ ad_disc_get_SiteName; ad_disc_get_TrustedDomains; ad_disc_get_DomainsInForest; + domain_eq; local: *; };
--- a/usr/src/lib/libc/common/sys/_pset.s Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libc/common/sys/_pset.s Mon Jul 20 13:07:46 2009 -0400 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -32,7 +32,7 @@ * _pset(int subcode, long arg1, long arg2, long arg3, long arg4) * * Syscall entry point for pset_create, pset_assign, pset_destroy, - * pset_bind, and pset_info. + * pset_bind, pset_bind_lwp and pset_info. */ SYSCALL2_RVAL1(_pset,pset) RETC
--- a/usr/src/lib/libc/port/llib-lc Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libc/port/llib-lc Mon Jul 20 13:07:46 2009 -0400 @@ -1347,6 +1347,8 @@ int pset_assign_forced(psetid_t pset, processorid_t cpu, psetid_t *opset); int pset_info(psetid_t pset, int *type, u_int *numcpus, processorid_t *cpulist); int pset_bind(psetid_t pset, idtype_t idtype, id_t id, psetid_t *opset); +int pset_bind_lwp(psetid_t pset, id_t id, pid_t, psetid_t *opset); + /* rctlsys.c */ int getrctl(const char *name, rctlblk_t *old_rblk, rctlblk_t *new_rblk,
--- a/usr/src/lib/libc/port/mapfile-vers Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libc/port/mapfile-vers Mon Jul 20 13:07:46 2009 -0400 @@ -1605,6 +1605,7 @@ __priv_bracket; __priv_relinquish; pset_assign_forced; + pset_bind_lwp; _psignal; _pthread_setcleanupinit; __putwchar_xpg5;
--- a/usr/src/lib/libc/port/sys/psetsys.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libc/port/sys/psetsys.c Mon Jul 20 13:07:46 2009 -0400 @@ -20,22 +20,10 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - -#pragma weak _pset_create = pset_create -#pragma weak _pset_destroy = pset_destroy -#pragma weak _pset_assign = pset_assign -#pragma weak _pset_info = pset_info -#pragma weak _pset_bind = pset_bind -#pragma weak _pset_getloadavg = pset_getloadavg -#pragma weak _pset_list = pset_list -#pragma weak _pset_setattr = pset_setattr -#pragma weak _pset_getattr = pset_getattr - #include "lint.h" #include <sys/types.h> #include <sys/procset.h> @@ -84,6 +72,12 @@ return (_pset(PSET_BIND, pset, idtype, id, opset)); } +int +pset_bind_lwp(psetid_t pset, id_t id, pid_t pid, psetid_t *opset) +{ + return (_pset(PSET_BIND_LWP, pset, id, pid, opset)); +} + /* * Get the per-processor-set load average. */
--- a/usr/src/lib/libdevinfo/Makefile.com Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libdevinfo/Makefile.com Mon Jul 20 13:07:46 2009 -0400 @@ -19,17 +19,15 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" -# LIBRARY= libdevinfo.a VERS= .1 OBJECTS= devfsinfo.o devinfo.o devinfo_prop_decode.o devinfo_devlink.o \ - devinfo_devperm.o devfsmap.o devinfo_devname.o \ + devinfo_devperm.o devfsmap.o devinfo_profile.o \ devinfo_finddev.o devinfo_dli.o devinfo_dim.o \ devinfo_realpath.o devinfo_retire.o
--- a/usr/src/lib/libdevinfo/devinfo_devname.c Tue Jul 14 11:18:27 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,701 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <stdio.h> -#include <strings.h> -#include <unistd.h> -#include <stdarg.h> -#include <fcntl.h> -#include <stdlib.h> -#include <libnvpair.h> -#include <libdevinfo.h> -#include <syslog.h> -#include <sys/param.h> -#include <errno.h> -#include <assert.h> -#include <sys/systeminfo.h> -#include <sys/modctl.h> -#include <sys/fs/sdev_node.h> - - -#define LINEMAX 1024 -#define SPC " \t\n" -#define QUOTES "\'\"" - -/* - * This is for local file supports of DBNR configurations. - */ -static int di_devname_getmapent_files(char *, char *, nvlist_t **); -static int di_devname_get_mapinfo_files(char *, nvlist_t **); -static int parse_mapinfo_file(FILE *, nvlist_t **); -static FILE *open_local_map(char *); -static void unquote(char *, char *); - -static int msglog = 1; -typedef enum { - DBG_ERR = 1, - DBG_INFO, - DBG_STEP, - DBG_ALL -} debug_level_t; -static int devname_debug = 1; -static void dprintf(debug_level_t, const char *, ...); - -extern int isspace(int); - -/* exported interfaces */ -void di_devname_print_mapinfo(nvlist_t *); -int di_devname_get_mapinfo(char *, nvlist_t **); -int di_devname_get_mapent(char *, char *, nvlist_t **); -int di_devname_action_on_key(nvlist_t *, uint8_t, char *, void *); - -/* - * Returns 0 and the valid maplist, otherwise errno. - */ -int -di_devname_get_mapinfo_files(char *mapname, nvlist_t **maplist) -{ - FILE *fp; - int rval = 0; - nvlist_t *nvl = NULL; - - fp = open_local_map(mapname); - if (fp == NULL) { - dprintf(DBG_INFO, "di_devname_get_mapinfo_files: file %s does" - "not exist\n", mapname); - return (ENOENT); - } - - rval = parse_mapinfo_file(fp, &nvl); - if (rval == 0) { - *maplist = nvl; - } - (void) fclose(fp); - - return (rval); -} - -static FILE * -open_local_map(char *mapname) -{ - char filename[LINEMAX]; - - if (*mapname != '/') { - (void) snprintf(filename, sizeof (filename), "/etc/dev/%s", - mapname); - } else { - (void) snprintf(filename, sizeof (filename), "%s", mapname); - } - - return (fopen(filename, "r")); -} - -static void -unquote(char *str, char *qbuf) -{ - register int escaped, inquote, quoted; - register char *ip, *bp, *qp; - char buf[LINEMAX]; - - escaped = inquote = quoted = 0; - - for (ip = str, bp = buf, qp = qbuf; *ip; ip++) { - if (!escaped) { - if (*ip == '\\') { - escaped = 1; - quoted ++; - continue; - } else if (*ip == '"') { - inquote = !inquote; - quoted ++; - continue; - } - } - - *bp++ = *ip; - *qp++ = (inquote || escaped) ? '^' : ' '; - escaped = 0; - } - *bp = '\0'; - *qp = '\0'; - if (quoted) - (void) strcpy(str, buf); -} - -/* - * gets the qualified characters in *p into w, which has space allocated - * already - */ -static int -getword(char *w, char *wq, char **p, char **pq, char delim, int wordsz) -{ - char *tmp = w; - char *tmpq = wq; - int count = wordsz; - - if (wordsz <= 0) { - return (-1); - } - - while ((delim == ' ' ? isspace(**p) : **p == delim) && **pq == ' ') { - (*p)++; - (*pq)++; - } - - while (**p && - !((delim == ' ' ? isspace(**p) : **p == delim) && - **pq == ' ')) { - if (--count <= 0) { - *tmp = '\0'; - *tmpq = '\0'; - dprintf(DBG_INFO, "maximum word length %d exceeded\n", - wordsz); - return (-1); - } - *w++ = *(*p)++; - *wq++ = *(*pq)++; - } - *w = '\0'; - *wq = '\0'; - return (0); -} - -static int -parse_mapinfo_file(FILE *fp, nvlist_t **ret_nvlp) -{ - int error = 0; - nvlist_t *nvl = NULL, *attrs = NULL; - char line[LINEMAX], lineq[LINEMAX]; - char word[MAXPATHLEN+1], wordq[MAXPATHLEN+1]; - char *lp, *lq; - - if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { - return (EFAULT); - } - - while (fgets(line, sizeof (line), fp)) { - char *name, *key, *val; - - lp = (char *)line; - lq = (char *)lineq; - unquote(lp, lq); - if ((getword(word, wordq, &lp, &lq, ' ', - sizeof (word)) == -1) || (word[0] == '\0')) - continue; - - if (word[0] == '#') - continue; - - name = strtok(line, SPC); - if (name == NULL) - continue; - - (void) dprintf(DBG_INFO, "get a line for %s\n", name); - key = strtok(NULL, "="); - if (key == NULL) { - (void) dprintf(DBG_INFO, "no attributes specified for " - "%s\n", name); - continue; - } - - attrs = NULL; - if (nvlist_alloc(&attrs, NV_UNIQUE_NAME, 0) != 0) { - error = EFAULT; - goto fail1; - } - - while (key && *key) { - char *rest; - rest = strtok(NULL, "\n"); - if (rest == NULL) { - (void) dprintf(DBG_INFO, "no value for key " - "%s\n", key); - break; - } - if (rest[0] == ';') { - val = strdup("devname_null"); - rest++; - } else { - val = strtok(rest, ";"); - rest = strtok(NULL, ""); - } - (void) dprintf(DBG_INFO, "parse_map_info: one entry " - "key=%s val=%s\n", key, val); - if (nvlist_add_string(attrs, key, val) != 0) { - error = EFAULT; - goto fail; - } - - key = strtok(rest, "="); - } - (void) dprintf(DBG_INFO, "parse_map_info: add entry name=%s\n", - name); - if (nvlist_add_nvlist(nvl, name, attrs) != 0) { - error = EFAULT; - goto fail; - } - } - -done: - *ret_nvlp = nvl; - return (0); - -fail: - nvlist_free(attrs); -fail1: - nvlist_free(nvl); - return (error); -} - -void -di_devname_print_mapinfo(nvlist_t *nvl) -{ - char *name, *key, *val; - nvlist_t *attrs; - nvpair_t *nvp, *kvp; - - nvp = nvlist_next_nvpair(nvl, NULL); - while (nvp) { - name = nvpair_name(nvp); - (void) nvpair_value_nvlist(nvp, &attrs); - (void) printf("name = %s, binding attributes:\n", name); - kvp = nvlist_next_nvpair(attrs, NULL); - while (kvp) { - key = nvpair_name(kvp); - (void) nvpair_value_string(kvp, &val); - (void) printf("\t%s = %s\n", key, val); - kvp = nvlist_next_nvpair(attrs, kvp); - } - nvp = nvlist_next_nvpair(nvl, nvp); - } -} - -static int -action_mklink(char *target, char *source) -{ - (void) dprintf(DBG_INFO, "mklink for source %s target %s\n", - source, target); - return (symlink(source, target)); -} - -static struct actions { - char *key; - devname_spec_t spec; - int (*action)(char *, char *); -} actions[] = { - {"devices-path", DEVNAME_NS_PATH, action_mklink}, - {"dev-path", DEVNAME_NS_DEV, action_mklink}, - {NULL, DEVNAME_NS_NONE, NULL} -}; - -static int -action_on_key(uint_t cmd, char *dir_name, char *devname, nvpair_t *attr, - uint32_t *nsmapcount, char **devfsadm_link, devname_spec_t *devfsadm_spec) -{ - int i = 0; - int error = 0; - char *attrname, *attrval; - int len = 0; - char *path = NULL; - - attrname = nvpair_name(attr); - (void) nvpair_value_string(attr, &attrval); - (void) dprintf(DBG_INFO, "key = %s; value = %s\n", attrname, attrval); - - while (actions[i].key) { - if (strcmp(actions[i].key, attrname) == 0) { - switch (cmd) { - case DEVFSADMD_NS_READDIR: - len = strlen(dir_name) + strlen(devname) + 2; - path = malloc(len); - (void) snprintf(path, len, "%s/%s", dir_name, - devname); - error = actions[i].action(path, attrval); - free(path); - if (error) { - (void) dprintf(DBG_INFO, "action " - "failed %d\n", error); - return (error); - } else { - (*nsmapcount)++; - (void) dprintf(DBG_INFO, - "mapcount %d\n", *nsmapcount); - } - break; - case DEVFSADMD_NS_LOOKUP: - *devfsadm_link = strdup(attrval); - *devfsadm_spec = actions[i].spec; - break; - default: - break; - } - } - i++; - } - return (0); -} - -int -di_devname_action_on_key(nvlist_t *map, uint8_t cmd, char *dir_name, void *hdl) -{ - char *name = NULL; - nvpair_t *entry; - nvlist_t *attrs; - int32_t error = 0; - uint32_t ns_mapcount = 0; - char *devfsadm_link = NULL; - devname_spec_t devfsadm_spec = DEVNAME_NS_NONE; - sdev_door_res_t *resp; - - entry = nvlist_next_nvpair(map, NULL); - while (entry) { - nvpair_t *attr; - name = nvpair_name(entry); - (void) dprintf(DBG_INFO, "di_devname_action_on_key: name %s\n", - name); - (void) nvpair_value_nvlist(entry, &attrs); - - attr = nvlist_next_nvpair(attrs, NULL); - while (attr) { - error = action_on_key(cmd, dir_name, name, attr, - &ns_mapcount, &devfsadm_link, &devfsadm_spec); - - /* do not continue if encountered the first error */ - if (error) { - (void) dprintf(DBG_INFO, "error %d\n", error); - return ((int32_t)error); - } - attr = nvlist_next_nvpair(attrs, attr); - } - entry = nvlist_next_nvpair(map, entry); - } - - resp = (sdev_door_res_t *)hdl; - (void) dprintf(DBG_INFO, "cmd is %d\n", cmd); - switch (cmd) { - case DEVFSADMD_NS_READDIR: - resp->ns_rdr_hdl.ns_mapcount = (uint32_t)ns_mapcount; - (void) dprintf(DBG_INFO, "mapcount is %d\n", ns_mapcount); - break; - case DEVFSADMD_NS_LOOKUP: - if (devfsadm_link && devfsadm_spec != DEVNAME_NS_NONE) { - (void) dprintf(DBG_INFO, "devfsadm_link is %s\n", - devfsadm_link); - (void) snprintf(resp->ns_lkp_hdl.devfsadm_link, - strlen(devfsadm_link) + 1, "%s", devfsadm_link); - resp->ns_lkp_hdl.devfsadm_spec = devfsadm_spec; - } else { - (void) dprintf(DBG_INFO, "error out\n"); - return (1); - } - break; - default: - (void) dprintf(DBG_INFO, "error NOTSUP out\n"); - return (ENOTSUP); - } - - return (0); -} - - -static nvlist_t * -getent_mapinfo_file(FILE *fp, char *match) -{ - nvlist_t *nvl, *attrs; - char line[LINEMAX], lineq[LINEMAX]; - char word[MAXPATHLEN+1], wordq[MAXPATHLEN+1]; - int count = 0; - char *lp, *lq; - - if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) - return (NULL); - - while (fgets(line, sizeof (line), fp)) { - char *name, *key, *val; - - if (line[0] == '#') - continue; - - dprintf(DBG_INFO, "getent_mapinfo_file: get a line %s\n", line); - lp = (char *)line; - lq = (char *)lineq; - unquote(lp, lq); - if ((getword(word, wordq, &lp, &lq, ' ', sizeof (word)) - == -1) || (word[0] == '\0')) - continue; - - name = strtok(line, SPC); - if (name == NULL) - continue; - - dprintf(DBG_INFO, "macthing with the key %s match %s\n", - name, match); - /* bypass the non-related entries */ - if (strcmp(name, match) != 0) - continue; - - /* get a matched entry */ - key = strtok(NULL, "="); - if (key == NULL) { - (void) dprintf(DBG_INFO, "no attributes specified " - "for %s\n", name); - goto fail1; - } - - attrs = NULL; - if (nvlist_alloc(&attrs, NV_UNIQUE_NAME, 0) != 0) - goto fail1; - while (key && *key) { - char *rest; - rest = strtok(NULL, "\n"); - if (rest == NULL) { - (void) dprintf(DBG_INFO, "no value for key " - "%s\n", key); - goto fail; - } - if (rest[0] == ';') { - val = strdup("devname_null"); - rest++; - } else { - val = strtok(rest, ";"); - rest = strtok(NULL, ""); - } - (void) dprintf(DBG_INFO, "found entry %s %s for %s\n", - key, val, name); - if (nvlist_add_string(attrs, key, val) != 0) - goto fail; - - key = strtok(rest, "="); - } - (void) dprintf(DBG_INFO, "adding nvlist for %s\n", name); - if (nvlist_add_nvlist(nvl, name, attrs) != 0) - goto fail; - count++; - break; - } - - if (count == 0) - goto fail1; - - return (nvl); - -fail: - nvlist_free(attrs); -fail1: - nvlist_free(nvl); - errno = EFAULT; - return (NULL); -} - -static int -di_devname_getmapent_files(char *key, char *mapname, nvlist_t **map) -{ - FILE *fp; - int rval = 0; - nvlist_t *nvl = NULL; - - fp = open_local_map(mapname); - if (fp == NULL) - return (1); - - nvl = getent_mapinfo_file(fp, key); - if (nvl != NULL) { - *map = nvl; - } else { - rval = errno; - } - (void) fclose(fp); - - return (rval); -} - -int -di_devname_get_mapent(char *key, char *mapname, nvlist_t **map) -{ - dprintf(DBG_INFO, "di_devname_get_mapent: called for %s in %s\n", - key, mapname); - - return (di_devname_getmapent_files(key, mapname, map)); - -} - -int -di_devname_get_mapinfo(char *mapname, nvlist_t **maps) -{ - dprintf(DBG_INFO, "di_devname_get_mapinfo: called for %s\n", mapname); - - return (di_devname_get_mapinfo_files(mapname, maps)); -} - -static void -debug_print(debug_level_t msglevel, const char *fmt, va_list ap) -{ - if (devname_debug < msglevel) - return; - - /* Print a distinctive label for error msgs */ - if (msglevel == DBG_ERR) { - (void) fprintf(stderr, "[ERROR]: "); - } - - if (msglog == TRUE) { - (void) vsyslog(LOG_NOTICE, fmt, ap); - } else { - (void) vfprintf(stderr, fmt, ap); - } -} - -/* ARGSUSED */ -/* PRINTFLIKE2 */ -static void -dprintf(debug_level_t msglevel, const char *fmt, ...) -{ - va_list ap; - - assert(msglevel > 0); - - if (!devname_debug) - return; - - va_start(ap, fmt); - debug_print(msglevel, fmt, ap); - va_end(ap); -} - - -/* - * Private interfaces for non-global /dev profile - */ - -/* - * Allocate opaque data structure for passing profile to the kernel for - * the given mount point. - * - * Note that this interface returns an empty, initialized, profile. - * It does not return what may have been previously committed. - */ -int -di_prof_init(const char *mountpt, di_prof_t *profp) -{ - nvlist_t *nvl; - - if (nvlist_alloc(&nvl, 0, 0)) - return (-1); - - if (nvlist_add_string(nvl, SDEV_NVNAME_MOUNTPT, mountpt)) { - nvlist_free(nvl); - return (-1); - } - - *profp = (di_prof_t)nvl; - return (0); -} - -/* - * Free space allocated by di_prof_init(). - */ -void -di_prof_fini(di_prof_t prof) -{ - nvlist_free((nvlist_t *)prof); -} - -/* - * Sends profile to the kernel. - */ -int -di_prof_commit(di_prof_t prof) -{ - char *buf = NULL; - size_t buflen = 0; - int rv; - - if (nvlist_pack((nvlist_t *)prof, &buf, &buflen, NV_ENCODE_NATIVE, 0)) - return (-1); - rv = modctl(MODDEVNAME, MODDEVNAME_PROFILE, buf, buflen); - free(buf); - return (rv); -} - -/* - * Add a device or directory to profile's include list. - * - * Note that there is no arbitration between conflicting - * include and exclude profile entries, most recent - * is the winner. - */ -int -di_prof_add_dev(di_prof_t prof, const char *dev) -{ - if (nvlist_add_string((nvlist_t *)prof, SDEV_NVNAME_INCLUDE, dev)) - return (-1); - return (0); -} - -/* - * Add a device or directory to profile's exclude list. - * This can effectively remove a previously committed device. - */ -int -di_prof_add_exclude(di_prof_t prof, const char *dev) -{ - if (nvlist_add_string((nvlist_t *)prof, SDEV_NVNAME_EXCLUDE, dev)) - return (-1); - return (0); -} - -/* - * Add a symlink to profile. - */ -int -di_prof_add_symlink(di_prof_t prof, const char *linkname, const char *target) -{ - nvlist_t *nvl = (nvlist_t *)prof; - char *syml[2]; - - syml[0] = (char *)linkname; /* 1st entry must be the symlink */ - syml[1] = (char *)target; /* 2nd entry must be the target */ - if (nvlist_add_string_array(nvl, SDEV_NVNAME_SYMLINK, syml, 2)) - return (-1); - return (0); -} - -/* - * Add a name mapping to profile. - */ -int -di_prof_add_map(di_prof_t prof, const char *source, const char *target) -{ - nvlist_t *nvl = (nvlist_t *)prof; - char *map[2]; - - map[0] = (char *)source; /* 1st entry must be the source */ - map[1] = (char *)target; /* 2nd entry must be the target */ - if (nvlist_add_string_array(nvl, SDEV_NVNAME_MAP, map, 2)) - return (-1); - return (0); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libdevinfo/devinfo_profile.c Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,153 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <stdio.h> +#include <strings.h> +#include <unistd.h> +#include <stdarg.h> +#include <fcntl.h> +#include <stdlib.h> +#include <libnvpair.h> +#include <libdevinfo.h> +#include <syslog.h> +#include <sys/param.h> +#include <errno.h> +#include <assert.h> +#include <sys/systeminfo.h> +#include <sys/modctl.h> +#include <sys/fs/sdev_impl.h> + +/* + * Private interfaces for non-global /dev profile + */ + +/* + * Allocate opaque data structure for passing profile to the kernel for + * the given mount point. + * + * Note that this interface returns an empty, initialized, profile. + * It does not return what may have been previously committed. + */ +int +di_prof_init(const char *mountpt, di_prof_t *profp) +{ + nvlist_t *nvl; + + if (nvlist_alloc(&nvl, 0, 0)) + return (-1); + + if (nvlist_add_string(nvl, SDEV_NVNAME_MOUNTPT, mountpt)) { + nvlist_free(nvl); + return (-1); + } + + *profp = (di_prof_t)nvl; + return (0); +} + +/* + * Free space allocated by di_prof_init(). + */ +void +di_prof_fini(di_prof_t prof) +{ + nvlist_free((nvlist_t *)prof); +} + +/* + * Sends profile to the kernel. + */ +int +di_prof_commit(di_prof_t prof) +{ + char *buf = NULL; + size_t buflen = 0; + int rv; + + if (nvlist_pack((nvlist_t *)prof, &buf, &buflen, NV_ENCODE_NATIVE, 0)) + return (-1); + rv = modctl(MODDEVNAME, MODDEVNAME_PROFILE, buf, buflen); + free(buf); + return (rv); +} + +/* + * Add a device or directory to profile's include list. + * + * Note that there is no arbitration between conflicting + * include and exclude profile entries, most recent + * is the winner. + */ +int +di_prof_add_dev(di_prof_t prof, const char *dev) +{ + if (nvlist_add_string((nvlist_t *)prof, SDEV_NVNAME_INCLUDE, dev)) + return (-1); + return (0); +} + +/* + * Add a device or directory to profile's exclude list. + * This can effectively remove a previously committed device. + */ +int +di_prof_add_exclude(di_prof_t prof, const char *dev) +{ + if (nvlist_add_string((nvlist_t *)prof, SDEV_NVNAME_EXCLUDE, dev)) + return (-1); + return (0); +} + +/* + * Add a symlink to profile. + */ +int +di_prof_add_symlink(di_prof_t prof, const char *linkname, const char *target) +{ + nvlist_t *nvl = (nvlist_t *)prof; + char *syml[2]; + + syml[0] = (char *)linkname; /* 1st entry must be the symlink */ + syml[1] = (char *)target; /* 2nd entry must be the target */ + if (nvlist_add_string_array(nvl, SDEV_NVNAME_SYMLINK, syml, 2)) + return (-1); + return (0); +} + +/* + * Add a name mapping to profile. + */ +int +di_prof_add_map(di_prof_t prof, const char *source, const char *target) +{ + nvlist_t *nvl = (nvlist_t *)prof; + char *map[2]; + + map[0] = (char *)source; /* 1st entry must be the source */ + map[1] = (char *)target; /* 2nd entry must be the target */ + if (nvlist_add_string_array(nvl, SDEV_NVNAME_MAP, map, 2)) + return (-1); + return (0); +}
--- a/usr/src/lib/libdevinfo/libdevinfo.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libdevinfo/libdevinfo.h Mon Jul 20 13:07:46 2009 -0400 @@ -19,15 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _LIBDEVINFO_H #define _LIBDEVINFO_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -487,14 +485,6 @@ extern void di_dli_close(int); /* - * Private interface for parsing devname binding info - */ -extern void di_devname_print_mapinfo(nvlist_t *); -extern int di_devname_get_mapinfo(char *, nvlist_t **); -extern int di_devname_get_mapent(char *, char *, nvlist_t **); -extern int di_devname_action_on_key(nvlist_t *, uint8_t, char *, void *); - -/* * Private interface for parsing path_to_inst binding file */ extern int devfs_parse_binding_file(const char *,
--- a/usr/src/lib/libdevinfo/mapfile-vers Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libdevinfo/mapfile-vers Mon Jul 20 13:07:46 2009 -0400 @@ -187,10 +187,6 @@ di_devlink_type; di_devlink_update; di_devlink_walk; - di_devname_action_on_key; - di_devname_get_mapent; - di_devname_get_mapinfo; - di_devname_print_mapinfo; di_devperm_login; di_devperm_logout; di_dim_fini;
--- a/usr/src/lib/libelfsign/common/elfcertlib.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libelfsign/common/elfcertlib.c Mon Jul 20 13:07:46 2009 -0400 @@ -20,12 +20,10 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <limits.h> #include <sys/types.h> #include <sys/stat.h> @@ -221,7 +219,7 @@ cert->c_verified = E_UNCHECKED; /* - * If the cert we are loading it the trust anchor (ie the CA) then + * If the cert we are loading is the trust anchor (ie the CA) then * we mark it as such in cert. This is so that we don't attempt * to verify it later. The CA is always implicitly verified. */ @@ -473,12 +471,13 @@ algid = KMF_ALGID_RSA; /* - * We tell KMF to use the OpenSSL verification - * APIs here to avoid a circular dependency with - * kcfd and libpkcs11. + * We tell KMF to use the PKCS11 verification APIs + * here to prevent the use of OpenSSL and to keep + * all validation within the FIPS-140 boundary for + * the Cryptographic Framework. */ rv = KMF_VerifyDataWithCert(ess->es_kmfhandle, - KMF_KEYSTORE_OPENSSL, algid, + KMF_KEYSTORE_PK11TOKEN, algid, &indata, &insig, &cert->c_cert.certificate); return ((rv == KMF_OK));
--- a/usr/src/lib/libidmap/Makefile Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libidmap/Makefile Mon Jul 20 13:07:46 2009 -0400 @@ -25,15 +25,18 @@ include $(SRC)/lib/Makefile.lib -HDRS = idmap.h +HDRS = idmap.h directory.h HDRDIR = common SUBDIRS = $(MACH) $(BUILD64)SUBDIRS += $(MACH64) POFILE = libidmap.po -MSGFILES = `$(GREP) -l gettext common/*.[ch]` -XGETFLAGS = -a +MSGFILES:sh = echo common/*.[ch] +XGETTEXT = $(GNUXGETTEXT) +XGETFLAGS = --foreign-user --strict -n -E --width=72 \ + --omit-header --keyword=directoryError:2 \ + --language=C --force-po all := TARGET = all clean := TARGET = clean @@ -49,7 +52,7 @@ check: $(CHECKHDRS) -$(POFILE): pofile_MSGFILES +$(POFILE): $(MSGFILES) $(BUILDPO.msgfiles) _msg: $(MSGDOMAINPOFILE)
--- a/usr/src/lib/libidmap/Makefile.com Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libidmap/Makefile.com Mon Jul 20 13:07:46 2009 -0400 @@ -26,11 +26,24 @@ LIBRARY = libidmap.a VERS = .1 -OBJECTS = idmap_xdr.o utils.o idmap_api.o namemaps.o idmap_cache.o -LINT_OBJECTS = utils.o idmap_api.o namemaps.o idmap_cache.o +LINT_OBJECTS = \ + directory_client.o \ + directory_error.o \ + directory_helper.o \ + directory_rpc_clnt.o \ + sidutil.o \ + sized_array.o \ + idmap_api.o \ + idmap_cache.o \ + miscutils.o \ + namemaps.o \ + utils.o + +OBJECTS = $(LINT_OBJECTS) \ + idmap_xdr.o include ../../Makefile.lib - +C99MODE = $(C99_ENABLE) LIBS = $(DYNLIB) $(LINTLIB) LDLIBS += -lc -lldap -lsldap -lavl -ladutils -lnsl
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libidmap/common/directory.h Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,167 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _DIRECTORY_H +#define _DIRECTORY_H + +/* + * A suite of functions for retrieving information about objects + * in a directory service. + * + * Currently it is limited to retrieving SIDs from names, and vice + * versa. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> + +/* + * This bitmap is a distillation of the objectClass attribute, + * reporting those classes that Solaris finds "interesting". + * + * All undefined bits are reserved and must be ignored. + */ +#define DIRECTORY_CLASS_USER 0x0000000000000001 +#define DIRECTORY_CLASS_GROUP 0x0000000000000002 + +/* + * Opaque pointer to a directory search context. + */ +typedef struct directory *directory_t; + +/* + * Opaque pointer to a structure that describes an error. + * Note that NULL means no error. + */ +typedef struct directory_error *directory_error_t; + +/* + * Initialize a directory query session, returning in *d a directory_t + * that should be used for query transactions. + */ +directory_error_t directory_open(directory_t *d); + +/* + * Tear down a directory query session. + * There is an argument that this should return a directory_error_t, but + * then what state would the directory_t be in, and what should you do + * if you were doing the directory_close as a result of encountering an error? + * + * Does nothing if d==NULL. + */ +void directory_close(directory_t d); + +/* + * All directory_t functions return NULL on success or a pointer to a + * directory_error_t structure on failure. The caller must call + * directory_error_free() on any non-NULL directory_error_t structures returned. + * + * Strings returned from the directory_error functions are are + * invalidated when the directory_error_t itself is freed. + */ + +directory_error_t directory_error(const char *code, const char *fmt, ...); + +/* + * Determines whether this directory_error_t is an instance of the + * particular error, or a subclass of that error. + */ +boolean_t directory_error_is_instance_of(directory_error_t de, + char *error_string); + +/* + * Returns a printable version of this directory_error_t, suitable for + * human consumption. + * + * The string returned is valid as long as the directory_error_t itself is + * valid, and is freed when the directory_error_t is freed. + */ +const char *directory_error_printable(directory_error_t de); + +/* + * Returns the error code for the particular error, as a string. + * Note that this function should not normally be used to answer + * the question "did error X happen", since the value returned + * could be a subclass of X. directory_error_is_instance_of is intended + * to answer that question. This function is more appropriate for + * logging, where one would want to log the error code and the list + * of parameters so as to allow structured analysis of the error + * after the fact. + * + * The string returned is valid as long as the directory_error_t itself is + * valid, and is freed when the directory_error_t is freed. + */ +const char *directory_error_code(directory_error_t de); + +/* + * Returns one of the parameters of the directory_error_t, or NULL if + * the parameter does not exist. + * + * Note that by definition error subclasses have initial parameters + * the same as their superclasses. + * + * The string returned is valid as long as the directory_error_t itself is + * valid, and is freed when the directory_error_t is freed. + */ +const char *directory_error_param(directory_error_t de, int param); + +/* + * Frees the memory (if any) allocated for the directory_error_t. + * This frees all strings that might have been derived from this + * directory_error_t through directory_error_code, directory_error_printable, + * et cetera. + * + * Does nothing if de==NULL. + */ +void directory_error_free(directory_error_t de); + +/* + * Utility functions to look up a SID given a name, and vice versa. + * Caller must free() the result (sid or name, respectively). + */ +directory_error_t directory_sid_from_name(directory_t d, char *name, char **sid, + uint64_t *classes); +directory_error_t directory_sid_from_user_name(directory_t d, char *name, + char **sid); +directory_error_t directory_sid_from_group_name(directory_t d, char *name, + char **sid); +directory_error_t directory_name_from_sid(directory_t d, char *sid, char **name, + uint64_t *classes); +directory_error_t directory_canon_from_name(directory_t d, char *name, + char **canon, uint64_t *classes); +directory_error_t directory_canon_from_user_name(directory_t d, char *name, + char **canon); +directory_error_t directory_canon_from_group_name(directory_t d, char *name, + char **canon); + +#ifdef __cplusplus +} +#endif + +#endif /* _DIRECTORY_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libidmap/common/directory_client.c Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,366 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Directory lookup functions. These are shims that translate from the API + * into the RPC protocol. + */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <malloc.h> +#include <sys/types.h> +#include <netdb.h> +#include <pthread.h> +#include <unistd.h> +#include <string.h> +#include "directory.h" +#include "directory_private.h" +#include <rpcsvc/idmap_prot.h> +#include "directory_library_impl.h" +#include "sized_array.h" + +static directory_error_t copy_directory_attribute_value( + directory_attribute_value_t *dav, + directory_values_rpc *dav_rpc); +static directory_error_t copy_directory_entry(directory_entry_t *ent, + directory_entry_rpc *ent_rpc); +static void directory_results_free(directory_results_rpc *dr); +static directory_datum_t directory_datum(void *data, size_t len); +static void directory_datum_free(directory_datum_t d); + +/* + * This is the actual implementation of the opaque directory_t structure. + */ +struct directory { + CLIENT *client; +}; + +/* + * Set up a directory search context. + */ +directory_error_t +directory_open(directory_t *ret) +{ + directory_t d; + directory_error_t de; + char host[] = "localhost"; + + *ret = NULL; + + d = calloc(1, sizeof (*d)); + if (d == NULL) + goto nomem; + + d->client = clnt_door_create(IDMAP_PROG, IDMAP_V1, 0); + if (d->client == NULL) { + de = directory_error("clnt_create.directory_open", + "Error: %1", + clnt_spcreateerror(host), + NULL); + goto err; + } + + *ret = d; + return (NULL); + +nomem: + de = directory_error("ENOMEM.directory_open", + "Insufficient memory setting up directory access", NULL); +err: + directory_close(d); + return (de); +} + +/* + * Tear down a directory search context. + * + * Does nothing if d==NULL. + */ +void +directory_close(directory_t d) +{ + if (d == NULL) + return; + + if (d->client != NULL) + clnt_destroy(d->client); + + free(d); +} + +/* + * Given a list of identifiers, a list of their types, and a list of attributes, + * return the information. + */ +directory_error_t +directory_get_v( + directory_t d, + directory_entry_list_t *ret, + char **ids, + int nids, + char *types, + char **attr_list) +{ + int nattrs; + directory_entry_list_t del; + directory_error_t de; + directory_results_rpc dr; + idmap_utf8str_list sl_ids; + idmap_utf8str_list sl_attrs; + directory_entry_rpc *users; + int i; + enum clnt_stat cs; + + *ret = NULL; + del = NULL; + + if (nids == 0) { + for (nids = 0; ids[nids] != NULL; nids++) + /* LOOP */; + } + + for (nattrs = 0; attr_list[nattrs] != NULL; nattrs++) + /* LOOP */; + + sl_ids.idmap_utf8str_list_len = nids; + sl_ids.idmap_utf8str_list_val = ids; + sl_attrs.idmap_utf8str_list_len = nattrs; + sl_attrs.idmap_utf8str_list_val = attr_list; + + (void) memset(&dr, 0, sizeof (dr)); + cs = directory_get_common_1(sl_ids, types, sl_attrs, &dr, d->client); + if (cs != RPC_SUCCESS) { + char errbuf[100]; /* well long enough for any integer */ + (void) sprintf(errbuf, "%d", cs); + de = directory_error("RPC.Get_common", + "Get_common RPC (%1)%2", errbuf, + clnt_sperror(d->client, ""), NULL); + goto err; + } + + if (dr.failed) { + de = directory_error_from_rpc( + &dr.directory_results_rpc_u.err); + goto err; + } + + assert(dr.directory_results_rpc_u.entries.entries_len == nids); + + users = dr.directory_results_rpc_u.entries.entries_val; + + del = sized_array(nids, sizeof (directory_entry_t)); + + for (i = 0; i < nids; i++) { + de = copy_directory_entry(&del[i], &users[i]); + if (de != NULL) + goto err; + } + + directory_results_free(&dr); + + *ret = del; + return (NULL); + +err: + directory_results_free(&dr); + directory_free(del); + return (de); +} + +/* + * Free the results from a directory_get_*() request. + */ +void +directory_free(directory_entry_list_t del) +{ + directory_entry_t *ent; + directory_attribute_value_t dav; + int i; + int j; + int k; + + if (del == NULL) + return; + + /* For each directory entry returned */ + for (i = 0; i < sized_array_n(del); i++) { + ent = &del[i]; + + if (ent->attrs != NULL) { + /* For each attribute */ + for (j = 0; j < sized_array_n(ent->attrs); j++) { + dav = ent->attrs[j]; + if (dav != NULL) { + for (k = 0; k < sized_array_n(dav); k++) + directory_datum_free(dav[k]); + + sized_array_free(dav); + } + } + sized_array_free(ent->attrs); + } + + directory_error_free(ent->err); + } + + sized_array_free(del); +} + +/* + * Create a directory datum. Note that we allocate an extra byte and + * zero it, so that strings get null-terminated. Return NULL on error. + */ +static +directory_datum_t +directory_datum(void *data, size_t len) +{ + void *p; + + p = sized_array(len + 1, 1); + if (p == NULL) + return (NULL); + (void) memcpy(p, data, len); + *((char *)p + len) = '\0'; + return (p); +} + +/* + * Return the size of a directory_datum_t. Note that this does not include + * the terminating \0, so it represents the value as returned by LDAP. + */ +size_t +directory_datum_len(directory_datum_t d) +{ + /* + * Deduct the terminal \0, so that binary data gets the + * expected length. + */ + return (sized_array_n(d) - 1); +} + +static +void +directory_datum_free(directory_datum_t d) +{ + sized_array_free(d); +} + +/* + * Unmarshall an RPC directory entry into an API directory entry. + */ +static +directory_error_t +copy_directory_entry( + directory_entry_t *ent, + directory_entry_rpc *ent_rpc) +{ + int nattrs; + int i; + directory_error_t de; + + /* If the entry wasn't found, leave the entry attrs and err NULL. */ + if (ent_rpc->status == DIRECTORY_NOT_FOUND) + return (NULL); + + if (ent_rpc->status == DIRECTORY_ERROR) { + ent->err = directory_error_from_rpc( + &ent_rpc->directory_entry_rpc_u.err); + return (NULL); + } + + nattrs = ent_rpc->directory_entry_rpc_u.attrs.attrs_len; + + ent->attrs = sized_array(nattrs, sizeof (directory_attribute_value_t)); + if (ent->attrs == NULL) { + return (directory_error("ENOMEM.copy_directory_entry", + "Insufficient memory copying directory entry", NULL)); + } + for (i = 0; i < nattrs; i++) { + de = copy_directory_attribute_value(&ent->attrs[i], + &ent_rpc->directory_entry_rpc_u.attrs.attrs_val[i]); + if (de != NULL) + return (de); + } + + return (NULL); +} + +/* + * Unmarshall an RPC directory attribute value into the API equivalent. + * + * Note that on error some entries may have been copied, and so + * the caller needs to clean up dav. This is normally not a problem + * since the caller will have called this function several times and + * will need to clean up the results from the other calls too. + */ +static +directory_error_t +copy_directory_attribute_value( + directory_attribute_value_t *dav, + directory_values_rpc *dav_rpc) +{ + int i; + int nvals; + directory_value_rpc *vals; + + /* If it wasn't found, leave the corresponding entry NULL */ + if (!dav_rpc->found) + return (NULL); + + nvals = dav_rpc->directory_values_rpc_u.values.values_len; + *dav = sized_array(nvals + 1, sizeof (directory_datum_t)); + if (*dav == NULL) { + return (directory_error("ENOMEM.copy_directory_attribute_value", + "Insufficient memory copying directory entry", NULL)); + } + + vals = dav_rpc->directory_values_rpc_u.values.values_val; + for (i = 0; i < nvals; i++) { + (*dav)[i] = directory_datum(vals[i].directory_value_rpc_val, + vals[i].directory_value_rpc_len); + if ((*dav)[i] == NULL) { + return (directory_error( + "ENOMEM.copy_directory_attribute_value", + "Insufficient memory copying directory entry", + NULL)); + } + } + + return (NULL); +} + +/* + * Free the results of a directory RPC request. + */ +static +void +directory_results_free(directory_results_rpc *dr) +{ + xdr_free(xdr_directory_results_rpc, (char *)&dr); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libidmap/common/directory_error.c Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,498 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Error handling support for directory lookup. + * Actually, this is intended to be a very generic and extensible error + * reporting mechanism. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <thread.h> +#include <errno.h> +#include <stdarg.h> +#include <malloc.h> +#include <string.h> +#include <ctype.h> +#include <syslog.h> +#include <idmap_impl.h> +#include <rpcsvc/idmap_prot.h> +#include <libintl.h> +#include "directory.h" + +/* + * This is the actual implementation of the opaque directory_error_t structure. + */ +struct directory_error { + /* + * True if this directory_error_t is statically allocated. Used to + * handle out of memory errors during error reporting. + */ + boolean_t is_static; + + /* + * The error code. This is a locale-independent string that + * represents the precise error (to some level of granularity) + * that occurred. Internationalization processing could map it + * to an message. Errors may be subclassed by appending a dot + * and a name for the subclass. + * + * Note that this code plus the parameters allows for structured + * processing of error results. + */ + char *code; + + /* + * The default (in the absence of internationalization) format for + * the error message. %n interposes params[n - 1]. + */ + char *fmt; + + /* + * Parameters to the error message. Note that subclasses are + * required to have the same initial parameters as their superclasses, + * so that code that processes the superclass can work on the subclass. + */ + int nparams; + char **params; + + /* + * Cached printable form (that is, with params[] interpolated into + * fmt) of the error message. Created when requested. + */ + char *printable; +}; + +static directory_error_t directory_error_internal_error(int err); + +/* + * For debugging, reference count of directory_error instances still in + * existence. When the system is idle, this should be zero. + * Note that no attempt is made to make this MT safe, so it is not reliable + * in an MT environment. + */ +static int directory_errors_outstanding = 0; + +/* + * Free the specified directory_error_t. Note that this invalidates all strings + * returned based on it. + * + * Does nothing when de==NULL. + */ +void +directory_error_free(directory_error_t de) +{ + int i; + + if (de == NULL) + return; + + /* Don't free our internal static directory_error_ts! */ + if (de->is_static) + return; + + free(de->code); + de->code = NULL; + free(de->fmt); + de->fmt = NULL; + + /* Free parameters, if any */ + if (de->params != NULL) { + for (i = 0; i < de->nparams; i++) { + free(de->params[i]); + de->params[i] = NULL; + } + free(de->params); + de->params = NULL; + } + + /* Free cached printable */ + free(de->printable); + de->printable = NULL; + + free(de); + + directory_errors_outstanding--; +} + +/* + * de = directory_error(code, fmt [, arg1 ... ]); + * Code, fmt, and arguments must be strings and will be copied. + */ +directory_error_t +directory_error(const char *code, const char *fmt, ...) +{ + directory_error_t de = NULL; + va_list va; + int i; + + de = calloc(1, sizeof (*de)); + if (de == NULL) + goto nomem; + + directory_errors_outstanding++; + + de->is_static = B_FALSE; + + de->code = strdup(code); + if (de->code == NULL) + goto nomem; + + de->fmt = strdup(fmt); + if (de->fmt == NULL) + goto nomem; + + /* Count our parameters */ + va_start(va, fmt); + for (i = 0; va_arg(va, char *) != NULL; i++) + /* LOOP */; + va_end(va); + + de->nparams = i; + + /* + * Note that we do not copy the terminating NULL because we have + * a count. + */ + de->params = calloc(de->nparams, sizeof (char *)); + if (de->params == NULL) + goto nomem; + + va_start(va, fmt); + for (i = 0; i < de->nparams; i++) { + de->params[i] = strdup((char *)va_arg(va, char *)); + if (de->params[i] == NULL) { + va_end(va); + goto nomem; + } + } + va_end(va); + + return (de); + +nomem:; + int err = errno; + directory_error_free(de); + return (directory_error_internal_error(err)); +} + +/* + * Transform a directory_error returned by RPC into a directory_error_t. + */ +directory_error_t +directory_error_from_rpc(directory_error_rpc *de_rpc) +{ + directory_error_t de; + int i; + + de = calloc(1, sizeof (*de)); + if (de == NULL) + goto nomem; + + directory_errors_outstanding++; + + de->is_static = B_FALSE; + de->code = strdup(de_rpc->code); + if (de->code == NULL) + goto nomem; + de->fmt = strdup(de_rpc->fmt); + if (de->fmt == NULL) + goto nomem; + + de->nparams = de_rpc->params.params_len; + + de->params = calloc(de->nparams, sizeof (char *)); + if (de->params == NULL) + goto nomem; + + for (i = 0; i < de->nparams; i++) { + de->params[i] = strdup(de_rpc->params.params_val[i]); + if (de->params[i] == NULL) + goto nomem; + } + + return (de); + +nomem:; + int err = errno; + directory_error_free(de); + return (directory_error_internal_error(err)); +} + +/* + * Convert a directory_error_t into a directory_error to send over RPC. + * + * Returns TRUE on successful conversion, FALSE on failure. + * + * Frees the directory_error_t. + * + * Note that most functions in this suite return boolean_t, as defined + * by types.h. This function is intended to be used directly as the + * return value from an RPC service function, and so it returns bool_t. + */ +bool_t +directory_error_to_rpc(directory_error_rpc *de_rpc, directory_error_t de) +{ + int i; + idmap_utf8str *params; + + de_rpc->code = strdup(de->code); + if (de_rpc->code == NULL) + goto nomem; + + de_rpc->fmt = strdup(de->fmt); + if (de_rpc->fmt == NULL) + goto nomem; + + params = calloc(de->nparams, sizeof (idmap_utf8str)); + if (params == NULL) + goto nomem; + de_rpc->params.params_val = params; + de_rpc->params.params_len = de->nparams; + + for (i = 0; i < de->nparams; i++) { + params[i] = strdup(de->params[i]); + if (params[i] == NULL) + goto nomem; + } + + directory_error_free(de); + return (TRUE); + +nomem: + logger(LOG_ERR, "Warning: failed to convert error for RPC\n" + "Original error: %s\n" + "Conversion error: %s\n", + strerror(errno), + directory_error_printable(de)); + directory_error_free(de); + return (FALSE); +} + +/* + * Determines whether this directory_error_t is an instance of the + * particular error, or a subclass of that error. + */ +boolean_t +directory_error_is_instance_of(directory_error_t de, char *code) +{ + int len; + + if (de == NULL || de->code == NULL) + return (B_FALSE); + + len = strlen(code); + + if (strncasecmp(de->code, code, len) != 0) + return (B_FALSE); + + if (de->code[len] == '\0' || de->code[len] == '.') + return (B_TRUE); + + return (B_FALSE); +} + +/* + * Expand the directory_error_t in de into buf, returning the size of the + * resulting string including terminating \0. If buf is NULL, just + * return the size. + * + * Return -1 if there are no substitutions, so that the caller can + * avoid memory allocation. + */ +static +int +directory_error_expand(char *buf, directory_error_t de) +{ + int bufsiz; + boolean_t has_subst; + const char *p; + char c; + long n; + const char *s; + char *newp; + + bufsiz = 0; + has_subst = B_FALSE; + + for (p = dgettext(TEXT_DOMAIN, de->fmt); *p != '\0'; ) { + c = *p++; + if (c == '%') { + has_subst = B_TRUE; + if (isdigit(*p)) { + n = strtol(p, &newp, 10); + p = newp; + if (de->params == NULL || + n < 1 || + n > de->nparams) + s = dgettext(TEXT_DOMAIN, "(missing)"); + else + s = de->params[n - 1]; + if (buf != NULL) + (void) strcpy(buf + bufsiz, s); + bufsiz += strlen(s); + continue; + } + } + if (buf != NULL) + buf[bufsiz] = c; + bufsiz++; + } + + if (buf != NULL) + buf[bufsiz] = '\0'; + bufsiz++; + + return (has_subst ? bufsiz : -1); +} + +/* + * Returns a printable version of this directory_error_t, suitable for + * human consumption. + * + * The value returned is valid as long as the directory_error_t is valid, + * and is freed when the directory_error_t is freed. + */ +const char * +directory_error_printable(directory_error_t de) +{ + char *s; + int bufsiz; + + if (de->printable != NULL) + return (de->printable); + + bufsiz = directory_error_expand(NULL, de); + + /* + * Short circuit case to avoid memory allocation when there is + * no parameter substitution. + */ + if (bufsiz < 0) + return (dgettext(TEXT_DOMAIN, de->fmt)); + + s = malloc(bufsiz); + if (s == NULL) { + return (dgettext(TEXT_DOMAIN, + "Out of memory while expanding directory_error_t")); + } + + (void) directory_error_expand(s, de); + + /* + * Stash the expansion away for later free, and to short-circuit + * repeated expansions. + */ + de->printable = s; + + return (de->printable); +} + +/* + * Returns the error code for the particular error, as a string. + * Note that this function should not normally be used to answer + * the question "did error X happen", since the value returned + * could be a subclass of X. directory_error_is_instance_of is intended + * to answer that question. + * + * The value returned is valid as long as the directory_error_t is valid, + * and is freed when the directory_error_t is freed. + */ +const char * +directory_error_code(directory_error_t de) +{ + return (de->code); +} + +/* + * Returns one of the parameters of the directory_error_t, or NULL if + * the parameter does not exist. + * + * Note that it is required that error subclasses have initial parameters + * the same as their superclasses. + * + * The value returned is valid as long as the directory_error_t is valid, + * and is freed when the directory_error_t is freed. + */ +const char * +directory_error_param(directory_error_t de, int param) +{ + if (param >= de->nparams) + return (NULL); + return (de->params[param]); +} + +/* + * Here are some (almost) constant directory_error_t structures + * for use in reporting errors encountered while creating a + * directory_error_t structure. Unfortunately, the original error + * report is lost. + */ +#define gettext(x) x /* let xgettext see these messages */ +static struct directory_error directory_error_ENOMEM = { + B_TRUE, + "ENOMEM.directory_error_t", + gettext("Out of memory while creating a directory_error_t"), + 0, NULL, + NULL, +}; + +static struct directory_error directory_error_EAGAIN = { + B_TRUE, + "EAGAIN.directory_error_t", + gettext("Out of resources while creating a directory_error_t"), + 0, NULL, + NULL, +}; + +/* 40 is big enough for even 128 bits */ +static char directory_error_unknown_errno[40] = "0"; +static char *directory_error_unknown_params[] = { + directory_error_unknown_errno +}; +static struct directory_error directory_error_unknown = { + B_TRUE, + "Unknown.directory_error_t", + gettext("Unknown error (%1) while creating a directory_error_t"), + 1, directory_error_unknown_params, + NULL, +}; +#undef gettext + +static +directory_error_t +directory_error_internal_error(int err) +{ + switch (err) { + case ENOMEM: return (&directory_error_ENOMEM); + case EAGAIN: return (&directory_error_EAGAIN); + default: + /* Pray that we don't have a reentrancy problem ... */ + (void) sprintf(directory_error_unknown_errno, "%u", err); + return (&directory_error_unknown); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libidmap/common/directory_helper.c Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,302 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Some helper routines for directory lookup. These offer functions that + * you could implement yourself on top of the generic routines, but since + * they're a common request we implement them here. (Well, OK, we cheat a bit + * and call an internal routine to do the dirty work to reduce code + * duplication, but you could still implement them using the generic routines.) + */ + +#include <stdio.h> +#include <string.h> +#include <libadutils.h> +#include <rpcsvc/idmap_prot.h> +#include "directory.h" +#include "directory_private.h" +#include "directory_library_impl.h" +#include "miscutils.h" +#include "sidutil.h" + +/* + * Given a username, return a text-form SID. + * + * The SID must be free()ed by the caller. + * + * d, if non-NULL, specifies an existing directory-search context. + * If NULL, a temporary one will be created. + */ +directory_error_t +directory_sid_from_name_common( + directory_t d, + char *name, + char *type, + char **sid, + uint64_t *classes) +{ + directory_t d1 = NULL; + static char *attrs[] = { + "objectSid", + "objectClass", + NULL, + }; + directory_entry_t *ret_list = NULL; + directory_error_t de; + struct ret_sid { + sid_t **objectSid; + char **objectClass; + } *ret_sid; + + /* Prep for error cases. */ + *sid = NULL; + if (classes != NULL) + *classes = 0; + + if (d == NULL) { + de = directory_open(&d1); + if (de != NULL) + goto out; + } else { + d1 = d; + } + + de = directory_get_v(d1, &ret_list, &name, 1, type, attrs); + if (de != NULL) + goto out; + if (ret_list[0].err != NULL) { + de = ret_list[0].err; + ret_list[0].err = NULL; + goto out; + } + + ret_sid = (struct ret_sid *)ret_list[0].attrs; + if (ret_sid == NULL) + goto out; + + if (ret_sid->objectSid != NULL && + ret_sid->objectSid[0] != NULL) { + char text_sid[SID_STRSZ+1]; + sid_from_le(ret_sid->objectSid[0]); + sid_tostr(ret_sid->objectSid[0], text_sid); + *sid = strdup(text_sid); + if (*sid == NULL) + goto nomem; + } + + if (ret_sid->objectClass != NULL && + classes != NULL) + *classes = class_bitmap(ret_sid->objectClass); + + goto out; + +nomem: + de = directory_error("ENOMEM.directory_sid_from_name_common", + "Insufficient memory retrieving data about SID", NULL); + +out: + directory_free(ret_list); + if (d == NULL) + directory_close(d1); + return (de); +} + +directory_error_t +directory_sid_from_name( + directory_t d, + char *name, + char **sid, + uint64_t *classes) +{ + return (directory_sid_from_name_common(d, name, DIRECTORY_ID_NAME, sid, + classes)); +} + +directory_error_t +directory_sid_from_user_name(directory_t d, char *name, char **sid) +{ + return (directory_sid_from_name_common(d, name, DIRECTORY_ID_USER, sid, + NULL)); +} + +directory_error_t +directory_sid_from_group_name(directory_t d, char *name, char **sid) +{ + return (directory_sid_from_name_common(d, name, DIRECTORY_ID_GROUP, sid, + NULL)); +} + +/* + * Given a name or text-format SID, return a user@domain. + * + * The user@domain returned must be free()ed by the caller. + * + * Returns NULL and sets *name to NULL if no error occurred but the specified + * entity does not exist. + * + * d, if non-NULL, specifies an existing directory-search context. + * If NULL, a temporary one will be created. + */ +static +directory_error_t +directory_canon_common( + directory_t d, + char *id, + char *id_type, + char **canon, + uint64_t *classes) +{ + directory_t d1 = NULL; + directory_entry_t *ret_list = NULL; + directory_error_t de; + /* + * Attributes required to generate a canonical name, in named-list and + * structure form. + */ + static char *attrs[] = { + "x-sun-canonicalName", + "objectClass", + NULL, + }; + + struct canon_name_ret { + char **x_sun_canonicalName; + char **objectClass; + } *ret_name; + + /* Prep for error cases. */ + *canon = NULL; + if (classes != NULL) + *classes = 0; + + if (d == NULL) { + de = directory_open(&d1); + if (de != NULL) + goto out; + } else { + d1 = d; + } + + de = directory_get_v(d1, &ret_list, &id, 1, id_type, attrs); + if (de != NULL) + goto out; + if (ret_list[0].err != NULL) { + de = ret_list[0].err; + ret_list[0].err = NULL; + goto out; + } + + ret_name = (struct canon_name_ret *)ret_list[0].attrs; + if (ret_name == NULL) + goto out; + + if (ret_name->x_sun_canonicalName != NULL && + ret_name->x_sun_canonicalName[0] != NULL) { + *canon = strdup(ret_name->x_sun_canonicalName[0]); + if (*canon == NULL) + goto nomem; + } + + if (ret_name->objectClass != NULL && + classes != NULL) + *classes = class_bitmap(ret_name->objectClass); + + goto out; + +nomem: + de = directory_error("ENOMEM.directory_canon_common", + "Insufficient memory retrieving data about name", NULL); + +out: + directory_free(ret_list); + if (d == NULL) + directory_close(d1); + return (de); +} + +directory_error_t +directory_name_from_sid( + directory_t d, + char *sid, + char **canon, + uint64_t *classes) +{ + return (directory_canon_common(d, sid, DIRECTORY_ID_SID, canon, + classes)); +} + +directory_error_t +directory_canon_from_name( + directory_t d, + char *name, + char **canon, + uint64_t *classes) +{ + return (directory_canon_common(d, name, DIRECTORY_ID_NAME, canon, + classes)); +} + +directory_error_t +directory_canon_from_user_name(directory_t d, char *name, char **canon) +{ + return ( + directory_canon_common(d, name, DIRECTORY_ID_USER, canon, NULL)); +} + +directory_error_t +directory_canon_from_group_name(directory_t d, char *name, char **canon) +{ + return ( + directory_canon_common(d, name, DIRECTORY_ID_GROUP, canon, NULL)); +} + +boolean_t +is_in_list(char **list, char *val) +{ + for (; *list != NULL; list++) { + if (strcaseeq(*list, val)) + return (B_TRUE); + } + return (B_FALSE); +} + +uint64_t +class_bitmap(char **objectClass) +{ + uint64_t ret = 0; + + for (; *objectClass != NULL; objectClass++) { + if (strcaseeq(*objectClass, "user") || + strcaseeq(*objectClass, "posixAccount")) + ret |= DIRECTORY_CLASS_USER; + + if (strcaseeq(*objectClass, "group") || + strcaseeq(*objectClass, "posixGroup")) + ret |= DIRECTORY_CLASS_GROUP; + } + + return (ret); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libidmap/common/directory_library_impl.h Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,50 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _DIRECTORY_LIBRARY_IMPL_H +#define _DIRECTORY_LIBRARY_IMPL_H + +/* + * Internal implementation of the client side of directory lookup. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +directory_error_t directory_error_from_rpc(directory_error_rpc *de_rpc); +bool_t directory_error_to_rpc(directory_error_rpc *de_rpc, + directory_error_t de); + + +directory_error_t directory_get_v(directory_t d, directory_entry_list_t *ret, + char **ids, int nids, char *types, char **attr_list); + +#ifdef __cplusplus +} +#endif + +#endif /* _DIRECTORY_LIBRARY_IMPL_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libidmap/common/directory_private.h Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,101 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _DIRECTORY_PRIVATE_H +#define _DIRECTORY_PRIVATE_H + +/* + * A suite of functions for retrieving information about objects + * in a directory service. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> + +#define DIRECTORY_ID_NAME "n" +#define DIRECTORY_ID_USER "u" +#define DIRECTORY_ID_GROUP "g" +#define DIRECTORY_ID_SID "s" + +/* + * Structure of the returned data. + * Note that this is constructed from the bottom up; what is returned is + * a directory_entry_list_t. + */ +typedef void *directory_datum_t; +typedef directory_datum_t *directory_attribute_value_t; +typedef struct { + directory_attribute_value_t *attrs; + directory_error_t err; +} directory_entry_t; +typedef directory_entry_t *directory_entry_list_t; + +/* + * Retrieve information about a user or group. By way of analogy to exec(2), + * the _v variants accept a list of attributes as an array, while + * the _l variants accept the attribute list as arguments. + * All variations accept a list of identifiers, and return a + * directory_entry_list_t in the same order. The length of the list of user + * identifiers can be specified either explicitly, or by a terminating + * NULL if the associated count is zero. Attributes are returned in the + * order they were requested, with missing attributes yielding NULL + * entries. + */ +directory_error_t directory_get_v(directory_t d, directory_entry_list_t *ret, + char **ids, int nids, char *types, char **attrlist); + +directory_error_t directory_get_l(directory_t d, directory_entry_list_t *ret, + char **ids, int nids, char *types, char *attr1, ...); + +/* + * Free the data structure returned by directory_get_by*(). + * + * Does nothing if list==NULL. + */ +void directory_free(directory_entry_list_t list); + +/* Return the number of bytes in a directory_datum_t */ +size_t directory_datum_len(directory_datum_t d); + +/* + * Search a list, case-insensitively, for a string + */ +boolean_t is_in_list(char **list, char *value); + +/* + * Examine an objectClass list and distill it into a bitmap of "interesting" + * classes. + */ +uint64_t class_bitmap(char **objectClass); + +#ifdef __cplusplus +} +#endif + +#endif /* _DIRECTORY_PRIVATE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libidmap/common/directory_rpc_clnt.c Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,57 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * RPC shims for directory lookup. Originally generated using rpcgen. + */ + +#include <memory.h> /* for memset */ +#include <rpcsvc/idmap_prot.h> +#ifndef _KERNEL +#include <stdio.h> +#include <stdlib.h> /* getenv, exit */ +#endif /* !_KERNEL */ + +/* Default timeout can be changed using clnt_control() */ +static struct timeval TIMEOUT = { 25, 0 }; + +enum clnt_stat +directory_get_common_1( + idmap_utf8str_list ids, + idmap_utf8str types, + idmap_utf8str_list attrs, + directory_results_rpc *clnt_res, + CLIENT *clnt) +{ + directory_get_common_1_argument arg; + arg.ids = ids; + arg.attrs = attrs; + arg.types = types; + return (clnt_call(clnt, DIRECTORY_GET_COMMON, + (xdrproc_t)xdr_directory_get_common_1_argument, (caddr_t)&arg, + (xdrproc_t)xdr_directory_results_rpc, (caddr_t)clnt_res, + TIMEOUT)); +}
--- a/usr/src/lib/libidmap/common/idmap_api.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libidmap/common/idmap_api.c Mon Jul 20 13:07:46 2009 -0400 @@ -2072,9 +2072,9 @@ for (i = 0; stattable[i].msg; i++) { if (stattable[i].retcode == status) - return (gettext(stattable[i].msg)); + return (dgettext(TEXT_DOMAIN, stattable[i].msg)); } - return (gettext("Unknown error")); + return (dgettext(TEXT_DOMAIN, "Unknown error")); }
--- a/usr/src/lib/libidmap/common/idmap_impl.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libidmap/common/idmap_impl.h Mon Jul 20 13:07:46 2009 -0400 @@ -134,6 +134,7 @@ extern idmap_stat idmap_get_prop_str(idmap_handle_t *, idmap_prop_type, char **); +extern idmap_logger logger; #ifdef __cplusplus }
--- a/usr/src/lib/libidmap/common/llib-lidmap Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libidmap/common/llib-lidmap Mon Jul 20 13:07:46 2009 -0400 @@ -19,13 +19,17 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* LINTLIBRARY */ /* PROTOLIB1 */ #include "idmap_impl.h" +#include "miscutils.h" +#include "directory.h" +#include "directory_private.h" +#include "sized_array.h" +#include "directory_library_impl.h" +#include "sidutil.h"
--- a/usr/src/lib/libidmap/common/mapfile-vers Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libidmap/common/mapfile-vers Mon Jul 20 13:07:46 2009 -0400 @@ -40,70 +40,105 @@ SUNWprivate { global: - xdr_idmap_retcode; + directory_canon_from_group_name; + directory_canon_from_name; + directory_canon_from_user_name; + directory_close; + directory_error; + directory_error_code; + directory_error_free; + directory_error_from_rpc; + directory_error_is_instance_of; + directory_error_param; + directory_error_printable; + directory_error_to_rpc; + directory_free; + directory_get_v; + directory_name_from_sid; + directory_open; + directory_sid_from_group_name; + directory_sid_from_name; + directory_sid_from_user_name; + idmap_cache_get_data; + idmap_fini; + idmap_fini_namemaps; + idmap_free; + idmap_getext_gidbysid; + idmap_getext_pidbysid; + idmap_getext_sidbygid; + idmap_getext_sidbyuid; + idmap_getext_uidbysid; + idmap_getgidbywinname; + idmap_getuidbywinname; + idmap_getwinnamebygid; + idmap_getwinnamebyuid; + idmap_get_create; + idmap_get_destroy; + idmap_get_gidbysid; + idmap_get_mappings; + idmap_get_namemap; + idmap_get_pidbysid; + idmap_get_sidbygid; + idmap_get_sidbyuid; + idmap_get_u2w_mapping; + idmap_get_uidbysid; + idmap_get_w2u_mapping; + idmap_info_cpy; + idmap_info_free; + idmap_info_mov; + idmap_init; + idmap_init_namemaps; + idmap_iter_destroy; + idmap_iter_mappings; + idmap_iter_namerules; + idmap_iter_next_mapping; + idmap_iter_next_namerule; + idmap_namerule_cpy; + idmap_set_logger; + idmap_set_namemap; + idmap_stat2string; + idmap_stat4prot; + idmap_string2stat; + idmap_udt_add_namerule; + idmap_udt_commit; + idmap_udt_create; + idmap_udt_destroy; + idmap_udt_flush_namerules; + idmap_udt_get_conflict_rule; + idmap_udt_get_error_index; + idmap_udt_get_error_rule; + idmap_udt_rm_namerule; + idmap_unset_namemap; + memdup; + sid_free; + sid_from_le; + sid_fromstr; + sid_len; + sid_to_le; + sid_tostr; + sized_array; + sized_array_free; + sized_array_n; + strcaseeq; + streq; + strndup; + xdr_directory_entry_rpc; + xdr_directory_get_common_1_argument; + xdr_directory_results_rpc; + xdr_idmap_ids_res; + xdr_idmap_id_res; + xdr_idmap_list_mappings_1_argument; + xdr_idmap_list_namerules_1_argument; + xdr_idmap_mapping; + xdr_idmap_mappings_res; + xdr_idmap_mapping_batch; xdr_idmap_namerule; xdr_idmap_namerules_res; - xdr_idmap_ids_res; - xdr_idmap_mapping_batch; - xdr_idmap_list_mappings_1_argument; - xdr_idmap_mappings_res; - xdr_idmap_update_batch; - xdr_idmap_list_namerules_1_argument; - xdr_idmap_mapping; - xdr_idmap_id_res; - xdr_idmap_update_res; xdr_idmap_prop_res; xdr_idmap_prop_type; - idmap_init; - idmap_fini; - idmap_free; - idmap_stat2string; - idmap_string2stat; - idmap_stat4prot; - idmap_iter_namerules; - idmap_iter_next_namerule; - idmap_iter_mappings; - idmap_iter_next_mapping; - idmap_iter_destroy; - idmap_get_create; - idmap_get_uidbysid; - idmap_get_gidbysid; - idmap_get_pidbysid; - idmap_get_sidbyuid; - idmap_get_sidbygid; - idmap_get_mappings; - idmap_get_destroy; - idmap_get_w2u_mapping; - idmap_get_u2w_mapping; - idmap_udt_add_namerule; - idmap_udt_rm_namerule; - idmap_udt_destroy; - idmap_udt_commit; - idmap_udt_create; - idmap_udt_get_error_index; - idmap_udt_get_error_rule; - idmap_udt_get_conflict_rule; - idmap_udt_flush_namerules; - idmap_getwinnamebyuid; - idmap_getwinnamebygid; - idmap_getuidbywinname; - idmap_getgidbywinname; - idmap_namerule_cpy; - idmap_info_free; - idmap_info_cpy; - idmap_info_mov; - idmap_getext_sidbygid; - idmap_getext_uidbysid; - idmap_getext_pidbysid; - idmap_getext_gidbysid; - idmap_getext_sidbyuid; - idmap_set_namemap; - idmap_unset_namemap; - idmap_get_namemap; - idmap_init_namemaps; - idmap_fini_namemaps; - idmap_cache_get_data; - idmap_set_logger; + xdr_idmap_retcode; + xdr_idmap_update_batch; + xdr_idmap_update_res; local: *; };
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libidmap/common/miscutils.c Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,124 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Miscellaneous utility functions not specifically related to + * the application. + */ + +#include <string.h> +#include <sys/types.h> +#include <stdarg.h> +#include <stdio.h> +#include <malloc.h> +#include <ctype.h> +#include "miscutils.h" + +/* Return true if strings are equal */ +boolean_t +streq(const char *a, const char *b) +{ + return (strcmp(a, b) == 0); +} + +/* Return true if strings are equal, case-insensitively */ +boolean_t +strcaseeq(const char *a, const char *b) +{ + return (strcasecmp(a, b) == 0); +} + +/* Return true if string a Begins With string b */ +boolean_t +strbw(const char *a, const char *b) +{ + return (strncmp(a, b, strlen(b)) == 0); +} + +/* + * Duplicate up to n bytes of a string. Kind of sort of like + * strdup(strlcpy(s, n)). + */ +char * +strndup(const char *s, int n) +{ + int len; + char *p; + + len = strnlen(s, n); + p = malloc(len + 1); + if (p == NULL) + return (NULL); + + if (len > 0) + (void) memcpy(p, s, len); + p[len] = '\0'; + + return (p); +} + +/* + * Duplicate a block of memory. Combines malloc with memcpy, much as + * strdup combines malloc, strlen, and strcpy. + */ +void * +memdup(const void *buf, size_t sz) +{ + void *p; + + p = malloc(sz); + if (p == NULL) + return (NULL); + (void) memcpy(p, buf, sz); + return (p); +} + +/* + * Dump a block of memory in hex+ascii, for debugging + */ +void +dump(FILE *out, const char *prefix, const void *buf, size_t len) +{ + const unsigned char *p = buf; + int i; + + for (i = 0; i < len; i += 16) { + int j; + + (void) fprintf(out, "%s", prefix); + for (j = 0; j < 16 && i + j < len; j++) { + (void) fprintf(out, "%2.2x ", p[i + j]); + } + for (; j < 16; j++) { + (void) fprintf(out, " "); + } + for (j = 0; j < 16 && i + j < len; j++) { + (void) fprintf(out, "%c", + isprint(p[i + j]) ? p[i + j] : '.'); + } + (void) fprintf(out, "\n"); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libidmap/common/miscutils.h Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,51 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _MISCUTILS_H +#define _MISCUTILS_H + +/* + * Miscellaneous functions and macros not directly related to the application. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define NELEM(a) (sizeof (a) / sizeof ((a)[0])) + +boolean_t strcaseeq(const char *a, const char *b); +boolean_t streq(const char *a, const char *b); +char *strndup(const char *s, int n); +boolean_t strbw(const char *a, const char *b); +void *memdup(const void *buf, size_t sz); +void dump(FILE *out, const char *prefix, const void *buf, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* _MISCUTILS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libidmap/common/sidutil.c Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,189 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * This is an extract from usr/src/common/smbsrv/smb_sid.c, + * with functions renamed as part of a tentative plan for convergence. + */ +#ifndef _KERNEL +#include <stdio.h> +#include <strings.h> +#include <stdlib.h> +#include <syslog.h> +#else /* _KERNEL */ +#include <sys/types.h> +#include <sys/sunddi.h> +#endif /* _KERNEL */ + +#include <sidutil.h> + +/* + * sid_len + * + * Returns the number of bytes required to hold the sid. + */ +int +sid_len(sid_t *sid) +{ + if (sid == NULL) + return (0); + + return (sizeof (sid_t) - sizeof (uint32_t) + + (sid->sid_subauthcnt * sizeof (uint32_t))); +} + +/* + * sid_tostr + * + * Fill in the passed buffer with the string form of the given + * binary sid. + */ +void +sid_tostr(sid_t *sid, char *strsid) +{ + char *p = strsid; + int i; + + if (sid == NULL || strsid == NULL) + return; + + (void) sprintf(p, "S-%d-", sid->sid_revision); + while (*p) + p++; + + for (i = 0; i < NT_SID_AUTH_MAX; ++i) { + if (sid->sid_authority[i] != 0 || i == NT_SID_AUTH_MAX - 1) { + (void) sprintf(p, "%d", sid->sid_authority[i]); + while (*p) + p++; + } + } + + for (i = 0; i < sid->sid_subauthcnt && i < NT_SID_SUBAUTH_MAX; ++i) { + (void) sprintf(p, "-%u", sid->sid_subauth[i]); + while (*p) + p++; + } +} + +/* + * sid_fromstr + * + * Converts a SID in string form to a SID structure. There are lots of + * simplifying assumptions in here. The memory for the SID is allocated + * as if it was the largest possible SID; the caller is responsible for + * freeing the memory when it is no longer required. We assume that the + * string starts with "S-1-" and that the authority is held in the last + * byte, which should be okay for most situations. It also assumes the + * sub-authorities are in decimal format. + * + * On success, a pointer to a SID is returned. Otherwise a null pointer + * is returned. + */ +sid_t * +sid_fromstr(char *sidstr) +{ + sid_t *sid; + char *p; + int size; + uint8_t i; + + if (sidstr == NULL) + return (NULL); + + if (strncmp(sidstr, "S-1-", 4) != 0) + return (NULL); + + size = sizeof (sid_t) + (NT_SID_SUBAUTH_MAX * sizeof (uint32_t)); + + if ((sid = malloc(size)) == NULL) + return (NULL); + + bzero(sid, size); + sid->sid_revision = NT_SID_REVISION; + sid->sid_authority[5] = atoi(&sidstr[4]); + + for (i = 0, p = &sidstr[5]; i < NT_SID_SUBAUTH_MAX && *p; ++i) { + while (*p && *p == '-') + ++p; + + if (*p < '0' || *p > '9') { + free(sid); + return (NULL); + } + + sid->sid_subauth[i] = strtoul(p, NULL, 10); + + while (*p && *p != '-') + ++p; + } + + sid->sid_subauthcnt = i; + return (sid); +} + +void +sid_free(sid_t *sid) +{ +#ifdef _KERNEL + if (sid == NULL) + return; + + kmem_free(sid, sid_len(sid)); +#else + free(sid); +#endif +} + +void +sid_to_le(sid_t *sid) +{ + int i; + + for (i = 0; i < sid->sid_subauthcnt && i < NT_SID_SUBAUTH_MAX; ++i) { + uint32_t v = sid->sid_subauth[i]; + uint8_t *p = (uint8_t *)&sid->sid_subauth[i]; + + p[0] = v & 0xff; + p[1] = (v >> 8) & 0xff; + p[2] = (v >> 16) & 0xff; + p[3] = (v >> 24) & 0xff; + } +} + +void +sid_from_le(sid_t *sid) +{ + int i; + + for (i = 0; i < sid->sid_subauthcnt && i < NT_SID_SUBAUTH_MAX; ++i) { + uint32_t v; + uint8_t *p = (uint8_t *)&sid->sid_subauth[i]; + + v = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); + + sid->sid_subauth[i] = v; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libidmap/common/sidutil.h Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,123 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SIDUTIL_H +#define _SIDUTIL_H + +/* + * Security Identifier (SID) interface definition. + * + * This is an extract from uts/common/smbsrv/smb_sid.h, with functions + * renamed as part of a tentative plan for convergence. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Common definition for a SID. + */ +#define NT_SID_REVISION 1 +#define NT_SID_AUTH_MAX 6 +#define NT_SID_SUBAUTH_MAX 15 + +#if !defined(ANY_SIZE_ARRAY) +#define ANY_SIZE_ARRAY 1 +#endif + +/* + * Security Identifier (SID) + * + * The security identifier (SID) uniquely identifies a user, group or + * a domain. It consists of a revision number, the identifier authority, + * and a list of sub-authorities. The revision number is currently 1. + * The identifier authority identifies which system issued the SID. The + * sub-authorities of a domain SID uniquely identify a domain. A user + * or group SID consists of a domain SID with the user or group id + * appended. The user or group id (also known as a relative id (RID) + * uniquely identifies a user within a domain. A user or group SID + * uniquely identifies a user or group across all domains. The SidType + * values identify the various types of SID. + * + * 1 1 1 1 1 1 + * 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +---------------------------------------------------------------+ + * | SubAuthorityCount |Reserved1 (SBZ)| Revision | + * +---------------------------------------------------------------+ + * | IdentifierAuthority[0] | + * +---------------------------------------------------------------+ + * | IdentifierAuthority[1] | + * +---------------------------------------------------------------+ + * | IdentifierAuthority[2] | + * +---------------------------------------------------------------+ + * | | + * +- - - - - - - - SubAuthority[] - - - - - - - - -+ + * | | + * +---------------------------------------------------------------+ + * + */ +/* + * Note: NT defines the Identifier Authority as a separate + * structure (SID_IDENTIFIER_AUTHORITY) containing a literal + * definition of a 6 byte vector but the effect is the same + * as defining it as a member value. + */ +typedef struct sid { + uint8_t sid_revision; + uint8_t sid_subauthcnt; + uint8_t sid_authority[NT_SID_AUTH_MAX]; + uint32_t sid_subauth[ANY_SIZE_ARRAY]; +} sid_t; + +/* + * The maximum size of a SID in string format + */ +#define SID_STRSZ 256 + +/* Given a SID, return its length in bytes. */ +int sid_len(sid_t *); + +/* Given a dynamically allocated SID (e.g. from sid_fromstr), free it. */ +void sid_free(sid_t *); + +/* Translate a binary-format SID into the supplied SID_STRSZ buffer. */ +void sid_tostr(sid_t *, char *); + +/* Translate a text-format SID into an allocated binary-format SID. */ +sid_t *sid_fromstr(char *); + +/* In-place, translate a host-order SID into MS-native little endian. */ +void sid_to_le(sid_t *); + +/* In-place, translate a MS-native little endian SID into host order. */ +void sid_from_le(sid_t *); + +#ifdef __cplusplus +} +#endif + + +#endif /* _SIDUTIL_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libidmap/common/sized_array.c Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,122 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Much like calloc, but with functions to report the size of the + * allocation given only the pointer. + */ + +#include <assert.h> +#include <string.h> +#include <malloc.h> +#include "sized_array.h" + +/* + * Assumes that int is at least 32 bits and that nothing needs more than + * 8-byte alignment. + */ + +/* COOKIE provides some bad-pointer protection. */ +#define COOKIE "SACOOKIE" + +struct sized_array { + int n; + int sz; +#if defined(COOKIE) + char cookie[8]; +#endif +}; + + +void * +sized_array(size_t n, size_t sz) +{ + struct sized_array *sa; + size_t total; + + total = sizeof (struct sized_array) + n*sz; + + sa = malloc(total); + + if (sa == NULL) + return (NULL); + + (void) memset(sa, 0, total); + + sa->n = n; + sa->sz = sz; + +#if defined(COOKIE) + (void) memcpy(sa->cookie, COOKIE, sizeof (sa->cookie)); +#endif + + return ((void *)(sa + 1)); +} + +void +sized_array_free(void *p) +{ + struct sized_array *sa; + + if (p == NULL) + return; + + sa = ((struct sized_array *)p)-1; + +#if defined(COOKIE) + assert(memcmp(sa->cookie, COOKIE, sizeof (sa->cookie)) == 0); +#endif + + free(sa); +} + +size_t +sized_array_n(void *p) +{ + struct sized_array *sa; + + sa = ((struct sized_array *)p)-1; + +#if defined(COOKIE) + assert(memcmp(sa->cookie, COOKIE, sizeof (sa->cookie)) == 0); +#endif + + return (sa->n); +} + +size_t +sized_array_sz(void *p) +{ + struct sized_array *sa; + + sa = ((struct sized_array *)p)-1; + +#if defined(COOKIE) + assert(memcmp(sa->cookie, COOKIE, sizeof (sa->cookie)) == 0); +#endif + + return (sa->sz); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libidmap/common/sized_array.h Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,48 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SIZED_ARRAY_H +#define _SIZED_ARRAY_H + +/* + * Like calloc, but with mechanisms to get the size of the allocated + * area given only the pointer. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +void *sized_array(size_t n, size_t sz); +void sized_array_free(void *p); +size_t sized_array_n(void *p); +size_t sized_array_sz(void *p); + +#ifdef __cplusplus +} +#endif + +#endif /* _SIZED_ARRAY_H */
--- a/usr/src/lib/libkmf/libkmf/common/certop.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libkmf/libkmf/common/certop.c Mon Jul 20 13:07:46 2009 -0400 @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <stdio.h> #include <link.h> #include <fcntl.h> @@ -955,12 +953,14 @@ * where we want to force this operation to happen in * a specific keystore. * For example: - * libelfsign verifies signatures on crypto libraries. - * We cannot use libpkcs11 functions to verify the pkcs11 - * libraries because it results in a circular dependency. - * So, when libelfsign is verifying library sigs, it - * always forces the operation to happen in OpenSSL - * to avoid the circular dependency. + * libelfsign.so.1 verifies signatures on crypto libraries. + * We must use pkcs11 functions to verify the pkcs11 + * plugins in order to keep the validation within the + * Cryptographic Framework's FIPS-140 boundary. To avoid + * a circular dependency, pksc11_softtoken.so.1 is + * interposed by libkcfd.so.1 via kcfd, which prevents + * libpkcs11.so.1's interfaces from being used when libkmf.so.1 + * is called from kcfd. */ static KMF_RETURN plugin_verify_data_with_cert(KMF_HANDLE_T handle, @@ -976,8 +976,6 @@ /* * If NSS, use PKCS#11, we are not accessing the database(s), * we just prefer the "verify" operation from the crypto framework. - * The OpenSSL version is unique in order to avoid a dependency loop - * with the kcfd(1M) process. */ if (kstype == KMF_KEYSTORE_NSS) kstype = KMF_KEYSTORE_PK11TOKEN; @@ -3109,9 +3107,8 @@ /* * Use a signer cert to verify another certificate's signature. - * This code forces the use of the OPENSSL mechanism - * for the verify operation to avoid a circular dependency - * with libelfsign when it attempts to verify the PKCS#11 libraries. + * This code forces the use of the PKCS11 mechanism for the verify + * operation for the Cryptographic Framework's FIPS-140 boundary. */ static KMF_RETURN verify_cert_with_cert(KMF_HANDLE_T handle, @@ -3172,11 +3169,10 @@ } /* - * To avoid recursion with kcfd consumer and libpkcs11, - * do the certificate verification using the OpenSSL - * plugin algorithms instead of the crypto framework. + * Force use of PKCS11 API for kcfd/libelfsign. This is + * required for the Cryptographic Framework's FIPS-140 boundary. */ - ret = plugin_verify_data_with_cert(handle, KMF_KEYSTORE_OPENSSL, + ret = plugin_verify_data_with_cert(handle, KMF_KEYSTORE_PK11TOKEN, algid, &data_to_verify, &signature, SignerCertData); cleanup:
--- a/usr/src/lib/libkmf/libkmf/common/generalop.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libkmf/libkmf/common/generalop.c Mon Jul 20 13:07:46 2009 -0400 @@ -19,13 +19,11 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <stdio.h> #include <dlfcn.h> #include <link.h> @@ -329,7 +327,13 @@ free(p); return (KMF_ERR_MEMORY); } - p->dldesc = dlopen(path, RTLD_LAZY | RTLD_GROUP | RTLD_PARENT); + /* + * Do not use RTLD_GROUP here, or this will cause a circular + * dependency when kmf_pkcs11.so.1 gets its PKCS#11 functions + * from libpkcs11.so.1 when kmf is used via libelfsign.so.1 + * called from kcfd. + */ + p->dldesc = dlopen(path, RTLD_LAZY | RTLD_PARENT); if (p->dldesc == NULL) { free(p->path); free(p);
--- a/usr/src/lib/libpkg/common/isdir.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libpkg/common/isdir.c Mon Jul 20 13:07:46 2009 -0400 @@ -20,7 +20,7 @@ */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -40,6 +40,7 @@ #include <string.h> #include "pkglocale.h" #include "pkglibmsgs.h" +#include "pkglib.h" /* * Defines for cpio/compression checks. @@ -77,6 +78,7 @@ int isdir(char *path); int isfile(char *dir, char *file); int iscpio(char *path, int *iscomp); +int eval_ftype(char *path, char ftype, char *myftype); /* * Name: isdir @@ -389,3 +391,83 @@ (void) fclose(fp); } + +/* + * Name: eval_ftype + * Description: Evaluate the target's file type + * Arguments: path - Path on filesystem + * ftype - Type to be changed to + * myftype - Address into which current + * type of target will be stored + * Returns: int + * 0 - Success + * VE_EXIST - Path does not exist + * VE_FTYPE - Path file type is not recognized, + * is not supported, + * or is not what is expected + */ +int +eval_ftype(char *path, char ftype, char *myftype) +{ + struct stat status; + int retcode = 0; + int statError = 0; + + /* If we are to process symlinks the old way then we follow the link */ + if (nonABI_symlinks()) { + if ((ftype == 's') ? lstat(path, &status) : + stat(path, &status)) { + (void) reperr(pkg_gt(ERR_EXIST)); + retcode = VE_EXIST; + *myftype = '?'; + statError++; + } + /* If not then we inspect the target of the link */ + } else { + if (lstat(path, &status) == -1) { + reperr(pkg_gt(ERR_EXIST)); + retcode = VE_EXIST; + *myftype = '?'; + statError++; + } + } + if (!statError) { + /* determining actual type of existing object */ + switch (status.st_mode & S_IFMT) { + case S_IFLNK: + *myftype = 's'; + break; + + case S_IFIFO: + *myftype = 'p'; + break; + + case S_IFCHR: + *myftype = 'c'; + break; + + case S_IFDIR: + *myftype = 'd'; + break; + + case S_IFBLK: + *myftype = 'b'; + break; + + case S_IFREG: + case 0: + *myftype = 'f'; + break; + + case S_IFDOOR: + *myftype = 'D'; + break; + + default: + *myftype = '?'; + return (VE_FTYPE); + } + retcode = 0; + } + return (retcode); +}
--- a/usr/src/lib/libpkg/common/mapfile-vers Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libpkg/common/mapfile-vers Mon Jul 20 13:07:46 2009 -0400 @@ -89,6 +89,7 @@ epclose; epopen; esystem; + eval_ftype; find_ca_certs; find_cl_certs; find_key_cert_pair;
--- a/usr/src/lib/libpkg/common/pkglib.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libpkg/common/pkglib.h Mon Jul 20 13:07:46 2009 -0400 @@ -499,10 +499,12 @@ extern void ds_putinfo(char *buf); extern void ds_skiptoend(char *device); extern void ecleanup(void); +extern int eval_ftype(char *path, char ftype, char *myftype); /*PRINTFLIKE1*/ extern void logerr(char *fmt, ...); extern int mappath(int flag, char *path); extern int mapvar(int flag, char *varname); +extern void reperr(char *fmt, ...); /*PRINTFLIKE1*/ extern void progerr(char *fmt, ...); extern void pkgerr(PKG_ERR *); @@ -626,6 +628,7 @@ extern int isPathRemote(); extern int iscpio(); extern int isdir(); +extern int eval_ftype(); extern int isfile(); extern int pkgexecl(); extern int pkgexecv(); @@ -653,6 +656,7 @@ extern void ds_skiptoend(); extern void ecleanup(); extern void logerr(); +extern void reperr(); extern int mappath(); extern int mapvar(); extern void progerr();
--- a/usr/src/lib/libpkg/common/verify.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libpkg/common/verify.c Mon Jul 20 13:07:46 2009 -0400 @@ -85,7 +85,7 @@ } CHECKSUM_T; /*PRINTFLIKE1*/ -static void +void reperr(char *fmt, ...) { char *pt; @@ -392,7 +392,6 @@ int uid, gid; int dochown; int retcode; - int statError = 0; int targ_is_dir = 0; /* replacing a directory */ char myftype; char buf[PATH_MAX]; @@ -491,62 +490,19 @@ retcode = 0; - /* If we are to process symlinks the old way then we follow the link */ - if (nonABI_symlinks()) { - if ((*ftype == 's') ? lstat(path, &status) : - stat(path, &status)) { - reperr(pkg_gt(ERR_EXIST)); - retcode = VE_EXIST; - myftype = '?'; - statError++; - } - /* If not then we inspect the target of the link */ - } else { - if ((n = lstat(path, &status)) == -1) { - reperr(pkg_gt(ERR_EXIST)); - retcode = VE_EXIST; - myftype = '?'; - statError++; - } - } - if (!statError) { - /* determining actual type of existing object */ - switch (status.st_mode & S_IFMT) { - case S_IFLNK: - myftype = 's'; - break; + /* Evaluate the file type of existing object */ + retcode = eval_ftype(path, *ftype, &myftype); - case S_IFIFO: - myftype = 'p'; - break; - - case S_IFCHR: - myftype = 'c'; - break; - - case S_IFDIR: - myftype = 'd'; - targ_is_dir = 1; - break; + /* + * If path file type is not recognized, is not supported or + * is not what is expected, return + */ + if (retcode == VE_FTYPE) + return (retcode); - case S_IFBLK: - myftype = 'b'; - break; - - case S_IFREG: - case 0: - myftype = 'f'; - break; - - case S_IFDOOR: - myftype = 'D'; - break; - - default: - reperr(pkg_gt(ERR_UNKNOWN)); - return (VE_FTYPE); - } - } + /* If existing type is Directory, then set flag */ + if (myftype == 'd') + targ_is_dir = 1; if (setval) { /*
--- a/usr/src/lib/libproc/common/libproc.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libproc/common/libproc.h Mon Jul 20 13:07:46 2009 -0400 @@ -359,8 +359,6 @@ int, int, int, void *, int *); extern int pr_processor_bind(struct ps_prochandle *, idtype_t, id_t, int, int *); -extern int pr_pset_bind(struct ps_prochandle *, - int, idtype_t, id_t, int *); /* * Function prototypes for accessing per-LWP register information.
--- a/usr/src/lib/libproc/common/llib-lproc Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libproc/common/llib-lproc Mon Jul 20 13:07:46 2009 -0400 @@ -22,7 +22,7 @@ /* PROTOLIB1 */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "libproc.h" @@ -304,7 +304,6 @@ /* pr_pbind.c */ int pr_processor_bind(struct ps_prochandle *Pr, idtype_t, id_t, int, int *); -int pr_pset_bind(struct ps_prochandle *Pr, int, idtype_t, id_t, int *); /* pr_rename.c */ int pr_rename(struct ps_prochandle *Pr, const char *old, const char *new);
--- a/usr/src/lib/libproc/common/mapfile-vers Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libproc/common/mapfile-vers Mon Jul 20 13:07:46 2009 -0400 @@ -220,7 +220,6 @@ proc_walk; pr_open; pr_processor_bind; - pr_pset_bind; pr_rename; pr_setitimer; pr_setprojrctl;
--- a/usr/src/lib/libproc/common/pr_pbind.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libproc/common/pr_pbind.c Mon Jul 20 13:07:46 2009 -0400 @@ -2,9 +2,8 @@ * 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. + * Common Development and Distribution License (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. @@ -20,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <sys/procset.h> #include <sys/processor.h> @@ -90,66 +87,3 @@ } return (rval.sys_rval1); } - -int -pr_pset_bind(struct ps_prochandle *Pr, int pset, idtype_t idtype, id_t id, - int *opset) -{ - sysret_t rval; /* return value */ - argdes_t argd[5]; /* arg descriptors */ - argdes_t *adp = &argd[0]; /* first argument */ - int error; - - if (Pr == NULL) /* no subject process */ - return (pset_bind(pset, idtype, id, opset)); - - adp->arg_value = PSET_BIND; /* PSET_BIND */ - adp->arg_object = NULL; - adp->arg_type = AT_BYVAL; - adp->arg_inout = AI_INPUT; - adp->arg_size = 0; - adp++; - - adp->arg_value = pset; /* pset */ - adp->arg_object = NULL; - adp->arg_type = AT_BYVAL; - adp->arg_inout = AI_INPUT; - adp->arg_size = 0; - adp++; - - adp->arg_value = idtype; /* idtype */ - adp->arg_object = NULL; - adp->arg_type = AT_BYVAL; - adp->arg_inout = AI_INPUT; - adp->arg_size = 0; - adp++; - - adp->arg_value = id; /* id */ - adp->arg_object = NULL; - adp->arg_type = AT_BYVAL; - adp->arg_inout = AI_INPUT; - adp->arg_size = 0; - adp++; - - if (opset == NULL) { - adp->arg_value = 0; /* opset */ - adp->arg_object = NULL; - adp->arg_type = AT_BYVAL; - adp->arg_inout = AI_INPUT; - adp->arg_size = 0; - } else { - adp->arg_value = 0; - adp->arg_object = opset; - adp->arg_type = AT_BYREF; - adp->arg_inout = AI_INOUT; - adp->arg_size = sizeof (int); - } - - error = Psyscall(Pr, &rval, SYS_pset, 5, &argd[0]); - - if (error) { - errno = (error < 0)? ENOSYS : error; - return (-1); - } - return (rval.sys_rval1); -}
--- a/usr/src/lib/libstmf/common/libstmf.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libstmf/common/libstmf.h Mon Jul 20 13:07:46 2009 -0400 @@ -129,6 +129,7 @@ STMF_LU_PROP_FILENAME, STMF_LU_PROP_GUID, STMF_LU_PROP_META_FILENAME, + STMF_LU_PROP_MGMT_URL, STMF_LU_PROP_NEW, STMF_LU_PROP_SIZE, STMF_LU_PROP_WRITE_PROTECT,
--- a/usr/src/lib/libstmf/common/libstmf_impl.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libstmf/common/libstmf_impl.h Mon Jul 20 13:07:46 2009 -0400 @@ -55,6 +55,8 @@ uint32_t companyId; boolean_t luAliasValid; char luAlias[256]; + boolean_t luMgmtUrlValid; + char luMgmtUrl[1024]; boolean_t vidValid; char vid[8]; boolean_t pidValid;
--- a/usr/src/lib/libstmf/common/stmf.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/libstmf/common/stmf.c Mon Jul 20 13:07:46 2009 -0400 @@ -1078,6 +1078,7 @@ int metaFileNameLen = 0; int serialNumLen = 0; int luAliasLen = 0; + int luMgmtUrlLen = 0; int sluBufSize = 0; int bufOffset = 0; int fd = 0; @@ -1117,6 +1118,11 @@ sluBufSize += luAliasLen + 1; } + if (disk->luMgmtUrlValid) { + luMgmtUrlLen = strlen(disk->luMgmtUrl); + sluBufSize += luMgmtUrlLen + 1; + } + /* * 8 is the size of the buffer set aside for * concatenation of variable length fields @@ -1161,6 +1167,14 @@ bufOffset += luAliasLen + 1; } + if (disk->luMgmtUrlValid) { + sbdLu->slu_mgmt_url_valid = 1; + sbdLu->slu_mgmt_url_off = bufOffset; + bcopy(disk->luMgmtUrl, &(sbdLu->slu_buf[bufOffset]), + luMgmtUrlLen + 1); + bufOffset += luMgmtUrlLen + 1; + } + if (disk->luSizeValid) { sbdLu->slu_lu_size_valid = 1; sbdLu->slu_lu_size = disk->luSize; @@ -1665,6 +1679,7 @@ switch (prop) { case STMF_LU_PROP_ALIAS: case STMF_LU_PROP_SIZE: + case STMF_LU_PROP_MGMT_URL: case STMF_LU_PROP_WRITE_PROTECT: case STMF_LU_PROP_WRITE_CACHE_DISABLE: return (STMF_STATUS_SUCCESS); @@ -1680,6 +1695,7 @@ { int ret = STMF_STATUS_SUCCESS; int luAliasLen = 0; + int luMgmtUrlLen = 0; int mluBufSize = 0; int bufOffset = 0; int fd = 0; @@ -1710,6 +1726,11 @@ mluBufSize += luAliasLen + 1; } + if (disk->luMgmtUrlValid) { + luMgmtUrlLen = strlen(disk->luMgmtUrl); + mluBufSize += luMgmtUrlLen + 1; + } + /* * 8 is the size of the buffer set aside for * concatenation of variable length fields @@ -1732,6 +1753,14 @@ bufOffset += luAliasLen + 1; } + if (disk->luMgmtUrlValid) { + sbdLu->mlu_mgmt_url_valid = 1; + sbdLu->mlu_mgmt_url_off = bufOffset; + bcopy(disk->luMgmtUrl, &(sbdLu->mlu_buf[bufOffset]), + luMgmtUrlLen + 1); + bufOffset += luMgmtUrlLen + 1; + } + if (disk->luSizeValid) { sbdLu->mlu_lu_size_valid = 1; sbdLu->mlu_lu_size = disk->luSize; @@ -2123,6 +2152,16 @@ diskLu->serialNum, sbdProps->slp_serial_size); } + if (sbdProps->slp_mgmt_url_valid) { + diskLu->luMgmtUrlValid = B_TRUE; + if (strlcpy(diskLu->luMgmtUrl, + (char *)&(sbdProps->slp_buf[sbdProps->slp_mgmt_url_off]), + sizeof (diskLu->luMgmtUrl)) >= + sizeof (diskLu->luMgmtUrl)) { + return (STMF_STATUS_ERROR); + } + } + if (sbdProps->slp_alias_valid) { diskLu->luAliasValid = B_TRUE; if (strlcpy(diskLu->luAlias, @@ -2250,6 +2289,16 @@ return (STMF_ERROR_INVALID_ARG); } break; + case STMF_LU_PROP_MGMT_URL: + if (diskLu->luMgmtUrlValid == B_FALSE) { + return (STMF_ERROR_NO_PROP); + } + if ((reqLen = strlcpy(propVal, diskLu->luMgmtUrl, + *propLen)) >= *propLen) { + *propLen = reqLen + 1; + return (STMF_ERROR_INVALID_ARG); + } + break; case STMF_LU_PROP_GUID: if (diskLu->luGuidValid == B_FALSE) { return (STMF_ERROR_NO_PROP); @@ -2463,6 +2512,14 @@ } diskLu->luMetaFileNameValid = B_TRUE; break; + case STMF_LU_PROP_MGMT_URL: + if ((strlcpy(diskLu->luMgmtUrl, propVal, + sizeof (diskLu->luMgmtUrl))) >= + sizeof (diskLu->luMgmtUrl)) { + return (STMF_ERROR_INVALID_PROPSIZE); + } + diskLu->luMgmtUrlValid = B_TRUE; + break; case STMF_LU_PROP_PID: if ((propSize = strlen(propVal)) > sizeof (diskLu->pid)) { @@ -3076,9 +3133,8 @@ } (*groupList)->cnt = stmfIoctl.stmf_obuf_nentries; for (i = 0; i < stmfIoctl.stmf_obuf_nentries; i++) { - bcopy(iGroupList->name, (*groupList)->name[i], + bcopy(iGroupList[i].name, (*groupList)->name[i], sizeof (stmfGroupName)); - iGroupList++; } done: @@ -3224,10 +3280,9 @@ (*groupProps)->cnt = stmfIoctl.stmf_obuf_nentries; for (i = 0; i < stmfIoctl.stmf_obuf_nentries; i++) { (*groupProps)->name[i].identLength = - iGroupMembers->ident_size; - bcopy(iGroupMembers->ident, (*groupProps)->name[i].ident, - iGroupMembers->ident_size); - iGroupMembers++; + iGroupMembers[i].ident_size; + bcopy(iGroupMembers[i].ident, (*groupProps)->name[i].ident, + iGroupMembers[i].ident_size); } done:
--- a/usr/src/lib/pkcs11/Makefile Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/pkcs11/Makefile Mon Jul 20 13:07:46 2009 -0400 @@ -35,7 +35,8 @@ SUBDIRS = \ libpkcs11 \ - libsoftcrypto + libsoftcrypto \ + libkcfd # # The PKCS11 TPM provider is only available for x86.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/pkcs11/libkcfd/Makefile Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,47 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# lib/pkcs11/libkcfd/Makefile +# + +include $(SRC)/lib/Makefile.lib + +SUBDIRS= $(MACH) + +all := TARGET= all +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install + +.KEEP_STATE: + +all clean clobber install: $(SUBDIRS) + +check lint install_h: + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/pkcs11/libkcfd/Makefile.com Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,40 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# lib/pkcs11/libkcfd/Makefile.com +# + +LIBRARY = libkcfd.a +VERS = .1 + +include $(SRC)/lib/Makefile.rootfs + +LIBS += $(LINTLIB) + +# +# Identify that this library is an interposer. This identification +# ensures that runtime symbol lookup resolves to this library +# (before libpkcs11.so.1) regardless of dependency link order. +# This library should only be linked to by kcfd. +# +DYNFLAGS += $(ZINTERPOSE) -R/usr/lib/security
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/pkcs11/libkcfd/README Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,37 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +This is a filter library that's used exclusively by kcfd; +it's 32-bit-only because kcfd is 32-bit-only. + +libkcfd forces interposition of pkcs11_softtoken.so.1 into libkmf +when used by kcfd as part of the Cryptographic Framework's FIPS-140 +project, to ensure that only pkcs11_softtoken.so.1 is used for +validation of the FIPS-140 boundary. + +libelfsign could not be the interposer, because it would prevent +the elfsign(1) command from accessing actual PKCS#11 tokens when using +the -T option.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/pkcs11/libkcfd/common/llib-lkcfd Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,34 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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 + */ +/* LINTLIBRARY */ +/* PROTOLIB1 */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * usr/src/lib/pkcs11/libkcfd + * EMPTY library + */ + +#include <security/cryptoki.h>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/pkcs11/libkcfd/common/mapfile-vers Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,112 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# MAPFILE HEADER START +# +# WARNING: STOP NOW. DO NOT MODIFY THIS FILE. +# Object versioning must comply with the rules detailed in +# +# usr/src/lib/README.mapfiles +# +# You should not be making modifications here until you've read the most current +# copy of that file. If you need help, contact a gatekeeper for guidance. +# +# MAPFILE HEADER END +# + +SUNW_1.1 { + global: + C_CancelFunction = FUNCTION FILTER pkcs11_softtoken.so.1; + C_CloseAllSessions = FUNCTION FILTER pkcs11_softtoken.so.1; + C_CloseSession = FUNCTION FILTER pkcs11_softtoken.so.1; + C_CopyObject = FUNCTION FILTER pkcs11_softtoken.so.1; + C_CreateObject = FUNCTION FILTER pkcs11_softtoken.so.1; + C_Decrypt = FUNCTION FILTER pkcs11_softtoken.so.1; + C_DecryptDigestUpdate = FUNCTION FILTER pkcs11_softtoken.so.1; + C_DecryptFinal = FUNCTION FILTER pkcs11_softtoken.so.1; + C_DecryptInit = FUNCTION FILTER pkcs11_softtoken.so.1; + C_DecryptUpdate = FUNCTION FILTER pkcs11_softtoken.so.1; + C_DecryptVerifyUpdate = FUNCTION FILTER pkcs11_softtoken.so.1; + C_DeriveKey = FUNCTION FILTER pkcs11_softtoken.so.1; + C_DestroyObject = FUNCTION FILTER pkcs11_softtoken.so.1; + C_Digest = FUNCTION FILTER pkcs11_softtoken.so.1; + C_DigestEncryptUpdate = FUNCTION FILTER pkcs11_softtoken.so.1; + C_DigestFinal = FUNCTION FILTER pkcs11_softtoken.so.1; + C_DigestInit = FUNCTION FILTER pkcs11_softtoken.so.1; + C_DigestKey = FUNCTION FILTER pkcs11_softtoken.so.1; + C_DigestUpdate = FUNCTION FILTER pkcs11_softtoken.so.1; + C_Encrypt = FUNCTION FILTER pkcs11_softtoken.so.1; + C_EncryptFinal = FUNCTION FILTER pkcs11_softtoken.so.1; + C_EncryptInit = FUNCTION FILTER pkcs11_softtoken.so.1; + C_EncryptUpdate = FUNCTION FILTER pkcs11_softtoken.so.1; + C_Finalize = FUNCTION FILTER pkcs11_softtoken.so.1; + C_FindObjects = FUNCTION FILTER pkcs11_softtoken.so.1; + C_FindObjectsFinal = FUNCTION FILTER pkcs11_softtoken.so.1; + C_FindObjectsInit = FUNCTION FILTER pkcs11_softtoken.so.1; + C_GenerateKey = FUNCTION FILTER pkcs11_softtoken.so.1; + C_GenerateKeyPair = FUNCTION FILTER pkcs11_softtoken.so.1; + C_GenerateRandom = FUNCTION FILTER pkcs11_softtoken.so.1; + C_GetAttributeValue = FUNCTION FILTER pkcs11_softtoken.so.1; + C_GetFunctionList = FUNCTION FILTER pkcs11_softtoken.so.1; + C_GetFunctionStatus = FUNCTION FILTER pkcs11_softtoken.so.1; + C_GetInfo = FUNCTION FILTER pkcs11_softtoken.so.1; + C_GetMechanismInfo = FUNCTION FILTER pkcs11_softtoken.so.1; + C_GetMechanismList = FUNCTION FILTER pkcs11_softtoken.so.1; + C_GetObjectSize = FUNCTION FILTER pkcs11_softtoken.so.1; + C_GetOperationState = FUNCTION FILTER pkcs11_softtoken.so.1; + C_GetSessionInfo = FUNCTION FILTER pkcs11_softtoken.so.1; + C_GetSlotInfo = FUNCTION FILTER pkcs11_softtoken.so.1; + C_GetSlotList = FUNCTION FILTER pkcs11_softtoken.so.1; + C_GetTokenInfo = FUNCTION FILTER pkcs11_softtoken.so.1; + C_Initialize = FUNCTION FILTER pkcs11_softtoken.so.1; + C_InitPIN = FUNCTION FILTER pkcs11_softtoken.so.1; + C_InitToken = FUNCTION FILTER pkcs11_softtoken.so.1; + C_Login = FUNCTION FILTER pkcs11_softtoken.so.1; + C_Logout = FUNCTION FILTER pkcs11_softtoken.so.1; + C_OpenSession = FUNCTION FILTER pkcs11_softtoken.so.1; + C_SeedRandom = FUNCTION FILTER pkcs11_softtoken.so.1; + C_SetAttributeValue = FUNCTION FILTER pkcs11_softtoken.so.1; + C_SetOperationState = FUNCTION FILTER pkcs11_softtoken.so.1; + C_SetPIN = FUNCTION FILTER pkcs11_softtoken.so.1; + C_Sign = FUNCTION FILTER pkcs11_softtoken.so.1; + C_SignEncryptUpdate = FUNCTION FILTER pkcs11_softtoken.so.1; + C_SignFinal = FUNCTION FILTER pkcs11_softtoken.so.1; + C_SignInit = FUNCTION FILTER pkcs11_softtoken.so.1; + C_SignRecover = FUNCTION FILTER pkcs11_softtoken.so.1; + C_SignRecoverInit = FUNCTION FILTER pkcs11_softtoken.so.1; + C_UnwrapKey = FUNCTION FILTER pkcs11_softtoken.so.1; + C_Verify = FUNCTION FILTER pkcs11_softtoken.so.1; + C_VerifyFinal = FUNCTION FILTER pkcs11_softtoken.so.1; + C_VerifyInit = FUNCTION FILTER pkcs11_softtoken.so.1; + C_VerifyRecover = FUNCTION FILTER pkcs11_softtoken.so.1; + C_VerifyRecoverInit = FUNCTION FILTER pkcs11_softtoken.so.1; + C_VerifyUpdate = FUNCTION FILTER pkcs11_softtoken.so.1; + C_WaitForSlotEvent = FUNCTION FILTER pkcs11_softtoken.so.1; + C_WrapKey = FUNCTION FILTER pkcs11_softtoken.so.1; + local: + *; +}; +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/pkcs11/libkcfd/i386/Makefile Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,34 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# lib/pkcs11/libkcfd/i386/Makefile +# + +include $(SRC)/lib/Makefile.filter.com +include ../Makefile.com + +install: all $(ROOTLIBDIR) .WAIT $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) + +include $(SRC)/lib/Makefile.filter.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/pkcs11/libkcfd/sparc/Makefile Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,34 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# lib/pkcs11/libkcfd/sparc/Makefile +# + +include $(SRC)/lib/Makefile.filter.com +include ../Makefile.com + +install: all $(ROOTLIBDIR) .WAIT $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) + +include $(SRC)/lib/Makefile.filter.targ
--- a/usr/src/lib/smbsrv/libmlrpc/common/libmlrpc.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/smbsrv/libmlrpc/common/libmlrpc.h Mon Jul 20 13:07:46 2009 -0400 @@ -245,7 +245,7 @@ typedef struct ndr_pipe { int np_fid; - smb_opipe_context_t np_ctx; + smb_netuserinfo_t np_user; char *np_buf; struct uio np_uio; iovec_t np_iov; @@ -516,7 +516,6 @@ int ndr_pipe_close(int); int ndr_pipe_read(int, uint8_t *, uint32_t *, uint32_t *); int ndr_pipe_write(int, uint8_t *, uint32_t); -int ndr_pipe_getinfo(int, ndr_pipe_info_t *); int ndr_generic_call_stub(ndr_xa_t *);
--- a/usr/src/lib/smbsrv/libmlrpc/common/mapfile-vers Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/smbsrv/libmlrpc/common/mapfile-vers Mon Jul 20 13:07:46 2009 -0400 @@ -67,7 +67,6 @@ ndr_mbtowc; ndr_native_os; ndr_params; - ndr_pipe_getinfo; ndr_pipe_open; ndr_pipe_close; ndr_pipe_read;
--- a/usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c Mon Jul 20 13:07:46 2009 -0400 @@ -89,7 +89,7 @@ return (ENOMEM); } - if (smb_opipe_context_decode(&np->np_ctx, data, datalen, NULL) == -1) { + if (smb_netuserinfo_decode(&np->np_user, data, datalen, NULL) == -1) { ndr_pipe_release(np); (void) mutex_unlock(&ndr_pipe_lock); return (EINVAL); @@ -257,37 +257,6 @@ } /* - * Return information about the specified pipe. - */ -int -ndr_pipe_getinfo(int ndx, ndr_pipe_info_t *npi) -{ - ndr_pipe_t *np; - - if ((ndx < 0) || (ndx >= NDR_PIPE_MAX) || (npi == NULL)) - return (-1); - - (void) mutex_lock(&ndr_pipe_lock); - np = &ndr_pipe_table[ndx]; - - if (np->np_fid == 0) { - (void) mutex_unlock(&ndr_pipe_lock); - return (-1); - } - - npi->npi_fid = np->np_fid; - npi->npi_permissions = FILE_READ_DATA | FILE_WRITE_DATA | FILE_EXECUTE; - npi->npi_num_locks = 0; - (void) snprintf(npi->npi_username, MAXNAMELEN, "%s\\%s", - np->np_ctx.oc_domain, np->np_ctx.oc_account); - (void) snprintf(npi->npi_pathname, MAXPATHLEN, "%s", - np->np_binding->service->sec_addr_port); - - (void) mutex_unlock(&ndr_pipe_lock); - return (0); -} - -/* * Must be called with ndr_pipe_lock held. */ static ndr_pipe_t * @@ -365,9 +334,9 @@ ndr_pipe_rewind(np); ndr_pipe_flush(np); free(np->np_buf); - free(np->np_ctx.oc_domain); - free(np->np_ctx.oc_account); - free(np->np_ctx.oc_workstation); + free(np->np_user.ui_domain); + free(np->np_user.ui_account); + free(np->np_user.ui_workstation); bzero(np, sizeof (ndr_pipe_t)); } } @@ -412,9 +381,9 @@ boolean_t ndr_is_admin(ndr_xa_t *xa) { - smb_opipe_context_t *ctx = &xa->pipe->np_ctx; + smb_netuserinfo_t *ctx = &xa->pipe->np_user; - return (ctx->oc_flags & SMB_ATF_ADMIN); + return (ctx->ui_flags & SMB_ATF_ADMIN); } /* @@ -426,18 +395,18 @@ boolean_t ndr_is_poweruser(ndr_xa_t *xa) { - smb_opipe_context_t *ctx = &xa->pipe->np_ctx; + smb_netuserinfo_t *ctx = &xa->pipe->np_user; - return ((ctx->oc_flags & SMB_ATF_ADMIN) || - (ctx->oc_flags & SMB_ATF_POWERUSER)); + return ((ctx->ui_flags & SMB_ATF_ADMIN) || + (ctx->ui_flags & SMB_ATF_POWERUSER)); } int32_t ndr_native_os(ndr_xa_t *xa) { - smb_opipe_context_t *ctx = &xa->pipe->np_ctx; + smb_netuserinfo_t *ctx = &xa->pipe->np_user; - return (ctx->oc_native_os); + return (ctx->ui_native_os); } /*
--- a/usr/src/lib/smbsrv/libmlsvc/common/eventlog.h Tue Jul 14 11:18:27 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _eventlog_H -#define _eventlog_H - -#include <netdb.h> -#include <smbsrv/libsmb.h> -#include <smbsrv/ndl/eventlog.ndl> - -#ifdef __cplusplus -extern "C" { -#endif - -#define LOGR_NMSGMASK 1023 - -typedef struct logr_entry { - struct timeval le_timestamp; /* Time of log entry */ - int le_pri; /* Message priority */ - char le_hostname[MAXHOSTNAMELEN]; /* Log hostname */ - char le_msg[LOGR_MAXENTRYLEN]; /* Log message text */ -} logr_entry_t; - -typedef struct logr_info { - logr_entry_t li_entry[LOGR_NMSGMASK+1]; /* Array of log entry */ - int li_idx; /* Index */ -} logr_info_t; - -typedef struct logr_read_data { - int rd_tot_recnum; /* Total no. of record read */ - int rd_last_sentrec; /* Last sentence read */ - char rd_first_read; /* First sentence read */ - logr_info_t *rd_log; /* Log information read */ -} logr_read_data_t; - -/* This structure provides the context for eventlog calls from clients. */ -typedef struct logr_context { - logr_read_data_t *lc_cached_read_data; - char *lc_source_name; -} logr_context_t; - -int logr_syslog_snapshot(logr_info_t *); - -#ifdef __cplusplus -} -#endif - -#endif /* _eventlog_H */
--- a/usr/src/lib/smbsrv/libmlsvc/common/eventlog_svc.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/smbsrv/libmlsvc/common/eventlog_svc.c Mon Jul 20 13:07:46 2009 -0400 @@ -29,15 +29,15 @@ #include <sys/utsname.h> #include <unistd.h> #include <strings.h> - #include <smbsrv/libsmb.h> #include <smbsrv/libmlrpc.h> #include <smbsrv/ntstatus.h> #include <smbsrv/nmpipes.h> #include <smbsrv/libmlsvc.h> -#include "eventlog.h" +#include <smbsrv/ndl/eventlog.ndl> #include <smbsrv/nterror.h> + #define LOGR_FWD +1 #define LOGR_REW -1 #define LOGR_RECORD_SIGNATURE 0x654C664C @@ -162,8 +162,6 @@ logr_stub_table /* stub_table */ }; -static int logr_get_snapshot(logr_context_t *); - /* * logr_initialize * @@ -175,6 +173,13 @@ logr_initialize(void) { (void) ndr_svc_register(&logr_service); + logr_init(); +} + +void +logr_finalize(void) +{ + logr_fini(); } /* @@ -222,12 +227,12 @@ } /* - * logr_mgr_hdalloc + * logr_hdalloc * * Handle allocation wrapper to setup the local manager context. */ static ndr_hdid_t * -logr_hdalloc(ndr_xa_t *mxa) +logr_hdalloc(ndr_xa_t *mxa, char *logname) { logr_context_t *ctx; @@ -235,8 +240,13 @@ return (NULL); bzero(ctx, sizeof (logr_context_t)); - ctx->lc_source_name = strdup("eventlog"); - if ((ctx->lc_source_name != NULL) && (logr_get_snapshot(ctx) < 0)) { + ctx->lc_source_name = strdup(logname); + if (ctx->lc_source_name == NULL) { + free(ctx); + return (NULL); + } + + if (logr_get_snapshot(ctx) != 0) { free(ctx->lc_source_name); free(ctx); return (NULL); @@ -287,16 +297,22 @@ ndr_handle_t *hd; char *log_name = NULL; - if (param->log_name.length != 0) - log_name = (char *)param->log_name.str; - - if ((log_name == NULL) || strcasecmp(log_name, "System") != 0) { + if (!ndr_is_admin(mxa)) { bzero(¶m->handle, sizeof (logr_handle_t)); param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED); return (NDR_DRC_OK); } - id = logr_hdalloc(mxa); + if (param->log_name.length != 0) + log_name = (char *)param->log_name.str; + + if (!logr_is_supported(log_name)) { + bzero(¶m->handle, sizeof (logr_handle_t)); + param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED); + return (NDR_DRC_OK); + } + + id = logr_hdalloc(mxa, log_name); if (id && ((hd = logr_hdlookup(mxa, id)) != NULL)) { hd->nh_data_free = logr_context_data_free; bcopy(id, ¶m->handle, sizeof (logr_handle_t)); @@ -310,42 +326,6 @@ } /* - * logr_get_snapshot - * - * Allocate memory and make a copy, as a snapshot, from system log. - */ -static int -logr_get_snapshot(logr_context_t *ctx) -{ - logr_read_data_t *data = NULL; - - ctx->lc_cached_read_data = malloc(sizeof (logr_read_data_t)); - if (ctx->lc_cached_read_data != NULL) { - data = ctx->lc_cached_read_data; - - data->rd_log = (logr_info_t *)malloc(sizeof (logr_info_t)); - if (data->rd_log == NULL) { - free(data); - return (-1); - } - bzero(data->rd_log, sizeof (logr_info_t)); - - data->rd_tot_recnum = logr_syslog_snapshot(data->rd_log); - if (data->rd_tot_recnum < 0) { - free(data->rd_log); - free(data); - return (-1); - } - - data->rd_first_read = 1; - - return (0); - } - - return (-1); -} - -/* * logr_s_EventLogQueryCount * * take a snapshot from system log, assign it to the given handle.
--- a/usr/src/lib/smbsrv/libmlsvc/common/eventlog_syslog.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/smbsrv/libmlsvc/common/eventlog_syslog.c Mon Jul 20 13:07:46 2009 -0400 @@ -32,11 +32,13 @@ #include <string.h> #include <strings.h> #include <stdarg.h> +#include <dlfcn.h> #include <sys/synch.h> #include <sys/stat.h> #include <sys/errno.h> #include <ctype.h> -#include "eventlog.h" +#include <smbsrv/ndl/eventlog.ndl> +#include <smbsrv/libmlsvc.h> typedef enum { LOGR_MONTH = 0, @@ -77,6 +79,12 @@ char ln_logline[LOGR_MAXENTRYLEN]; } logr_syslog_node_t; +static void *logr_interposer_hdl = NULL; +static struct { + boolean_t (*logr_op_supported)(char *); + int (*logr_op_snapshot)(logr_context_t *); +} logr_interposer_ops; + /* * Set the syslog timestamp. * @@ -289,12 +297,12 @@ * provided by the caller. Returns the number of entries in * the log. */ -int -logr_syslog_snapshot(logr_info_t *loginfo) +static int +logr_syslog_snapshot(char *logname, logr_info_t *loginfo) { FILE *fp; - if (loginfo == NULL) + if ((loginfo == NULL) || (!logr_is_supported(logname))) return (-1); if ((fp = fopen("/var/adm/messages", "r")) == 0) @@ -311,3 +319,107 @@ return (LOGR_NMSGMASK+1); } + +/* + * logr_is_supported + * + * Determines if a given log is supported or not. + * Returns B_TRUE on success, B_FALSE on failure. + */ +boolean_t +logr_is_supported(char *log_name) +{ + if (log_name == NULL) + return (B_FALSE); + + if (logr_interposer_ops.logr_op_supported != NULL) + return (logr_interposer_ops.logr_op_supported(log_name)); + + if (strcasecmp(log_name, LOGR_SYSTEM_LOG) != 0) + return (B_FALSE); + + return (B_TRUE); +} + +/* + * logr_get_snapshot + * + * Allocate memory and make a copy, as a snapshot, from system log. + * Returns 0 on success, -1 on failure. + */ +int +logr_get_snapshot(logr_context_t *ctx) +{ + logr_read_data_t *data = NULL; + + if (logr_interposer_ops.logr_op_snapshot != NULL) + return (logr_interposer_ops.logr_op_snapshot(ctx)); + + ctx->lc_cached_read_data = malloc(sizeof (logr_read_data_t)); + if (ctx->lc_cached_read_data != NULL) { + data = ctx->lc_cached_read_data; + + data->rd_log = (logr_info_t *)malloc(sizeof (logr_info_t)); + if (data->rd_log == NULL) { + free(data); + return (-1); + } + bzero(data->rd_log, sizeof (logr_info_t)); + + data->rd_tot_recnum = logr_syslog_snapshot(ctx->lc_source_name, + data->rd_log); + if (data->rd_tot_recnum < 0) { + free(data->rd_log); + free(data); + return (-1); + } + + data->rd_first_read = 1; + + return (0); + } + + return (-1); +} + +/* + * logr_init + * + * Initializes the Eventlog service. + * Checks to see if a event log utility library + * is interposed. If yes then it'll initializes logr_interposer_ops + * structure with function pointers from this library. + */ +void +logr_init(void) +{ + logr_interposer_hdl = smb_dlopen(); + if (logr_interposer_hdl == NULL) + return; + + bzero((void *)&logr_interposer_ops, sizeof (logr_interposer_ops)); + + logr_interposer_ops.logr_op_supported = + (boolean_t (*)())dlsym(logr_interposer_hdl, "logr_is_supported"); + + logr_interposer_ops.logr_op_snapshot = + (int (*)())dlsym(logr_interposer_hdl, "logr_get_snapshot"); + + if (logr_interposer_ops.logr_op_supported == NULL || + logr_interposer_ops.logr_op_snapshot == NULL) + logr_fini(); +} + +/* + * logr_fini + * + * Finalizes the Eventlog service. + * Closes handle to interposed library. + */ +void +logr_fini(void) +{ + smb_dlclose(logr_interposer_hdl); + logr_interposer_hdl = NULL; + bzero((void *)&logr_interposer_ops, sizeof (logr_interposer_ops)); +}
--- a/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h Mon Jul 20 13:07:46 2009 -0400 @@ -26,12 +26,15 @@ #ifndef _LIBMLSVC_H #define _LIBMLSVC_H +#include <uuid/uuid.h> #include <sys/param.h> #include <sys/types.h> #include <sys/uio.h> #include <sys/ksynch.h> #include <stdio.h> #include <string.h> +#include <netdb.h> +#include <libuutil.h> #include <smbsrv/wintypes.h> #include <smbsrv/hash_table.h> #include <smbsrv/smb_token.h> @@ -59,12 +62,9 @@ extern boolean_t smb_domain_getinfo(smb_domain_t *); -extern uint64_t mlsvc_get_num_users(void); -extern int mlsvc_get_user_list(smb_ulist_t *); extern void dssetup_clear_domain_info(void); extern int mlsvc_init(void); extern void mlsvc_fini(void); -extern int mlsvc_set_share(int, char *, char *); extern DWORD mlsvc_netlogon(char *, char *); extern DWORD mlsvc_join(smb_domain_t *, char *, char *); @@ -126,6 +126,21 @@ } ms_luid_t; /* + * Information about a server as reported by NetServerGetInfo. + * The SV_PLATFORM and SV_TYPE definitions are in srvsvc.ndl. + */ +typedef struct srvsvc_server_info { + uint32_t sv_platform_id; + char *sv_name; + uint32_t sv_version_major; + uint32_t sv_version_minor; + uint32_t sv_type; + char *sv_comment; +} srvsvc_server_info_t; + +int srvsvc_net_server_getinfo(char *, char *, srvsvc_server_info_t *); + +/* * A client_t is created while binding a client connection to hold the * context for calls made using that connection. * @@ -137,11 +152,14 @@ ndr_hdid_t handle; ndr_client_t *clnt; int remote_os; + srvsvc_server_info_t svinfo; } mlsvc_handle_t; int ndr_rpc_bind(mlsvc_handle_t *, char *, char *, char *, const char *); void ndr_rpc_unbind(mlsvc_handle_t *); int ndr_rpc_call(mlsvc_handle_t *, int, void *); +void ndr_rpc_server_setinfo(mlsvc_handle_t *, const srvsvc_server_info_t *); +void ndr_rpc_server_getinfo(mlsvc_handle_t *, srvsvc_server_info_t *); int ndr_rpc_server_os(mlsvc_handle_t *); void *ndr_rpc_malloc(mlsvc_handle_t *, size_t); ndr_heap_t *ndr_rpc_get_heap(mlsvc_handle_t *); @@ -151,6 +169,108 @@ void ndr_inherit_handle(mlsvc_handle_t *, mlsvc_handle_t *); void ndr_rpc_status(mlsvc_handle_t *, int, uint32_t); +/* SVCCTL service */ +/* + * Calculate the wide-char equivalent string length required to + * store a string - including the terminating null wide-char. + */ +#define SVCCTL_WNSTRLEN(S) ((strlen((S)) + 1) * sizeof (mts_wchar_t)) + +/* An AVL-storable node representing each service in the SCM database. */ +typedef struct svcctl_svc_node { + uu_avl_node_t sn_node; + char *sn_name; /* Service Name (Key) */ + char *sn_fmri; /* Display Name (FMRI) */ + char *sn_desc; /* Description */ + char *sn_state; /* State */ +} svcctl_svc_node_t; + +/* This structure provides context for each svcctl_s_OpenManager call. */ +typedef struct svcctl_manager_context { + scf_handle_t *mc_scf_hdl; /* SCF handle */ + scf_propertygroup_t *mc_scf_gpg; /* Property group */ + scf_property_t *mc_scf_gprop; /* Property */ + scf_value_t *mc_scf_gval; /* Value */ + uint32_t mc_scf_numsvcs; /* Number of SMF services */ + ssize_t mc_scf_max_fmri_len; /* Max FMRI length */ + ssize_t mc_scf_max_value_len; /* Max Value length */ + uint32_t mc_bytes_needed; /* Number of bytes needed */ + uu_avl_pool_t *mc_svcs_pool; /* AVL pool */ + uu_avl_t *mc_svcs; /* AVL tree of SMF services */ +} svcctl_manager_context_t; + +/* This structure provides context for each svcctl_s_OpenService call. */ +typedef struct svcctl_service_context { + ndr_hdid_t *sc_mgrid; /* Manager ID */ + char *sc_svcname; /* Service Name */ +} svcctl_service_context_t; + +typedef enum { + SVCCTL_MANAGER_CONTEXT = 0, + SVCCTL_SERVICE_CONTEXT +} svcctl_context_type_t; + +/* This structure provides abstraction for service and manager context call. */ +typedef struct svcctl_context { + svcctl_context_type_t c_type; + union { + svcctl_manager_context_t *uc_mgr; + svcctl_service_context_t *uc_svc; + void *uc_cp; + } c_ctx; +} svcctl_context_t; + +/* Service Control Manager (SCM) functions */ +void svcctl_init(void); +void svcctl_fini(void); +int svcctl_scm_init(svcctl_manager_context_t *); +void svcctl_scm_fini(svcctl_manager_context_t *); +int svcctl_scm_scf_handle_init(svcctl_manager_context_t *); +void svcctl_scm_scf_handle_fini(svcctl_manager_context_t *); +int svcctl_scm_refresh(svcctl_manager_context_t *); +uint32_t svcctl_scm_enum_services(svcctl_manager_context_t *, uint8_t *, + size_t, uint32_t *, boolean_t); +uint32_t svcctl_scm_validate_service(svcctl_manager_context_t *, char *); +svcctl_svc_node_t *svcctl_scm_find_service(svcctl_manager_context_t *, char *); +uint32_t svcctl_scm_map_status(const char *); + +/* LOGR service */ +#define LOGR_APPLICATION_LOG "Application" +#define LOGR_SECURITY_LOG "Security" +#define LOGR_SYSTEM_LOG "System" +#define LOGR_NMSGMASK 1023 +#define LOGR_MAXMSGLEN 800 + +typedef struct logr_entry { + struct timeval le_timestamp; /* Time of log entry */ + int le_pri; /* Message priority */ + char le_hostname[MAXHOSTNAMELEN]; /* Log hostname */ + char le_msg[LOGR_MAXMSGLEN]; /* Log message text */ +} logr_entry_t; + +typedef struct logr_info { + logr_entry_t li_entry[LOGR_NMSGMASK+1]; /* Array of log entry */ + int li_idx; /* Index */ +} logr_info_t; + +typedef struct logr_read_data { + int rd_tot_recnum; /* Total no. of record read */ + int rd_last_sentrec; /* Last sentence read */ + char rd_first_read; /* First sentence read */ + logr_info_t *rd_log; /* Log information read */ +} logr_read_data_t; + +/* This structure provides the context for eventlog calls from clients. */ +typedef struct logr_context { + logr_read_data_t *lc_cached_read_data; + char *lc_source_name; +} logr_context_t; + +void logr_init(void); +void logr_fini(void); +boolean_t logr_is_supported(char *); +int logr_get_snapshot(logr_context_t *); + #ifdef __cplusplus } #endif
--- a/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers Mon Jul 20 13:07:46 2009 -0400 @@ -41,15 +41,12 @@ SUNWprivate { global: dssetup_clear_domain_info; - mlsvc_get_num_users; - mlsvc_get_user_list; mlsvc_fini; mlsvc_init; mlsvc_join; mlsvc_lookup_name; mlsvc_lookup_sid; mlsvc_netlogon; - mlsvc_set_share; smb_autohome_add; smb_autohome_remove; smb_domain_getinfo;
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc.h Mon Jul 20 13:07:46 2009 -0400 @@ -47,6 +47,9 @@ void msgsvcsend_initialize(void); void spoolss_initialize(void); +void logr_finalize(void); +void svcctl_finalize(void); + int netr_open(char *, char *, mlsvc_handle_t *); int netr_close(mlsvc_handle_t *); DWORD netlogon_auth(char *, mlsvc_handle_t *, DWORD);
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c Mon Jul 20 13:07:46 2009 -0400 @@ -170,6 +170,36 @@ } /* + * Set information about the remote RPC server in the handle. + */ +void +ndr_rpc_server_setinfo(mlsvc_handle_t *handle, + const srvsvc_server_info_t *svinfo) +{ + bcopy(svinfo, &handle->svinfo, sizeof (srvsvc_server_info_t)); + handle->svinfo.sv_name = NULL; + handle->svinfo.sv_comment = NULL; + + if (svinfo->sv_version_major > 4) + handle->remote_os = NATIVE_OS_WIN2000; + else + handle->remote_os = NATIVE_OS_WINNT; + + smb_tracef("NdrRpcServerSetInfo: %s (version %d.%d)", + svinfo->sv_name ? svinfo->sv_name : "<unknown>", + svinfo->sv_version_major, svinfo->sv_version_minor); +} + +/* + * Get information about the remote RPC server from the handle. + */ +void +ndr_rpc_server_getinfo(mlsvc_handle_t *handle, srvsvc_server_info_t *svinfo) +{ + bcopy(&handle->svinfo, svinfo, sizeof (srvsvc_server_info_t)); +} + +/* * Returns the Native-OS of the RPC server. */ int
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c Mon Jul 20 13:07:46 2009 -0400 @@ -82,6 +82,8 @@ mlsvc_fini(void) { smb_logon_fini(); + svcctl_finalize(); + logr_finalize(); } /*ARGSUSED*/ @@ -100,43 +102,3 @@ /*NOTREACHED*/ return (NULL); } - -uint64_t -mlsvc_get_num_users(void) -{ - uint32_t n_users = 0; - - (void) smb_kmod_get_usernum(&n_users); - return ((uint64_t)n_users); -} - -/* - * The calling function must free the output parameter 'users'. - */ -int -mlsvc_get_user_list(smb_ulist_t *ulist) -{ - return (smb_kmod_get_userlist(ulist)); -} - -/* - * Downcall to the kernel that is executed upon share enable and disable. - */ -int -mlsvc_set_share(int shrop, char *path, char *name) -{ - int rc; - - switch (shrop) { - case SMB_SHROP_ADD: - rc = smb_kmod_share(path, name); - break; - case SMB_SHROP_DELETE: - rc = smb_kmod_unshare(path, name); - break; - default: - rc = EINVAL; - break; - } - return (rc); -}
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_lsa.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_lsa.c Mon Jul 20 13:07:46 2009 -0400 @@ -518,7 +518,7 @@ lsarpc_s_GetConnectedUser(void *arg, ndr_xa_t *mxa) { struct mslsa_GetConnectedUser *param = arg; - smb_opipe_context_t *ctx = &mxa->pipe->np_ctx; + smb_netuserinfo_t *user = &mxa->pipe->np_user; DWORD status = NT_STATUS_SUCCESS; smb_domain_t di; int rc1; @@ -546,8 +546,9 @@ return (NDR_DRC_OK); } - rc1 = NDR_MSTRING(mxa, ctx->oc_account, (ndr_mstring_t *)param->owner); - rc2 = NDR_MSTRING(mxa, ctx->oc_domain, + rc1 = NDR_MSTRING(mxa, user->ui_account, + (ndr_mstring_t *)param->owner); + rc2 = NDR_MSTRING(mxa, user->ui_domain, (ndr_mstring_t *)param->domain->name); if (rc1 == -1 || rc2 == -1)
--- a/usr/src/lib/smbsrv/libmlsvc/common/netr_auth.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/smbsrv/libmlsvc/common/netr_auth.c Mon Jul 20 13:07:46 2009 -0400 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -118,19 +118,27 @@ /* * netr_open * - * Open an anonymous session to the NETLOGON pipe on a domain - * controller and bind to the NETR RPC interface. We store the - * remote server's native OS type - we may need it due to - * differences between versions of Windows. + * Open an anonymous session to the NETLOGON pipe on a domain controller + * and bind to the NETR RPC interface. + * + * We store the remote server information, which is used to drive Windows + * version specific behavior. */ int netr_open(char *server, char *domain, mlsvc_handle_t *netr_handle) { + srvsvc_server_info_t svinfo; char *user = smbrdr_ipc_get_user(); + if (srvsvc_net_server_getinfo(server, domain, &svinfo) < 0) + return (-1); + if (ndr_rpc_bind(netr_handle, server, domain, user, "NETR") < 0) return (-1); + ndr_rpc_server_setinfo(netr_handle, &svinfo); + free(svinfo.sv_name); + free(svinfo.sv_comment); return (0); }
--- a/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c Mon Jul 20 13:07:46 2009 -0400 @@ -406,7 +406,7 @@ smb_shr_cache_unlock(); /* call kernel to take a hold on the shared file system */ - rc = mlsvc_set_share(SMB_SHROP_ADD, si->shr_path, si->shr_name); + rc = smb_kmod_share(si->shr_path, si->shr_name); if (rc == 0) { smb_shr_publish(si->shr_name, si->shr_container); @@ -483,7 +483,7 @@ smb_shr_unpublish(sharename, container); /* call kernel to release the hold on the shared file system */ - (void) mlsvc_set_share(SMB_SHROP_DELETE, path, sharename); + (void) smb_kmod_unshare(path, sharename); return (NERR_Success); }
--- a/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_clnt.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_clnt.c Mon Jul 20 13:07:46 2009 -0400 @@ -347,6 +347,52 @@ return (0); } +int +srvsvc_net_server_getinfo(char *server, char *domain, + srvsvc_server_info_t *svinfo) +{ + mlsvc_handle_t handle; + struct mslm_NetServerGetInfo arg; + struct mslm_SERVER_INFO_101 *sv101; + int len, opnum, rc; + char *user = smbrdr_ipc_get_user(); + + if (srvsvc_open(server, domain, user, &handle) != 0) + return (-1); + + opnum = SRVSVC_OPNUM_NetServerGetInfo; + bzero(&arg, sizeof (arg)); + + len = strlen(server) + 4; + arg.servername = ndr_rpc_malloc(&handle, len); + if (arg.servername == NULL) + return (-1); + + (void) snprintf((char *)arg.servername, len, "\\\\%s", server); + arg.level = 101; + + rc = ndr_rpc_call(&handle, opnum, &arg); + if ((rc != 0) || (arg.status != 0)) { + srvsvc_close(&handle); + return (-1); + } + + sv101 = arg.result.bufptr.bufptr101; + + bzero(svinfo, sizeof (srvsvc_server_info_t)); + svinfo->sv_platform_id = sv101->sv101_platform_id; + svinfo->sv_version_major = sv101->sv101_version_major; + svinfo->sv_version_minor = sv101->sv101_version_minor; + svinfo->sv_type = sv101->sv101_type; + if (sv101->sv101_name) + svinfo->sv_name = strdup((char *)sv101->sv101_name); + if (sv101->sv101_comment) + svinfo->sv_comment = strdup((char *)sv101->sv101_comment); + + srvsvc_close(&handle); + return (0); +} + /* * Synchronize the local system clock with the domain controller. */ @@ -490,6 +536,7 @@ srvsvc_net_test(char *server, char *domain, char *netname) { smb_domain_t di; + srvsvc_server_info_t svinfo; (void) smb_tracef("%s %s %s", server, domain, netname); @@ -498,6 +545,17 @@ domain = di.d_info.di_nbname; } + if (srvsvc_net_server_getinfo(server, domain, &svinfo) == 0) { + smb_tracef("NetServerGetInfo: %s %s (%d.%d) id=%d type=0x%08x", + svinfo.sv_name ? svinfo.sv_name : "NULL", + svinfo.sv_comment ? svinfo.sv_comment : "NULL", + svinfo.sv_version_major, svinfo.sv_version_minor, + svinfo.sv_platform_id, svinfo.sv_type); + + free(svinfo.sv_name); + free(svinfo.sv_comment); + } + (void) srvsvc_net_share_get_info(server, domain, netname); #if 0 /*
--- a/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c Mon Jul 20 13:07:46 2009 -0400 @@ -65,26 +65,8 @@ #define SRVSVC_CONNECT_ENUM_SHARE 1 #define SRVSVC_CONNECT_ENUM_WKSTN 2 -#define SMB_SRVSVC_MAXBUFLEN (8 * 1024 * 1024) -#define SMB_SRVSVC_MAXPREFLEN ((uint32_t)(-1)) - -/* - * prefmaxlen: Client specified response buffer limit. - * resume_handle: Cookie used to track enumeration across multiple calls. - * n_total: Total number of entries. - * n_enum: Number of entries to enumerate (derived from prefmaxlen). - * n_skip: Number of entries to skip (from incoming resume handle). - * n_read: Number of objects returned for current enumeration request. - */ -typedef struct srvsvc_enum { - uint32_t se_level; - uint32_t se_prefmaxlen; - uint32_t se_resume_handle; - uint32_t se_n_total; - uint32_t se_n_enum; - uint32_t se_n_skip; - uint32_t se_n_read; -} srvsvc_enum_t; +#define SMB_SRVSVC_MAXBUFLEN (8 * 1024 * 1024) +#define SMB_SRVSVC_MAXPREFLEN ((uint32_t)(-1)) typedef struct srvsvc_sd { uint8_t *sd_buf; @@ -112,46 +94,45 @@ struct mslm_NetShareInfo_1501 nsg_info1501; } srvsvc_netshare_getinfo_t; -static DWORD srvsvc_s_NetConnectEnumLevel0(ndr_xa_t *, - srvsvc_NetConnectInfo0_t *); -static DWORD srvsvc_s_NetConnectEnumLevel1(ndr_xa_t *, - srvsvc_NetConnectInfo1_t *); - -static DWORD srvsvc_NetFileEnum2(ndr_xa_t *, - struct mslm_NetFileEnum *); -static DWORD srvsvc_NetFileEnum3(ndr_xa_t *, - struct mslm_NetFileEnum *); - -static DWORD mlsvc_NetSessionEnumLevel0(struct mslm_infonres *, DWORD, - ndr_xa_t *); -static DWORD mlsvc_NetSessionEnumLevel1(struct mslm_infonres *, DWORD, - ndr_xa_t *); -static DWORD mlsvc_NetSessionEnumLevel2(struct mslm_infonres *, DWORD, - ndr_xa_t *); -static DWORD mlsvc_NetSessionEnumLevel10(struct mslm_infonres *, DWORD, - ndr_xa_t *); -static DWORD mlsvc_NetSessionEnumLevel502(struct mslm_infonres *, DWORD, - ndr_xa_t *); - -static DWORD mlsvc_NetShareEnumLevel0(ndr_xa_t *, - struct mslm_infonres *, srvsvc_enum_t *, int); -static DWORD mlsvc_NetShareEnumLevel1(ndr_xa_t *, - struct mslm_infonres *, srvsvc_enum_t *, int); -static DWORD mlsvc_NetShareEnumLevel2(ndr_xa_t *, - struct mslm_infonres *, srvsvc_enum_t *, int); -static DWORD mlsvc_NetShareEnumLevel501(ndr_xa_t *, - struct mslm_infonres *, srvsvc_enum_t *, int); -static DWORD mlsvc_NetShareEnumLevel502(ndr_xa_t *, - struct mslm_infonres *, srvsvc_enum_t *, int); -static DWORD mlsvc_NetShareEnumCommon(ndr_xa_t *, - srvsvc_enum_t *, smb_share_t *, void *); -static boolean_t srvsvc_add_autohome(ndr_xa_t *, srvsvc_enum_t *, - void *); +typedef struct mslm_infonres srvsvc_infonres_t; +typedef struct mslm_NetConnectEnum srvsvc_NetConnectEnum_t; + +static uint32_t srvsvc_netconnectenum_level0(ndr_xa_t *, smb_svcenum_t *, + srvsvc_NetConnectEnum_t *); +static uint32_t srvsvc_netconnectenum_level1(ndr_xa_t *, smb_svcenum_t *, + srvsvc_NetConnectEnum_t *); +static uint32_t srvsvc_netconnectenum_common(ndr_xa_t *, + srvsvc_NetConnectInfo_t *, smb_netsvc_t *, smb_svcenum_t *); + +static DWORD srvsvc_NetFileEnum2(ndr_xa_t *, struct mslm_NetFileEnum *, + smb_svcenum_t *se); +static DWORD srvsvc_NetFileEnum3(ndr_xa_t *, struct mslm_NetFileEnum *, + smb_svcenum_t *se); + +static uint32_t srvsvc_NetSessionEnumCommon(ndr_xa_t *, srvsvc_infonres_t *, + smb_netsvc_t *, smb_svcenum_t *); + +static DWORD mlsvc_NetShareEnumLevel0(ndr_xa_t *, srvsvc_infonres_t *, + smb_svcenum_t *, int); +static DWORD mlsvc_NetShareEnumLevel1(ndr_xa_t *, srvsvc_infonres_t *, + smb_svcenum_t *, int); +static DWORD mlsvc_NetShareEnumLevel2(ndr_xa_t *, srvsvc_infonres_t *, + smb_svcenum_t *, int); +static DWORD mlsvc_NetShareEnumLevel501(ndr_xa_t *, srvsvc_infonres_t *, + smb_svcenum_t *, int); +static DWORD mlsvc_NetShareEnumLevel502(ndr_xa_t *, srvsvc_infonres_t *, + smb_svcenum_t *, int); +static DWORD mlsvc_NetShareEnumCommon(ndr_xa_t *, smb_svcenum_t *, + smb_share_t *, void *); +static boolean_t srvsvc_add_autohome(ndr_xa_t *, smb_svcenum_t *, void *); static char *srvsvc_share_mkpath(ndr_xa_t *, char *); static uint32_t srvsvc_share_getsd(ndr_xa_t *, smb_share_t *, srvsvc_sd_t *); static int srvsvc_netconnect_qualifier(const char *); -static uint32_t srvsvc_estimate_objcnt(uint32_t, uint32_t, uint32_t); +static void srvsvc_estimate_limit(smb_svcenum_t *, uint32_t); +static uint32_t srvsvc_open_sessions(void); +static uint32_t srvsvc_open_connections(uint32_t, const char *); +static uint32_t srvsvc_open_files(void); static uint32_t srvsvc_modify_share(smb_share_t *, srvsvc_netshare_setinfo_t *); @@ -224,112 +205,222 @@ static int srvsvc_s_NetConnectEnum(void *arg, ndr_xa_t *mxa) { - struct mslm_NetConnectEnum *param = arg; - srvsvc_NetConnectInfo0_t *info0; - srvsvc_NetConnectInfo1_t *info1; - char *qualifier; - int qualtype; - DWORD status = ERROR_SUCCESS; + srvsvc_NetConnectEnum_t *param = arg; + smb_netsvc_t *ns; + smb_svcenum_t se; + char *qualifier; + int qualtype; + DWORD status = ERROR_SUCCESS; if (!ndr_is_poweruser(mxa)) { - bzero(param, sizeof (struct mslm_NetConnectEnum)); - param->status = ERROR_ACCESS_DENIED; - return (NDR_DRC_OK); + status = ERROR_ACCESS_DENIED; + goto srvsvc_netconnectenum_error; } qualifier = (char *)param->qualifier; qualtype = srvsvc_netconnect_qualifier(qualifier); - if (qualtype == SRVSVC_CONNECT_ENUM_NULL) { - bzero(param, sizeof (struct mslm_NetConnectEnum)); - param->status = NERR_NetNameNotFound; + status = NERR_NetNameNotFound; + goto srvsvc_netconnectenum_error; + } + + param->total_entries = srvsvc_open_connections(qualtype, qualifier); + if (param->total_entries == 0) { + bzero(param, sizeof (srvsvc_NetConnectEnum_t)); + param->status = ERROR_SUCCESS; return (NDR_DRC_OK); } + bzero(&se, sizeof (smb_svcenum_t)); + se.se_type = SMB_SVCENUM_TYPE_TREE; + se.se_level = param->info.level; + se.se_ntotal = param->total_entries; + se.se_nlimit = se.se_ntotal; + + if (param->pref_max_len == SMB_SRVSVC_MAXPREFLEN || + param->pref_max_len > SMB_SRVSVC_MAXBUFLEN) + se.se_prefmaxlen = SMB_SRVSVC_MAXBUFLEN; + else + se.se_prefmaxlen = param->pref_max_len; + + if (param->resume_handle) { + se.se_resume = *param->resume_handle; + se.se_nskip = se.se_resume; + *param->resume_handle = 0; + } + switch (param->info.level) { case 0: - info0 = NDR_NEW(mxa, srvsvc_NetConnectInfo0_t); - if (info0 == NULL) { - status = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - bzero(info0, sizeof (srvsvc_NetConnectInfo0_t)); - param->info.ru.info0 = info0; - - status = srvsvc_s_NetConnectEnumLevel0(mxa, info0); - - param->total_entries = info0->entries_read; - param->resume_handle = NULL; + status = srvsvc_netconnectenum_level0(mxa, &se, param); break; - case 1: - info1 = NDR_NEW(mxa, srvsvc_NetConnectInfo1_t); - if (info1 == NULL) { - status = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - bzero(info1, sizeof (srvsvc_NetConnectInfo1_t)); - param->info.ru.info1 = info1; - - status = srvsvc_s_NetConnectEnumLevel1(mxa, info1); - - param->total_entries = info1->entries_read; - param->resume_handle = NULL; + status = srvsvc_netconnectenum_level1(mxa, &se, param); break; - case 50: status = ERROR_NOT_SUPPORTED; break; - default: status = ERROR_INVALID_LEVEL; break; } if (status != ERROR_SUCCESS) - bzero(param, sizeof (struct mslm_NetConnectEnum)); - + goto srvsvc_netconnectenum_error; + + if ((ns = smb_kmod_enum_init(&se)) == NULL) { + status = ERROR_NOT_ENOUGH_MEMORY; + goto srvsvc_netconnectenum_error; + } + + status = srvsvc_netconnectenum_common(mxa, ¶m->info, ns, &se); + smb_kmod_enum_fini(ns); + + if (status != ERROR_SUCCESS) + goto srvsvc_netconnectenum_error; + + if (param->resume_handle && + param->pref_max_len != SMB_SRVSVC_MAXPREFLEN) { + if (se.se_resume < param->total_entries) { + *param->resume_handle = se.se_resume; + status = ERROR_MORE_DATA; + } + } + + param->status = status; + return (NDR_DRC_OK); + +srvsvc_netconnectenum_error: + bzero(param, sizeof (srvsvc_NetConnectEnum_t)); param->status = status; return (NDR_DRC_OK); } -static DWORD -srvsvc_s_NetConnectEnumLevel0(ndr_xa_t *mxa, srvsvc_NetConnectInfo0_t *info0) +/* + * Allocate memory and estimate the number of objects that can + * be returned for NetConnectEnum level 0. + */ +static uint32_t +srvsvc_netconnectenum_level0(ndr_xa_t *mxa, smb_svcenum_t *se, + srvsvc_NetConnectEnum_t *param) { - srvsvc_NetConnectInfoBuf0_t *ci0; - - ci0 = NDR_NEW(mxa, srvsvc_NetConnectInfoBuf0_t); + srvsvc_NetConnectInfo0_t *info0; + srvsvc_NetConnectInfoBuf0_t *ci0; + + if ((info0 = NDR_NEW(mxa, srvsvc_NetConnectInfo0_t)) == NULL) + return (ERROR_NOT_ENOUGH_MEMORY); + + bzero(info0, sizeof (srvsvc_NetConnectInfo0_t)); + param->info.ru.info0 = info0; + + srvsvc_estimate_limit(se, sizeof (srvsvc_NetConnectInfoBuf0_t)); + if (se->se_nlimit == 0) + return (NERR_BufTooSmall); + + do { + ci0 = NDR_NEWN(mxa, srvsvc_NetConnectInfoBuf0_t, se->se_nlimit); + if (ci0 == NULL) + se->se_nlimit >>= 1; + } while ((se->se_nlimit > 0) && (ci0 == NULL)); + if (ci0 == NULL) return (ERROR_NOT_ENOUGH_MEMORY); - ci0->coni0_id = 0x17; - info0->ci0 = ci0; - info0->entries_read = 1; + info0->entries_read = 0; return (ERROR_SUCCESS); } -static DWORD -srvsvc_s_NetConnectEnumLevel1(ndr_xa_t *mxa, srvsvc_NetConnectInfo1_t *info1) +/* + * Allocate memory and estimate the number of objects that can + * be returned for NetConnectEnum level 1. + */ +static uint32_t +srvsvc_netconnectenum_level1(ndr_xa_t *mxa, smb_svcenum_t *se, + srvsvc_NetConnectEnum_t *param) { - srvsvc_NetConnectInfoBuf1_t *ci1; - - ci1 = NDR_NEW(mxa, srvsvc_NetConnectInfoBuf1_t); + srvsvc_NetConnectInfo1_t *info1; + srvsvc_NetConnectInfoBuf1_t *ci1; + + if ((info1 = NDR_NEW(mxa, srvsvc_NetConnectInfo1_t)) == NULL) + return (ERROR_NOT_ENOUGH_MEMORY); + + bzero(info1, sizeof (srvsvc_NetConnectInfo1_t)); + param->info.ru.info1 = info1; + + srvsvc_estimate_limit(se, + sizeof (srvsvc_NetConnectInfoBuf1_t) + MAXNAMELEN); + if (se->se_nlimit == 0) + return (NERR_BufTooSmall); + + do { + ci1 = NDR_NEWN(mxa, srvsvc_NetConnectInfoBuf1_t, se->se_nlimit); + if (ci1 == NULL) + se->se_nlimit >>= 1; + } while ((se->se_nlimit > 0) && (ci1 == NULL)); + if (ci1 == NULL) return (ERROR_NOT_ENOUGH_MEMORY); - ci1->coni1_id = 0x17; - ci1->coni1_type = STYPE_IPC; - ci1->coni1_num_opens = 1; - ci1->coni1_num_users = 1; - ci1->coni1_time = 16; - ci1->coni1_username = (uint8_t *)NDR_STRDUP(mxa, "Administrator"); - ci1->coni1_netname = (uint8_t *)NDR_STRDUP(mxa, "IPC$"); - info1->ci1 = ci1; - info1->entries_read = 1; + info1->entries_read = 0; + return (ERROR_SUCCESS); +} + +/* + * Request a list of connections from the kernel and set up + * the connection information to be returned to the client. + */ +static uint32_t +srvsvc_netconnectenum_common(ndr_xa_t *mxa, srvsvc_NetConnectInfo_t *info, + smb_netsvc_t *ns, smb_svcenum_t *se) +{ + srvsvc_NetConnectInfo0_t *info0; + srvsvc_NetConnectInfo1_t *info1; + srvsvc_NetConnectInfoBuf0_t *ci0; + srvsvc_NetConnectInfoBuf1_t *ci1; + smb_netsvcitem_t *item; + smb_netconnectinfo_t *tree; + + if (smb_kmod_enum(ns) != 0) + return (ERROR_INTERNAL_ERROR); + + info0 = info->ru.info0; + ci0 = info0->ci0; + + info1 = info->ru.info1; + ci1 = info1->ci1; + + item = list_head(&ns->ns_list); + while (item != NULL) { + tree = &item->nsi_un.nsi_tree; + + switch (se->se_level) { + case 0: + ci0->coni0_id = tree->ci_id; + ++ci0; + ++info0->entries_read; + break; + case 1: + ci1->coni1_id = tree->ci_id; + ci1->coni1_type = tree->ci_type; + ci1->coni1_num_opens = tree->ci_numopens; + ci1->coni1_num_users = tree->ci_numusers; + ci1->coni1_time = tree->ci_time; + ci1->coni1_username = (uint8_t *) + NDR_STRDUP(mxa, tree->ci_username); + ci1->coni1_netname = (uint8_t *) + NDR_STRDUP(mxa, tree->ci_share); + ++ci1; + ++info1->entries_read; + break; + default: + return (ERROR_INVALID_LEVEL); + } + + ++se->se_resume; + item = list_next(&ns->ns_list, item); + } + return (ERROR_SUCCESS); } @@ -361,6 +452,45 @@ } } +static uint32_t +srvsvc_open_sessions(void) +{ + smb_opennum_t opennum; + + bzero(&opennum, sizeof (smb_opennum_t)); + if (smb_kmod_get_open_num(&opennum) != 0) + return (0); + + return (opennum.open_users); +} + +static uint32_t +srvsvc_open_connections(uint32_t qualtype, const char *qualifier) +{ + smb_opennum_t opennum; + + bzero(&opennum, sizeof (smb_opennum_t)); + opennum.qualtype = qualtype; + (void) strlcpy(opennum.qualifier, qualifier, MAXNAMELEN); + + if (smb_kmod_get_open_num(&opennum) != 0) + return (0); + + return (opennum.open_trees); +} + +static uint32_t +srvsvc_open_files(void) +{ + smb_opennum_t opennum; + + bzero(&opennum, sizeof (smb_opennum_t)); + if (smb_kmod_get_open_num(&opennum) != 0) + return (0); + + return (opennum.open_files); +} + /* * srvsvc_s_NetFileEnum * @@ -416,8 +546,9 @@ static int srvsvc_s_NetFileEnum(void *arg, ndr_xa_t *mxa) { - struct mslm_NetFileEnum *param = arg; - DWORD status; + struct mslm_NetFileEnum *param = arg; + smb_svcenum_t se; + DWORD status; if (!ndr_is_admin(mxa)) { bzero(param, sizeof (struct mslm_NetFileEnum)); @@ -425,13 +556,37 @@ return (NDR_DRC_OK); } + if ((param->total_entries = srvsvc_open_files()) == 0) { + bzero(param, sizeof (struct mslm_NetFileEnum)); + param->status = ERROR_SUCCESS; + return (NDR_DRC_OK); + } + + bzero(&se, sizeof (smb_svcenum_t)); + se.se_type = SMB_SVCENUM_TYPE_FILE; + se.se_level = param->info.switch_value; + se.se_ntotal = param->total_entries; + se.se_nlimit = se.se_ntotal; + + if (param->pref_max_len == SMB_SRVSVC_MAXPREFLEN || + param->pref_max_len > SMB_SRVSVC_MAXBUFLEN) + se.se_prefmaxlen = SMB_SRVSVC_MAXBUFLEN; + else + se.se_prefmaxlen = param->pref_max_len; + + if (param->resume_handle) { + se.se_resume = *param->resume_handle; + se.se_nskip = se.se_resume; + *param->resume_handle = 0; + } + switch (param->info.switch_value) { case 2: - status = srvsvc_NetFileEnum2(mxa, param); + status = srvsvc_NetFileEnum2(mxa, param, &se); break; case 3: - status = srvsvc_NetFileEnum3(mxa, param); + status = srvsvc_NetFileEnum3(mxa, param, &se); break; case 50: @@ -449,92 +604,144 @@ return (NDR_DRC_OK); } - if (param->resume_handle) - *param->resume_handle = 0; - - param->status = ERROR_SUCCESS; + if (param->resume_handle && + param->pref_max_len != SMB_SRVSVC_MAXPREFLEN) { + if (se.se_resume < param->total_entries) { + *param->resume_handle = se.se_resume; + status = ERROR_MORE_DATA; + } + } + + param->status = status; return (NDR_DRC_OK); } /* * Build level 2 file information. * + * SMB fids are 16-bit values but this interface expects 32-bit file ids. + * So we use the uniqid here. + * * On success, the caller expects that the info2, fi2 and entries_read * fields have been set up. */ static DWORD -srvsvc_NetFileEnum2(ndr_xa_t *mxa, struct mslm_NetFileEnum *param) +srvsvc_NetFileEnum2(ndr_xa_t *mxa, struct mslm_NetFileEnum *param, + smb_svcenum_t *se) { - struct mslm_NetFileInfoBuf2 *fi2; - ndr_pipe_info_t pi; - uint32_t entries_read = 0; - int i; + struct mslm_NetFileInfoBuf2 *fi2; + smb_netsvc_t *ns; + smb_netsvcitem_t *item; + smb_netfileinfo_t *ofile; + uint32_t entries_read = 0; param->info.ru.info2 = NDR_NEW(mxa, struct mslm_NetFileInfo2); if (param->info.ru.info2 == NULL) return (ERROR_NOT_ENOUGH_MEMORY); - fi2 = NDR_NEWN(mxa, struct mslm_NetFileInfoBuf2, 128); + srvsvc_estimate_limit(se, sizeof (struct mslm_NetFileInfoBuf2)); + if (se->se_nlimit == 0) + return (NERR_BufTooSmall); + + do { + fi2 = NDR_NEWN(mxa, struct mslm_NetFileInfoBuf2, se->se_nlimit); + if (fi2 == NULL) + se->se_nlimit >>= 1; + } while ((se->se_nlimit > 0) && (fi2 == NULL)); + if (fi2 == NULL) return (ERROR_NOT_ENOUGH_MEMORY); param->info.ru.info2->fi2 = fi2; - for (i = 0; i < 128; ++i) { - if (ndr_pipe_getinfo(i, &pi) == -1) - continue; - - fi2->fi2_id = pi.npi_fid; + if ((ns = smb_kmod_enum_init(se)) == NULL) + return (ERROR_NOT_ENOUGH_MEMORY); + + if (smb_kmod_enum(ns) != 0) { + smb_kmod_enum_fini(ns); + return (ERROR_INTERNAL_ERROR); + } + + item = list_head(&ns->ns_list); + while (item != NULL) { + ofile = &item->nsi_un.nsi_ofile; + fi2->fi2_id = ofile->fi_uniqid; ++entries_read; ++fi2; + item = list_next(&ns->ns_list, item); } + se->se_resume += entries_read; param->info.ru.info2->entries_read = entries_read; - param->total_entries = entries_read; + smb_kmod_enum_fini(ns); return (ERROR_SUCCESS); } /* * Build level 3 file information. * + * SMB fids are 16-bit values but this interface expects 32-bit file ids. + * So we use the uniqid here. + * * On success, the caller expects that the info3, fi3 and entries_read * fields have been set up. */ static DWORD -srvsvc_NetFileEnum3(ndr_xa_t *mxa, struct mslm_NetFileEnum *param) +srvsvc_NetFileEnum3(ndr_xa_t *mxa, struct mslm_NetFileEnum *param, + smb_svcenum_t *se) { - struct mslm_NetFileInfoBuf3 *fi3; - ndr_pipe_info_t pi; - uint32_t entries_read = 0; - int i; + struct mslm_NetFileInfoBuf3 *fi3; + smb_netsvc_t *ns; + smb_netsvcitem_t *item; + smb_netfileinfo_t *ofile; + uint32_t entries_read = 0; param->info.ru.info3 = NDR_NEW(mxa, struct mslm_NetFileInfo3); if (param->info.ru.info3 == NULL) return (ERROR_NOT_ENOUGH_MEMORY); - fi3 = NDR_NEWN(mxa, struct mslm_NetFileInfoBuf3, 128); + srvsvc_estimate_limit(se, + sizeof (struct mslm_NetFileInfoBuf3) + MAXNAMELEN); + if (se->se_nlimit == 0) + return (NERR_BufTooSmall); + + do { + fi3 = NDR_NEWN(mxa, struct mslm_NetFileInfoBuf3, se->se_nlimit); + if (fi3 == NULL) + se->se_nlimit >>= 1; + } while ((se->se_nlimit > 0) && (fi3 == NULL)); + if (fi3 == NULL) return (ERROR_NOT_ENOUGH_MEMORY); param->info.ru.info3->fi3 = fi3; - for (i = 0; i < 128; ++i) { - if (ndr_pipe_getinfo(i, &pi) == -1) - continue; - - fi3->fi3_id = pi.npi_fid; - fi3->fi3_permissions = pi.npi_permissions; - fi3->fi3_num_locks = pi.npi_num_locks; + if ((ns = smb_kmod_enum_init(se)) == NULL) + return (ERROR_NOT_ENOUGH_MEMORY); + + if (smb_kmod_enum(ns) != 0) { + smb_kmod_enum_fini(ns); + return (ERROR_INTERNAL_ERROR); + } + + item = list_head(&ns->ns_list); + while (item != NULL) { + ofile = &item->nsi_un.nsi_ofile; + fi3->fi3_id = ofile->fi_uniqid; + fi3->fi3_permissions = ofile->fi_permissions; + fi3->fi3_num_locks = ofile->fi_numlocks; fi3->fi3_pathname = (uint8_t *) - NDR_STRDUP(mxa, pi.npi_pathname); + NDR_STRDUP(mxa, ofile->fi_path); fi3->fi3_username = (uint8_t *) - NDR_STRDUP(mxa, pi.npi_username); + NDR_STRDUP(mxa, ofile->fi_username); ++entries_read; ++fi3; + item = list_next(&ns->ns_list, item); } + se->se_resume += entries_read; param->info.ru.info3->entries_read = entries_read; param->total_entries = entries_read; return (ERROR_SUCCESS); @@ -544,32 +751,56 @@ * srvsvc_s_NetFileClose * * NetFileClose forces a file to close. This function can be used when - * an error prevents closure by any other means. Use NetFileClose with + * an error prevents closure by other means. Use NetFileClose with * caution because it does not flush data, cached on a client, to the * file before closing the file. * + * SMB fids are 16-bit values but this interface expects 32-bit file ids. + * So we use the uniqid here. + * * Return Values * ERROR_SUCCESS Operation succeeded. * ERROR_ACCESS_DENIED Operation denied. * NERR_FileIdNotFound No open file with the specified id. * - * Note: MSDN suggests that the error code should be ERROR_FILE_NOT_FOUND - * but network captures using NT show NERR_FileIdNotFound. - * The NetFileClose2 MSDN page has the right error code. + * Note: MSDN suggests ERROR_FILE_NOT_FOUND for NetFileClose but network + * captures using NT show NERR_FileIdNotFound, which is consistent with + * the NetFileClose2 page on MSDN. */ static int srvsvc_s_NetFileClose(void *arg, ndr_xa_t *mxa) { + static struct { + int errnum; + int nerr; + } errmap[] = { + 0, ERROR_SUCCESS, + EACCES, ERROR_ACCESS_DENIED, + EPERM, ERROR_ACCESS_DENIED, + EINVAL, ERROR_INVALID_PARAMETER, + ENOMEM, ERROR_NOT_ENOUGH_MEMORY, + ENOENT, NERR_FileIdNotFound + }; + struct mslm_NetFileClose *param = arg; + int i; + int rc; if (!ndr_is_admin(mxa)) { - bzero(param, sizeof (struct mslm_NetFileClose)); param->status = ERROR_ACCESS_DENIED; return (NDR_DRC_OK); } - bzero(param, sizeof (struct mslm_NetFileClose)); - param->status = ERROR_SUCCESS; + rc = smb_kmod_file_close(param->file_id); + + for (i = 0; i < (sizeof (errmap) / sizeof (errmap[0])); ++i) { + if (rc == errmap[i].errnum) { + param->status = errmap[i].nerr; + return (NDR_DRC_OK); + } + } + + param->status = ERROR_INTERNAL_ERROR; return (NDR_DRC_OK); } @@ -1059,393 +1290,222 @@ static int srvsvc_s_NetSessionEnum(void *arg, ndr_xa_t *mxa) { - struct mslm_NetSessionEnum *param = arg; - struct mslm_infonres *infonres; - DWORD status; - DWORD n_sessions; - - infonres = NDR_NEW(mxa, struct mslm_infonres); - if (infonres == NULL) { - bzero(param, sizeof (struct mslm_NetSessionEnum)); - param->status = ERROR_NOT_ENOUGH_MEMORY; + struct mslm_NetSessionEnum *param = arg; + srvsvc_infonres_t *info; + smb_netsvc_t *ns; + smb_svcenum_t se; + DWORD status = ERROR_SUCCESS; + + if (!ndr_is_admin(mxa)) { + status = ERROR_ACCESS_DENIED; + goto srvsvc_netsessionenum_error; + } + + if ((info = NDR_NEW(mxa, srvsvc_infonres_t)) == NULL) { + status = ERROR_NOT_ENOUGH_MEMORY; + goto srvsvc_netsessionenum_error; + } + + info->entriesread = 0; + info->entries = NULL; + param->result.level = param->level; + param->result.bufptr.p = info; + + if ((param->total_entries = srvsvc_open_sessions()) == 0) { + param->resume_handle = NULL; + param->status = ERROR_SUCCESS; return (NDR_DRC_OK); } - infonres->entriesread = 0; - infonres->entries = NULL; - param->result.level = param->level; - param->result.bufptr.p = infonres; - param->total_entries = 0; - param->resume_handle = NULL; - param->status = ERROR_SUCCESS; - - if ((n_sessions = (DWORD) mlsvc_get_num_users()) == 0) - return (NDR_DRC_OK); + bzero(&se, sizeof (smb_svcenum_t)); + se.se_type = SMB_SVCENUM_TYPE_USER; + se.se_level = param->level; + se.se_ntotal = param->total_entries; + se.se_nlimit = se.se_ntotal; + + if (param->resume_handle) { + se.se_resume = *param->resume_handle; + se.se_nskip = se.se_resume; + *param->resume_handle = 0; + } switch (param->level) { case 0: - status = mlsvc_NetSessionEnumLevel0(infonres, n_sessions, mxa); - break; - - case 1: - status = mlsvc_NetSessionEnumLevel1(infonres, n_sessions, mxa); + info->entries = NDR_NEWN(mxa, struct mslm_SESSION_INFO_0, + se.se_nlimit); break; - - case 2: - status = mlsvc_NetSessionEnumLevel2(infonres, n_sessions, mxa); + case 1: + info->entries = NDR_NEWN(mxa, struct mslm_SESSION_INFO_1, + se.se_nlimit); break; - - case 10: - status = mlsvc_NetSessionEnumLevel10(infonres, n_sessions, mxa); + case 2: + info->entries = NDR_NEWN(mxa, struct mslm_SESSION_INFO_2, + se.se_nlimit); break; - + case 10: + info->entries = NDR_NEWN(mxa, struct mslm_SESSION_INFO_10, + se.se_nlimit); + break; case 502: - status = mlsvc_NetSessionEnumLevel502(infonres, n_sessions, - mxa); + info->entries = NDR_NEWN(mxa, struct mslm_SESSION_INFO_502, + se.se_nlimit); break; - default: - status = ERROR_INVALID_LEVEL; - break; - } - - if (status != 0) { bzero(param, sizeof (struct mslm_NetSessionEnum)); - param->status = status; + param->status = ERROR_INVALID_LEVEL; return (NDR_DRC_OK); } - param->total_entries = infonres->entriesread; + if (info->entries == NULL) { + status = ERROR_NOT_ENOUGH_MEMORY; + goto srvsvc_netsessionenum_error; + } + + if ((ns = smb_kmod_enum_init(&se)) == NULL) { + status = ERROR_NOT_ENOUGH_MEMORY; + goto srvsvc_netsessionenum_error; + } + + status = srvsvc_NetSessionEnumCommon(mxa, info, ns, &se); + smb_kmod_enum_fini(ns); + + if (status != ERROR_SUCCESS) + goto srvsvc_netsessionenum_error; + + if (param->resume_handle && + param->pref_max_len != SMB_SRVSVC_MAXPREFLEN) { + if (se.se_resume < param->total_entries) { + *param->resume_handle = se.se_resume; + status = ERROR_MORE_DATA; + } + } + + param->total_entries = info->entriesread; + param->status = status; + return (NDR_DRC_OK); + +srvsvc_netsessionenum_error: + bzero(param, sizeof (struct mslm_NetSessionEnum)); param->status = status; return (NDR_DRC_OK); } -/* - * mlsvc_NetSessionEnumLevel0 - * - * Build the level 0 session information. - */ -static DWORD -mlsvc_NetSessionEnumLevel0(struct mslm_infonres *infonres, DWORD n_sessions, - ndr_xa_t *mxa) +static uint32_t +srvsvc_NetSessionEnumCommon(ndr_xa_t *mxa, srvsvc_infonres_t *info, + smb_netsvc_t *ns, smb_svcenum_t *se) { - struct mslm_SESSION_INFO_0 *info0; - smb_ulist_t *ulist; - smb_opipe_context_t *user; - char *workstation; - char ipaddr_buf[INET6_ADDRSTRLEN]; - int i; - - ulist = smb_ulist_alloc(); - if (ulist == NULL) - return (ERROR_NOT_ENOUGH_MEMORY); - - if (mlsvc_get_user_list(ulist) != 0) { - smb_ulist_free(ulist); - return (ERROR_NOT_ENOUGH_MEMORY); - } - - if (ulist->ul_cnt < n_sessions) - n_sessions = ulist->ul_cnt; - - info0 = NDR_NEWN(mxa, struct mslm_SESSION_INFO_0, n_sessions); - if (info0 == NULL) { - smb_ulist_free(ulist); - return (ERROR_NOT_ENOUGH_MEMORY); - } - - user = ulist->ul_users; - for (i = 0; i < n_sessions; ++i, user++) { - workstation = user->oc_workstation; + struct mslm_SESSION_INFO_0 *info0 = info->entries; + struct mslm_SESSION_INFO_1 *info1 = info->entries; + struct mslm_SESSION_INFO_2 *info2 = info->entries; + struct mslm_SESSION_INFO_10 *info10 = info->entries; + struct mslm_SESSION_INFO_502 *info502 = info->entries; + smb_netsvcitem_t *item; + smb_netuserinfo_t *user; + char *workstation; + char account[MAXNAMELEN]; + char ipaddr_buf[INET6_ADDRSTRLEN]; + uint32_t logon_time; + uint32_t flags; + uint32_t entries_read = 0; + + if (smb_kmod_enum(ns) != 0) + return (ERROR_INTERNAL_ERROR); + + item = list_head(&ns->ns_list); + while (item != NULL) { + user = &item->nsi_un.nsi_user; + + workstation = user->ui_workstation; if (workstation == NULL || *workstation == '\0') { - (void) smb_inet_ntop(&user->oc_ipaddr, - ipaddr_buf, SMB_IPSTRLEN(user->oc_ipaddr.a_family)); - workstation = ipaddr_buf; - } - - info0[i].sesi0_cname = NDR_STRDUP(mxa, workstation); - if (info0[i].sesi0_cname == NULL) { - smb_ulist_free(ulist); - return (ERROR_NOT_ENOUGH_MEMORY); - } - } - - smb_ulist_free(ulist); - infonres->entriesread = n_sessions; - infonres->entries = info0; - return (ERROR_SUCCESS); -} - -/* - * mlsvc_NetSessionEnumLevel1 - * - * Build the level 1 session information. - */ -static DWORD -mlsvc_NetSessionEnumLevel1(struct mslm_infonres *infonres, DWORD n_sessions, - ndr_xa_t *mxa) -{ - struct mslm_SESSION_INFO_1 *info1; - smb_ulist_t *ulist; - smb_opipe_context_t *user; - char *workstation; - char account[MAXNAMELEN]; - char ipaddr_buf[INET6_ADDRSTRLEN]; - int i; - - ulist = smb_ulist_alloc(); - if (ulist == NULL) - return (ERROR_NOT_ENOUGH_MEMORY); - - if (mlsvc_get_user_list(ulist) != 0) { - smb_ulist_free(ulist); - return (ERROR_NOT_ENOUGH_MEMORY); - } - - if (ulist->ul_cnt < n_sessions) - n_sessions = ulist->ul_cnt; - - info1 = NDR_NEWN(mxa, struct mslm_SESSION_INFO_1, n_sessions); - if (info1 == NULL) { - smb_ulist_free(ulist); - return (ERROR_NOT_ENOUGH_MEMORY); - } - - user = ulist->ul_users; - for (i = 0; i < n_sessions; ++i, user++) { - workstation = user->oc_workstation; - if (workstation == NULL || *workstation == '\0') { - (void) smb_inet_ntop(&user->oc_ipaddr, - ipaddr_buf, SMB_IPSTRLEN(user->oc_ipaddr.a_family)); + (void) smb_inet_ntop(&user->ui_ipaddr, ipaddr_buf, + SMB_IPSTRLEN(user->ui_ipaddr.a_family)); workstation = ipaddr_buf; } (void) snprintf(account, MAXNAMELEN, "%s\\%s", - user->oc_domain, user->oc_account); - - info1[i].sesi1_cname = NDR_STRDUP(mxa, workstation); - info1[i].sesi1_uname = NDR_STRDUP(mxa, account); - - if (info1[i].sesi1_cname == NULL || - info1[i].sesi1_uname == NULL) { - smb_ulist_free(ulist); - return (ERROR_NOT_ENOUGH_MEMORY); + user->ui_domain, user->ui_account); + + logon_time = time(0) - user->ui_logon_time; + flags = (user->ui_flags & SMB_ATF_GUEST) ? SESS_GUEST : 0; + + switch (se->se_level) { + case 0: + info0->sesi0_cname = NDR_STRDUP(mxa, workstation); + if (info0->sesi0_cname == NULL) + return (ERROR_NOT_ENOUGH_MEMORY); + ++info0; + break; + + case 1: + info1->sesi1_cname = NDR_STRDUP(mxa, workstation); + info1->sesi1_uname = NDR_STRDUP(mxa, account); + + if (info1->sesi1_cname == NULL || + info1->sesi1_uname == NULL) + return (ERROR_NOT_ENOUGH_MEMORY); + + info1->sesi1_nopens = user->ui_numopens; + info1->sesi1_time = logon_time; + info1->sesi1_itime = 0; + info1->sesi1_uflags = flags; + ++info1; + break; + + case 2: + info2->sesi2_cname = NDR_STRDUP(mxa, workstation); + info2->sesi2_uname = NDR_STRDUP(mxa, account); + + if (info2->sesi2_cname == NULL || + info2->sesi2_uname == NULL) + return (ERROR_NOT_ENOUGH_MEMORY); + + info2->sesi2_nopens = user->ui_numopens; + info2->sesi2_time = logon_time; + info2->sesi2_itime = 0; + info2->sesi2_uflags = flags; + info2->sesi2_cltype_name = (uint8_t *)""; + ++info2; + break; + + case 10: + info10->sesi10_cname = NDR_STRDUP(mxa, workstation); + info10->sesi10_uname = NDR_STRDUP(mxa, account); + + if (info10->sesi10_cname == NULL || + info10->sesi10_uname == NULL) + return (ERROR_NOT_ENOUGH_MEMORY); + + info10->sesi10_time = logon_time; + info10->sesi10_itime = 0; + ++info10; + break; + + case 502: + info502->sesi502_cname = NDR_STRDUP(mxa, workstation); + info502->sesi502_uname = NDR_STRDUP(mxa, account); + + if (info502->sesi502_cname == NULL || + info502->sesi502_uname == NULL) + return (ERROR_NOT_ENOUGH_MEMORY); + + info502->sesi502_nopens = user->ui_numopens; + info502->sesi502_time = logon_time; + info502->sesi502_itime = 0; + info502->sesi502_uflags = flags; + info502->sesi502_cltype_name = (uint8_t *)""; + info502->sesi502_transport = (uint8_t *)""; + ++info502; + break; + + default: + return (ERROR_INVALID_LEVEL); } - info1[i].sesi1_nopens = 1; - info1[i].sesi1_time = time(0) - user->oc_logon_time; - info1[i].sesi1_itime = 0; - info1[i].sesi1_uflags = - (user->oc_flags & SMB_ATF_GUEST) ? SESS_GUEST : 0; - } - - smb_ulist_free(ulist); - infonres->entriesread = n_sessions; - infonres->entries = info1; - return (ERROR_SUCCESS); -} - -/* - * mlsvc_NetSessionEnumLevel2 - * - * Build the level 2 session information. - */ -static DWORD -mlsvc_NetSessionEnumLevel2(struct mslm_infonres *infonres, DWORD n_sessions, - ndr_xa_t *mxa) -{ - struct mslm_SESSION_INFO_2 *info2; - smb_ulist_t *ulist; - smb_opipe_context_t *user; - char *workstation; - char account[MAXNAMELEN]; - char ipaddr_buf[INET6_ADDRSTRLEN]; - int i; - - if ((ulist = smb_ulist_alloc()) == NULL) - return (ERROR_NOT_ENOUGH_MEMORY); - - if (mlsvc_get_user_list(ulist) != 0) { - smb_ulist_free(ulist); - return (ERROR_NOT_ENOUGH_MEMORY); - } - - if (ulist->ul_cnt < n_sessions) - n_sessions = ulist->ul_cnt; - - info2 = NDR_NEWN(mxa, struct mslm_SESSION_INFO_2, n_sessions); - if (info2 == NULL) { - smb_ulist_free(ulist); - return (ERROR_NOT_ENOUGH_MEMORY); - } - - user = ulist->ul_users; - for (i = 0; i < n_sessions; ++i, user++) { - workstation = user->oc_workstation; - if (workstation == NULL || *workstation == '\0') { - (void) smb_inet_ntop(&user->oc_ipaddr, - ipaddr_buf, SMB_IPSTRLEN(user->oc_ipaddr.a_family)); - workstation = ipaddr_buf; - } - - (void) snprintf(account, MAXNAMELEN, "%s\\%s", - user->oc_domain, user->oc_account); - - info2[i].sesi2_cname = NDR_STRDUP(mxa, workstation); - info2[i].sesi2_uname = NDR_STRDUP(mxa, account); - - if (info2[i].sesi2_cname == NULL || - info2[i].sesi2_uname == NULL) { - smb_ulist_free(ulist); - return (ERROR_NOT_ENOUGH_MEMORY); - } - - info2[i].sesi2_nopens = 1; - info2[i].sesi2_time = time(0) - user->oc_logon_time; - info2[i].sesi2_itime = 0; - info2[i].sesi2_uflags = - (user->oc_flags & SMB_ATF_GUEST) ? SESS_GUEST : 0; - info2[i].sesi2_cltype_name = (uint8_t *)""; + ++entries_read; + item = list_next(&ns->ns_list, item); } - smb_ulist_free(ulist); - infonres->entriesread = n_sessions; - infonres->entries = info2; - return (ERROR_SUCCESS); -} - -/* - * mlsvc_NetSessionEnumLevel10 - * - * Build the level 10 session information. - */ -static DWORD -mlsvc_NetSessionEnumLevel10(struct mslm_infonres *infonres, DWORD n_sessions, - ndr_xa_t *mxa) -{ - struct mslm_SESSION_INFO_10 *info10; - smb_ulist_t *ulist; - smb_opipe_context_t *user; - char *workstation; - char account[MAXNAMELEN]; - char ipaddr_buf[INET6_ADDRSTRLEN]; - int i; - - if ((ulist = smb_ulist_alloc()) == NULL) - return (ERROR_NOT_ENOUGH_MEMORY); - - if (mlsvc_get_user_list(ulist) != 0) { - smb_ulist_free(ulist); - return (ERROR_NOT_ENOUGH_MEMORY); - } - - if (ulist->ul_cnt < n_sessions) - n_sessions = ulist->ul_cnt; - - info10 = NDR_NEWN(mxa, struct mslm_SESSION_INFO_10, n_sessions); - if (info10 == NULL) { - smb_ulist_free(ulist); - return (ERROR_NOT_ENOUGH_MEMORY); - } - - user = ulist->ul_users; - for (i = 0; i < n_sessions; ++i, user++) { - workstation = user->oc_workstation; - if (workstation == NULL || *workstation == '\0') { - (void) smb_inet_ntop(&user->oc_ipaddr, - ipaddr_buf, SMB_IPSTRLEN(user->oc_ipaddr.a_family)); - workstation = ipaddr_buf; - } - - (void) snprintf(account, MAXNAMELEN, "%s\\%s", - user->oc_domain, user->oc_account); - - info10[i].sesi10_cname = NDR_STRDUP(mxa, workstation); - info10[i].sesi10_uname = NDR_STRDUP(mxa, account); - - if (info10[i].sesi10_cname == NULL || - info10[i].sesi10_uname == NULL) { - smb_ulist_free(ulist); - return (ERROR_NOT_ENOUGH_MEMORY); - } - - info10[i].sesi10_time = time(0) - user->oc_logon_time; - info10[i].sesi10_itime = 0; - } - - smb_ulist_free(ulist); - infonres->entriesread = n_sessions; - infonres->entries = info10; - return (ERROR_SUCCESS); -} - -/* - * mlsvc_NetSessionEnumLevel502 - * - * Build the level 502 session information. - */ -static DWORD -mlsvc_NetSessionEnumLevel502(struct mslm_infonres *infonres, DWORD n_sessions, - ndr_xa_t *mxa) -{ - struct mslm_SESSION_INFO_502 *info502; - smb_ulist_t *ulist; - smb_opipe_context_t *user; - char *workstation; - char account[MAXNAMELEN]; - char ipaddr_buf[INET6_ADDRSTRLEN]; - int i; - - if ((ulist = smb_ulist_alloc()) == NULL) - return (ERROR_NOT_ENOUGH_MEMORY); - - if (mlsvc_get_user_list(ulist) != 0) { - smb_ulist_free(ulist); - return (ERROR_NOT_ENOUGH_MEMORY); - } - - if (ulist->ul_cnt < n_sessions) - n_sessions = ulist->ul_cnt; - - info502 = NDR_NEWN(mxa, struct mslm_SESSION_INFO_502, n_sessions); - if (info502 == NULL) { - smb_ulist_free(ulist); - return (ERROR_NOT_ENOUGH_MEMORY); - } - - user = ulist->ul_users; - for (i = 0; i < n_sessions; ++i, user++) { - workstation = user->oc_workstation; - if (workstation == NULL || *workstation == '\0') { - (void) smb_inet_ntop(&user->oc_ipaddr, - ipaddr_buf, SMB_IPSTRLEN(user->oc_ipaddr.a_family)); - workstation = ipaddr_buf; - } - - (void) snprintf(account, MAXNAMELEN, "%s\\%s", - user->oc_domain, user->oc_account); - - info502[i].sesi502_cname = NDR_STRDUP(mxa, workstation); - info502[i].sesi502_uname = NDR_STRDUP(mxa, account); - - if (info502[i].sesi502_cname == NULL || - info502[i].sesi502_uname == NULL) { - smb_ulist_free(ulist); - return (ERROR_NOT_ENOUGH_MEMORY); - } - - info502[i].sesi502_nopens = 1; - info502[i].sesi502_time = time(0) - user->oc_logon_time; - info502[i].sesi502_itime = 0; - info502[i].sesi502_uflags = - (user->oc_flags & SMB_ATF_GUEST) ? SESS_GUEST : 0; - info502[i].sesi502_cltype_name = (uint8_t *)""; - info502[i].sesi502_transport = (uint8_t *)""; - } - - smb_ulist_free(ulist); - infonres->entriesread = n_sessions; - infonres->entries = info502; + info->entriesread = entries_read; return (ERROR_SUCCESS); } @@ -1456,29 +1516,58 @@ * On NT only members of the Administrators or Account Operators * local groups are permitted to use NetSessionDel. * + * If unc_clientname is NULL, all sessions associated with the + * specified user will be disconnected. + * + * If username is NULL, all sessions from the specified client + * will be disconnected. + * * Return Values - * If the function succeeds, the return value is NERR_Success/ - * ERROR_SUCCESS. If the function fails, the return value can be - * one of the following error codes: + * On success, the return value is NERR_Success/ERROR_SUCCESS. + * On failure, the return value can be one of the following errors: * * ERROR_ACCESS_DENIED The user does not have access to the - * requested information. + * requested information. * ERROR_INVALID_PARAMETER The specified parameter is invalid. * ERROR_NOT_ENOUGH_MEMORY Insufficient memory is available. * NERR_ClientNameNotFound A session does not exist with that - * computer name. + * computer name. */ static int srvsvc_s_NetSessionDel(void *arg, ndr_xa_t *mxa) { + static struct { + int errnum; + int nerr; + } errmap[] = { + 0, ERROR_SUCCESS, + EACCES, ERROR_ACCESS_DENIED, + EPERM, ERROR_ACCESS_DENIED, + EINVAL, ERROR_INVALID_PARAMETER, + ENOMEM, ERROR_NOT_ENOUGH_MEMORY, + ENOENT, NERR_ClientNameNotFound + }; + struct mslm_NetSessionDel *param = arg; - - if (!ndr_is_poweruser(mxa)) { + int i; + int rc; + + if (!ndr_is_admin(mxa)) { param->status = ERROR_ACCESS_DENIED; return (NDR_DRC_OK); } - param->status = ERROR_ACCESS_DENIED; + rc = smb_kmod_session_close((char *)param->unc_clientname, + (char *)param->username); + + for (i = 0; i < (sizeof (errmap) / sizeof (errmap[0])); ++i) { + if (rc == errmap[i].errnum) { + param->status = errmap[i].nerr; + return (NDR_DRC_OK); + } + } + + param->status = ERROR_INTERNAL_ERROR; return (NDR_DRC_OK); } @@ -1853,25 +1942,30 @@ } /* - * srvsvc_estimate_objcnt + * srvsvc_estimate_limit * * Estimate the number of objects that will fit in prefmaxlen. + * nlimit is adjusted here. */ -static uint32_t -srvsvc_estimate_objcnt(uint32_t prefmaxlen, uint32_t n_obj, uint32_t obj_size) +static void +srvsvc_estimate_limit(smb_svcenum_t *se, uint32_t obj_size) { DWORD max_cnt; - if (obj_size == 0) - return (0); - - if ((max_cnt = (prefmaxlen / obj_size)) == 0) - return (0); - - if (n_obj > max_cnt) - n_obj = max_cnt; - - return (n_obj); + if (obj_size == 0) { + se->se_nlimit = 0; + return; + } + + if ((max_cnt = (se->se_prefmaxlen / obj_size)) == 0) { + se->se_nlimit = 0; + return; + } + + if (se->se_ntotal > max_cnt) + se->se_nlimit = max_cnt; + else + se->se_nlimit = se->se_ntotal; } /* @@ -1890,11 +1984,11 @@ srvsvc_s_NetShareEnum(void *arg, ndr_xa_t *mxa) { struct mslm_NetShareEnum *param = arg; - struct mslm_infonres *infonres; - srvsvc_enum_t se; + srvsvc_infonres_t *infonres; + smb_svcenum_t se; DWORD status; - infonres = NDR_NEW(mxa, struct mslm_infonres); + infonres = NDR_NEW(mxa, srvsvc_infonres_t); if (infonres == NULL) { bzero(param, sizeof (struct mslm_NetShareEnum)); param->status = ERROR_NOT_ENOUGH_MEMORY; @@ -1906,9 +2000,11 @@ param->result.level = param->level; param->result.bufptr.p = infonres; - bzero(&se, sizeof (srvsvc_enum_t)); + bzero(&se, sizeof (smb_svcenum_t)); + se.se_type = SMB_SVCENUM_TYPE_SHARE; se.se_level = param->level; - se.se_n_total = smb_shr_count(); + se.se_ntotal = smb_shr_count(); + se.se_nlimit = se.se_ntotal; if (param->prefmaxlen == SMB_SRVSVC_MAXPREFLEN || param->prefmaxlen > SMB_SRVSVC_MAXBUFLEN) @@ -1917,8 +2013,9 @@ se.se_prefmaxlen = param->prefmaxlen; if (param->resume_handle) { - se.se_resume_handle = *param->resume_handle; - se.se_n_skip = se.se_resume_handle; + se.se_resume = *param->resume_handle; + se.se_nskip = se.se_resume; + *param->resume_handle = 0; } switch (param->level) { @@ -1953,24 +2050,20 @@ return (NDR_DRC_OK); } - if (se.se_n_enum == 0) { - if (param->resume_handle) - *param->resume_handle = 0; + if (se.se_nlimit == 0) { param->status = ERROR_SUCCESS; return (NDR_DRC_OK); } if (param->resume_handle && param->prefmaxlen != SMB_SRVSVC_MAXPREFLEN) { - if (se.se_resume_handle < se.se_n_total) { - *param->resume_handle = se.se_resume_handle; + if (se.se_resume < se.se_ntotal) { + *param->resume_handle = se.se_resume; status = ERROR_MORE_DATA; - } else { - *param->resume_handle = 0; } } - param->totalentries = se.se_n_total; + param->totalentries = se.se_ntotal; param->status = status; return (NDR_DRC_OK); } @@ -1996,11 +2089,11 @@ srvsvc_s_NetShareEnumSticky(void *arg, ndr_xa_t *mxa) { struct mslm_NetShareEnum *param = arg; - struct mslm_infonres *infonres; - srvsvc_enum_t se; + srvsvc_infonres_t *infonres; + smb_svcenum_t se; DWORD status; - infonres = NDR_NEW(mxa, struct mslm_infonres); + infonres = NDR_NEW(mxa, srvsvc_infonres_t); if (infonres == NULL) { bzero(param, sizeof (struct mslm_NetShareEnum)); param->status = ERROR_NOT_ENOUGH_MEMORY; @@ -2012,9 +2105,11 @@ param->result.level = param->level; param->result.bufptr.p = infonres; - bzero(&se, sizeof (srvsvc_enum_t)); + bzero(&se, sizeof (smb_svcenum_t)); + se.se_type = SMB_SVCENUM_TYPE_SHARE; se.se_level = param->level; - se.se_n_total = smb_shr_count(); + se.se_ntotal = smb_shr_count(); + se.se_nlimit = se.se_ntotal; if (param->prefmaxlen == SMB_SRVSVC_MAXPREFLEN || param->prefmaxlen > SMB_SRVSVC_MAXBUFLEN) @@ -2023,8 +2118,9 @@ se.se_prefmaxlen = param->prefmaxlen; if (param->resume_handle) { - se.se_resume_handle = *param->resume_handle; - se.se_n_skip = se.se_resume_handle; + se.se_resume = *param->resume_handle; + se.se_nskip = se.se_resume; + *param->resume_handle = 0; } switch (param->level) { @@ -2056,24 +2152,20 @@ return (NDR_DRC_OK); } - if (se.se_n_enum == 0) { - if (param->resume_handle) - *param->resume_handle = 0; + if (se.se_nlimit == 0) { param->status = ERROR_SUCCESS; return (NDR_DRC_OK); } if (param->resume_handle && param->prefmaxlen != SMB_SRVSVC_MAXPREFLEN) { - if (se.se_resume_handle < se.se_n_total) { - *param->resume_handle = se.se_resume_handle; + if (se.se_resume < se.se_ntotal) { + *param->resume_handle = se.se_resume; status = ERROR_MORE_DATA; - } else { - *param->resume_handle = 0; } } - param->totalentries = se.se_n_total; + param->totalentries = se.se_ntotal; param->status = status; return (NDR_DRC_OK); } @@ -2082,33 +2174,33 @@ * NetShareEnum Level 0 */ static DWORD -mlsvc_NetShareEnumLevel0(ndr_xa_t *mxa, - struct mslm_infonres *infonres, srvsvc_enum_t *se, int sticky) +mlsvc_NetShareEnumLevel0(ndr_xa_t *mxa, srvsvc_infonres_t *infonres, + smb_svcenum_t *se, int sticky) { struct mslm_NetShareInfo_0 *info0; smb_shriter_t iterator; smb_share_t *si; DWORD status; - se->se_n_enum = srvsvc_estimate_objcnt(se->se_prefmaxlen, - se->se_n_total, sizeof (struct mslm_NetShareInfo_0) + MAXNAMELEN); - if (se->se_n_enum == 0) + srvsvc_estimate_limit(se, + sizeof (struct mslm_NetShareInfo_0) + MAXNAMELEN); + if (se->se_nlimit == 0) return (ERROR_SUCCESS); - info0 = NDR_NEWN(mxa, struct mslm_NetShareInfo_0, se->se_n_enum); + info0 = NDR_NEWN(mxa, struct mslm_NetShareInfo_0, se->se_nlimit); if (info0 == NULL) return (ERROR_NOT_ENOUGH_MEMORY); smb_shr_iterinit(&iterator); - se->se_n_read = 0; + se->se_nitems = 0; while ((si = smb_shr_iterate(&iterator)) != NULL) { - if (se->se_n_skip > 0) { - --se->se_n_skip; + if (se->se_nskip > 0) { + --se->se_nskip; continue; } - ++se->se_resume_handle; + ++se->se_resume; if (sticky && (si->shr_flags & SMB_SHRF_TRANS)) continue; @@ -2116,8 +2208,8 @@ if (si->shr_flags & SMB_SHRF_AUTOHOME) continue; - if (se->se_n_read >= se->se_n_enum) { - se->se_n_read = se->se_n_enum; + if (se->se_nitems >= se->se_nlimit) { + se->se_nitems = se->se_nlimit; break; } @@ -2125,15 +2217,15 @@ if (status != ERROR_SUCCESS) break; - ++se->se_n_read; + ++se->se_nitems; } - if (se->se_n_read < se->se_n_enum) { + if (se->se_nitems < se->se_nlimit) { if (srvsvc_add_autohome(mxa, se, (void *)info0)) - ++se->se_n_read; + ++se->se_nitems; } - infonres->entriesread = se->se_n_read; + infonres->entriesread = se->se_nitems; infonres->entries = info0; return (ERROR_SUCCESS); } @@ -2142,33 +2234,33 @@ * NetShareEnum Level 1 */ static DWORD -mlsvc_NetShareEnumLevel1(ndr_xa_t *mxa, - struct mslm_infonres *infonres, srvsvc_enum_t *se, int sticky) +mlsvc_NetShareEnumLevel1(ndr_xa_t *mxa, srvsvc_infonres_t *infonres, + smb_svcenum_t *se, int sticky) { struct mslm_NetShareInfo_1 *info1; smb_shriter_t iterator; smb_share_t *si; DWORD status; - se->se_n_enum = srvsvc_estimate_objcnt(se->se_prefmaxlen, - se->se_n_total, sizeof (struct mslm_NetShareInfo_1) + MAXNAMELEN); - if (se->se_n_enum == 0) + srvsvc_estimate_limit(se, + sizeof (struct mslm_NetShareInfo_1) + MAXNAMELEN); + if (se->se_nlimit == 0) return (ERROR_SUCCESS); - info1 = NDR_NEWN(mxa, struct mslm_NetShareInfo_1, se->se_n_enum); + info1 = NDR_NEWN(mxa, struct mslm_NetShareInfo_1, se->se_nlimit); if (info1 == NULL) return (ERROR_NOT_ENOUGH_MEMORY); smb_shr_iterinit(&iterator); - se->se_n_read = 0; + se->se_nitems = 0; while ((si = smb_shr_iterate(&iterator)) != 0) { - if (se->se_n_skip > 0) { - --se->se_n_skip; + if (se->se_nskip > 0) { + --se->se_nskip; continue; } - ++se->se_resume_handle; + ++se->se_resume; if (sticky && (si->shr_flags & SMB_SHRF_TRANS)) continue; @@ -2176,8 +2268,8 @@ if (si->shr_flags & SMB_SHRF_AUTOHOME) continue; - if (se->se_n_read >= se->se_n_enum) { - se->se_n_read = se->se_n_enum; + if (se->se_nitems >= se->se_nlimit) { + se->se_nitems = se->se_nlimit; break; } @@ -2185,15 +2277,15 @@ if (status != ERROR_SUCCESS) break; - ++se->se_n_read; + ++se->se_nitems; } - if (se->se_n_read < se->se_n_enum) { + if (se->se_nitems < se->se_nlimit) { if (srvsvc_add_autohome(mxa, se, (void *)info1)) - ++se->se_n_read; + ++se->se_nitems; } - infonres->entriesread = se->se_n_read; + infonres->entriesread = se->se_nitems; infonres->entries = info1; return (ERROR_SUCCESS); } @@ -2202,33 +2294,33 @@ * NetShareEnum Level 2 */ static DWORD -mlsvc_NetShareEnumLevel2(ndr_xa_t *mxa, - struct mslm_infonres *infonres, srvsvc_enum_t *se, int sticky) +mlsvc_NetShareEnumLevel2(ndr_xa_t *mxa, srvsvc_infonres_t *infonres, + smb_svcenum_t *se, int sticky) { struct mslm_NetShareInfo_2 *info2; smb_shriter_t iterator; smb_share_t *si; DWORD status; - se->se_n_enum = srvsvc_estimate_objcnt(se->se_prefmaxlen, - se->se_n_total, sizeof (struct mslm_NetShareInfo_2) + MAXNAMELEN); - if (se->se_n_enum == 0) + srvsvc_estimate_limit(se, + sizeof (struct mslm_NetShareInfo_2) + MAXNAMELEN); + if (se->se_nlimit == 0) return (ERROR_SUCCESS); - info2 = NDR_NEWN(mxa, struct mslm_NetShareInfo_2, se->se_n_enum); + info2 = NDR_NEWN(mxa, struct mslm_NetShareInfo_2, se->se_nlimit); if (info2 == NULL) return (ERROR_NOT_ENOUGH_MEMORY); smb_shr_iterinit(&iterator); - se->se_n_read = 0; + se->se_nitems = 0; while ((si = smb_shr_iterate(&iterator)) != 0) { - if (se->se_n_skip > 0) { - --se->se_n_skip; + if (se->se_nskip > 0) { + --se->se_nskip; continue; } - ++se->se_resume_handle; + ++se->se_resume; if (sticky && (si->shr_flags & SMB_SHRF_TRANS)) continue; @@ -2236,8 +2328,8 @@ if (si->shr_flags & SMB_SHRF_AUTOHOME) continue; - if (se->se_n_read >= se->se_n_enum) { - se->se_n_read = se->se_n_enum; + if (se->se_nitems >= se->se_nlimit) { + se->se_nitems = se->se_nlimit; break; } @@ -2245,15 +2337,15 @@ if (status != ERROR_SUCCESS) break; - ++se->se_n_read; + ++se->se_nitems; } - if (se->se_n_read < se->se_n_enum) { + if (se->se_nitems < se->se_nlimit) { if (srvsvc_add_autohome(mxa, se, (void *)info2)) - ++se->se_n_read; + ++se->se_nitems; } - infonres->entriesread = se->se_n_read; + infonres->entriesread = se->se_nitems; infonres->entries = info2; return (ERROR_SUCCESS); } @@ -2262,34 +2354,34 @@ * NetShareEnum Level 501 */ static DWORD -mlsvc_NetShareEnumLevel501(ndr_xa_t *mxa, - struct mslm_infonres *infonres, srvsvc_enum_t *se, int sticky) +mlsvc_NetShareEnumLevel501(ndr_xa_t *mxa, srvsvc_infonres_t *infonres, + smb_svcenum_t *se, int sticky) { struct mslm_NetShareInfo_501 *info501; smb_shriter_t iterator; smb_share_t *si; DWORD status; - se->se_n_enum = srvsvc_estimate_objcnt(se->se_prefmaxlen, - se->se_n_total, sizeof (struct mslm_NetShareInfo_501) + MAXNAMELEN); - if (se->se_n_enum == 0) + srvsvc_estimate_limit(se, + sizeof (struct mslm_NetShareInfo_501) + MAXNAMELEN); + if (se->se_nlimit == 0) return (ERROR_SUCCESS); info501 = NDR_NEWN(mxa, struct mslm_NetShareInfo_501, - se->se_n_enum); + se->se_nlimit); if (info501 == NULL) return (ERROR_NOT_ENOUGH_MEMORY); smb_shr_iterinit(&iterator); - se->se_n_read = 0; + se->se_nitems = 0; while ((si = smb_shr_iterate(&iterator)) != 0) { - if (se->se_n_skip > 0) { - --se->se_n_skip; + if (se->se_nskip > 0) { + --se->se_nskip; continue; } - ++se->se_resume_handle; + ++se->se_resume; if (sticky && (si->shr_flags & SMB_SHRF_TRANS)) continue; @@ -2297,8 +2389,8 @@ if (si->shr_flags & SMB_SHRF_AUTOHOME) continue; - if (se->se_n_read >= se->se_n_enum) { - se->se_n_read = se->se_n_enum; + if (se->se_nitems >= se->se_nlimit) { + se->se_nitems = se->se_nlimit; break; } @@ -2306,15 +2398,15 @@ if (status != ERROR_SUCCESS) break; - ++se->se_n_read; + ++se->se_nitems; } - if (se->se_n_read < se->se_n_enum) { + if (se->se_nitems < se->se_nlimit) { if (srvsvc_add_autohome(mxa, se, (void *)info501)) - ++se->se_n_read; + ++se->se_nitems; } - infonres->entriesread = se->se_n_read; + infonres->entriesread = se->se_nitems; infonres->entries = info501; return (ERROR_SUCCESS); } @@ -2323,34 +2415,34 @@ * NetShareEnum Level 502 */ static DWORD -mlsvc_NetShareEnumLevel502(ndr_xa_t *mxa, - struct mslm_infonres *infonres, srvsvc_enum_t *se, int sticky) +mlsvc_NetShareEnumLevel502(ndr_xa_t *mxa, srvsvc_infonres_t *infonres, + smb_svcenum_t *se, int sticky) { struct mslm_NetShareInfo_502 *info502; smb_shriter_t iterator; smb_share_t *si; DWORD status; - se->se_n_enum = srvsvc_estimate_objcnt(se->se_prefmaxlen, - se->se_n_total, sizeof (struct mslm_NetShareInfo_502) + MAXNAMELEN); - if (se->se_n_enum == 0) + srvsvc_estimate_limit(se, + sizeof (struct mslm_NetShareInfo_502) + MAXNAMELEN); + if (se->se_nlimit == 0) return (ERROR_SUCCESS); info502 = NDR_NEWN(mxa, struct mslm_NetShareInfo_502, - se->se_n_enum); + se->se_nlimit); if (info502 == NULL) return (ERROR_NOT_ENOUGH_MEMORY); smb_shr_iterinit(&iterator); - se->se_n_read = 0; + se->se_nitems = 0; while ((si = smb_shr_iterate(&iterator)) != NULL) { - if (se->se_n_skip > 0) { - --se->se_n_skip; + if (se->se_nskip > 0) { + --se->se_nskip; continue; } - ++se->se_resume_handle; + ++se->se_resume; if (sticky && (si->shr_flags & SMB_SHRF_TRANS)) continue; @@ -2358,8 +2450,8 @@ if (si->shr_flags & SMB_SHRF_AUTOHOME) continue; - if (se->se_n_read >= se->se_n_enum) { - se->se_n_read = se->se_n_enum; + if (se->se_nitems >= se->se_nlimit) { + se->se_nitems = se->se_nlimit; break; } @@ -2367,15 +2459,15 @@ if (status != ERROR_SUCCESS) break; - ++se->se_n_read; + ++se->se_nitems; } - if (se->se_n_read < se->se_n_enum) { + if (se->se_nitems < se->se_nlimit) { if (srvsvc_add_autohome(mxa, se, (void *)info502)) - ++se->se_n_read; + ++se->se_nitems; } - infonres->entriesread = se->se_n_read; + infonres->entriesread = se->se_nitems; infonres->entries = info502; return (ERROR_SUCCESS); } @@ -2396,7 +2488,7 @@ * ERROR_INVALID_LEVEL */ static DWORD -mlsvc_NetShareEnumCommon(ndr_xa_t *mxa, srvsvc_enum_t *se, +mlsvc_NetShareEnumCommon(ndr_xa_t *mxa, smb_svcenum_t *se, smb_share_t *si, void *infop) { struct mslm_NetShareInfo_0 *info0; @@ -2409,7 +2501,7 @@ uint8_t *comment; uint8_t *passwd; uint8_t *path; - int i = se->se_n_read; + int i = se->se_nitems; netname = (uint8_t *)NDR_STRDUP(mxa, si->shr_name); comment = (uint8_t *)NDR_STRDUP(mxa, si->shr_cmnt); @@ -2487,10 +2579,10 @@ * share to avoid duplicates. */ static boolean_t -srvsvc_add_autohome(ndr_xa_t *mxa, srvsvc_enum_t *se, void *infop) +srvsvc_add_autohome(ndr_xa_t *mxa, smb_svcenum_t *se, void *infop) { - smb_opipe_context_t *ctx = &mxa->pipe->np_ctx; - char *username = ctx->oc_account; + smb_netuserinfo_t *user = &mxa->pipe->np_user; + char *username = user->ui_account; smb_share_t si; DWORD status; @@ -2580,8 +2672,8 @@ /* * srvsvc_s_NetShareDel * - * Delete a share. Only the administrator, or a member of the domain - * administrators group, is allowed to delete shares. + * Delete a share. Only members of the Administrators, Server Operators + * or Power Users local groups are allowed to delete shares. * * This interface is used by the rmtshare command from the NT resource * kit. Rmtshare allows a client to add or remove shares on a server
--- a/usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.c Mon Jul 20 13:07:46 2009 -0400 @@ -30,7 +30,6 @@ * of Solaris SMF service are displayed on the Server/Connection Manager * Windows client. */ - #include <stdio.h> #include <stdlib.h> #include <stdarg.h> @@ -40,9 +39,12 @@ #include <libscf.h> #include <libscf_priv.h> #include <time.h> +#include <dlfcn.h> #include <sys/types.h> - -#include "svcctl_scm.h" +#include <smbsrv/winsvc.h> +#include <smbsrv/nterror.h> +#include <smbsrv/ndl/svcctl.ndl> +#include <smbsrv/libmlsvc.h> #define LEGACY_UNKNOWN "unknown" #define SVC_NAME_PROP "name" @@ -51,6 +53,12 @@ #define EMPTY_OK 0x01 #define MULTI_OK 0x02 +static void *svcctl_scm_interposer_hdl = NULL; +static struct { + int (*svcctl_op_scm_init)(svcctl_manager_context_t *); + int (*svcctl_op_scf_init)(svcctl_manager_context_t *); +} svcctl_scm_ops; + /* * svcctl_scm_avl_nodecmp * @@ -659,7 +667,7 @@ * * Calculates bytes needed to enumerate SMF services. */ -void +static void svcctl_scm_bytes_needed(svcctl_manager_context_t *mgr_ctx) { int bytes_needed = 0, svc_enum_status_size = 0; @@ -761,6 +769,10 @@ svcctl_scm_refresh(svcctl_manager_context_t *mgr_ctx) { svcctl_scm_fini(mgr_ctx); + + if (svcctl_scm_ops.svcctl_op_scm_init != NULL) + return (svcctl_scm_ops.svcctl_op_scm_init(mgr_ctx)); + return (svcctl_scm_init(mgr_ctx)); } @@ -772,6 +784,10 @@ int svcctl_scm_scf_handle_init(svcctl_manager_context_t *mgr_ctx) { + if (svcctl_scm_ops.svcctl_op_scf_init != NULL) + return (svcctl_scm_ops. + svcctl_op_scf_init(mgr_ctx)); + mgr_ctx->mc_scf_hdl = scf_handle_create(SCF_VERSION); if (mgr_ctx->mc_scf_hdl == NULL) return (-1); @@ -810,8 +826,11 @@ scf_value_destroy(mgr_ctx->mc_scf_gval); scf_property_destroy(mgr_ctx->mc_scf_gprop); scf_pg_destroy(mgr_ctx->mc_scf_gpg); - (void) scf_handle_unbind(mgr_ctx->mc_scf_hdl); - scf_handle_destroy(mgr_ctx->mc_scf_hdl); + + if (mgr_ctx->mc_scf_hdl != NULL) { + (void) scf_handle_unbind(mgr_ctx->mc_scf_hdl); + scf_handle_destroy(mgr_ctx->mc_scf_hdl); + } } /* @@ -829,6 +848,9 @@ assert(mgr_ctx->mc_svcs_pool == NULL); assert(mgr_ctx->mc_svcs == NULL); + if (svcctl_scm_ops.svcctl_op_scm_init != NULL) + return (svcctl_scm_ops.svcctl_op_scm_init(mgr_ctx)); + mgr_ctx->mc_svcs_pool = uu_avl_pool_create("smf_svcs_pool", sizeof (svcctl_svc_node_t), offsetof(svcctl_svc_node_t, sn_node), svcctl_scm_avl_nodecmp, UU_AVL_DEBUG); @@ -890,3 +912,47 @@ mgr_ctx->mc_svcs_pool = NULL; mgr_ctx->mc_svcs = NULL; } + +/* + * svcctl_init + * + * Initializes the SVCCTL service. + * Initializes handle and ops structure to interposed library. + */ +void +svcctl_init(void) +{ + svcctl_scm_interposer_hdl = smb_dlopen(); + if (svcctl_scm_interposer_hdl == NULL) + return; + + bzero((void *)&svcctl_scm_ops, + sizeof (svcctl_scm_ops)); + + svcctl_scm_ops.svcctl_op_scm_init = + (int (*)())dlsym(svcctl_scm_interposer_hdl, "svcctl_scm_init"); + + svcctl_scm_ops.svcctl_op_scf_init = + (int (*)())dlsym(svcctl_scm_interposer_hdl, + "svcctl_scm_scf_handle_init"); + + if (svcctl_scm_ops.svcctl_op_scm_init == NULL || + svcctl_scm_ops.svcctl_op_scf_init == NULL) + svcctl_fini(); + +} + +/* + * svcctl_fini + * + * Finalizes the SVCCTL service. + * Closes handle to interposed library. + */ +void +svcctl_fini(void) +{ + smb_dlclose(svcctl_scm_interposer_hdl); + svcctl_scm_interposer_hdl = NULL; + bzero((void *)&svcctl_scm_ops, + sizeof (svcctl_scm_ops)); +}
--- a/usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.h Tue Jul 14 11:18:27 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,108 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _SVCCTL_H -#define _SVCCTL_H - -#include <libuutil.h> -#include <smbsrv/libsmb.h> -#include <smbsrv/libmlrpc.h> -#include <smbsrv/libmlsvc.h> -#include <smbsrv/nterror.h> -#include <smbsrv/winsvc.h> -#include <smbsrv/ndl/svcctl.ndl> - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Calculate the wide-char equivalent string length required to - * store a string - including the terminating null wide-char. - */ -#define SVCCTL_WNSTRLEN(S) ((strlen((S)) + 1) * sizeof (mts_wchar_t)) - -/* An AVL-storable node representing each service in the SCM database. */ -typedef struct svcctl_svc_node { - uu_avl_node_t sn_node; - char *sn_name; /* Service Name (Key) */ - char *sn_fmri; /* Display Name (FMRI) */ - char *sn_desc; /* Description */ - char *sn_state; /* State */ -} svcctl_svc_node_t; - -/* This structure provides context for each svcctl_s_OpenManager call. */ -typedef struct svcctl_manager_context { - scf_handle_t *mc_scf_hdl; /* SCF handle */ - scf_propertygroup_t *mc_scf_gpg; /* Property group */ - scf_property_t *mc_scf_gprop; /* Property */ - scf_value_t *mc_scf_gval; /* Value */ - uint32_t mc_scf_numsvcs; /* Number of SMF services */ - ssize_t mc_scf_max_fmri_len; /* Max FMRI length */ - ssize_t mc_scf_max_value_len; /* Max Value length */ - uint32_t mc_bytes_needed; /* Number of bytes needed */ - uu_avl_pool_t *mc_svcs_pool; /* AVL pool */ - uu_avl_t *mc_svcs; /* AVL tree of SMF services */ -} svcctl_manager_context_t; - -/* This structure provides context for each svcctl_s_OpenService call. */ -typedef struct svcctl_service_context { - ndr_hdid_t *sc_mgrid; /* Manager ID */ - char *sc_svcname; /* Service Name */ -} svcctl_service_context_t; - -typedef enum { - SVCCTL_MANAGER_CONTEXT = 0, - SVCCTL_SERVICE_CONTEXT -} svcctl_context_type_t; - -/* This structure provides abstraction for service and manager context call. */ -typedef struct svcctl_context { - svcctl_context_type_t c_type; - union { - svcctl_manager_context_t *uc_mgr; - svcctl_service_context_t *uc_svc; - void *uc_cp; - } c_ctx; -} svcctl_context_t; - -/* Service Control Manager (SCM) functions */ -int svcctl_scm_init(svcctl_manager_context_t *); -void svcctl_scm_fini(svcctl_manager_context_t *); -int svcctl_scm_scf_handle_init(svcctl_manager_context_t *); -void svcctl_scm_scf_handle_fini(svcctl_manager_context_t *); -int svcctl_scm_refresh(svcctl_manager_context_t *); -void svcctl_scm_bytes_needed(svcctl_manager_context_t *); -uint32_t svcctl_scm_enum_services(svcctl_manager_context_t *, uint8_t *, - size_t, uint32_t *, boolean_t); -uint32_t svcctl_scm_validate_service(svcctl_manager_context_t *, char *); -svcctl_svc_node_t *svcctl_scm_find_service(svcctl_manager_context_t *, char *); -uint32_t svcctl_scm_map_status(const char *); - -#ifdef __cplusplus -} -#endif - -#endif /* _SVCCTL_H */
--- a/usr/src/lib/smbsrv/libmlsvc/common/svcctl_svc.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/smbsrv/libmlsvc/common/svcctl_svc.c Mon Jul 20 13:07:46 2009 -0400 @@ -37,7 +37,10 @@ #include <smbsrv/ntstatus.h> #include <smbsrv/nmpipes.h> #include <smbsrv/ntifs.h> -#include "svcctl_scm.h" +#include <smbsrv/winsvc.h> +#include <smbsrv/nterror.h> +#include <smbsrv/ndl/svcctl.ndl> +#include <smbsrv/libmlsvc.h> #define SVCCTL_SECURITY_BUFSIZE 256 #define SVCCTL_ENUMSERVICES_MINBUFSIZE 1024 @@ -120,6 +123,13 @@ svcctl_initialize(void) { (void) ndr_svc_register(&svcctl_service); + svcctl_init(); +} + +void +svcctl_finalize(void) +{ + svcctl_fini(); } /*
--- a/usr/src/lib/smbsrv/libsmb/Makefile.com Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/smbsrv/libsmb/Makefile.com Mon Jul 20 13:07:46 2009 -0400 @@ -79,7 +79,7 @@ INCS += -I$(SRC)/common/smbsrv LDLIBS += $(MACH_LDLIBS) -LDLIBS += -lscf -lmd -lnsl -lpkcs11 -lsec -lsocket -lresolv +LDLIBS += -lscf -lmd -luuid -lnsl -lpkcs11 -lsec -lsocket -lresolv LDLIBS += -lidmap -lavl -lc CPPFLAGS += $(INCS) -D_REENTRANT
--- a/usr/src/lib/smbsrv/libsmb/common/libsmb.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/smbsrv/libsmb/common/libsmb.h Mon Jul 20 13:07:46 2009 -0400 @@ -41,6 +41,7 @@ #include <libscf.h> #include <libshare.h> #include <sqlite/sqlite.h> +#include <uuid/uuid.h> #include <smbsrv/string.h> #include <smbsrv/smb_idmap.h> @@ -65,7 +66,6 @@ #define SMB_CCACHE_PATH SMB_VARRUN_DIR "/" SMB_CCACHE_FILE - /* Max value length of all SMB properties */ #define MAX_VALUE_BUFLEN 512 @@ -272,9 +272,6 @@ extern int smb_chk_hostaccess(smb_inaddr_t *, char *); extern int smb_getnameinfo(smb_inaddr_t *, char *, int, int); -extern smb_ulist_t *smb_ulist_alloc(void); -extern void smb_ulist_free(smb_ulist_t *); -extern void smb_ulist_cleanup(smb_ulist_t *); void smb_trace(const char *s); void smb_tracef(const char *fmt, ...); @@ -848,8 +845,24 @@ void smb_kmod_unbind(void); int smb_kmod_share(char *, char *); int smb_kmod_unshare(char *, char *); -int smb_kmod_get_usernum(uint32_t *); -int smb_kmod_get_userlist(smb_ulist_t *); +int smb_kmod_get_open_num(smb_opennum_t *); +int smb_kmod_enum(smb_netsvc_t *); +smb_netsvc_t *smb_kmod_enum_init(smb_svcenum_t *); +void smb_kmod_enum_fini(smb_netsvc_t *); +int smb_kmod_session_close(const char *, const char *); +int smb_kmod_file_close(uint32_t); + +/* + * Interposer library validation + */ +#define SMBEX_VERSION 1 +#define SMBEX_KEY "82273fdc-e32a-18c3-3f78-827929dc23ea" +typedef struct smbex_version { + uint32_t v_version; + uuid_t v_uuid; +} smbex_version_t; +void *smb_dlopen(void); +void smb_dlclose(void *); #ifdef __cplusplus }
--- a/usr/src/lib/smbsrv/libsmb/common/mapfile-vers Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/smbsrv/libsmb/common/mapfile-vers Mon Jul 20 13:07:46 2009 -0400 @@ -147,6 +147,8 @@ smb_ctxbuf_init; smb_ctxbuf_len; smb_ctxbuf_printf; + smb_dlclose; + smb_dlopen; smb_dr_clnt_call; smb_dr_clnt_cleanup; smb_dr_clnt_setup; @@ -219,10 +221,14 @@ smb_inet_iszero; smb_inet_ntop; smb_kmod_bind; - smb_kmod_get_userlist; - smb_kmod_get_usernum; + smb_kmod_enum; + smb_kmod_enum_init; + smb_kmod_enum_fini; + smb_kmod_file_close; + smb_kmod_get_open_num; smb_kmod_nbtlisten; smb_kmod_nbtreceive; + smb_kmod_session_close; smb_kmod_setcfg; smb_kmod_setgmtoff; smb_kmod_share; @@ -275,6 +281,12 @@ smb_msgbuf_term; smb_msgbuf_used; smb_msgbuf_word_align; + smb_netconnectinfo_decode; + smb_netconnectinfo_encode; + smb_netfileinfo_decode; + smb_netfileinfo_encode; + smb_netuserinfo_decode; + smb_netuserinfo_encode; smb_nic_addhost; smb_nic_delhost; smb_nic_is_local; @@ -289,9 +301,6 @@ smb_opipe_hdr_encode; smb_opipe_hdr_decode; smb_opipe_hdr_xdr; - smb_opipe_context_encode; - smb_opipe_context_decode; - smb_opipe_context_xdr; smb_priv_getbyname; smb_priv_getbyvalue; smb_priv_presentable_ids; @@ -348,8 +357,6 @@ smb_tonetbiosname; smb_trace; smb_tracef; - smb_ulist_alloc; - smb_ulist_free; smb_update_netlogon_seqnum; smb_wka_fini; smb_wka_get_domain;
--- a/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c Mon Jul 20 13:07:46 2009 -0400 @@ -181,83 +181,213 @@ } int -smb_kmod_get_usernum(uint32_t *punum) +smb_kmod_get_open_num(smb_opennum_t *opennum) { - smb_ioc_usernum_t ioc; + smb_ioc_opennum_t ioc; int rc; - ioc.num = 0; - rc = smb_kmod_ioctl(SMB_IOC_USER_NUMBER, &ioc.hdr, sizeof (ioc)); - if (rc == 0) - *punum = ioc.num; + bzero(&ioc, sizeof (ioc)); + ioc.qualtype = opennum->qualtype; + (void) strlcpy(ioc.qualifier, opennum->qualifier, MAXNAMELEN); + + rc = smb_kmod_ioctl(SMB_IOC_NUMOPEN, &ioc.hdr, sizeof (ioc)); + if (rc == 0) { + opennum->open_users = ioc.open_users; + opennum->open_trees = ioc.open_trees; + opennum->open_files = ioc.open_files; + } + + return (rc); +} + +/* + * Initialization for an smb_kmod_enum request. If this call succeeds, + * smb_kmod_enum_fini() must be called later to deallocate resources. + */ +smb_netsvc_t * +smb_kmod_enum_init(smb_svcenum_t *request) +{ + smb_netsvc_t *ns; + smb_svcenum_t *svcenum; + smb_ioc_svcenum_t *ioc; + uint32_t ioclen; + + if ((ns = calloc(1, sizeof (smb_netsvc_t))) == NULL) + return (NULL); + + ioclen = sizeof (smb_ioc_svcenum_t) + SMB_IOC_DATA_SIZE; + if ((ioc = malloc(ioclen)) == NULL) { + free(ns); + return (NULL); + } + + bzero(ioc, ioclen); + svcenum = &ioc->svcenum; + svcenum->se_type = request->se_type; + svcenum->se_level = request->se_level; + svcenum->se_bavail = SMB_IOC_DATA_SIZE; + svcenum->se_nlimit = request->se_nlimit; + svcenum->se_nskip = request->se_nskip; + svcenum->se_buflen = SMB_IOC_DATA_SIZE; + + list_create(&ns->ns_list, sizeof (smb_netsvcitem_t), + offsetof(smb_netsvcitem_t, nsi_lnd)); + + ns->ns_ioc = ioc; + ns->ns_ioclen = ioclen; + return (ns); +} + +/* + * Cleanup resources allocated via smb_kmod_enum_init and smb_kmod_enum. + */ +void +smb_kmod_enum_fini(smb_netsvc_t *ns) +{ + list_t *lst; + smb_netsvcitem_t *item; + smb_netuserinfo_t *user; + smb_netconnectinfo_t *tree; + smb_netfileinfo_t *ofile; + uint32_t se_type; + + if (ns == NULL) + return; + + lst = &ns->ns_list; + se_type = ns->ns_ioc->svcenum.se_type; + + while ((item = list_head(lst)) != NULL) { + list_remove(lst, item); + switch (se_type) { + case SMB_SVCENUM_TYPE_USER: + user = &item->nsi_un.nsi_user; + free(user->ui_domain); + free(user->ui_account); + free(user->ui_workstation); + break; + case SMB_SVCENUM_TYPE_TREE: + tree = &item->nsi_un.nsi_tree; + free(tree->ci_username); + free(tree->ci_share); + break; + case SMB_SVCENUM_TYPE_FILE: + ofile = &item->nsi_un.nsi_ofile; + free(ofile->fi_path); + free(ofile->fi_username); + break; + default: + break; + } + } + + list_destroy(&ns->ns_list); + free(ns->ns_items); + free(ns->ns_ioc); + free(ns); +} + +/* + * Enumerate users, connections or files. + */ +int +smb_kmod_enum(smb_netsvc_t *ns) +{ + smb_ioc_svcenum_t *ioc; + uint32_t ioclen; + smb_svcenum_t *svcenum; + smb_netsvcitem_t *items; + smb_netuserinfo_t *user; + smb_netconnectinfo_t *tree; + smb_netfileinfo_t *ofile; + uint8_t *data; + uint32_t len; + uint32_t se_type; + uint_t nbytes; + int i; + int rc; + + ioc = ns->ns_ioc; + ioclen = ns->ns_ioclen; + rc = smb_kmod_ioctl(SMB_IOC_SVCENUM, &ioc->hdr, ioclen); + if (rc != 0) + return (rc); + + svcenum = &ioc->svcenum; + items = calloc(svcenum->se_nitems, sizeof (smb_netsvcitem_t)); + if (items == NULL) + return (ENOMEM); + + ns->ns_items = items; + se_type = ns->ns_ioc->svcenum.se_type; + data = svcenum->se_buf; + len = svcenum->se_bused; + + for (i = 0; i < svcenum->se_nitems; ++i) { + switch (se_type) { + case SMB_SVCENUM_TYPE_USER: + user = &items->nsi_un.nsi_user; + rc = smb_netuserinfo_decode(user, data, len, &nbytes); + break; + case SMB_SVCENUM_TYPE_TREE: + tree = &items->nsi_un.nsi_tree; + rc = smb_netconnectinfo_decode(tree, data, len, + &nbytes); + break; + case SMB_SVCENUM_TYPE_FILE: + ofile = &items->nsi_un.nsi_ofile; + rc = smb_netfileinfo_decode(ofile, data, len, &nbytes); + break; + default: + rc = -1; + break; + } + + if (rc != 0) + return (EINVAL); + + list_insert_tail(&ns->ns_list, items); + + ++items; + data += nbytes; + len -= nbytes; + } + + return (0); +} + +/* + * A NULL pointer is a wildcard indicator, which we pass on + * as an empty string (by virtue of the bzero). + */ +int +smb_kmod_session_close(const char *client, const char *username) +{ + smb_ioc_session_t ioc; + int rc; + + bzero(&ioc, sizeof (ioc)); + + if (client != NULL) + (void) strlcpy(ioc.client, client, MAXNAMELEN); + if (username != NULL) + (void) strlcpy(ioc.username, username, MAXNAMELEN); + + rc = smb_kmod_ioctl(SMB_IOC_SESSION_CLOSE, &ioc.hdr, sizeof (ioc)); return (rc); } int -smb_kmod_get_userlist(smb_ulist_t *ulist) +smb_kmod_file_close(uint32_t uniqid) { - smb_opipe_context_t *ctx; - smb_ioc_ulist_t *ioc; - uint32_t ioc_len; - uint8_t *data; - uint32_t data_len; - uint32_t unum; - int rc; - - smb_ulist_cleanup(ulist); - - rc = smb_kmod_get_usernum(&unum); - if ((rc != 0) || (unum == 0)) - return (rc); - - ioc_len = sizeof (smb_ioc_ulist_t) + SMB_IOC_DATA_SIZE; - ioc = malloc(ioc_len); - if (ioc == NULL) - return (ENOMEM); - - ctx = malloc(sizeof (smb_opipe_context_t) * unum); - if (ctx == NULL) { - free(ioc); - return (ENOMEM); - } - ulist->ul_users = ctx; + smb_ioc_fileid_t ioc; + int rc; - while (ulist->ul_cnt < unum) { - ioc->cookie = ulist->ul_cnt; - ioc->data_len = SMB_IOC_DATA_SIZE; - rc = smb_kmod_ioctl(SMB_IOC_USER_LIST, &ioc->hdr, - ioc_len); - if (rc != 0) - break; - - if ((ulist->ul_cnt + ioc->num) > unum) - ioc->num = unum - ulist->ul_cnt; - - if (ioc->num == 0) - break; + bzero(&ioc, sizeof (ioc)); + ioc.uniqid = uniqid; - data = ioc->data; - data_len = ioc->data_len; - while (ioc->num > 0) { - uint_t bd = 0; - - rc = smb_opipe_context_decode(ctx, data, data_len, &bd); - if (rc != 0) - break; - - ctx++; - ioc->num--; - ulist->ul_cnt++; - data += bd; - data_len -= bd; - } - } - - if (rc != 0) - smb_ulist_cleanup(ulist); - - free(ioc); + rc = smb_kmod_ioctl(SMB_IOC_FILE_CLOSE, &ioc.hdr, sizeof (ioc)); return (rc); }
--- a/usr/src/lib/smbsrv/libsmb/common/smb_pwdutil.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/smbsrv/libsmb/common/smb_pwdutil.c Mon Jul 20 13:07:46 2009 -0400 @@ -45,8 +45,6 @@ #define SMB_PASSTEMP "/var/smb/ptmp" #define SMB_PASSLCK "/var/smb/.pwd.lock" -#define SMB_LIB_ALT "/usr/lib/smbsrv/libsmb_pwd.so" - #define SMB_PWD_DISABLE "*DIS*" #define SMB_PWD_BUFSIZE 256 @@ -172,11 +170,9 @@ smb_lucache_update(); } - smb_pwd_hdl = dlopen(SMB_LIB_ALT, RTLD_NOW | RTLD_LOCAL); - if (smb_pwd_hdl == NULL) { - /* No library is interposed */ + smb_pwd_hdl = smb_dlopen(); + if (smb_pwd_hdl == NULL) return; - } bzero((void *)&smb_pwd_ops, sizeof (smb_pwd_ops)); @@ -212,7 +208,7 @@ smb_pwd_ops.pwop_iteropen == NULL || smb_pwd_ops.pwop_iterclose == NULL || smb_pwd_ops.pwop_iterate == NULL) { - (void) dlclose(smb_pwd_hdl); + smb_dlclose(smb_pwd_hdl); smb_pwd_hdl = NULL; /* If error or function(s) are missing, use original lib */ @@ -230,11 +226,9 @@ smb_pwd_fini(void) { smb_lucache_destroy(); - - if (smb_pwd_hdl) { - (void) dlclose(smb_pwd_hdl); - smb_pwd_hdl = NULL; - } + smb_dlclose(smb_pwd_hdl); + smb_pwd_hdl = NULL; + bzero((void *)&smb_pwd_ops, sizeof (smb_pwd_ops)); } /*
--- a/usr/src/lib/smbsrv/libsmb/common/smb_util.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/smbsrv/libsmb/common/smb_util.c Mon Jul 20 13:07:46 2009 -0400 @@ -26,6 +26,7 @@ #include <ctype.h> #include <stdio.h> #include <string.h> +#include <strings.h> #include <stdlib.h> #include <pthread.h> #include <sys/varargs.h> @@ -37,9 +38,12 @@ #include <sys/systeminfo.h> #include <sys/utsname.h> #include <libzfs.h> +#include <dlfcn.h> #include <smbsrv/string.h> #include <smbsrv/libsmb.h> +#define SMB_LIB_ALT "/usr/lib/smbsrv/libsmbex.so" + static uint_t smb_make_mask(char *, uint_t); static boolean_t smb_netmatch(struct netbuf *, char *); static boolean_t smb_netgroup_match(struct nd_hostservlist *, char *, int); @@ -755,6 +759,64 @@ } /* + * smb_dlopen + * + * Check to see if an interposer library exists. If it exists + * and reports a valid version number and key (UUID), return + * a handle to the library. Otherwise, return NULL. + */ +void * +smb_dlopen(void) +{ + uuid_t uuid; + void *interposer_hdl; + typedef int (*smbex_versionfn_t)(smbex_version_t *); + smbex_versionfn_t getversion; + smbex_version_t *version; + + bzero(&uuid, sizeof (uuid_t)); + if (uuid_parse(SMBEX_KEY, uuid) < 0) + return (NULL); + + interposer_hdl = dlopen(SMB_LIB_ALT, RTLD_NOW | RTLD_LOCAL); + if (interposer_hdl == NULL) + return (NULL); + + bzero(&getversion, sizeof (smbex_versionfn_t)); + getversion = (smbex_versionfn_t)dlsym(interposer_hdl, + "smbex_get_version"); + if ((getversion == NULL) || + (version = malloc(sizeof (smbex_version_t))) == NULL) { + (void) dlclose(interposer_hdl); + return (NULL); + } + bzero(version, sizeof (smbex_version_t)); + + if ((getversion(version) != 0) || + (version->v_version != SMBEX_VERSION) || + (uuid_compare(version->v_uuid, uuid) != 0)) { + free(version); + (void) dlclose(interposer_hdl); + return (NULL); + } + + free(version); + return (interposer_hdl); +} + +/* + * smb_dlclose + * + * Closes handle to the interposed library. + */ +void +smb_dlclose(void *handle) +{ + if (handle) + (void) dlclose(handle); +} + +/* * Returns the hostname given the IP address. Wrapper for getnameinfo. */ int @@ -782,47 +844,3 @@ return (getnameinfo((struct sockaddr *)sp, salen, hostname, hostlen, NULL, 0, flags)); } - -smb_ulist_t * -smb_ulist_alloc(void) -{ - smb_ulist_t *ulist; - - ulist = malloc(sizeof (smb_ulist_t)); - if (ulist != NULL) { - ulist->ul_cnt = 0; - ulist->ul_users = NULL; - } - return (ulist); -} - -void -smb_ulist_free(smb_ulist_t *ulist) -{ - if (ulist != NULL) { - smb_ulist_cleanup(ulist); - free(ulist); - } -} - -void -smb_ulist_cleanup(smb_ulist_t *ulist) -{ - smb_opipe_context_t *ctx; - - if (ulist->ul_users != NULL) { - ctx = ulist->ul_users; - while (ulist->ul_cnt != 0) { - free(ctx->oc_domain); - free(ctx->oc_account); - free(ctx->oc_workstation); - ctx->oc_domain = NULL; - ctx->oc_account = NULL; - ctx->oc_workstation = NULL; - ulist->ul_cnt--; - ctx++; - } - free(ulist->ul_users); - ulist->ul_users = NULL; - } -}
--- a/usr/src/lib/sun_fc/common/TgtFCHBAPort.cc Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/lib/sun_fc/common/TgtFCHBAPort.cc Mon Jul 20 13:07:46 2009 -0400 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -401,6 +401,7 @@ fctio_t fctio; // fc_hba_adapter_port_stats_t fc_port_stat; uint64_t en_portWWN; + uint64_t DestPortID; // Validate the arguments if (pRspBuffer == NULL || @@ -417,13 +418,14 @@ /* The destWWN is either the adapter port or a discovered port. */ memset(&fctio, 0, sizeof (fctio)); - fctio.fctio_cmd = FCTIO_GET_ADAPTER_PORT_STATS; + fctio.fctio_cmd = FCTIO_GET_LINK_STATUS; fctio.fctio_ibuf = (uint64_t)(uintptr_t)&en_portWWN; fctio.fctio_ilen = (uint32_t)(sizeof (en_portWWN)); if (portWWN != destWWN) { attrs = getDiscoveredAttributes(destWWN, tmp); - fctio.fctio_abuf = (uint64_t)(uintptr_t)&attrs.PortFcId; - fctio.fctio_alen = (uint32_t)(sizeof (attrs.PortFcId)); + DestPortID = (uint64_t)attrs.PortFcId; + fctio.fctio_abuf = (uint64_t)(uintptr_t)&DestPortID; + fctio.fctio_alen = (uint32_t)(sizeof (DestPortID)); } fctio.fctio_xfer = FCTIO_XFER_READ; fctio.fctio_flags = 0;
--- a/usr/src/pkgdefs/Makefile Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/pkgdefs/Makefile Mon Jul 20 13:07:46 2009 -0400 @@ -159,6 +159,7 @@ SUNWrwn \ SUNWsi3124 \ SUNWtpm \ + SUNWuath \ SUNWural \ SUNWurtw \ SUNWvia823x \
--- a/usr/src/pkgdefs/SUNWckr/prototype_com Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/pkgdefs/SUNWckr/prototype_com Mon Jul 20 13:07:46 2009 -0400 @@ -150,5 +150,4 @@ f manifest var/svc/manifest/system/fmd.xml 0444 root sys f manifest var/svc/manifest/system/intrd.xml 0444 root sys f manifest var/svc/manifest/system/scheduler.xml 0444 root sys -d none kernel/devname 755 root sys d none kernel/kiconv 755 root sys
--- a/usr/src/pkgdefs/SUNWckr/prototype_i386 Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/pkgdefs/SUNWckr/prototype_i386 Mon Jul 20 13:07:46 2009 -0400 @@ -63,7 +63,6 @@ f none kernel/crypto/sha2 755 root sys f none kernel/crypto/swrand 755 root sys f none kernel/dacf/net_dacf 755 root sys -f none kernel/devname/sdev_nsconfig_mod 755 root sys f none kernel/drv/aggr 755 root sys f none kernel/drv/arp 755 root sys f none kernel/drv/acpi_drv 755 root sys @@ -291,8 +290,6 @@ f none kernel/crypto/amd64/swrand 755 root sys d none kernel/dacf/amd64 755 root sys f none kernel/dacf/amd64/net_dacf 755 root sys -d none kernel/devname/amd64 755 root sys -f none kernel/devname/amd64/sdev_nsconfig_mod 755 root sys d none kernel/drv/amd64 755 root sys f none kernel/drv/amd64/aggr 755 root sys f none kernel/drv/amd64/arp 755 root sys
--- a/usr/src/pkgdefs/SUNWckr/prototype_sparc Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/pkgdefs/SUNWckr/prototype_sparc Mon Jul 20 13:07:46 2009 -0400 @@ -262,8 +262,6 @@ l none kernel/sys/sparcv9/rpcmod=../../../kernel/strmod/sparcv9/rpcmod f none kernel/sys/sparcv9/semsys 755 root sys f none kernel/sys/sparcv9/shmsys 755 root sys -d none kernel/devname/sparcv9 755 root sys -f none kernel/devname/sparcv9/sdev_nsconfig_mod 755 root sys d none kernel/kiconv/sparcv9 755 root sys f none kernel/kiconv/sparcv9/kiconv_emea 755 root sys f none kernel/kiconv/sparcv9/kiconv_ja 755 root sys
--- a/usr/src/pkgdefs/SUNWcslr/prototype_com Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/pkgdefs/SUNWcslr/prototype_com Mon Jul 20 13:07:46 2009 -0400 @@ -97,6 +97,7 @@ f none lib/libintl.so.1 755 root bin s none lib/libipmp.so=./libipmp.so.1 f none lib/libipmp.so.1 755 root bin +f none lib/libkcfd.so.1 755 root bin s none lib/libkmf.so=libkmf.so.1 f none lib/libkmf.so.1 755 root bin s none lib/libkmfberder.so=libkmfberder.so.1
--- a/usr/src/pkgdefs/SUNWfmd/depend Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/pkgdefs/SUNWfmd/depend Mon Jul 20 13:07:46 2009 -0400 @@ -34,6 +34,6 @@ P SUNWcsd Core Solaris Devices P SUNWcsl Core Solaris Libraries P SUNWfmdr Fault Management Daemon and Utilities (Root) -P SUNWsmagt System Management Agent files and libraries +P SUNWnet-snmp-core Net-SNMP Agent files and libraries P SUNWlxmlr The XML library (Root) P SUNWzfsr ZFS (Root)
--- a/usr/src/pkgdefs/SUNWfmdr/prototype_com Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/pkgdefs/SUNWfmdr/prototype_com Mon Jul 20 13:07:46 2009 -0400 @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -33,11 +33,11 @@ d none etc 755 root sys d none etc/fm 755 root sys d none etc/fm/fmd 755 root sys -d none etc/sma 755 root bin -d none etc/sma/snmp 755 root bin -f none etc/sma/snmp/fmd-trapgen.conf 600 root bin -d none etc/sma/snmp/mibs 755 root bin -f none etc/sma/snmp/mibs/SUN-FM-MIB.mib 644 root bin +d none etc/net-snmp 755 root bin +d none etc/net-snmp/snmp 755 root bin +f none etc/net-snmp/snmp/fmd-trapgen.conf 600 root bin +d none etc/net-snmp/snmp/mibs 755 root bin +f none etc/net-snmp/snmp/mibs/SUN-FM-MIB.mib 644 root bin d none kernel 755 root sys d none kernel/drv 755 root sys f none kernel/drv/fm.conf 644 root sys
--- a/usr/src/pkgdefs/SUNWhea/prototype_com Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/pkgdefs/SUNWhea/prototype_com Mon Jul 20 13:07:46 2009 -0400 @@ -861,7 +861,6 @@ f none usr/include/sys/fs/cachefs_ioctl.h 644 root bin f none usr/include/sys/fs/decomp.h 644 root bin f none usr/include/sys/fs/dv_node.h 644 root bin -f none usr/include/sys/fs/sdev_node.h 644 root bin f none usr/include/sys/fs/sdev_impl.h 644 root bin f none usr/include/sys/fs/fifonode.h 644 root bin f none usr/include/sys/fs/hsfs_isospec.h 644 root bin
--- a/usr/src/pkgdefs/SUNWldomr.v/prototype_sparc Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/pkgdefs/SUNWldomr.v/prototype_sparc Mon Jul 20 13:07:46 2009 -0400 @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # @@ -75,6 +75,7 @@ d none platform/sun4v/kernel/misc/sparcv9 755 root sys f none platform/sun4v/kernel/misc/sparcv9/dr_cpu 755 root sys f none platform/sun4v/kernel/misc/sparcv9/dr_io 755 root sys +f none platform/sun4v/kernel/misc/sparcv9/dr_mem 755 root sys f none platform/sun4v/kernel/misc/sparcv9/ds 755 root sys f none platform/sun4v/kernel/misc/sparcv9/fault_iso 755 root sys f none platform/sun4v/kernel/misc/sparcv9/ldc 755 root sys
--- a/usr/src/pkgdefs/SUNWlibsasl/pkginfo.tmpl Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/pkgdefs/SUNWlibsasl/pkginfo.tmpl Mon Jul 20 13:07:46 2009 -0400 @@ -1,9 +1,7 @@ # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" -# # # This required package information file describes characteristics of the @@ -11,7 +9,7 @@ # and package architecture. # PKG="SUNWlibsasl" -NAME="SASL v2" +NAME="Simple Authentication and Security Layer (SASL) v2 shared library and plugins" ARCH="ISA" VERSION="ONVERS,REV=0.0.0" SUNW_PRODNAME="SunOS" @@ -19,7 +17,7 @@ SUNW_PKGTYPE="usr" MAXINST="1000" CATEGORY="system" -DESC="Simple Authentication and Security Layer shared library and plugins" +DESC="Simple Authentication and Security Layer (SASL) v2 shared library and plugins" VENDOR="Sun Microsystems, Inc." HOTLINE="Please contact your local service provider" EMAIL=""
--- a/usr/src/pkgdefs/SUNWmdb/prototype_i386 Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/pkgdefs/SUNWmdb/prototype_i386 Mon Jul 20 13:07:46 2009 -0400 @@ -82,6 +82,7 @@ f none usr/lib/mdb/kvm/amd64/ptm.so 555 root sys f none usr/lib/mdb/kvm/amd64/random.so 555 root sys f none usr/lib/mdb/kvm/amd64/s1394.so 555 root sys +f none usr/lib/mdb/kvm/amd64/sata.so 555 root sys f none usr/lib/mdb/kvm/amd64/scsi_vhci.so 555 root sys f none usr/lib/mdb/kvm/amd64/sctp.so 555 root sys f none usr/lib/mdb/kvm/amd64/sd.so 555 root sys @@ -117,6 +118,7 @@ f none usr/lib/mdb/kvm/ptm.so 555 root sys f none usr/lib/mdb/kvm/random.so 555 root sys f none usr/lib/mdb/kvm/s1394.so 555 root sys +f none usr/lib/mdb/kvm/sata.so 555 root sys f none usr/lib/mdb/kvm/scsi_vhci.so 555 root sys f none usr/lib/mdb/kvm/sctp.so 555 root sys f none usr/lib/mdb/kvm/sd.so 555 root sys
--- a/usr/src/pkgdefs/SUNWmdbr/prototype_i386 Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/pkgdefs/SUNWmdbr/prototype_i386 Mon Jul 20 13:07:46 2009 -0400 @@ -51,6 +51,7 @@ f none kernel/kmdb/amd64/ptm 555 root sys f none kernel/kmdb/amd64/random 555 root sys f none kernel/kmdb/amd64/s1394 555 root sys +f none kernel/kmdb/amd64/sata 555 root sys f none kernel/kmdb/amd64/scsi_vhci 555 root sys f none kernel/kmdb/amd64/sctp 555 root sys f none kernel/kmdb/amd64/sd 555 root sys @@ -85,6 +86,7 @@ f none kernel/kmdb/ptm 555 root sys f none kernel/kmdb/random 555 root sys f none kernel/kmdb/s1394 555 root sys +f none kernel/kmdb/sata 555 root sys f none kernel/kmdb/scsi_vhci 555 root sys f none kernel/kmdb/sctp 555 root sys f none kernel/kmdb/sd 555 root sys
--- a/usr/src/pkgdefs/SUNWpcu/prototype_com Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/pkgdefs/SUNWpcu/prototype_com Mon Jul 20 13:07:46 2009 -0400 @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # This required package information file contains a list of package contents. @@ -46,7 +46,7 @@ f none usr/bin/lpset 4511 root lp f none usr/bin/lptest 555 root lp s none usr/bin/desktop-print-management=../sbin/print-service -s none usr/bin/desktop-print-management-applet=../sbin/print-service +f none usr/bin/desktop-print-management-applet 0555 root bin s none usr/bin/desktop-print-management-prefs=../sbin/print-service d none usr/lib 0755 root bin d none usr/lib/lp 0755 root lp
--- a/usr/src/pkgdefs/SUNWsacom/Makefile Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/pkgdefs/SUNWsacom/Makefile Mon Jul 20 13:07:46 2009 -0400 @@ -20,10 +20,9 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" # include ../Makefile.com @@ -36,7 +35,7 @@ ( chmod 666 depend; \ echo "P SUNWmibii Solstice Enterprise Agents SNMP daemon" >> depend; \ echo "P SUNWsasnm Solstice Enterprise Agents Simple Network Management Protocol" >> depend; \ - echo "P SUNWsmmgr System Management Agent Startup scripts" >> depend; \ + echo "P SUNWnet-snmp-mgr Net-SNMP Agent configuration files and Startup scripts" >> depend; \ echo "P SUNWlibC SPARCompilers Bundled libC" >> depend; \ chmod 444 depend )
--- a/usr/src/pkgdefs/SUNWstmfu/Makefile Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/pkgdefs/SUNWstmfu/Makefile Mon Jul 20 13:07:46 2009 -0400 @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -27,8 +27,6 @@ .KEEP_STATE: -DATAFILES += depend - all: $(FILES) install: all pkg
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkgdefs/SUNWstmfu/depend Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,50 @@ +# +# Copyright 2009 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 (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 +# +# This package information file defines software dependencies associated +# with the pkg. You can define three types of pkg dependencies with this file: +# P indicates a prerequisite for installation +# I indicates an incompatible package +# R indicates a reverse dependency +# <pkg.abbr> see pkginfo(4), PKG parameter +# <name> see pkginfo(4), NAME parameter +# <version> see pkginfo(4), VERSION parameter +# <arch> see pkginfo(4), ARCH parameter +# <type> <pkg.abbr> <name> +# (<arch>)<version> +# (<arch>)<version> +# ... +# <type> <pkg.abbr> <name> +# ... +# + +P SUNWcar Core Architecture, (Root) +P SUNWcakr Core Solaris Kernel Architecture (Root) +P SUNWkvm Core Architecture, (Kvm) +P SUNWcsr Core Solaris, (Root) +P SUNWckr Core Solaris Kernel (Root) +P SUNWcnetr Core Solaris Network Infrastructure (Root) +P SUNWcsu Core Solaris, (Usr) +P SUNWcsd Core Solaris Devices +P SUNWcsl Core Solaris Libraries +P SUNWlibmsr Math & Microtasking Libraries (Root)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkgdefs/SUNWuath/Makefile Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,38 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# + +include ../Makefile.com + +LICENSEFILES = \ + ../../uts/common/io/uath/THIRDPARTYLICENSE \ + ../../uts/common/io/uath/uath_fw/LICENSE +CDDL = + +.KEEP_STATE: + +all: $(FILES) depend postinstall postremove +install: all pkg + +include ../Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkgdefs/SUNWuath/depend Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,50 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# This package information file defines software dependencies associated +# with the pkg. You can define three types of pkg dependencies with this file: +# P indicates a prerequisite for installation +# I indicates an incompatible package +# R indicates a reverse dependency +# <pkg.abbr> see pkginfo(4), PKG parameter +# <name> see pkginfo(4), NAME parameter +# <version> see pkginfo(4), VERSION parameter +# <arch> see pkginfo(4), ARCH parameter +# <type> <pkg.abbr> <name> +# (<arch>)<version> +# (<arch>)<version> +# ... +# <type> <pkg.abbr> <name> +# ... + +P SUNWcar Core Architecture, (Root) +P SUNWcakr Core Solaris Kernel Architecture (Root) +P SUNWkvm Core Architecture, (Kvm) +P SUNWcsr Core Solaris, (Root) +P SUNWckr Core Solaris Kernel (Root) +P SUNWcnetr Core Solaris Network Infrastructure (Root) +P SUNWcsu Core Solaris, (Usr) +P SUNWcsd Core Solaris Devices +P SUNWcsl Core Solaris Libraries +P SUNWusb USB Device Drivers
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkgdefs/SUNWuath/pkginfo.tmpl Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,45 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# + +PKG="SUNWuath" +NAME="Atheros AR5523 USB IEEE802.11b/g Wireless Network Driver" +ARCH="ISA" +VERSION="ONVERS,REV=0.0.0" +SUNW_PRODNAME="SunOS" +SUNW_PRODVERS="RELEASE/VERSION" +SUNW_PKGVERS="1.0" +SUNW_PKGTYPE="root" +MAXINST="1000" +CATEGORY="system" +VENDOR="Sun Microsystems, Inc." +DESC="Atheros AR5523 USB IEEE802.11b/g Wireless Network Driver" +CLASSES="none" +HOTLINE="Please contact your local service provider" +EMAIL="" +BASEDIR=/ +SUNW_PKG_ALLZONES="true" +SUNW_PKG_HOLLOW="true" +SUNW_PKG_THISZONE="false"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkgdefs/SUNWuath/postinstall Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,91 @@ +#! /usr/bin/sh +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# Driver info +DRV=uath +DRVALIAS='"usbcf3,2" "usbcf3,3" "usb1385,4251" "usb1385,4252"' + +BASEDIR=${BASEDIR:-/} + +# Function: check_add_drv() +# +# This function will check if add_drv has been executed. +# If not simply calls add_drv. Otherwise adds entries to +# driver_aliases, driver_classes and minor_perm if necessary. +# The syntax of this function is the same as add_drv. + +check_add_drv() +{ + CMD="add_drv" + + ALIAS="" + ALIASDIR="${BASEDIR}"/etc/driver_aliases + while getopts i:b: opt 2>/dev/null; do + case "$opt" in + i) CMD="${CMD} -i ${OPTARG}" + ALIAS=`echo ${OPTARG} | /usr/bin/sed -e "s/'//g"` + ;; + b) if [ "${OPTARG}" != "/" ]; then + # On a client + # modify the sytem files and touch + # /reconfigure for reconfigure reboot + CMD="${CMD} -b \"${OPTARG}\"" + fi + ;; + \?) echo "check_add_drv(): Unknown option $opt" + return + ;; + esac + done + shift `/usr/bin/expr ${OPTIND} - 1` + DRIVER=$1 + CMD="${CMD} ${DRIVER}" + + # Make sure add_drv has not been previously executed + # before attempting to add the driver + /usr/bin/egrep -s "^${DRIVER}[ ]" "$BASEDIR"/etc/name_to_major + + if [ $? -ne 0 ]; then + eval ${CMD} + if [ $? -ne 0 ]; then + echo "Failed add_drv ${DRIVER}!\n" >&2 + exit 1 + fi + else + # Add driver entry if necessary + if [ -n "${ALIAS}" ]; then + for i in ${ALIAS}; do + /usr/bin/egrep -s "^${DRIVER}[ ]+$i" ${ALIASDIR} + if [ $? -ne 0 ]; then + echo "${DRIVER} $i" >> ${ALIASDIR} + fi + done + fi + fi +} + +check_add_drv -b "${BASEDIR}" -i "'${DRVALIAS}'" ${DRV}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkgdefs/SUNWuath/postremove Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,39 @@ +#! /usr/bin/sh +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# + +DRV=uath +BD=${BASEDIR:-/} +if grep -w $DRV $BD/etc/name_to_major > /dev/null 2>&1 +then + rem_drv -b ${BD} $DRV + if [ $? -ne 0 ] + then + exit 1 + fi +fi + +exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkgdefs/SUNWuath/prototype_com Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,46 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# + +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search <pathname pathname ...> # where to find pkg objects +#!include <filename> # include another 'prototype' file +#!default <mode> <owner> <group> # default used if not specified on entry +#!<param>=<value> # puts parameter in pkg environment + +# +# SUNWuath +# + +i pkginfo +i copyright +i depend +i postinstall +i postremove
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkgdefs/SUNWuath/prototype_i386 Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,55 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# + +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search <pathname pathname ...> # where to find pkg objects +#!include <filename> # include another 'prototype' file +#!default <mode> <owner> <group> # default used if not specified on entry +#!<param>=<value> # puts parameter in pkg environment + +# +# SUNWuath +# + +# Include ISA independent files (prototype_com) +# +!include prototype_com + +# uath ieee80211a/b/g wifi driver +d none kernel 0755 root sys +d none kernel/drv 0755 root sys +f none kernel/drv/uath 0755 root sys +d none kernel/misc 0755 root sys +f none kernel/misc/uathfw 0755 root sys +d none kernel/drv/amd64 0755 root sys +f none kernel/drv/amd64/uath 0755 root sys +d none kernel/misc/amd64 0755 root sys +f none kernel/misc/amd64/uathfw 0755 root sys
--- a/usr/src/pkgdefs/common_files/i.minorperm_i386 Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/pkgdefs/common_files/i.minorperm_i386 Mon Jul 20 13:07:46 2009 -0400 @@ -123,6 +123,7 @@ clone:rum 0600 root sys 0666 root sys /dev/rum clone:rwd 0600 root sys 0666 root sys /dev/rwd clone:rwn 0600 root sys 0666 root sys /dev/rwn +clone:uath 0600 root sys 0666 root sys /dev/uath clone:ural 0600 root sys 0666 root sys /dev/ural clone:urtw 0600 root sys 0666 root sys /dev/urtw clone:wpi 0600 root sys 0666 root sys /dev/wpi @@ -154,6 +155,7 @@ rum:* 0600 root sys 0666 root sys /dev/rum* rwd:* 0600 root sys 0666 root sys /dev/rwd* rwn:* 0600 root sys 0666 root sys /dev/rwn* +uath:* 0600 root sys 0666 root sys /dev/uath* ural:* 0600 root sys 0666 root sys /dev/ural* urtw:* 0600 root sys 0666 root sys /dev/urtw* wpi:* 0600 root sys 0666 root sys /dev/wpi* @@ -312,6 +314,7 @@ clone:rum clone:rwd clone:rwn +clone:uath clone:ural clone:urtw clone:wpi @@ -343,6 +346,7 @@ rum:* rwd:* rwn:* +uath:* ural:* urtw:* wpi:*
--- a/usr/src/pkgdefs/etc/exception_list_i386 Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/pkgdefs/etc/exception_list_i386 Mon Jul 20 13:07:46 2009 -0400 @@ -67,6 +67,9 @@ usr/lib/llib-lsoftcrypto i386 usr/lib/llib-lsoftcrypto.ln i386 usr/lib/amd64/llib-lsoftcrypto.ln i386 +lib/llib-lkcfd i386 +lib/llib-lkcfd.ln i386 +lib/libkcfd.so i386 # # The following files are used by the DHCP service, the # standalone's DHCP implementation, and the kernel (nfs_dlboot). @@ -1256,3 +1259,6 @@ # Private idmap RPC protocol usr/include/rpcsvc/idmap_prot.h i386 usr/include/rpcsvc/idmap_prot.x i386 + +# Private idmap directory API +usr/include/directory.h i386
--- a/usr/src/pkgdefs/etc/exception_list_sparc Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/pkgdefs/etc/exception_list_sparc Mon Jul 20 13:07:46 2009 -0400 @@ -56,6 +56,9 @@ usr/lib/llib-lsoftcrypto sparc usr/lib/llib-lsoftcrypto.ln sparc usr/lib/sparcv9/llib-lsoftcrypto.ln sparc +lib/llib-lkcfd.ln sparc +lib/llib-lkcfd sparc +lib/libkcfd.so sparc # # The following files are used by libdhcpsvc, the # standalone's DHCP implementation, and the kernel (nfs_dlboot). @@ -1355,3 +1358,6 @@ # Private idmap RPC protocol usr/include/rpcsvc/idmap_prot.h sparc usr/include/rpcsvc/idmap_prot.x sparc + +# Private idmap directory API +usr/include/directory.h sparc
--- a/usr/src/tools/elfsign/Makefile Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/tools/elfsign/Makefile Mon Jul 20 13:07:46 2009 -0400 @@ -20,9 +20,7 @@ # # -#ident "%Z%%M% %I% %E% SMI" -# -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -53,17 +51,6 @@ CPPFLAGS += -I$(SRC)/lib/libcryptoutil/common LDFLAGS += -L/lib -lmd -lelf -lkmf -lcryptoutil -lc -# -# While the gate builds a libelfsign.so linked staticly against -# pksc11_softtoken, the tools version of libelfsign is dynamically linked -# against the build machines pkcs11_softtoken.so. -# -SOFTTOKENDIR = /usr/lib/security -SOFTTOKENLIB = pkcs11_softtoken.so -LDFLAGS += -R $(SOFTTOKENDIR) $(SOFTTOKENDIR)/$(SOFTTOKENLIB) - -MKDIR= mkdir - .KEEP_STATE: all: $(PROG) $(SHFILES)
--- a/usr/src/tools/opensolaris/license-list Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/tools/opensolaris/license-list Mon Jul 20 13:07:46 2009 -0400 @@ -168,6 +168,8 @@ usr/src/uts/common/io/rwn/THIRDPARTYLICENSE usr/src/uts/common/io/rwn/fw-rt2860/LICENSE usr/src/uts/common/io/sfe/THIRDPARTYLICENSE +usr/src/uts/common/io/uath/THIRDPARTYLICENSE +usr/src/uts/common/io/uath/uath_fw/LICENSE usr/src/uts/common/io/ural/THIRDPARTYLICENSE usr/src/uts/common/io/urtw/THIRDPARTYLICENSE usr/src/uts/common/io/usb/clients/hwa1480_fw/i1480/LICENSE
--- a/usr/src/tools/scripts/bfu.sh Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/tools/scripts/bfu.sh Mon Jul 20 13:07:46 2009 -0400 @@ -6053,6 +6053,8 @@ find $root/kernel/drv -name zvol 2> /dev/null | xargs rm -f rm -f $root/kernel/drv/zvol.conf + rm -rf $root/kernel/devname + rm -f $usr/include/sys/fs/sdev_node.h # # Remove /usr/lib/old_libthread since support for it has
--- a/usr/src/tools/scripts/check_rtime.pl Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/tools/scripts/check_rtime.pl Mon Jul 20 13:07:46 2009 -0400 @@ -182,7 +182,7 @@ /usr/sfw/lib.*\ from\ .*libgthread-2\.0\.so\.0 | # non-OSNet /usr/X11/lib.*\ from\ .*libgthread-2\.0\.so\.0 | # non-OSNet /usr/sfw/lib.*\ from\ .*libcrypto\.so\.0\.9\.8 | # non-OSNet - /usr/sfw/lib.*\ from\ .*libnetsnmp\.so\.5 | # non-OSNet + /usr/sfw/lib.*\ from\ .*libnetsnmp\.so\.15 | # non-OSNet /usr/sfw/lib.*\ from\ .*libgcc_s\.so\.1 | # non-OSNet /usr.*\ from\ .*tst\.gcc\.exe | # gcc built /usr/postgres/8.3/lib.*\ from\ .*libpq\.so\.5 | # non-OSNET @@ -197,10 +197,10 @@ /lib.*\ of\ .*/lib/picl/plugins/ | # picl /lib.*\ of\ .*libcimapi\.so | # non-OSNET /lib.*\ of\ .*libjvm\.so | # non-OSNET - /lib.*\ of\ .*libnetsnmp\.so\.5 | # non-OSNET - /lib.*\ of\ .*libnetsnmpagent\.so\.5 | # non-OSNET - /lib.*\ of\ .*libnetsnmpmibs\.so\.5 | # non-OSNET - /lib.*\ of\ .*libnetsnmphelpers\.so\.5 | # non-OSNET + /lib.*\ of\ .*libnetsnmp\.so\.15 | # non-OSNET + /lib.*\ of\ .*libnetsnmpagent\.so\.15 | # non-OSNET + /lib.*\ of\ .*libnetsnmpmibs\.so\.15 | # non-OSNET + /lib.*\ of\ .*libnetsnmphelpers\.so\.15 | # non-OSNET /lib.*\ of\ .*libnspr4\.so | # non-OSNET /lib.*\ of\ .*libsoftokn3\.so | # non-OSNET /lib.*\ of\ .*libspmicommon\.so\.1 | # non-OSNET @@ -209,7 +209,9 @@ /lib.*\ of\ .*libxml2\.so\.2 | # non-OSNET /lib.*\ of\ .*libxslt\.so\.1 | # non-OSNET /lib.*\ of\ .*libpq\.so\.4 | # non-OSNET - /lib.*\ of\ .*libpython2\.4\.so\.1\.0 # non-OSNET + /lib.*\ of\ .*libpython2\.4\.so\.1\.0 | # non-OSNET + /lib.*\ of\ .*kcfd | # interposer + /libpkcs11\.so\.1;\.*\ of\ .*libkmf\.so\.1 # interposed }x; # Define any files that should only have unused (ldd -u) processing.
--- a/usr/src/uts/Makefile.targ Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/Makefile.targ Mon Jul 20 13:07:46 2009 -0400 @@ -207,9 +207,6 @@ $(ROOT_MAC_DIR)/%: $(OBJS_DIR)/% $(ROOT_MOD_DIR) $(ROOT_MAC_DIR) FRC $(INS.file) -$(ROOT_DEVNAME_DIR)/%: $(OBJS_DIR)/% $(ROOT_DEVNAME_DIR) FRC - $(INS.file) - $(USR_DRV_DIR)/%: $(OBJS_DIR)/% $(USR_DRV_DIR) FRC $(INS.file) @@ -237,9 +234,6 @@ $(USR_PCBE_DIR)/%: $(OBJS_DIR)/% $(USR_PCBE_DIR) FRC $(INS.file) -$(USR_DEVNAME_DIR)/%: $(OBJS_DIR)/% $(USR_DEVNAME_DIR) FRC - $(INS.file) - $(USR_DTRACE_DIR)/%: $(OBJS_DIR)/% $(USR_DTRACE_DIR) FRC $(INS.file)
--- a/usr/src/uts/Makefile.uts Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/Makefile.uts Mon Jul 20 13:07:46 2009 -0400 @@ -462,7 +462,6 @@ ROOT_DACF_DIR_32 = $(ROOT_MOD_DIR)/dacf ROOT_CRYPTO_DIR_32 = $(ROOT_MOD_DIR)/crypto ROOT_MAC_DIR_32 = $(ROOT_MOD_DIR)/mac -ROOT_DEVNAME_DIR_32 = $(ROOT_MOD_DIR)/devname ROOT_KICONV_DIR_32 = $(ROOT_MOD_DIR)/kiconv ROOT_KERN_DIR_64 = $(ROOT_MOD_DIR)/$(SUBDIR64) @@ -489,7 +488,6 @@ ROOT_DACF_DIR_64 = $(ROOT_MOD_DIR)/dacf/$(SUBDIR64) ROOT_CRYPTO_DIR_64 = $(ROOT_MOD_DIR)/crypto/$(SUBDIR64) ROOT_MAC_DIR_64 = $(ROOT_MOD_DIR)/mac/$(SUBDIR64) -ROOT_DEVNAME_DIR_64 = $(ROOT_MOD_DIR)/devname/$(SUBDIR64) ROOT_KICONV_DIR_64 = $(ROOT_MOD_DIR)/kiconv/$(SUBDIR64) ROOT_KERN_DIR = $(ROOT_KERN_DIR_$(CLASS)) @@ -516,7 +514,6 @@ ROOT_DACF_DIR = $(ROOT_DACF_DIR_$(CLASS)) ROOT_CRYPTO_DIR = $(ROOT_CRYPTO_DIR_$(CLASS)) ROOT_MAC_DIR = $(ROOT_MAC_DIR_$(CLASS)) -ROOT_DEVNAME_DIR = $(ROOT_DEVNAME_DIR_$(CLASS)) ROOT_KICONV_DIR = $(ROOT_KICONV_DIR_$(CLASS)) ROOT_MOD_DIRS_32 = $(ROOT_BRAND_DIR_32) $(ROOT_DRV_DIR_32) @@ -533,7 +530,7 @@ ROOT_MOD_DIRS_32 += $(ROOT_CPU_DIR_32) $(ROOT_FONT_DIR_32) ROOT_MOD_DIRS_32 += $(ROOT_TOD_DIR_32) $(ROOT_DACF_DIR_32) ROOT_MOD_DIRS_32 += $(ROOT_CRYPTO_DIR_32) $(ROOT_MAC_DIR_32) -ROOT_MOD_DIRS_32 += $(ROOT_DEVNAME_DIR_32) $(ROOT_KICONV_DIR_32) +ROOT_MOD_DIRS_32 += $(ROOT_KICONV_DIR_32) USR_MOD_DIR = $(ROOT)/usr/kernel @@ -547,7 +544,6 @@ USR_MISC_DIR_32 = $(USR_MOD_DIR)/misc USR_DACF_DIR_32 = $(USR_MOD_DIR)/dacf USR_PCBE_DIR_32 = $(USR_MOD_DIR)/pcbe -USR_DEVNAME_DIR_32 = $(USR_MOD_DIR)/devname USR_DTRACE_DIR_32 = $(USR_MOD_DIR)/dtrace USR_BRAND_DIR_32 = $(USR_MOD_DIR)/brand @@ -561,7 +557,6 @@ USR_MISC_DIR_64 = $(USR_MOD_DIR)/misc/$(SUBDIR64) USR_DACF_DIR_64 = $(USR_MOD_DIR)/dacf/$(SUBDIR64) USR_PCBE_DIR_64 = $(USR_MOD_DIR)/pcbe/$(SUBDIR64) -USR_DEVNAME_DIR_64 = $(USR_MOD_DIR)/devname/$(SUBDIR64) USR_DTRACE_DIR_64 = $(USR_MOD_DIR)/dtrace/$(SUBDIR64) USR_BRAND_DIR_64 = $(USR_MOD_DIR)/brand/$(SUBDIR64) @@ -575,7 +570,6 @@ USR_MISC_DIR = $(USR_MISC_DIR_$(CLASS)) USR_DACF_DIR = $(USR_DACF_DIR_$(CLASS)) USR_PCBE_DIR = $(USR_PCBE_DIR_$(CLASS)) -USR_DEVNAME_DIR = $(USR_DEVNAME_DIR_$(CLASS)) USR_DTRACE_DIR = $(USR_DTRACE_DIR_$(CLASS)) USR_BRAND_DIR = $(USR_BRAND_DIR_$(CLASS)) @@ -583,7 +577,7 @@ USR_MOD_DIRS_32 += $(USR_FS_DIR_32) $(USR_SCHED_DIR_32) USR_MOD_DIRS_32 += $(USR_STRMOD_DIR_32) $(USR_SYS_DIR_32) USR_MOD_DIRS_32 += $(USR_MISC_DIR_32) $(USR_DACF_DIR_32) -USR_MOD_DIRS_32 += $(USR_PCBE_DIR_32) $(USR_DEVNAME_DIR_32) +USR_MOD_DIRS_32 += $(USR_PCBE_DIR_32) USR_MOD_DIRS_32 += $(USR_DTRACE_DIR_32) $(USR_BRAND_DIR_32) # @@ -635,7 +629,7 @@ $(MMU_KMODS) $(DACF_KMODS) $(EXPORT_KMODS) $(IPP_KMODS) \ $(CRYPTO_KMODS) $(PCBE_KMODS) \ $(DRV_KMODS_$(CLASS)) $(MISC_KMODS_$(CLASS)) $(MAC_KMODS) \ - $(DEVNAME_KMODS) $(BRAND_KMODS) $(KICONV_KMODS) \ + $(BRAND_KMODS) $(KICONV_KMODS) \ $(SOCKET_KMODS) KMODS = $(GENUNIX_KMODS) $(PARALLEL_KMODS) @@ -649,7 +643,7 @@ LINT_KMODS = $(DRV_KMODS) $(EXEC_KMODS) $(FS_KMODS) $(SCHED_KMODS) \ $(TOD_KMODS) $(STRMOD_KMODS) $(SYS_KMODS) $(MISC_KMODS) \ $(MACH_KMODS) $(GSS_KMODS) $(DACF_KMODS) $(IPP_KMODS) \ - $(CRYPTO_KMODS) $(PCBE_KMODS) $(DEVNAME_KMODS) \ + $(CRYPTO_KMODS) $(PCBE_KMODS) \ $(DRV_KMODS_$(CLASS)) $(MISC_KMODS_$(CLASS)) $(MAC_KMODS) \ $(BRAND_KMODS) $(KICONV_KMODS) $(SOCKET_KMODS)
--- a/usr/src/uts/common/Makefile.files Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/Makefile.files Mon Jul 20 13:07:46 2009 -0400 @@ -1005,8 +1005,6 @@ SI3124_OBJS += si3124.o -NSCONFIG_DEVNAME_OBJS += sdev_nsconfig_mod.o - AHCI_OBJS += ahci.o PCIIDE_OBJS += pci-ide.o @@ -1733,6 +1731,10 @@ RWN_OBJS += rt2860.o +UATH_OBJS += uath.o + +UATHFW_OBJS += uathfw_mod.o + URAL_OBJS += ural.o RTW_OBJS += rtw.o smc93cx6.o rtwphy.o rtwphyio.o
--- a/usr/src/uts/common/Makefile.rules Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/Makefile.rules Mon Jul 20 13:07:46 2009 -0400 @@ -1003,6 +1003,14 @@ $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) +$(OBJS_DIR)/%.o: $(UTSBASE)/common/io/uath/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + +$(OBJS_DIR)/%.o: $(UTSBASE)/common/io/uath/uath_fw/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + $(OBJS_DIR)/%.o: $(UTSBASE)/common/io/ural/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) @@ -2121,6 +2129,12 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/softmac/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) +$(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/uath/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + +$(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/uath/uath_fw/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + $(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/ural/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL))
--- a/usr/src/uts/common/dtrace/sdt_subr.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/dtrace/sdt_subr.c Mon Jul 20 13:07:46 2009 -0400 @@ -1085,6 +1085,15 @@ "fc_port_info_t *" }, { "fc", "xfer-done", 4, 4, "stmf_data_buf_t *", "fc_xferinfo_t *" }, + { "fc", "rscn-receive", 0, 0, "fct_i_local_port_t *", + "conninfo_t *" }, + { "fc", "rscn-receive", 1, 1, "int", "int"}, + { "fc", "abts-receive", 0, 0, "fct_cmd_t *", + "conninfo_t *" }, + { "fc", "abts-receive", 1, 1, "fct_i_local_port_t *", + "fc_port_info_t *" }, + { "fc", "abts-receive", 2, 2, "fct_i_remote_port_t *", + "fc_port_info_t *" }, { NULL }
--- a/usr/src/uts/common/fs/dev/sdev_comm.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/dev/sdev_comm.c Mon Jul 20 13:07:46 2009 -0400 @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * routines to invoke user level name lookup services */ @@ -59,7 +57,6 @@ #include <sys/fs/snode.h> #include <sys/fs/dv_node.h> #include <sys/fs/sdev_impl.h> -#include <sys/fs/sdev_node.h> #include <sys/sunndi.h> #include <sys/sunddi.h> #include <sys/sunmdi.h> @@ -77,7 +74,6 @@ static kmutex_t devfsadm_lock; static kcondvar_t devfsadm_cv; -int devname_nsmaps_loaded = 0; static int dev_node_wait_timeout = DEV_NODE_WAIT_TIMEOUT; static int dev_devfsadm_startup = DEV_DEVFSADM_STARTUP; @@ -89,19 +85,9 @@ static int sdev_upcall_door_revoked = 0; static int sdev_door_upcall_filename_size; -static void sdev_devfsadmd_nsrdr(sdev_nsrdr_work_t *); static int sdev_devfsadm_revoked(void); static int sdev_ki_call_devfsadmd(sdev_door_arg_t *, sdev_door_res_t *); -/* - * nsmap_readdir processing thread - */ -static uint_t sdev_nsrdr_thread_created = 0; -static kmutex_t sdev_nsrdr_thread_lock; -static kcondvar_t sdev_nsrdr_thread_cv; -static sdev_nsrdr_work_t *sdev_nsrdr_thread_workq = NULL; -static sdev_nsrdr_work_t *sdev_nsrdr_thread_tail = NULL; - void sdev_devfsadm_lockinit(void) { @@ -164,7 +150,7 @@ } else if ((rv == -1) && (ddi_get_lbolt() >= expire)) { sdcmn_err6(("%s: wait time is up\n", - dv->sdev_name)); + dv->sdev_name)); break; } sdcmn_err6(("%s: wait " @@ -463,16 +449,13 @@ } int -devname_filename_register(int cmd, char *name) +devname_filename_register(char *name) { int error = 0; char *strbuf; char *namep; int n; - ASSERT(cmd == MODDEVNAME_LOOKUPDOOR || - cmd == MODDEVNAME_DEVFSADMNODE); - strbuf = kmem_zalloc(MOD_MAXPATH, KM_SLEEP); if (copyinstr(name, strbuf, MOD_MAXPATH, 0)) { @@ -480,272 +463,20 @@ error = EFAULT; } else { sdcmn_err6(("file %s is registering\n", strbuf)); - switch (cmd) { - case MODDEVNAME_LOOKUPDOOR: - /* handling the daemon re-start situations */ - n = strlen(strbuf) + 1; - namep = i_ddi_strdup(strbuf, KM_SLEEP); - mutex_enter(&devfsadm_lock); - sdev_release_door(); - sdev_door_upcall_filename_size = n; - sdev_door_upcall_filename = namep; - sdcmn_err6(("size %d file name %s\n", - sdev_door_upcall_filename_size, - sdev_door_upcall_filename)); - cv_broadcast(&devfsadm_cv); - mutex_exit(&devfsadm_lock); - break; - case MODDEVNAME_DEVFSADMNODE: - break; - } + /* handling the daemon re-start situations */ + n = strlen(strbuf) + 1; + namep = i_ddi_strdup(strbuf, KM_SLEEP); + mutex_enter(&devfsadm_lock); + sdev_release_door(); + sdev_door_upcall_filename_size = n; + sdev_door_upcall_filename = namep; + sdcmn_err6(("size %d file name %s\n", + sdev_door_upcall_filename_size, + sdev_door_upcall_filename)); + cv_broadcast(&devfsadm_cv); + mutex_exit(&devfsadm_lock); } kmem_free(strbuf, MOD_MAXPATH); return (error); } -static void -sdev_nsrdr_thread(void) -{ - sdev_nsrdr_work_t *work; - - for (;;) { - mutex_enter(&sdev_nsrdr_thread_lock); - if (sdev_nsrdr_thread_workq == NULL) { - cv_wait(&sdev_nsrdr_thread_cv, &sdev_nsrdr_thread_lock); - } - work = sdev_nsrdr_thread_workq; - sdev_nsrdr_thread_workq = work->next; - if (sdev_nsrdr_thread_tail == work) - sdev_nsrdr_thread_tail = work->next; - mutex_exit(&sdev_nsrdr_thread_lock); - sdev_devfsadmd_nsrdr(work); - } - /*NOTREACHED*/ -} - -int -devname_nsmaps_register(char *nvlbuf, size_t nvlsize) -{ - int error = 0; - nvlist_t *nvl, *attrs; - nvpair_t *nvp = NULL; - nvpair_t *kvp = NULL; - char *buf; - char *key; - char *dirname = NULL; - char *dirmodule = NULL; - char *dirmap = NULL; - char *orig_module; - char *orig_map; - int len = 0; - char *tmpmap; - int mapcount = 0; - - buf = kmem_zalloc(nvlsize, KM_SLEEP); - if ((error = ddi_copyin(nvlbuf, buf, nvlsize, 0)) != 0) { - kmem_free(buf, nvlsize); - return (error); - } - - ASSERT(buf); - sdcmn_err6(("devname_nsmaps_register: nsmap buf %p\n", (void *)buf)); - nvl = NULL; - error = nvlist_unpack(buf, nvlsize, &nvl, KM_SLEEP); - kmem_free(buf, nvlsize); - if (error || (nvl == NULL)) - return (error); - - /* invalidate all the nsmaps */ - mutex_enter(&devname_nsmaps_lock); - sdev_invalidate_nsmaps(); - for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; - nvp = nvlist_next_nvpair(nvl, nvp)) { - dirname = nvpair_name(nvp); - if (dirname == NULL) { - nvlist_free(nvl); - mutex_exit(&devname_nsmaps_lock); - return (-1); - } - - sdcmn_err6(("dirname %s\n", dirname)); - (void) nvpair_value_nvlist(nvp, &attrs); - for (kvp = nvlist_next_nvpair(attrs, NULL); kvp; - kvp = nvlist_next_nvpair(attrs, kvp)) { - key = nvpair_name(kvp); - sdcmn_err6(("key %s\n", key)); - if (strcmp(key, "module") == 0) { - (void) nvpair_value_string(kvp, &orig_module); - sdcmn_err6(("module %s\n", orig_module)); - dirmodule = i_ddi_strdup(orig_module, KM_SLEEP); - if (strcmp(dirmodule, "devname_null") == 0) - dirmodule = NULL; - } - - if (strcmp(key, "nsconfig") == 0) { - (void) nvpair_value_string(kvp, &orig_map); - sdcmn_err6(("dirmap %s\n", orig_map)); - dirmap = i_ddi_strdup(orig_map, KM_SLEEP); - if (strcmp(dirmap, "devname_null") == 0) - dirmap = NULL; - else if (dirmap[0] != '/') { - len = strlen(dirmap) + - strlen(ETC_DEV_DIR) + 2; - tmpmap = i_ddi_strdup(dirmap, KM_SLEEP); - (void) snprintf(dirmap, len, "%s/%s", - ETC_DEV_DIR, tmpmap); - kmem_free(tmpmap, strlen(tmpmap) + 1); - } - } - } - - if (dirmodule == NULL && dirmap == NULL) { - nvlist_free(nvl); - mutex_exit(&devname_nsmaps_lock); - return (-1); - } - - sdcmn_err6(("sdev_nsmaps_register: dir %s module %s map %s\n", - dirname, dirmodule, dirmap)); - sdev_insert_nsmap(dirname, dirmodule, dirmap); - mapcount++; - } - - if (mapcount > 0) - devname_nsmaps_loaded = 1; - - /* clean up obsolete nsmaps */ - sdev_validate_nsmaps(); - mutex_exit(&devname_nsmaps_lock); - if (nvl) - nvlist_free(nvl); - - if (sdev_nsrdr_thread_created) { - return (0); - } - - mutex_init(&sdev_nsrdr_thread_lock, NULL, MUTEX_DEFAULT, NULL); - cv_init(&sdev_nsrdr_thread_cv, NULL, CV_DEFAULT, NULL); - (void) thread_create(NULL, 0, (void (*)())sdev_nsrdr_thread, NULL, 0, - &p0, TS_RUN, minclsyspri); - sdev_nsrdr_thread_created = 1; - - return (0); -} - -void -sdev_dispatch_to_nsrdr_thread(struct sdev_node *ddv, char *dir_map, - devname_rdr_result_t *result) -{ - sdev_nsrdr_work_t *new_work; - - new_work = kmem_zalloc(sizeof (sdev_nsrdr_work_t), KM_SLEEP); - new_work->dir_name = i_ddi_strdup(ddv->sdev_name, KM_SLEEP); - new_work->dir_map = i_ddi_strdup(dir_map, KM_SLEEP); - new_work->dir_dv = ddv; - new_work->result = &result; - mutex_enter(&sdev_nsrdr_thread_lock); - if (sdev_nsrdr_thread_workq == NULL) { - sdev_nsrdr_thread_workq = new_work; - sdev_nsrdr_thread_tail = new_work; - new_work->next = NULL; - } else { - sdev_nsrdr_thread_tail->next = new_work; - sdev_nsrdr_thread_tail = new_work; - new_work->next = NULL; - } - cv_signal(&sdev_nsrdr_thread_cv); - mutex_exit(&sdev_nsrdr_thread_lock); -} - -static void -sdev_devfsadmd_nsrdr(sdev_nsrdr_work_t *work) -{ - int32_t error; - struct sdev_door_arg *argp; - struct sdev_door_res res; - struct sdev_node *ddv = work->dir_dv; - uint32_t mapcount; - - argp = kmem_zalloc(sizeof (sdev_door_arg_t), KM_SLEEP); - argp->devfsadm_cmd = DEVFSADMD_NS_READDIR; - - (void) snprintf(argp->ns_hdl.ns_name, - strlen(work->dir_dv->sdev_path) + 1, "%s", work->dir_dv->sdev_path); - (void) snprintf(argp->ns_hdl.ns_map, strlen(work->dir_map) + 1, "%s", - work->dir_map); - - sdcmn_err6(("sdev_devfsadmd_nsrdr: ns_name %s, ns_map %s\n", - argp->ns_hdl.ns_name, argp->ns_hdl.ns_map)); - error = sdev_ki_call_devfsadmd(argp, &res); - sdcmn_err6(("sdev_devfsadmd_nsrdr error %d\n", error)); - if (error == 0) { - error = res.devfsadm_error; - if (error) { - goto out; - } - - mapcount = (uint32_t)res.ns_rdr_hdl.ns_mapcount; - sdcmn_err6(("nsmapcount %d\n", mapcount)); - if (mapcount > 0) { - struct devname_nsmap *map = - ddv->sdev_mapinfo; - ASSERT(map && map->dir_map); - rw_enter(&map->dir_lock, RW_WRITER); - map->dir_maploaded = 1; - rw_exit(&map->dir_lock); - } - } - -out: - mutex_enter(&ddv->sdev_lookup_lock); - SDEV_UNBLOCK_OTHERS(ddv, SDEV_READDIR); - mutex_exit(&ddv->sdev_lookup_lock); - - kmem_free(argp, sizeof (sdev_door_arg_t)); -} - - -int -devname_nsmap_lookup(devname_lkp_arg_t *args, devname_lkp_result_t **result) -{ - int32_t error = 0; - struct sdev_door_arg *argp; - struct sdev_door_res resp; - char *link; - devname_spec_t spec; - - argp = kmem_zalloc(sizeof (sdev_door_arg_t), KM_SLEEP); - argp->devfsadm_cmd = DEVFSADMD_NS_LOOKUP; - - (void) snprintf(argp->ns_hdl.ns_name, strlen(args->devname_name) + 1, - "%s", args->devname_name); - (void) snprintf(argp->ns_hdl.ns_map, strlen(args->devname_map) + 1, - "%s", args->devname_map); - - error = sdev_ki_call_devfsadmd(argp, &resp); - if (error == 0) { - error = resp.devfsadm_error; - sdcmn_err6(("devfsadm: error %d\n", error)); - if (error) { - goto done; - } - link = resp.ns_lkp_hdl.devfsadm_link; - if (link == NULL) { - error = ENOENT; - goto done; - } - spec = resp.ns_lkp_hdl.devfsadm_spec; - sdcmn_err6(("devfsadm_link %s spec %d\n", - link, (int)spec)); - - - (*result)->devname_spec = (devname_spec_t)spec; - (*result)->devname_link = i_ddi_strdup(link, KM_SLEEP); - } else { - (*result)->devname_spec = DEVNAME_NS_NONE; - (*result)->devname_link = NULL; - } -done: - kmem_free(argp, sizeof (sdev_door_arg_t)); - return (error); -}
--- a/usr/src/uts/common/fs/dev/sdev_ncache.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/dev/sdev_ncache.c Mon Jul 20 13:07:46 2009 -0400 @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * negative cache handling for the /dev fs */ @@ -54,7 +52,7 @@ #include <sys/mount.h> #include <sys/fs/snode.h> #include <sys/fs/dv_node.h> -#include <sys/fs/sdev_node.h> +#include <sys/fs/sdev_impl.h> #include <sys/sunndi.h> #include <sys/sunmdi.h> #include <sys/ddi.h> @@ -195,9 +193,9 @@ kmem_free(*p, strlen(*p)+1); } kmem_free(dp->nvp_paths, - dp->nvp_npaths * sizeof (char *)); + dp->nvp_npaths * sizeof (char *)); kmem_free(dp->nvp_expirecnts, - dp->nvp_npaths * sizeof (int)); + dp->nvp_npaths * sizeof (int)); } kmem_free(dp, sizeof (nvp_devname_t)); @@ -297,7 +295,7 @@ rval = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP); if (rval != 0) { nvf_error("%s: nvlist alloc error %d\n", - nvf_cache_name(fd), rval); + nvf_cache_name(fd), rval); return (DDI_FAILURE); } @@ -308,7 +306,7 @@ rval = nvlist_alloc(&sub_nvl, NV_UNIQUE_NAME, KM_SLEEP); if (rval != 0) { nvf_error("%s: nvlist alloc error %d\n", - nvf_cache_name(fd), rval); + nvf_cache_name(fd), rval); sub_nvl = NULL; goto err; } @@ -706,7 +704,7 @@ !SDEV_IS_NO_NCACHE(dv) && ((failed_flags & SLF_NO_NCACHE) == 0) && ((sdev_reconfig_boot && - (sdev_boot_state != SDEV_BOOT_STATE_COMPLETE)) || + (sdev_boot_state != SDEV_BOOT_STATE_COMPLETE)) || (!sdev_reconfig_boot && ((failed_flags & SLF_REBUILT))))) { sdev_nc_addname(sdev_ncache, dv, nm, NCN_SRC_CURRENT|NCN_ACTIVE); @@ -818,7 +816,7 @@ n = strlen(dv->sdev_path) + strlen(nm) + 2; lp->ncn_name = kmem_alloc(n, KM_SLEEP); (void) sprintf(lp->ncn_name, "%s/%s", - dv->sdev_path, nm); + dv->sdev_path, nm); lp->ncn_flags = flags; lp->ncn_expirecnt = sdev_nc_expirecnt; sdev_nc_insertnode(ncl, lp);
--- a/usr/src/uts/common/fs/dev/sdev_nsconfig_mod.c Tue Jul 14 11:18:27 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,198 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * this module implements the devname_ops to fetch - * a specific entry from a /etc/dev/devname_map file or - * a name service map. - */ - -#include <sys/types.h> -#include <sys/param.h> -#include <sys/errno.h> -#include <sys/stat.h> -#include <sys/cmn_err.h> -#include <sys/sunddi.h> -#include <sys/sunndi.h> -#include <sys/modctl.h> -#include <sys/debug.h> -#include <sys/fs/sdev_impl.h> -#include <sys/fs/sdev_node.h> - -static int devname_lookup(char *, devname_handle_t *, struct cred *); -static int devname_remove(devname_handle_t *); -static int devname_rename(devname_handle_t *, char *); -static int devname_readdir(devname_handle_t *, struct cred *); -static int devname_getattr(devname_handle_t *, struct vattr *, - struct cred *); -static void devname_inactive(devname_handle_t *, struct cred *); - -static struct devname_ops devname_ops = { - DEVNOPS_REV, /* devnops_rev, */ - devname_lookup, /* devnops_lookup */ - devname_remove, /* devnops_remove */ - devname_rename, /* devnops_rename */ - devname_getattr, /* devnops_getattr */ - devname_readdir, /* devname_readdir */ - devname_inactive /* devname_inactive */ -}; - -/* - * Module linkage information for the kernel. - */ -static struct modldev modldev = { - &mod_devfsops, - "devname name service mod 1.0", - &devname_ops, -}; - -static struct modlinkage modlinkage = { - MODREV_1, &modldev, NULL -}; - -int -_init(void) -{ - return (mod_install(&modlinkage)); -} - -int -_fini(void) -{ - return (mod_remove(&modlinkage)); -} - -int -_info(struct modinfo *modinfop) -{ - return (mod_info(&modlinkage, modinfop)); -} - -/*ARGSUSED2*/ -static int -devname_lookup(char *nm, devname_handle_t *dhl, struct cred *cred) -{ - int error = 0; - char *dir = NULL; - devname_lkp_arg_t *args = NULL; - devname_lkp_result_t *result = NULL; - struct devname_nsmap *map = NULL; - - args = kmem_zalloc(sizeof (struct devname_lkp_arg), KM_SLEEP); - if (args == NULL) { - error = ENOENT; - goto errout; - } - - args->devname_name = i_ddi_strdup(nm, KM_SLEEP); - error = devname_get_dir_path(dhl, &dir); - if (error) { - error = ENOENT; - goto errout; - } - - args->devname_dir = i_ddi_strdup(dir, KM_SLEEP); - error = devname_get_dir_nsmap(dhl, &map); - if (map && map->dir_map) - args->devname_map = i_ddi_strdup(map->dir_map, KM_SLEEP); - - result = kmem_zalloc(sizeof (struct devname_lkp_result), KM_SLEEP); - if (result == NULL) { - error = ENOENT; - goto errout; - } - - - error = devname_nsmap_lookup(args, &result); - if (error) { - error = ENOENT; - goto errout; - } - - devname_set_nodetype(dhl, (void *)result->devname_link, - (int)result->devname_spec); - -errout: - if (args->devname_name) - kmem_free(args->devname_name, strlen(args->devname_name) + 1); - if (args->devname_dir) - kmem_free(args->devname_dir, strlen(args->devname_dir) + 1); - if (args->devname_map) - kmem_free(args->devname_map, strlen(args->devname_map) + 1); - if (args) - kmem_free(args, sizeof (struct devname_lkp_arg)); - if (result) - kmem_free(result, sizeof (struct devname_lkp_result)); - return (error); -} - -/*ARGSUSED*/ -static int -devname_readdir(devname_handle_t *hdl, struct cred *cred) -{ - char *entry; - char *dir; - - (void) devname_get_name(hdl, &entry); - (void) devname_get_dir_name(hdl, &dir); - - /* do not waste to do the map check */ - return (0); -} - -/*ARGSUSED*/ -static int -devname_remove(devname_handle_t *hdl) -{ - char *entry; - - (void) devname_get_name(hdl, &entry); - return (EROFS); -} - -/*ARGSUSED*/ -static int -devname_rename(devname_handle_t *ohdl, char *new_name) -{ - char *oname; - - (void) devname_get_name(ohdl, &oname); - return (ENOTSUP); -} - -/*ARGSUSED*/ -static int -devname_getattr(devname_handle_t *hdl, vattr_t *vap, struct cred *cred) -{ - return (0); -} - -/*ARGSUSED*/ -static void -devname_inactive(devname_handle_t *hdl, struct cred *cred) -{ -}
--- a/usr/src/uts/common/fs/dev/sdev_subr.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/dev/sdev_subr.c Mon Jul 20 13:07:46 2009 -0400 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -55,7 +55,6 @@ #include <sys/fs/snode.h> #include <sys/fs/dv_node.h> #include <sys/fs/sdev_impl.h> -#include <sys/fs/sdev_node.h> #include <sys/sunndi.h> #include <sys/sunmdi.h> #include <sys/conf.h> @@ -151,17 +150,9 @@ kmem_cache_t *sdev_node_cache; /* sdev_node cache */ int devtype; /* fstype */ -struct devname_ops *devname_ns_ops; /* default name service directory ops */ -kmutex_t devname_nsmaps_lock; /* protect devname_nsmaps */ - /* static */ -static struct devname_nsmap *devname_nsmaps = NULL; - /* contents from /etc/dev/devname_master */ -static int devname_nsmaps_invalidated = 0; /* "devfsadm -m" has run */ - static struct vnodeops *sdev_get_vop(struct sdev_node *); static void sdev_set_no_nocache(struct sdev_node *); -static int sdev_get_moduleops(struct sdev_node *); static fs_operation_def_t *sdev_merge_vtab(const fs_operation_def_t []); static void sdev_free_vtab(fs_operation_def_t *); @@ -335,10 +326,8 @@ cv_init(&dv->sdev_lookup_cv, NULL, CV_DEFAULT, NULL); if (SDEV_IS_GLOBAL(ddv)) { dv->sdev_flags |= SDEV_GLOBAL; - dv->sdev_mapinfo = NULL; dhl = &(dv->sdev_handle); dhl->dh_data = dv; - dhl->dh_spec = DEVNAME_NS_NONE; dhl->dh_args = NULL; sdev_set_no_nocache(dv); dv->sdev_gdir_gen = 0; @@ -380,7 +369,6 @@ dv->sdev_flags &= ~SDEV_PERSIST; dv->sdev_flags &= ~SDEV_DYNAMIC; vn_setops(vp, sdev_get_vop(dv)); /* from internal vtab */ - error = sdev_get_moduleops(dv); /* from plug-in module */ ASSERT(dv->sdev_dotdot); ASSERT(SDEVTOV(dv->sdev_dotdot)->v_type == VDIR); vp->v_rdev = SDEVTOV(dv->sdev_dotdot)->v_rdev; @@ -484,8 +472,6 @@ mutex_init(&dv->sdev_lookup_lock, NULL, MUTEX_DEFAULT, NULL); cv_init(&dv->sdev_lookup_cv, NULL, CV_DEFAULT, NULL); if (strcmp(dv->sdev_name, "/dev") == 0) { - mutex_init(&devname_nsmaps_lock, NULL, MUTEX_DEFAULT, NULL); - dv->sdev_mapinfo = NULL; dv->sdev_flags = SDEV_BUILD|SDEV_GLOBAL|SDEV_PERSIST; bzero(&dv->sdev_handle, sizeof (dv->sdev_handle)); dv->sdev_gdir_gen = 0; @@ -509,84 +495,6 @@ return (dv); } -/* - * 1. load the module - * 2. modload invokes sdev_module_register, which in turn sets - * the dv->sdev_mapinfo->dir_ops - * - * note: locking order: - * dv->sdev_contents -> map->dir_lock - */ -static int -sdev_get_moduleops(struct sdev_node *dv) -{ - int error = 0; - struct devname_nsmap *map = NULL; - char *module; - char *path; - int load = 1; - - ASSERT(SDEVTOV(dv)->v_type == VDIR); - - if (devname_nsmaps == NULL) - return (0); - - if (!sdev_nsmaps_loaded() && !sdev_nsmaps_reloaded()) - return (0); - - - path = dv->sdev_path; - if ((map = sdev_get_nsmap_by_dir(path, 0))) { - rw_enter(&map->dir_lock, RW_READER); - if (map->dir_invalid) { - if (map->dir_module && map->dir_newmodule && - (strcmp(map->dir_module, - map->dir_newmodule) == 0)) { - load = 0; - } - sdev_replace_nsmap(map, map->dir_newmodule, - map->dir_newmap); - } - - module = map->dir_module; - if (module && load) { - sdcmn_err6(("sdev_get_moduleops: " - "load module %s", module)); - rw_exit(&map->dir_lock); - error = modload("devname", module); - sdcmn_err6(("sdev_get_moduleops: error %d\n", error)); - if (error < 0) { - return (-1); - } - } else if (module == NULL) { - /* - * loading the module ops for name services - */ - if (devname_ns_ops == NULL) { - sdcmn_err6(( - "sdev_get_moduleops: modload default\n")); - error = modload("devname", DEVNAME_NSCONFIG); - sdcmn_err6(( - "sdev_get_moduleops: error %d\n", error)); - if (error < 0) { - return (-1); - } - } - - if (!rw_tryupgrade(&map->dir_lock)) { - rw_exit(&map->dir_lock); - rw_enter(&map->dir_lock, RW_WRITER); - } - ASSERT(devname_ns_ops); - map->dir_ops = devname_ns_ops; - rw_exit(&map->dir_lock); - } - } - - dv->sdev_mapinfo = map; - return (0); -} - /* directory dependent vop table */ struct sdev_vop_table { char *vt_name; /* subdirectory name */ @@ -1419,25 +1327,6 @@ } /* - * loopback into sdev_lookup() - */ -static struct vnode * -devname_find_by_devpath(char *devpath, struct vattr *vattr) -{ - int error = 0; - struct vnode *vp; - - error = lookupname(devpath, UIO_SYSSPACE, NO_FOLLOW, NULLVPP, &vp); - if (error) { - return (NULL); - } - - if (vattr) - (void) VOP_GETATTR(vp, vattr, 0, kcred, NULL); - return (vp); -} - -/* * the junction between devname and devfs */ static struct vnode * @@ -1838,92 +1727,6 @@ return (error); } -static int -sdev_call_modulelookup(struct sdev_node *ddv, struct sdev_node **dvp, char *nm, - int (*fn)(char *, devname_handle_t *, struct cred *), struct cred *cred) -{ - struct vnode *rvp = NULL; - int error = 0; - struct vattr *vap; - devname_spec_t spec; - devname_handle_t *hdl; - void *args = NULL; - struct sdev_node *dv = *dvp; - - ASSERT(dv && ddv); - hdl = &(dv->sdev_handle); - ASSERT(hdl->dh_data == dv); - mutex_enter(&dv->sdev_lookup_lock); - SDEV_BLOCK_OTHERS(dv, SDEV_LOOKUP); - mutex_exit(&dv->sdev_lookup_lock); - error = (*fn)(nm, hdl, cred); - if (error) { - return (error); - } - - spec = hdl->dh_spec; - args = hdl->dh_args; - ASSERT(args); - - switch (spec) { - case DEVNAME_NS_PATH: - /* - * symlink of: - * /dev/dir/nm -> /device/... - */ - rvp = devname_configure_by_path((char *)args, NULL); - break; - case DEVNAME_NS_DEV: - /* - * symlink of: - * /dev/dir/nm -> /dev/... - */ - rvp = devname_find_by_devpath((char *)args, NULL); - break; - default: - if (args) - kmem_free((char *)args, strlen(args) + 1); - return (ENOENT); - - } - - if (rvp == NULL) { - if (args) - kmem_free((char *)args, strlen(args) + 1); - return (ENOENT); - } else { - vap = sdev_getdefault_attr(VLNK); - ASSERT(RW_READ_HELD(&ddv->sdev_contents)); - /* - * Could sdev_mknode return a different dv_node - * once the lock is dropped? - */ - if (!rw_tryupgrade(&ddv->sdev_contents)) { - rw_exit(&ddv->sdev_contents); - rw_enter(&ddv->sdev_contents, RW_WRITER); - } - error = sdev_mknode(ddv, nm, &dv, vap, NULL, args, cred, - SDEV_READY); - rw_downgrade(&ddv->sdev_contents); - if (error) { - if (args) - kmem_free((char *)args, strlen(args) + 1); - return (error); - } else { - mutex_enter(&dv->sdev_lookup_lock); - SDEV_UNBLOCK_OTHERS(dv, SDEV_LOOKUP); - mutex_exit(&dv->sdev_lookup_lock); - error = 0; - } - } - - if (args) - kmem_free((char *)args, strlen(args) + 1); - - *dvp = dv; - return (0); -} - /* * Support for specialized device naming construction mechanisms */ @@ -2129,9 +1932,6 @@ struct sdev_node *dv = NULL; int retried = 0; int error = 0; - struct devname_nsmap *map = NULL; - struct devname_ops *dirops = NULL; - int (*fn)(char *, devname_handle_t *, struct cred *) = NULL; struct vattr vattr; char *lookup_thread = curproc->p_user.u_comm; int failed_flags = 0; @@ -2356,16 +2156,10 @@ failed_flags |= SLF_NO_NCACHE; } - if (SDEV_IS_GLOBAL(ddv)) { - map = sdev_get_map(ddv, 1); - dirops = map ? map->dir_ops : NULL; - fn = dirops ? dirops->devnops_lookup : NULL; - } - /* * (b1) invoking devfsadm once per life time for devfsadm nodes */ - if ((fn == NULL) && !callback) { + if (!callback) { if (sdev_reconfig_boot || !i_ddi_io_initialized() || SDEV_IS_DYNAMIC(ddv) || SDEV_IS_NO_NCACHE(dv) || @@ -2424,15 +2218,7 @@ * * note: module vnode ops take precedence than the build-in ones */ - if (fn) { - error = sdev_call_modulelookup(ddv, &dv, nm, fn, cred); - if (error) { - SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); - goto notfound; - } else { - goto found; - } - } else if (callback) { + if (callback) { error = sdev_call_dircallback(ddv, &dv, nm, callback, flags, cred); if (error == 0) { @@ -2493,11 +2279,6 @@ } } - if ((SDEVTOV(dv)->v_type == VDIR) && SDEV_IS_GLOBAL(dv)) { - rw_enter(&dv->sdev_contents, RW_READER); - (void) sdev_get_map(dv, 1); - rw_exit(&dv->sdev_contents); - } rw_exit(&ddv->sdev_contents); rv = sdev_to_vp(dv, vpp); sdcmn_err3(("devname_lookup_func: returning vp %p v_count %d state %d " @@ -2743,9 +2524,6 @@ offset_t diroff; offset_t soff; int this_reclen; - struct devname_nsmap *map = NULL; - struct devname_ops *dirops = NULL; - int (*fn)(devname_handle_t *, struct cred *) = NULL; int (*vtor)(struct sdev_node *) = NULL; struct vattr attr; timestruc_t now; @@ -2783,32 +2561,8 @@ goto get_cache; if (SDEV_IS_GLOBAL(ddv)) { - map = sdev_get_map(ddv, 0); - dirops = map ? map->dir_ops : NULL; - fn = dirops ? dirops->devnops_readdir : NULL; - - if (map && map->dir_map) { - /* - * load the name mapping rule database - * through invoking devfsadm and symlink - * all the entries in the map - */ - devname_rdr_result_t rdr_result; - int do_thread = 0; - - rw_enter(&map->dir_lock, RW_READER); - do_thread = map->dir_maploaded ? 0 : 1; - rw_exit(&map->dir_lock); - - if (do_thread) { - mutex_enter(&ddv->sdev_lookup_lock); - SDEV_BLOCK_OTHERS(ddv, SDEV_READDIR); - mutex_exit(&ddv->sdev_lookup_lock); - - sdev_dispatch_to_nsrdr_thread(ddv, - map->dir_map, &rdr_result); - } - } else if ((sdev_boot_state == SDEV_BOOT_STATE_COMPLETE) && + + if ((sdev_boot_state == SDEV_BOOT_STATE_COMPLETE) && !sdev_reconfig_boot && (flags & SDEV_BROWSE) && !SDEV_IS_DYNAMIC(ddv) && !SDEV_IS_NO_NCACHE(ddv) && ((moddebug & MODDEBUG_FINI_EBUSY) == 0) && @@ -2937,19 +2691,6 @@ } } - /* - * call back into the module for the validity/bookkeeping - * of this entry - */ - if (fn) { - error = (*fn)(&(dv->sdev_handle), cred); - if (error) { - sdcmn_err4(("sdev_readdir: module did not " - "validate %s\n", dv->sdev_name)); - continue; - } - } - namelen = strlen(dv->sdev_name); reclen = DIRENT64_RECLEN(namelen); if (outcount + reclen > alloc_count) { @@ -3279,306 +3020,6 @@ return (error); } -void -sdev_update_newnsmap(struct devname_nsmap *map, char *module, char *mapname) -{ - rw_enter(&map->dir_lock, RW_WRITER); - if (module) { - ASSERT(map->dir_newmodule == NULL); - map->dir_newmodule = i_ddi_strdup(module, KM_SLEEP); - } - if (mapname) { - ASSERT(map->dir_newmap == NULL); - map->dir_newmap = i_ddi_strdup(mapname, KM_SLEEP); - } - - map->dir_invalid = 1; - rw_exit(&map->dir_lock); -} - -void -sdev_replace_nsmap(struct devname_nsmap *map, char *module, char *mapname) -{ - char *old_module = NULL; - char *old_map = NULL; - - ASSERT(RW_LOCK_HELD(&map->dir_lock)); - if (!rw_tryupgrade(&map->dir_lock)) { - rw_exit(&map->dir_lock); - rw_enter(&map->dir_lock, RW_WRITER); - } - - old_module = map->dir_module; - if (module) { - if (old_module && strcmp(old_module, module) != 0) { - kmem_free(old_module, strlen(old_module) + 1); - } - map->dir_module = module; - map->dir_newmodule = NULL; - } - - old_map = map->dir_map; - if (mapname) { - if (old_map && strcmp(old_map, mapname) != 0) { - kmem_free(old_map, strlen(old_map) + 1); - } - - map->dir_map = mapname; - map->dir_newmap = NULL; - } - map->dir_maploaded = 0; - map->dir_invalid = 0; - rw_downgrade(&map->dir_lock); -} - -/* - * dir_name should have at least one attribute, - * dir_module - * or dir_map - * or both - * caller holds the devname_nsmaps_lock - */ -void -sdev_insert_nsmap(char *dir_name, char *dir_module, char *dir_map) -{ - struct devname_nsmap *map; - int len = 0; - - ASSERT(dir_name); - ASSERT(dir_module || dir_map); - ASSERT(MUTEX_HELD(&devname_nsmaps_lock)); - - if (map = sdev_get_nsmap_by_dir(dir_name, 1)) { - sdev_update_newnsmap(map, dir_module, dir_map); - return; - } - - map = (struct devname_nsmap *)kmem_zalloc(sizeof (*map), KM_SLEEP); - map->dir_name = i_ddi_strdup(dir_name, KM_SLEEP); - if (dir_module) { - map->dir_module = i_ddi_strdup(dir_module, KM_SLEEP); - } - - if (dir_map) { - if (dir_map[0] != '/') { - len = strlen(ETC_DEV_DIR) + strlen(dir_map) + 2; - map->dir_map = kmem_zalloc(len, KM_SLEEP); - (void) snprintf(map->dir_map, len, "%s/%s", ETC_DEV_DIR, - dir_map); - } else { - map->dir_map = i_ddi_strdup(dir_map, KM_SLEEP); - } - } - - map->dir_ops = NULL; - map->dir_maploaded = 0; - map->dir_invalid = 0; - rw_init(&map->dir_lock, NULL, RW_DEFAULT, NULL); - - map->next = devname_nsmaps; - map->prev = NULL; - if (devname_nsmaps) { - devname_nsmaps->prev = map; - } - devname_nsmaps = map; -} - -struct devname_nsmap * -sdev_get_nsmap_by_dir(char *dir_path, int locked) -{ - struct devname_nsmap *map = NULL; - - if (!locked) - mutex_enter(&devname_nsmaps_lock); - for (map = devname_nsmaps; map; map = map->next) { - sdcmn_err6(("sdev_get_nsmap_by_dir: dir %s\n", map->dir_name)); - if (strcmp(map->dir_name, dir_path) == 0) { - if (!locked) - mutex_exit(&devname_nsmaps_lock); - return (map); - } - } - if (!locked) - mutex_exit(&devname_nsmaps_lock); - return (NULL); -} - -struct devname_nsmap * -sdev_get_nsmap_by_module(char *mod_name) -{ - struct devname_nsmap *map = NULL; - - mutex_enter(&devname_nsmaps_lock); - for (map = devname_nsmaps; map; map = map->next) { - sdcmn_err7(("sdev_get_nsmap_by_module: module %s\n", - map->dir_module)); - if (map->dir_module && strcmp(map->dir_module, mod_name) == 0) { - mutex_exit(&devname_nsmaps_lock); - return (map); - } - } - mutex_exit(&devname_nsmaps_lock); - return (NULL); -} - -void -sdev_invalidate_nsmaps() -{ - struct devname_nsmap *map = NULL; - - ASSERT(MUTEX_HELD(&devname_nsmaps_lock)); - - if (devname_nsmaps == NULL) - return; - - for (map = devname_nsmaps; map; map = map->next) { - rw_enter(&map->dir_lock, RW_WRITER); - map->dir_invalid = 1; - rw_exit(&map->dir_lock); - } - devname_nsmaps_invalidated = 1; -} - - -int -sdev_nsmaps_loaded() -{ - int ret = 0; - - mutex_enter(&devname_nsmaps_lock); - if (devname_nsmaps_loaded) - ret = 1; - - mutex_exit(&devname_nsmaps_lock); - return (ret); -} - -int -sdev_nsmaps_reloaded() -{ - int ret = 0; - - mutex_enter(&devname_nsmaps_lock); - if (devname_nsmaps_invalidated) - ret = 1; - - mutex_exit(&devname_nsmaps_lock); - return (ret); -} - -static void -sdev_free_nsmap(struct devname_nsmap *map) -{ - ASSERT(map); - if (map->dir_name) - kmem_free(map->dir_name, strlen(map->dir_name) + 1); - if (map->dir_module) - kmem_free(map->dir_module, strlen(map->dir_module) + 1); - if (map->dir_map) - kmem_free(map->dir_map, strlen(map->dir_map) + 1); - rw_destroy(&map->dir_lock); - kmem_free(map, sizeof (*map)); -} - -void -sdev_validate_nsmaps() -{ - struct devname_nsmap *map = NULL; - struct devname_nsmap *oldmap = NULL; - - ASSERT(MUTEX_HELD(&devname_nsmaps_lock)); - map = devname_nsmaps; - while (map) { - rw_enter(&map->dir_lock, RW_READER); - if ((map->dir_invalid == 1) && (map->dir_newmodule == NULL) && - (map->dir_newmap == NULL)) { - oldmap = map; - rw_exit(&map->dir_lock); - if (map->prev) - map->prev->next = oldmap->next; - if (map == devname_nsmaps) - devname_nsmaps = oldmap->next; - - map = oldmap->next; - if (map) - map->prev = oldmap->prev; - sdev_free_nsmap(oldmap); - oldmap = NULL; - } else { - rw_exit(&map->dir_lock); - map = map->next; - } - } - devname_nsmaps_invalidated = 0; -} - -static int -sdev_map_is_invalid(struct devname_nsmap *map) -{ - int ret = 0; - - ASSERT(map); - rw_enter(&map->dir_lock, RW_READER); - if (map->dir_invalid) - ret = 1; - rw_exit(&map->dir_lock); - return (ret); -} - -static int -sdev_check_map(struct devname_nsmap *map) -{ - struct devname_nsmap *mapp; - - mutex_enter(&devname_nsmaps_lock); - if (devname_nsmaps == NULL) { - mutex_exit(&devname_nsmaps_lock); - return (1); - } - - for (mapp = devname_nsmaps; mapp; mapp = mapp->next) { - if (mapp == map) { - mutex_exit(&devname_nsmaps_lock); - return (0); - } - } - - mutex_exit(&devname_nsmaps_lock); - return (1); - -} - -struct devname_nsmap * -sdev_get_map(struct sdev_node *dv, int validate) -{ - struct devname_nsmap *map; - int error; - - ASSERT(RW_READ_HELD(&dv->sdev_contents)); - map = dv->sdev_mapinfo; - if (map && sdev_check_map(map)) { - if (!rw_tryupgrade(&dv->sdev_contents)) { - rw_exit(&dv->sdev_contents); - rw_enter(&dv->sdev_contents, RW_WRITER); - } - dv->sdev_mapinfo = NULL; - rw_downgrade(&dv->sdev_contents); - return (NULL); - } - - if (validate && (!map || (map && sdev_map_is_invalid(map)))) { - if (!rw_tryupgrade(&dv->sdev_contents)) { - rw_exit(&dv->sdev_contents); - rw_enter(&dv->sdev_contents, RW_WRITER); - } - error = sdev_get_moduleops(dv); - if (!error) - map = dv->sdev_mapinfo; - rw_downgrade(&dv->sdev_contents); - } - return (map); -} - extern int sdev_vnodeops_tbl_size; /* @@ -3619,115 +3060,6 @@ kmem_free(new, sdev_vnodeops_tbl_size); } -void -devname_get_vnode(devname_handle_t *hdl, vnode_t **vpp) -{ - struct sdev_node *dv = hdl->dh_data; - - ASSERT(dv); - - rw_enter(&dv->sdev_contents, RW_READER); - *vpp = SDEVTOV(dv); - rw_exit(&dv->sdev_contents); -} - -int -devname_get_path(devname_handle_t *hdl, char **path) -{ - struct sdev_node *dv = hdl->dh_data; - - ASSERT(dv); - - rw_enter(&dv->sdev_contents, RW_READER); - *path = dv->sdev_path; - rw_exit(&dv->sdev_contents); - return (0); -} - -int -devname_get_name(devname_handle_t *hdl, char **entry) -{ - struct sdev_node *dv = hdl->dh_data; - - ASSERT(dv); - rw_enter(&dv->sdev_contents, RW_READER); - *entry = dv->sdev_name; - rw_exit(&dv->sdev_contents); - return (0); -} - -void -devname_get_dir_vnode(devname_handle_t *hdl, vnode_t **vpp) -{ - struct sdev_node *dv = hdl->dh_data->sdev_dotdot; - - ASSERT(dv); - - rw_enter(&dv->sdev_contents, RW_READER); - *vpp = SDEVTOV(dv); - rw_exit(&dv->sdev_contents); -} - -int -devname_get_dir_path(devname_handle_t *hdl, char **path) -{ - struct sdev_node *dv = hdl->dh_data->sdev_dotdot; - - ASSERT(dv); - rw_enter(&dv->sdev_contents, RW_READER); - *path = dv->sdev_path; - rw_exit(&dv->sdev_contents); - return (0); -} - -int -devname_get_dir_name(devname_handle_t *hdl, char **entry) -{ - struct sdev_node *dv = hdl->dh_data->sdev_dotdot; - - ASSERT(dv); - rw_enter(&dv->sdev_contents, RW_READER); - *entry = dv->sdev_name; - rw_exit(&dv->sdev_contents); - return (0); -} - -int -devname_get_dir_nsmap(devname_handle_t *hdl, struct devname_nsmap **map) -{ - struct sdev_node *dv = hdl->dh_data->sdev_dotdot; - - ASSERT(dv); - rw_enter(&dv->sdev_contents, RW_READER); - *map = dv->sdev_mapinfo; - rw_exit(&dv->sdev_contents); - return (0); -} - -int -devname_get_dir_handle(devname_handle_t *hdl, devname_handle_t **dir_hdl) -{ - struct sdev_node *dv = hdl->dh_data->sdev_dotdot; - - ASSERT(dv); - rw_enter(&dv->sdev_contents, RW_READER); - *dir_hdl = &(dv->sdev_handle); - rw_exit(&dv->sdev_contents); - return (0); -} - -void -devname_set_nodetype(devname_handle_t *hdl, void *args, int spec) -{ - struct sdev_node *dv = hdl->dh_data; - - ASSERT(dv); - rw_enter(&dv->sdev_contents, RW_WRITER); - hdl->dh_spec = (devname_spec_t)spec; - hdl->dh_args = (void *)i_ddi_strdup((char *)args, KM_SLEEP); - rw_exit(&dv->sdev_contents); -} - /* * a generic setattr() function * @@ -3841,6 +3173,7 @@ /* * a generic inactive() function */ +/*ARGSUSED*/ void devname_inactive_func(struct vnode *vp, struct cred *cred, void (*callback)(struct vnode *)) @@ -3849,9 +3182,6 @@ struct sdev_node *dv = VTOSDEV(vp); struct sdev_node *ddv = dv->sdev_dotdot; int state; - struct devname_nsmap *map = NULL; - struct devname_ops *dirops = NULL; - void (*fn)(devname_handle_t *, struct cred *) = NULL; rw_enter(&ddv->sdev_contents, RW_WRITER); state = dv->sdev_state; @@ -3872,12 +3202,6 @@ */ if (clean) { ASSERT(ddv); - if (SDEV_IS_GLOBAL(dv)) { - map = ddv->sdev_mapinfo; - dirops = map ? map->dir_ops : NULL; - if (dirops && (fn = dirops->devnops_inactive)) - (*fn)(&(dv->sdev_handle), cred); - } ddv->sdev_nlink--; if (vp->v_type == VDIR) {
--- a/usr/src/uts/common/fs/dev/sdev_vfsops.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/dev/sdev_vfsops.c Mon Jul 20 13:07:46 2009 -0400 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -52,7 +52,6 @@ #include <sys/mkdev.h> #include <fs/fs_subr.h> #include <sys/fs/sdev_impl.h> -#include <sys/fs/sdev_node.h> #include <sys/fs/snode.h> #include <sys/fs/dv_node.h> #include <sys/sunndi.h> @@ -466,26 +465,6 @@ return (0); } -int -sdev_module_register(char *mod_name, struct devname_ops *dev_ops) -{ - struct devname_nsmap *map = NULL; - - if (strcmp(mod_name, DEVNAME_NSCONFIG) == 0) { - devname_ns_ops = dev_ops; - return (0); - } - - map = sdev_get_nsmap_by_module(mod_name); - if (map == NULL) - return (EFAULT); - - rw_enter(&map->dir_lock, RW_WRITER); - map->dir_ops = dev_ops; - rw_exit(&map->dir_lock); - return (0); -} - static void sdev_insert_mntinfo(struct sdev_data *data) {
--- a/usr/src/uts/common/fs/dev/sdev_vnops.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/dev/sdev_vnops.c Mon Jul 20 13:07:46 2009 -0400 @@ -70,7 +70,6 @@ #include <fs/fs_subr.h> #include <sys/fs/dv_node.h> #include <sys/fs/sdev_impl.h> -#include <sys/fs/sdev_node.h> /*ARGSUSED*/ static int @@ -208,18 +207,11 @@ int error = 0; struct sdev_node *dv = VTOSDEV(vp); struct sdev_node *parent = dv->sdev_dotdot; - struct devname_nsmap *map = NULL; - struct devname_ops *dirops = NULL; - int (*fn)(devname_handle_t *, struct vattr *, struct cred *); ASSERT(parent); rw_enter(&parent->sdev_contents, RW_READER); ASSERT(dv->sdev_attr || dv->sdev_attrvp); - if (SDEV_IS_GLOBAL(dv) && (dv->sdev_state != SDEV_ZOMBIE)) { - map = sdev_get_map(parent, 0); - dirops = map ? map->dir_ops : NULL; - } /* * search order: @@ -230,10 +222,6 @@ rw_exit(&parent->sdev_contents); error = VOP_GETATTR(dv->sdev_attrvp, vap, flags, cr, ct); sdev_vattr_merge(dv, vap); - } else if (dirops && (fn = dirops->devnops_getattr)) { - sdev_vattr_merge(dv, vap); - rw_exit(&parent->sdev_contents); - error = (*fn)(&(dv->sdev_handle), vap, cr); } else { ASSERT(dv->sdev_attr); *vap = *dv->sdev_attr; @@ -522,9 +510,6 @@ struct sdev_node *parent = (struct sdev_node *)VTOSDEV(dvp); struct vnode *vp = NULL; struct sdev_node *dv = NULL; - struct devname_nsmap *map = NULL; - struct devname_ops *dirops = NULL; - int (*fn)(devname_handle_t *); int len; int bkstore = 0; @@ -573,18 +558,6 @@ return (error); } - /* the module may record/reject removing a device node */ - map = sdev_get_map(parent, 0); - dirops = map ? map->dir_ops : NULL; - if (dirops && ((fn = dirops->devnops_remove) != NULL)) { - error = (*fn)(&(dv->sdev_handle)); - if (error) { - rw_exit(&parent->sdev_contents); - VN_RELE(vp); - return (error); - } - } - /* * sdev_dirdelete does the real job of: * - make sure no open ref count @@ -653,12 +626,6 @@ struct vnode *nvp = NULL; /* destination vnode */ int samedir = 0; /* set if odvp == ndvp */ struct vnode *realvp; - int len; - char nnm_path[MAXPATHLEN]; - struct devname_nsmap *omap = NULL; - struct devname_ops *odirops = NULL; - int (*fn)(devname_handle_t *, char *); - int (*rmfn)(devname_handle_t *); int error = 0; dev_t fsid; int bkstore = 0; @@ -782,30 +749,6 @@ fromdv = VTOSDEV(ovp); ASSERT(fromdv); - /* check with the plug-in modules for the source directory */ - rw_enter(&fromparent->sdev_contents, RW_READER); - omap = sdev_get_map(fromparent, 0); - rw_exit(&fromparent->sdev_contents); - odirops = omap ? omap->dir_ops : NULL; - if (odirops && ((fn = odirops->devnops_rename) != NULL)) { - if (samedir) { - error = (*fn)(&(fromdv->sdev_handle), nnm); - } else { - len = strlen(nnm) + strlen(toparent->sdev_name) + 2; - (void) snprintf(nnm_path, len, "%s/%s", - toparent->sdev_name, nnm); - error = (*fn)(&(fromdv->sdev_handle), nnm); - } - - if (error) { - mutex_exit(&sdev_lock); - sdcmn_err2(("sdev_rename: DBNR doesn't " - "allow rename, error %d", error)); - VN_RELE(ovp); - return (error); - } - } - /* destination file exists */ if (nvp) { todv = VTOSDEV(nvp); @@ -826,11 +769,6 @@ return (error); } - /* notify the DBNR module the node is going away */ - if (odirops && ((rmfn = odirops->devnops_remove) != NULL)) { - (void) (*rmfn)(&(fromdv->sdev_handle)); - } - /* * unlink from source */
--- a/usr/src/uts/common/fs/fsflush.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/fsflush.c Mon Jul 20 13:07:46 2009 -0400 @@ -125,7 +125,9 @@ ulong_t nlocked = 0; ulong_t nmodified = 0; ulong_t ncoalesce = 0; + ulong_t cnt; int mod; + int fspage = 1; u_offset_t offset; uint_t szc; @@ -135,8 +137,7 @@ static ulong_t nscan = 0; static pgcnt_t last_total_pages = 0; - static void *pp_cookie = NULL; - static page_t *pp; + static page_t *pp = NULL; uint8_t key; #define GET_KEY(p,k) \ __asm__ (" lgr 1,%1\n" \ @@ -152,11 +153,8 @@ nscan = (last_total_pages * (tune.t_fsflushr))/v.v_autoup; } - /* - * On first time through initialize the cookie used for page_t scans - */ - if (pp_cookie == NULL) - pp = page_next_scan_init(&pp_cookie); + if (pp == NULL) + pp = memsegs->pages; pcount = 0; while (pcount < nscan) { @@ -165,9 +163,19 @@ * move to the next page, skipping over large pages * and issuing prefetches. */ - pp = page_next_scan_large(pp, &pcount, &pp_cookie); + if (pp->p_szc && fspage == 0) { + pfn_t pfn; + + pfn = page_pptonum(pp); + cnt = page_get_pagecnt(pp->p_szc); + cnt -= pfn & (cnt - 1); + } else + cnt = 1; + + pp = page_nextn(pp, cnt); prefetch_page_r((void *)pp); ASSERT(pp != NULL); + pcount += cnt; /* * Do a bunch of dirty tests (ie. no locking) to determine @@ -176,6 +184,7 @@ */ ++nexamined; if (PP_ISSWAP(pp)) { + fspage = 0; coal_page = NULL; continue; } @@ -189,6 +198,7 @@ * skip pages with a file system identity or that * are already maximum size */ + fspage = 0; szc = pp->p_szc; if (pp->p_vnode != NULL || szc == fsf_npgsz - 1) { coal_page = NULL; @@ -238,8 +248,10 @@ if (PP_ISKAS(pp) || PAGE_LOCKED(pp) || pp->p_lckcnt != 0 || - pp->p_cowcnt != 0) + pp->p_cowcnt != 0) { + fspage = 0; continue; + } /* @@ -259,13 +271,17 @@ PP_ISFREE(pp) || vp == NULL || PP_ISKAS(pp) || - pp->p_lckcnt != 0 || - pp->p_cowcnt != 0 || (vp->v_flag & VISSWAP) != 0) { page_unlock(pp); + fspage = 0; + continue; + } + if (pp->p_lckcnt != 0 || pp->p_cowcnt != 0) { + page_unlock(pp); continue; } + fspage = 1; ASSERT(vp->v_type != VCHR); /* @@ -293,6 +309,7 @@ (void) VOP_PUTPAGE(vp, offset, PAGESIZE, B_ASYNC, kcred, NULL); + VN_RELE(vp); } else {
--- a/usr/src/uts/common/fs/nfs/nfs4_srv.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/nfs/nfs4_srv.c Mon Jul 20 13:07:46 2009 -0400 @@ -6676,6 +6676,21 @@ rfs4_recall_deleg(fp, FALSE, sp->rs_owner->ro_client); delay(NFS4_DELEGATION_CONFLICT_DELAY); rfs4_dbe_lock(sp->rs_dbe); + + /* if state closed while lock was dropped */ + if (sp->rs_closed) { + if (dmodes || amodes) + (void) rfs4_unshare(sp); + rfs4_dbe_unlock(sp->rs_dbe); + rfs4_file_rele(fp); + /* Not a fully formed open; "close" it */ + if (screate == TRUE) + rfs4_state_close(sp, FALSE, FALSE, cs->cr); + rfs4_state_rele(sp); + resp->status = NFS4ERR_OLD_STATEID; + return; + } + rfs4_dbe_lock(fp->rf_dbe); /* Let's see if the delegation was returned */ if (rfs4_check_recall(sp, access)) { @@ -6743,6 +6758,7 @@ fflags |= FWRITE; vn_open_upgrade(cs->vp, fflags); } + sp->rs_opened = TRUE; if (dmodes & OPEN4_SHARE_DENY_READ) fp->rf_deny_read++; @@ -8183,35 +8199,6 @@ int fflags = 0; /* - * Decrement the count for each access and deny bit that this - * state has contributed to the file. If the file counts go to zero - * clear the appropriate bit in the appropriate mask. - */ - - if (sp->rs_share_access & OPEN4_SHARE_ACCESS_READ) { - fp->rf_access_read--; - fflags |= FREAD; - if (fp->rf_access_read == 0) - fp->rf_share_access &= ~OPEN4_SHARE_ACCESS_READ; - } - if (sp->rs_share_access & OPEN4_SHARE_ACCESS_WRITE) { - fp->rf_access_write--; - fflags |= FWRITE; - if (fp->rf_access_write == 0) - fp->rf_share_access &= ~OPEN4_SHARE_ACCESS_WRITE; - } - if (sp->rs_share_deny & OPEN4_SHARE_DENY_READ) { - fp->rf_deny_read--; - if (fp->rf_deny_read == 0) - fp->rf_share_deny &= ~OPEN4_SHARE_DENY_READ; - } - if (sp->rs_share_deny & OPEN4_SHARE_DENY_WRITE) { - fp->rf_deny_write--; - if (fp->rf_deny_write == 0) - fp->rf_share_deny &= ~OPEN4_SHARE_DENY_WRITE; - } - - /* * If this call is part of the larger closing down of client * state then it is just easier to release all locks * associated with this client instead of going through each @@ -8280,7 +8267,41 @@ if (sp->rs_owner->ro_client->rc_sysidt != LM_NOSYSID) (void) rfs4_unshare(sp); - (void) VOP_CLOSE(fp->rf_vp, fflags, 1, (offset_t)0, cr, NULL); + if (sp->rs_opened) { + /* + * Decrement the count for each access and deny bit that this + * state has contributed to the file. + * If the file counts go to zero + * clear the appropriate bit in the appropriate mask. + */ + if (sp->rs_share_access & OPEN4_SHARE_ACCESS_READ) { + fp->rf_access_read--; + fflags |= FREAD; + if (fp->rf_access_read == 0) + fp->rf_share_access &= ~OPEN4_SHARE_ACCESS_READ; + } + if (sp->rs_share_access & OPEN4_SHARE_ACCESS_WRITE) { + fp->rf_access_write--; + fflags |= FWRITE; + if (fp->rf_access_write == 0) + fp->rf_share_access &= + ~OPEN4_SHARE_ACCESS_WRITE; + } + if (sp->rs_share_deny & OPEN4_SHARE_DENY_READ) { + fp->rf_deny_read--; + if (fp->rf_deny_read == 0) + fp->rf_share_deny &= ~OPEN4_SHARE_DENY_READ; + } + if (sp->rs_share_deny & OPEN4_SHARE_DENY_WRITE) { + fp->rf_deny_write--; + if (fp->rf_deny_write == 0) + fp->rf_share_deny &= ~OPEN4_SHARE_DENY_WRITE; + } + + (void) VOP_CLOSE(fp->rf_vp, fflags, 1, (offset_t)0, cr, NULL); + + sp->rs_opened = FALSE; + } } /*
--- a/usr/src/uts/common/fs/smbsrv/smb_common_open.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/smbsrv/smb_common_open.c Mon Jul 20 13:07:46 2009 -0400 @@ -414,7 +414,7 @@ sizeof (op->fqi.fq_last_comp), "%s%s", cur_node->od_name, pn->pn_sname); - op->fqi.fq_dnode = cur_node->dir_snode; + op->fqi.fq_dnode = cur_node->n_dnode; smb_node_ref(op->fqi.fq_dnode); } else { if (rc = smb_pathname_reduce(sr, sr->user_cr, pn->pn_path,
--- a/usr/src/uts/common/fs/smbsrv/smb_delete.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/smbsrv/smb_delete.c Mon Jul 20 13:07:46 2009 -0400 @@ -519,7 +519,7 @@ if (SMB_TREE_SUPPORTS_CATIA(sr)) flags |= SMB_CATIA; - rc = smb_fsop_remove(sr, sr->user_cr, node->dir_snode, + rc = smb_fsop_remove(sr, sr->user_cr, node->n_dnode, node->od_name, flags); if (rc != 0) { if (rc == ENOENT)
--- a/usr/src/uts/common/fs/smbsrv/smb_fsops.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/smbsrv/smb_fsops.c Mon Jul 20 13:07:46 2009 -0400 @@ -694,7 +694,7 @@ sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); if (dnode->flags & NODE_XATTR_DIR) { - rc = smb_vop_stream_remove(dnode->dir_snode->vp, + rc = smb_vop_stream_remove(dnode->n_dnode->vp, name, flags, cr); } else if (smb_is_stream_name(name)) { smb_stream_parse_name(name, fname, sname); @@ -1453,7 +1453,7 @@ faccess &= sr->tid_tree->t_access; if (acl_check) { - dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL; + dir_vp = (snode->n_dnode) ? snode->n_dnode->vp : NULL; error = smb_vop_access(snode->vp, faccess, V_ACE_MASK, dir_vp, cr); } else { @@ -2297,7 +2297,7 @@ } if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) { - dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL; + dir_vp = (snode->n_dnode) ? snode->n_dnode->vp : NULL; smb_vop_eaccess(snode->vp, (int *)eaccess, V_ACE_MASK, dir_vp, cr); return;
--- a/usr/src/uts/common/fs/smbsrv/smb_init.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/smbsrv/smb_init.c Mon Jul 20 13:07:46 2009 -0400 @@ -245,14 +245,20 @@ case SMB_IOC_UNSHARE: rc = smb_server_share_unexport(&ioc->ioc_share); break; - case SMB_IOC_USER_NUMBER: - rc = smb_server_user_number(&ioc->ioc_unum); + case SMB_IOC_NUMOPEN: + rc = smb_server_numopen(&ioc->ioc_opennum); copyout = B_TRUE; break; - case SMB_IOC_USER_LIST: - rc = smb_server_user_list(&ioc->ioc_ulist); + case SMB_IOC_SVCENUM: + rc = smb_server_enum(&ioc->ioc_svcenum); copyout = B_TRUE; break; + case SMB_IOC_SESSION_CLOSE: + rc = smb_server_session_close(&ioc->ioc_session); + break; + case SMB_IOC_FILE_CLOSE: + rc = smb_server_file_close(&ioc->ioc_fileid); + break; default: rc = ENOTTY; break;
--- a/usr/src/uts/common/fs/smbsrv/smb_lock.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/smbsrv/smb_lock.c Mon Jul 20 13:07:46 2009 -0400 @@ -52,7 +52,22 @@ static void smb_lock_destroy(smb_lock_t *); static void smb_lock_free(smb_lock_t *); +/* + * Return the number of range locks on the specified node. + */ +uint32_t +smb_lock_get_lock_count(smb_node_t *node) +{ + uint32_t count; + SMB_NODE_VALID(node); + + smb_llist_enter(&node->n_lock_list, RW_READER); + count = smb_llist_get_count(&node->n_ofile_list); + smb_llist_exit(&node->n_lock_list); + + return (count); +} /* * smb_unlock_range
--- a/usr/src/uts/common/fs/smbsrv/smb_node.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/smbsrv/smb_node.c Mon Jul 20 13:07:46 2009 -0400 @@ -153,7 +153,7 @@ #define VALIDATE_DIR_NODE(_dir_, _node_) \ ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \ ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \ - ASSERT((_dir_)->dir_snode != (_node_)); + ASSERT((_dir_)->n_dnode != (_node_)); static kmem_cache_t *smb_node_cache = NULL; static boolean_t smb_node_initialized = B_FALSE; @@ -246,7 +246,7 @@ * or newly created. * * If an smb_node needs to be created, a reference is also taken on the - * dir_snode (if passed in). + * dnode (if passed in). * * See smb_node_release() for details on the release of these references. */ @@ -259,8 +259,8 @@ cred_t *cred, vnode_t *vp, char *od_name, - smb_node_t *dir_snode, - smb_node_t *unnamed_node) + smb_node_t *dnode, + smb_node_t *unode) { smb_llist_t *node_hdr; smb_node_t *node; @@ -277,8 +277,8 @@ * it with the list lock held. */ - if (unnamed_node) - unnamed_vp = unnamed_node->vp; + if (unode) + unnamed_vp = unode->vp; /* * This getattr is performed on behalf of the server @@ -323,14 +323,13 @@ case SMB_NODE_STATE_AVAILABLE: /* The node was found. */ node->n_refcnt++; - if ((node->dir_snode == NULL) && - (dir_snode != NULL) && + if ((node->n_dnode == NULL) && + (dnode != NULL) && (strcmp(od_name, "..") != 0) && (strcmp(od_name, ".") != 0)) { - VALIDATE_DIR_NODE(dir_snode, - node); - node->dir_snode = dir_snode; - smb_node_ref(dir_snode); + VALIDATE_DIR_NODE(dnode, node); + node->n_dnode = dnode; + smb_node_ref(dnode); } smb_node_audit(node); @@ -371,17 +370,17 @@ if (op) node->flags |= smb_is_executable(op->fqi.fq_last_comp); - if (dir_snode) { - smb_node_ref(dir_snode); - node->dir_snode = dir_snode; - ASSERT(dir_snode->dir_snode != node); - ASSERT((dir_snode->vp->v_xattrdir) || - (dir_snode->vp->v_type == VDIR)); + if (dnode) { + smb_node_ref(dnode); + node->n_dnode = dnode; + ASSERT(dnode->n_dnode != node); + ASSERT((dnode->vp->v_xattrdir) || + (dnode->vp->v_type == VDIR)); } - if (unnamed_node) { - smb_node_ref(unnamed_node); - node->unnamed_stream_node = unnamed_node; + if (unode) { + smb_node_ref(unode); + node->n_unode = unode; } DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node); @@ -472,8 +471,8 @@ * then the caller with the local variable should call smb_node_release() * directly. * - * smb_node_release() itself will call smb_node_release() on a node's dir_snode, - * as smb_node_lookup() takes a hold on dir_snode. + * smb_node_release() itself will call smb_node_release() on a node's n_dnode, + * as smb_node_lookup() takes a hold on dnode. */ void smb_node_release(smb_node_t *node) @@ -499,16 +498,16 @@ */ smb_node_delete_on_close(node); - if (node->dir_snode) { - ASSERT(node->dir_snode->n_magic == + if (node->n_dnode) { + ASSERT(node->n_dnode->n_magic == SMB_NODE_MAGIC); - smb_node_release(node->dir_snode); + smb_node_release(node->n_dnode); } - if (node->unnamed_stream_node) { - ASSERT(node->unnamed_stream_node->n_magic == + if (node->n_unode) { + ASSERT(node->n_unode->n_magic == SMB_NODE_MAGIC); - smb_node_release(node->unnamed_stream_node); + smb_node_release(node->n_unode); } smb_node_free(node); @@ -529,7 +528,7 @@ int rc = 0; uint32_t flags = 0; - d_snode = node->dir_snode; + d_snode = node->n_dnode; if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE; flags = node->n_delete_on_close_flags; @@ -570,9 +569,9 @@ case SMB_NODE_STATE_AVAILABLE: case SMB_NODE_STATE_OPLOCK_GRANTED: case SMB_NODE_STATE_OPLOCK_BREAKING: - ret_node->dir_snode = to_dnode; + ret_node->n_dnode = to_dnode; mutex_exit(&ret_node->n_mutex); - ASSERT(to_dnode->dir_snode != ret_node); + ASSERT(to_dnode->n_dnode != ret_node); ASSERT((to_dnode->vp->v_xattrdir) || (to_dnode->vp->v_type == VDIR)); smb_node_release(from_dnode); @@ -956,10 +955,9 @@ node->n_orig_uid = 0; node->readonly_creator = NULL; node->waiting_event = 0; - node->what = 0; node->n_open_count = 0; - node->dir_snode = NULL; - node->unnamed_stream_node = NULL; + node->n_dnode = NULL; + node->n_unode = NULL; node->delete_on_close_cred = NULL; node->n_delete_on_close_flags = 0;
--- a/usr/src/uts/common/fs/smbsrv/smb_ofile.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/smbsrv/smb_ofile.c Mon Jul 20 13:07:46 2009 -0400 @@ -164,10 +164,14 @@ #include <smbsrv/smb_kproto.h> #include <smbsrv/smb_fsops.h> -/* Static functions defined further down this file. */ -static void smb_ofile_delete(smb_ofile_t *of); -static smb_ofile_t *smb_ofile_close_and_next(smb_ofile_t *of); +static boolean_t smb_ofile_is_open_locked(smb_ofile_t *); +static void smb_ofile_delete(smb_ofile_t *); +static smb_ofile_t *smb_ofile_close_and_next(smb_ofile_t *); static void smb_ofile_set_close_attrs(smb_ofile_t *, uint32_t); +static int smb_ofile_netinfo_encode(smb_ofile_t *, uint8_t *, size_t, + uint32_t *); +static int smb_ofile_netinfo_init(smb_ofile_t *, smb_netfileinfo_t *); +static void smb_ofile_netinfo_fini(smb_netfileinfo_t *); /* * smb_ofile_open @@ -277,6 +281,7 @@ smb_llist_enter(&tree->t_ofile_list, RW_WRITER); smb_llist_insert_tail(&tree->t_ofile_list, of); smb_llist_exit(&tree->t_ofile_list); + atomic_inc_32(&tree->t_open_files); atomic_inc_32(&tree->t_server->sv_open_files); atomic_inc_32(&of->f_session->s_file_cnt); @@ -328,6 +333,7 @@ if (of->f_node->flags & NODE_FLAGS_NOTIFY_CHANGE) smb_process_file_notify_change_queue(of); } + atomic_dec_32(&of->f_tree->t_open_files); atomic_dec_32(&of->f_tree->t_server->sv_open_files); mutex_enter(&of->f_mutex); @@ -409,6 +415,70 @@ } /* + * If the enumeration request is for ofile data, handle it here. + * Otherwise, return. + * + * This function should be called with a hold on the ofile. + */ +int +smb_ofile_enum(smb_ofile_t *of, smb_svcenum_t *svcenum) +{ + uint8_t *pb; + uint_t nbytes; + int rc; + + ASSERT(of); + ASSERT(of->f_magic == SMB_OFILE_MAGIC); + ASSERT(of->f_refcnt); + + if (svcenum->se_type != SMB_SVCENUM_TYPE_FILE) + return (0); + + if (svcenum->se_nskip > 0) { + svcenum->se_nskip--; + return (0); + } + + if (svcenum->se_nitems >= svcenum->se_nlimit) { + svcenum->se_nitems = svcenum->se_nlimit; + return (0); + } + + pb = &svcenum->se_buf[svcenum->se_bused]; + + rc = smb_ofile_netinfo_encode(of, pb, svcenum->se_bavail, + &nbytes); + if (rc == 0) { + svcenum->se_bavail -= nbytes; + svcenum->se_bused += nbytes; + svcenum->se_nitems++; + } + + return (rc); +} + +/* + * Take a reference on an open file. + */ +boolean_t +smb_ofile_hold(smb_ofile_t *of) +{ + ASSERT(of); + ASSERT(of->f_magic == SMB_OFILE_MAGIC); + + mutex_enter(&of->f_mutex); + + if (smb_ofile_is_open_locked(of)) { + of->f_refcnt++; + mutex_exit(&of->f_mutex); + return (B_TRUE); + } + + mutex_exit(&of->f_mutex); + return (B_FALSE); +} + +/* * smb_ofile_release * */ @@ -487,6 +557,71 @@ } /* + * smb_ofile_lookup_by_uniqid + * + * Find the open file whose uniqid matches the one specified in the request. + */ +smb_ofile_t * +smb_ofile_lookup_by_uniqid(smb_tree_t *tree, uint32_t uniqid) +{ + smb_llist_t *of_list; + smb_ofile_t *of; + + ASSERT(tree->t_magic == SMB_TREE_MAGIC); + + of_list = &tree->t_ofile_list; + smb_llist_enter(of_list, RW_READER); + of = smb_llist_head(of_list); + + while (of) { + ASSERT(of->f_magic == SMB_OFILE_MAGIC); + ASSERT(of->f_tree == tree); + + if (of->f_uniqid == uniqid) { + if (smb_ofile_hold(of)) { + smb_llist_exit(of_list); + return (of); + } + } + + of = smb_llist_next(of_list, of); + } + + smb_llist_exit(of_list); + return (NULL); +} + +/* + * Disallow NetFileClose on certain ofiles to avoid side-effects. + * Closing a tree root is not allowed: use NetSessionDel or NetShareDel. + * Closing SRVSVC connections is not allowed because this NetFileClose + * request may depend on this ofile. + */ +boolean_t +smb_ofile_disallow_fclose(smb_ofile_t *of) +{ + ASSERT(of); + ASSERT(of->f_magic == SMB_OFILE_MAGIC); + ASSERT(of->f_refcnt); + + switch (of->f_ftype) { + case SMB_FTYPE_DISK: + ASSERT(of->f_tree); + return (of->f_node == of->f_tree->t_snode); + + case SMB_FTYPE_MESG_PIPE: + ASSERT(of->f_pipe); + if (utf8_strcasecmp(of->f_pipe->p_name, "SRVSVC") == 0) + return (B_TRUE); + break; + default: + break; + } + + return (B_FALSE); +} + +/* * smb_ofile_set_flags * * Return value: @@ -588,14 +723,12 @@ boolean_t smb_ofile_is_open(smb_ofile_t *of) { - boolean_t rc = B_FALSE; + boolean_t rc; SMB_OFILE_VALID(of); mutex_enter(&of->f_mutex); - if (of->f_state == SMB_OFILE_STATE_OPEN) { - rc = B_TRUE; - } + rc = smb_ofile_is_open_locked(of); mutex_exit(&of->f_mutex); return (rc); } @@ -674,6 +807,27 @@ /* *************************** Static Functions ***************************** */ /* + * Determine whether or not an ofile is open. + * This function must be called with the mutex held. + */ +static boolean_t +smb_ofile_is_open_locked(smb_ofile_t *of) +{ + switch (of->f_state) { + case SMB_OFILE_STATE_OPEN: + return (B_TRUE); + + case SMB_OFILE_STATE_CLOSING: + case SMB_OFILE_STATE_CLOSED: + return (B_FALSE); + + default: + ASSERT(0); + return (B_FALSE); + } +} + +/* * smb_ofile_set_close_attrs * * Updates timestamps, size and readonly bit. @@ -1038,3 +1192,107 @@ of->f_flags |= SMB_OFLAGS_SET_DELETE_ON_CLOSE; mutex_exit(&of->f_mutex); } + +/* + * Encode open file information into a buffer; needed in user space to + * support RPC requests. + */ +static int +smb_ofile_netinfo_encode(smb_ofile_t *of, uint8_t *buf, size_t buflen, + uint32_t *nbytes) +{ + smb_netfileinfo_t fi; + int rc; + + rc = smb_ofile_netinfo_init(of, &fi); + if (rc == 0) { + rc = smb_netfileinfo_encode(&fi, buf, buflen, nbytes); + smb_ofile_netinfo_fini(&fi); + } + + return (rc); +} + +static int +smb_ofile_netinfo_init(smb_ofile_t *of, smb_netfileinfo_t *fi) +{ + smb_user_t *user; + smb_tree_t *tree; + smb_node_t *node; + char *path; + char *buf; + int rc; + + ASSERT(of); + user = of->f_user; + tree = of->f_tree; + ASSERT(user); + ASSERT(tree); + + buf = kmem_zalloc(MAXPATHLEN, KM_SLEEP); + + switch (of->f_ftype) { + case SMB_FTYPE_DISK: + node = of->f_node; + ASSERT(node); + + fi->fi_permissions = of->f_granted_access; + fi->fi_numlocks = smb_lock_get_lock_count(node); + + path = kmem_zalloc(MAXPATHLEN, KM_SLEEP); + + if (node != tree->t_snode) { + rc = vnodetopath(tree->t_snode->vp, node->vp, path, + MAXPATHLEN, kcred); + if (rc == 0) + (void) strsubst(path, '/', '\\'); + else + (void) strlcpy(path, node->od_name, MAXPATHLEN); + } + + (void) snprintf(buf, MAXPATHLEN, "%s:%s", tree->t_sharename, + path); + kmem_free(path, MAXPATHLEN); + break; + + case SMB_FTYPE_MESG_PIPE: + ASSERT(of->f_pipe); + + fi->fi_permissions = FILE_READ_DATA | FILE_WRITE_DATA | + FILE_EXECUTE; + fi->fi_numlocks = 0; + (void) snprintf(buf, MAXPATHLEN, "\\PIPE\\%s", + of->f_pipe->p_name); + break; + + default: + kmem_free(buf, MAXPATHLEN); + return (-1); + } + + fi->fi_fid = of->f_fid; + fi->fi_uniqid = of->f_uniqid; + fi->fi_pathlen = strlen(buf) + 1; + fi->fi_path = smb_kstrdup(buf, fi->fi_pathlen); + kmem_free(buf, MAXPATHLEN); + + fi->fi_namelen = user->u_domain_len + user->u_name_len + 2; + fi->fi_username = kmem_alloc(fi->fi_namelen, KM_SLEEP); + (void) snprintf(fi->fi_username, fi->fi_namelen, "%s\\%s", + user->u_domain, user->u_name); + return (0); +} + +static void +smb_ofile_netinfo_fini(smb_netfileinfo_t *fi) +{ + if (fi == NULL) + return; + + if (fi->fi_path) + kmem_free(fi->fi_path, fi->fi_pathlen); + if (fi->fi_username) + kmem_free(fi->fi_username, fi->fi_namelen); + + bzero(fi, sizeof (smb_netfileinfo_t)); +}
--- a/usr/src/uts/common/fs/smbsrv/smb_opipe.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/smbsrv/smb_opipe.c Mon Jul 20 13:07:46 2009 -0400 @@ -143,13 +143,14 @@ * The full pipe path will be in the form \\PIPE\\SERVICE. The first part * can be assumed, so all we need here are the service names. * - * Returns a pointer to the pipe name (without any leading \'s) on sucess. + * Returns a pointer to the pipe name (without any leading \'s) on success. * Otherwise returns a null pointer. */ static char * smb_opipe_lookup(const char *path) { static char *named_pipes[] = { + "lsass", "LSARPC", "NETLOGON", "SAMR", @@ -188,14 +189,14 @@ static int smb_opipe_do_open(smb_request_t *sr, smb_opipe_t *opipe) { - smb_opipe_context_t *ctx = &opipe->p_context; + smb_netuserinfo_t *userinfo = &opipe->p_user; smb_user_t *user = sr->uid_user; uint8_t *buf = opipe->p_doorbuf; uint32_t buflen = SMB_OPIPE_DOOR_BUFSIZE; uint32_t len; - smb_user_context_init(user, ctx); - len = xdr_sizeof(smb_opipe_context_xdr, ctx); + smb_user_netinfo_init(user, userinfo); + len = xdr_sizeof(smb_netuserinfo_xdr, userinfo); bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t)); opipe->p_hdr.oh_magic = SMB_OPIPE_HDR_MAGIC; @@ -208,7 +209,7 @@ buf += len; buflen -= len; - if (smb_opipe_context_encode(ctx, buf, buflen, NULL) == -1) + if (smb_netuserinfo_encode(userinfo, buf, buflen, NULL) == -1) return (-1); return (smb_opipe_door_call(opipe)); @@ -266,7 +267,7 @@ kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE); } - smb_user_context_fini(&opipe->p_context); + smb_user_netinfo_fini(&opipe->p_user); smb_opipe_exit(opipe); cv_destroy(&opipe->p_cv); mutex_destroy(&opipe->p_mutex); @@ -620,48 +621,3 @@ opipe->p_hdr.oh_resid = hdr.oh_resid; return (0); } - -void -smb_user_context_init(smb_user_t *user, smb_opipe_context_t *ctx) -{ - smb_session_t *session; - - ASSERT(user); - ASSERT(user->u_domain); - ASSERT(user->u_name); - - session = user->u_session; - ASSERT(session); - ASSERT(session->workstation); - - ctx->oc_session_id = session->s_kid; - ctx->oc_native_os = session->native_os; - ctx->oc_ipaddr = session->ipaddr; - ctx->oc_uid = user->u_uid; - ctx->oc_logon_time = user->u_logon_time; - ctx->oc_flags = user->u_flags; - - ctx->oc_domain_len = user->u_domain_len; - ctx->oc_domain = smb_kstrdup(user->u_domain, ctx->oc_domain_len); - - ctx->oc_account_len = user->u_name_len; - ctx->oc_account = smb_kstrdup(user->u_name, ctx->oc_account_len); - - ctx->oc_workstation_len = strlen(session->workstation) + 1; - ctx->oc_workstation = smb_kstrdup(session->workstation, - ctx->oc_workstation_len); -} - -void -smb_user_context_fini(smb_opipe_context_t *ctx) -{ - if (ctx) { - if (ctx->oc_domain) - kmem_free(ctx->oc_domain, ctx->oc_domain_len); - if (ctx->oc_account) - kmem_free(ctx->oc_account, ctx->oc_account_len); - if (ctx->oc_workstation) - kmem_free(ctx->oc_workstation, ctx->oc_workstation_len); - bzero(ctx, sizeof (smb_opipe_context_t)); - } -}
--- a/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c Mon Jul 20 13:07:46 2009 -0400 @@ -367,7 +367,7 @@ * ENOENT will be returned. * * Path components are processed one at a time so that smb_nodes can be - * created for each component. This allows the dir_snode field in the + * created for each component. This allows the n_dnode field in the * smb_node to be properly populated. * * Because of the above, links are also processed in this routine
--- a/usr/src/uts/common/fs/smbsrv/smb_query_information.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/smbsrv/smb_query_information.c Mon Jul 20 13:07:46 2009 -0400 @@ -102,9 +102,9 @@ timestruc_t *mtime; if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { - rc = smbsr_encode_result(sr, 10, 0, "bwll10.w", - 10, FILE_ATTRIBUTE_NORMAL, 0, 0, 0); - return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); + smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, + ERROR_ACCESS_DENIED); + return (SDRC_ERROR); } if ((rc = smb_pathname_reduce(sr, sr->user_cr, path,
--- a/usr/src/uts/common/fs/smbsrv/smb_query_information2.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/smbsrv/smb_query_information2.c Mon Jul 20 13:07:46 2009 -0400 @@ -93,8 +93,9 @@ } if (sr->fid_ofile->f_ftype != SMB_FTYPE_DISK) { - smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess); - return (SDRC_ERROR); + rc = smbsr_encode_result(sr, 11, 0, "blllllww", + 11, 0, 0, 0, 0, 0, 0, 0); + return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); } node = sr->fid_ofile->f_node;
--- a/usr/src/uts/common/fs/smbsrv/smb_server.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/smbsrv/smb_server.c Mon Jul 20 13:07:46 2009 -0400 @@ -236,8 +236,6 @@ in_port_t, int, int); static int smb_server_lookup(smb_server_t **); static void smb_server_release(smb_server_t *); -static int smb_server_ulist_geti(smb_session_list_t *, uint32_t, - uint8_t *, uint32_t, uint_t *); static void smb_server_store_cfg(smb_server_t *, smb_ioc_cfg_t *); static void smb_server_stop(smb_server_t *); static int smb_server_fsop_start(smb_server_t *); @@ -246,6 +244,11 @@ static void smb_server_disconnect_share(char *, smb_server_t *); static void smb_server_thread_unexport(smb_thread_t *, void *); +static void smb_server_enum_private(smb_session_list_t *, smb_svcenum_t *); +static int smb_server_sesion_disconnect(smb_session_list_t *, const char *, + const char *); +static int smb_server_fclose(smb_session_list_t *, uint32_t); + static smb_llist_t smb_servers; /* @@ -253,7 +256,8 @@ * **************** Functions called from the device interface ***************** * ***************************************************************************** * - * These functions determine the relevant smb server to which the call apply. + * These functions typically have to determine the relevant smb server + * to which the call applies. */ /* @@ -759,75 +763,117 @@ } int -smb_server_user_number(smb_ioc_usernum_t *ioc) +smb_server_numopen(smb_ioc_opennum_t *ioc) { smb_server_t *sv; int rc; if ((rc = smb_server_lookup(&sv)) == 0) { - ioc->num = sv->sv_open_users; - smb_server_release(sv); - } - return (rc); -} - -int -smb_server_user_list(smb_ioc_ulist_t *ioc) -{ - smb_server_t *sv; - uint8_t *data; - uint32_t data_len; - uint_t bytes_encoded; - int rc; - - if ((rc = smb_server_lookup(&sv)) == 0) { - - bytes_encoded = 0; - data = ioc->data; - data_len = ioc->data_len; - ioc->num = - smb_server_ulist_geti(&sv->sv_nbt_daemon.ld_session_list, - ioc->cookie, data, data_len, &bytes_encoded); - - data += bytes_encoded; - data_len -= bytes_encoded; - ioc->data_len = bytes_encoded; - ioc->cookie += ioc->num; - - ioc->num += - smb_server_ulist_geti(&sv->sv_tcp_daemon.ld_session_list, - ioc->cookie, data, data_len, &bytes_encoded); - - ioc->data_len += bytes_encoded; - + ioc->open_users = sv->sv_open_users; + ioc->open_trees = sv->sv_open_trees; + ioc->open_files = sv->sv_open_files; smb_server_release(sv); } return (rc); } /* - * ***************************************************************************** - * ****************** Functions called from the door interface ***************** - * ***************************************************************************** - * + * Enumerate objects within the server. The svcenum provides the + * enumeration context, i.e. what the caller want to get back. + */ +int +smb_server_enum(smb_ioc_svcenum_t *ioc) +{ + smb_svcenum_t *svcenum = &ioc->svcenum; + smb_server_t *sv; + smb_session_list_t *se; + int rc; + + switch (svcenum->se_type) { + case SMB_SVCENUM_TYPE_USER: + case SMB_SVCENUM_TYPE_TREE: + case SMB_SVCENUM_TYPE_FILE: + break; + default: + return (EINVAL); + } + + if ((rc = smb_server_lookup(&sv)) != 0) + return (rc); + + svcenum->se_bavail = svcenum->se_buflen; + svcenum->se_bused = 0; + svcenum->se_nitems = 0; + + se = &sv->sv_nbt_daemon.ld_session_list; + smb_server_enum_private(se, svcenum); + + se = &sv->sv_tcp_daemon.ld_session_list; + smb_server_enum_private(se, svcenum); + + smb_server_release(sv); + return (0); +} + +/* + * Look for sessions to disconnect by client and user name. + */ +int +smb_server_session_close(smb_ioc_session_t *ioc) +{ + smb_session_list_t *se; + smb_server_t *sv; + int nbt_cnt; + int tcp_cnt; + int rc; + + if ((rc = smb_server_lookup(&sv)) != 0) + return (rc); + + se = &sv->sv_nbt_daemon.ld_session_list; + nbt_cnt = smb_server_sesion_disconnect(se, ioc->client, ioc->username); + + se = &sv->sv_tcp_daemon.ld_session_list; + tcp_cnt = smb_server_sesion_disconnect(se, ioc->client, ioc->username); + + smb_server_release(sv); + + if ((nbt_cnt == 0) && (tcp_cnt == 0)) + return (ENOENT); + return (0); +} + +/* + * Close a file by uniqid. + */ +int +smb_server_file_close(smb_ioc_fileid_t *ioc) +{ + uint32_t uniqid = ioc->uniqid; + smb_session_list_t *se; + smb_server_t *sv; + int rc; + + if ((rc = smb_server_lookup(&sv)) != 0) + return (rc); + + se = &sv->sv_nbt_daemon.ld_session_list; + rc = smb_server_fclose(se, uniqid); + + if (rc == ENOENT) { + se = &sv->sv_tcp_daemon.ld_session_list; + rc = smb_server_fclose(se, uniqid); + } + + smb_server_release(sv); + return (rc); +} + +/* * These functions determine the relevant smb server to which the call apply. */ uint32_t -smb_server_get_user_count(void) -{ - smb_server_t *sv; - uint32_t counter = 0; - - if (smb_server_lookup(&sv) == 0) { - counter = (uint32_t)sv->sv_open_users; - smb_server_release(sv); - } - - return (counter); -} - -uint32_t smb_server_get_session_count(void) { smb_server_t *sv; @@ -1422,51 +1468,140 @@ mutex_exit(&sv->sv_mutex); } -static int -smb_server_ulist_geti(smb_session_list_t *se, uint32_t cookie, - uint8_t *buf, uint32_t buf_len, uint_t *pbe) +/* + * Enumerate the users associated with a session list. + */ +static void +smb_server_enum_private(smb_session_list_t *se, smb_svcenum_t *svcenum) { - smb_session_t *sn = NULL; - smb_user_t *user; - smb_llist_t *ulist; - smb_opipe_context_t ctx; - uint_t bytes_encoded; - int rc = 0; - int cnt = 0; + smb_session_t *sn; + smb_llist_t *ulist; + smb_user_t *user; + int rc = 0; rw_enter(&se->se_lock, RW_READER); sn = list_head(&se->se_act.lst); - while ((sn != NULL) && (rc == 0)) { + + while (sn != NULL) { ASSERT(sn->s_magic == SMB_SESSION_MAGIC); ulist = &sn->s_user_list; smb_llist_enter(ulist, RW_READER); user = smb_llist_head(ulist); - while ((user != NULL) && (rc == 0)) { - ASSERT(user->u_magic == SMB_USER_MAGIC); - mutex_enter(&user->u_mutex); - if ((user->u_state == SMB_USER_STATE_LOGGED_IN) && - (cookie == 0)) { - smb_user_context_init(user, &ctx); - rc = smb_opipe_context_encode(&ctx, buf, - buf_len, &bytes_encoded); - smb_user_context_fini(&ctx); - if (rc == 0) { - *pbe += bytes_encoded; - buf += bytes_encoded; - buf_len -= bytes_encoded; - cnt++; + + while (user != NULL) { + if (smb_user_hold(user)) { + rc = smb_user_enum(user, svcenum); + smb_user_release(user); + } + + user = smb_llist_next(ulist, user); + } + + smb_llist_exit(ulist); + + if (rc != 0) + break; + + sn = list_next(&se->se_act.lst, sn); + } + + rw_exit(&se->se_lock); +} + +/* + * Disconnect sessions associated with the specified client and username. + * Empty strings are treated as wildcards. + */ +static int +smb_server_sesion_disconnect(smb_session_list_t *se, + const char *client, const char *name) +{ + smb_session_t *sn; + smb_llist_t *ulist; + smb_user_t *user; + boolean_t match; + int count = 0; + + rw_enter(&se->se_lock, RW_READER); + sn = list_head(&se->se_act.lst); + + while (sn != NULL) { + ASSERT(sn->s_magic == SMB_SESSION_MAGIC); + + if ((*client != '\0') && (!smb_session_isclient(sn, client))) { + sn = list_next(&se->se_act.lst, sn); + continue; + } + + ulist = &sn->s_user_list; + smb_llist_enter(ulist, RW_READER); + user = smb_llist_head(ulist); + + while (user != NULL) { + if (smb_user_hold(user)) { + match = (*name == '\0'); + if (!match) + match = smb_user_namecmp(user, name); + + if (match) { + smb_llist_exit(ulist); + smb_user_logoff(user); + ++count; + smb_user_release(user); + smb_llist_enter(ulist, RW_READER); + user = smb_llist_head(ulist); + continue; } + + smb_user_release(user); } - mutex_exit(&user->u_mutex); + user = smb_llist_next(ulist, user); - if (cookie > 0) - cookie--; } + smb_llist_exit(ulist); sn = list_next(&se->se_act.lst, sn); } + rw_exit(&se->se_lock); - return (cnt); + return (count); +} + +/* + * Close a file by its unique id. + */ +static int +smb_server_fclose(smb_session_list_t *se, uint32_t uniqid) +{ + smb_session_t *sn; + smb_llist_t *ulist; + smb_user_t *user; + int rc = ENOENT; + + rw_enter(&se->se_lock, RW_READER); + sn = list_head(&se->se_act.lst); + + while ((sn != NULL) && (rc == ENOENT)) { + ASSERT(sn->s_magic == SMB_SESSION_MAGIC); + ulist = &sn->s_user_list; + smb_llist_enter(ulist, RW_READER); + user = smb_llist_head(ulist); + + while ((user != NULL) && (rc == ENOENT)) { + if (smb_user_hold(user)) { + rc = smb_user_fclose(user, uniqid); + smb_user_release(user); + } + + user = smb_llist_next(ulist, user); + } + + smb_llist_exit(ulist); + sn = list_next(&se->se_act.lst, sn); + } + + rw_exit(&se->se_lock); + return (rc); } static void
--- a/usr/src/uts/common/fs/smbsrv/smb_session.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/smbsrv/smb_session.c Mon Jul 20 13:07:46 2009 -0400 @@ -1041,13 +1041,8 @@ ASSERT(user->u_magic == SMB_USER_MAGIC); if (!utf8_strcasecmp(user->u_name, name) && !utf8_strcasecmp(user->u_domain, domain)) { - mutex_enter(&user->u_mutex); - if (user->u_state == SMB_USER_STATE_LOGGED_IN) { - user->u_refcnt++; - mutex_exit(&user->u_mutex); + if (smb_user_hold(user)) break; - } - mutex_exit(&user->u_mutex); } user = smb_llist_next(ulist, user); } @@ -1084,6 +1079,64 @@ } /* + * Copy the session workstation/client name to buf. If the workstation + * is an empty string (which it will be on TCP connections), use the + * client IP address. + */ +void +smb_session_getclient(smb_session_t *sn, char *buf, size_t buflen) +{ + char ipbuf[INET6_ADDRSTRLEN]; + smb_inaddr_t *ipaddr; + + ASSERT(sn); + ASSERT(buf); + ASSERT(buflen); + + *buf = '\0'; + + if (sn->workstation[0] != '\0') { + (void) strlcpy(buf, sn->workstation, buflen); + return; + } + + ipaddr = &sn->ipaddr; + if (smb_inet_ntop(ipaddr, ipbuf, SMB_IPSTRLEN(ipaddr->a_family))) + (void) strlcpy(buf, ipbuf, buflen); +} + +/* + * Check whether or not the specified client name is the client of this + * session. The name may be in UNC format (\\CLIENT). + * + * A workstation/client name is setup on NBT connections as part of the + * NetBIOS session request but that isn't available on TCP connections. + * If the session doesn't have a client name we typically return the + * client IP address as the workstation name on MSRPC requests. So we + * check for the IP address here in addition to the workstation name. + */ +boolean_t +smb_session_isclient(smb_session_t *sn, const char *client) +{ + char buf[INET6_ADDRSTRLEN]; + smb_inaddr_t *ipaddr; + + client += strspn(client, "\\"); + + if (utf8_strcasecmp(client, sn->workstation) == 0) + return (B_TRUE); + + ipaddr = &sn->ipaddr; + if (smb_inet_ntop(ipaddr, buf, SMB_IPSTRLEN(ipaddr->a_family)) == NULL) + return (B_FALSE); + + if (utf8_strcasecmp(client, buf) == 0) + return (B_TRUE); + + return (B_FALSE); +} + +/* * smb_request_alloc * * Allocate an smb_request_t structure from the kmem_cache. Partially @@ -1171,7 +1224,7 @@ void dump_smb_inaddr(smb_inaddr_t *ipaddr) { -char ipstr[INET6_ADDRSTRLEN]; + char ipstr[INET6_ADDRSTRLEN]; if (smb_inet_ntop(ipaddr, ipstr, SMB_IPSTRLEN(ipaddr->a_family))) cmn_err(CE_WARN, "error ipstr=%s", ipstr);
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c Mon Jul 20 13:07:46 2009 -0400 @@ -519,8 +519,12 @@ if (count != 0) smb_odir_save_cookie(od, 0, cookie); - /* if eos not already detected, check if more entries */ - if (!*eos) + /* + * If all retrieved entries have been successfully encoded + * and eos has not already been detected, check if there are + * any more entries. eos will be set if there are no more. + */ + if ((rc == 0) && (!*eos)) (void) smb_odir_read_fileinfo(sr, od, &fileinfo, eos); return (count);
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c Mon Jul 20 13:07:46 2009 -0400 @@ -52,6 +52,8 @@ #include <smbsrv/smb_fsops.h> uint32_t smb_pad_align(uint32_t offset, uint32_t align); +void smb_encode_smb_datetimes(smb_request_t *, smb_xa_t *, smb_attr_t *); +void smb_encode_nt_times(smb_request_t *, smb_xa_t *, smb_attr_t *); extern int smb_query_all_info_filename(smb_tree_t *, smb_node_t *, char *, size_t); @@ -80,11 +82,10 @@ u_offset_t datasz = 0, allocsz = 0; smb_attr_t *ap = NULL; char *namep = NULL; - char *filename = NULL, *alt_nm_ptr = NULL; + char *filename = NULL; int filename_len = 0; smb_node_t *node = NULL; /* only set for SMB_FTYPE_DISK files */ - smb_node_t *dir_snode = NULL; - timestruc_t *creation_time = NULL; + smb_node_t *dnode = NULL; unsigned char delete_on_close = 0; unsigned char is_dir = 0; char *filebuf = NULL; @@ -133,7 +134,6 @@ } dattr = ap->sa_dosattr; - creation_time = &ap->sa_crtime; if (smb_node_is_dir(node)) { is_dir = 1; @@ -144,31 +144,55 @@ allocsz = ap->sa_vattr.va_nblocks * DEV_BSIZE; } - dir_snode = node->dir_snode; + dnode = node->n_dnode; delete_on_close = (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0; + + /* + * The number of links reported should be the number of + * non-deleted links. Thus if delete_on_close is set, + * decrement the link count. + */ + if (delete_on_close && ap->sa_vattr.va_nlink > 0) + --(ap->sa_vattr.va_nlink); + } break; case SMB_FTYPE_MESG_PIPE: { - /* - * The pipe is only valid for SMB_FTYPE_MESG_PIPE files. - */ + /* The pipe is only valid for SMB_FTYPE_MESG_PIPE files */ namep = sr->fid_ofile->f_pipe->p_name; filename = namep; filename_len = smb_ascii_or_unicode_strlen(sr, filename); ap = &pipe_attr; - creation_time = (timestruc_t *)&ap->sa_vattr.va_ctime; + ap->sa_vattr.va_nlink = 1; dattr = FILE_ATTRIBUTE_NORMAL; datasz = allocsz = 0; - delete_on_close = 0; + delete_on_close = 1; is_dir = 0; + + /* some levels are not valid for pipes */ + switch (infolev) { + case SMB_QUERY_FILE_ALT_NAME_INFO: + case SMB_FILE_ALT_NAME_INFORMATION: + case SMB_QUERY_FILE_STREAM_INFO: + case SMB_FILE_STREAM_INFORMATION: + case SMB_QUERY_FILE_COMPRESSION_INFO: + case SMB_FILE_COMPRESSION_INFORMATION: + case SMB_FILE_ATTR_TAG_INFORMATION: + smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, + ERRDOS, ERROR_INVALID_PARAMETER); + return (SDRC_ERROR); + case SMB_INFO_QUERY_ALL_EAS: + smbsr_error(sr, NT_STATUS_ACCESS_DENIED, + ERRDOS, ERROR_ACCESS_DENIED); + return (SDRC_ERROR); + } } break; - default: smbsr_error(sr, 0, ERRDOS, ERRbadfile); return (SDRC_ERROR); @@ -188,16 +212,14 @@ if (allocsz > UINT_MAX) allocsz = UINT_MAX; + /* unlike other levels attributes should be 0 here for pipes */ + if (sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE) + dattr = 0; + (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); - (void) smb_mbc_encodef(&xa->rep_data_mb, - ((sr->session->native_os == NATIVE_OS_WIN95) - ? "YYYllw" : "yyyllw"), - smb_gmt2local(sr, creation_time->tv_sec), - smb_gmt2local(sr, ap->sa_vattr.va_atime.tv_sec), - smb_gmt2local(sr, ap->sa_vattr.va_mtime.tv_sec), - (uint32_t)datasz, - (uint32_t)allocsz, - dattr); + smb_encode_smb_datetimes(sr, xa, ap); + (void) smb_mbc_encodef(&xa->rep_data_mb, "llw", + (uint32_t)datasz, (uint32_t)allocsz, dattr); break; case SMB_INFO_QUERY_EA_SIZE: @@ -206,20 +228,18 @@ if (allocsz > UINT_MAX) allocsz = UINT_MAX; + /* unlike other levels attributes should be 0 here for pipes */ + if (sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE) + dattr = 0; + (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); - (void) smb_mbc_encodef(&xa->rep_data_mb, - ((sr->session->native_os == NATIVE_OS_WIN95) - ? "YYYllwl" : "yyyllwl"), - smb_gmt2local(sr, creation_time->tv_sec), - smb_gmt2local(sr, ap->sa_vattr.va_atime.tv_sec), - smb_gmt2local(sr, ap->sa_vattr.va_mtime.tv_sec), - (uint32_t)datasz, - (uint32_t)allocsz, - dattr, 0); + smb_encode_smb_datetimes(sr, xa, ap); + (void) smb_mbc_encodef(&xa->rep_data_mb, "llwl", + (uint32_t)datasz, (uint32_t)allocsz, dattr, 0); break; + case SMB_INFO_QUERY_ALL_EAS: case SMB_INFO_QUERY_EAS_FROM_LIST: - case SMB_INFO_QUERY_ALL_EAS: case SMB_FILE_EA_INFORMATION: (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0); @@ -236,12 +256,8 @@ * Similar change in smb_trans2_query_path_information.c. */ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); - (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.", - creation_time, - &ap->sa_vattr.va_atime, - &ap->sa_vattr.va_mtime, - &ap->sa_vattr.va_ctime, - dattr); + smb_encode_nt_times(sr, xa, ap); + (void) smb_mbc_encodef(&xa->rep_data_mb, "w6.", dattr); break; case SMB_QUERY_FILE_STANDARD_INFO: @@ -294,19 +310,28 @@ case SMB_QUERY_FILE_ALL_INFO: case SMB_FILE_ALL_INFORMATION: + if (sr->fid_ofile->f_ftype == SMB_FTYPE_DISK) { + rc = smb_query_all_info_filename(sr->tid_tree, node, + filebuf, MAXPATHLEN); + if (rc != 0) { + smbsr_errno(sr, rc); + kmem_free(filebuf, MAXPATHLEN+1); + return (SDRC_ERROR); + } + filename = filebuf; + } else { + /* If the leading \ is missing, add it. */ + if (*namep != '\\') { + (void) snprintf(filebuf, MAXNAMELEN, + "\\%s", namep); + filename = filebuf; + } + } + filename_len = smb_ascii_or_unicode_strlen(sr, filename); + /* - * The reply of this information level on the - * wire doesn't match with protocol specification. - * This is what spec. needs: "TTTTwqqlbbqllqqll" - * But this is actually is sent on the wire: - * "TTTTw6.qqlbb2.l" - * So, there is a 6-byte pad between Attributes and - * AllocationSize. Also there is a 2-byte pad After - * Directory field. Between Directory and FileNameLength - * there is just 4 bytes that it seems is AlignmentRequirement. - * There are 6 other fields between Directory and - * AlignmentRequirement in spec. that aren't sent - * on the wire. + * There is a 6-byte pad between Attributes and AllocationSize, + * and a 2-byte pad after the Directory field. */ if (node) { rc = smb_query_all_info_filename(sr->tid_tree, node, @@ -322,11 +347,8 @@ } (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); - (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.qqlbb2.l", - creation_time, - &ap->sa_vattr.va_atime, - &ap->sa_vattr.va_mtime, - &ap->sa_vattr.va_ctime, + smb_encode_nt_times(sr, xa, ap); + (void) smb_mbc_encodef(&xa->rep_data_mb, "w6.qqlbb2.l", dattr, (uint64_t)allocsz, (uint64_t)datasz, @@ -342,43 +364,41 @@ case SMB_QUERY_FILE_ALT_NAME_INFO: case SMB_FILE_ALT_NAME_INFORMATION: /* - * Conform to the rule used by Windows NT/2003 servers. - * Shortname is created only if either the filename or - * extension portion of a file is made up of mixed case. - * - * If the shortname is generated, it will be returned as - * the alternative name. Otherwise, convert the original - * name to all upper-case and return it as the alternative - * name. + * If the shortname is generated by smb_mangle_name() + * it will be returned as the alternative name. + * Otherwise, convert the original name to upper-case + * and return it as the alternative name. */ (void) smb_mangle_name(ap->sa_vattr.va_nodeid, filename, short_name, name83, 0); - alt_nm_ptr = (*short_name == 0) ? - utf8_strupr(filename) : short_name; + if (*short_name == 0) { + (void) strlcpy(short_name, filename, SMB_SHORTNAMELEN); + (void) utf8_strupr(short_name); + } + (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); (void) smb_mbc_encodef(&xa->rep_data_mb, "%lU", sr, - mts_wcequiv_strlen(alt_nm_ptr), alt_nm_ptr); + mts_wcequiv_strlen(short_name), short_name); break; case SMB_QUERY_FILE_STREAM_INFO: case SMB_FILE_STREAM_INFORMATION: { struct smb_node *node = sr->fid_ofile->f_node; - if (dir_snode == NULL) { + if (dnode == NULL) { kmem_free(filebuf, MAXPATHLEN+1); smbsr_error(sr, 0, ERRDOS, ERRbadfile); return (SDRC_ERROR); } (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); if (SMB_IS_STREAM(node)) { - ASSERT(node->unnamed_stream_node); - ASSERT(node->unnamed_stream_node->n_magic == - SMB_NODE_MAGIC); - ASSERT(node->unnamed_stream_node->n_state != + ASSERT(node->n_unode); + ASSERT(node->n_unode->n_magic == SMB_NODE_MAGIC); + ASSERT(node->n_unode->n_state != SMB_NODE_STATE_DESTROYING); (void) smb_encode_stream_info(sr, xa, - node->unnamed_stream_node, ap); + node->n_unode, ap); } else { (void) smb_encode_stream_info(sr, xa, node, ap); } @@ -572,3 +592,45 @@ return (pad); } + +/* + * smb_encode_smb_datetimes + * + * Encode timestamps in the SMB_DATE / SMB_TIME format. + */ +void +smb_encode_smb_datetimes(smb_request_t *sr, smb_xa_t *xa, smb_attr_t *attr) +{ + if ((sr->fid_ofile) && + (sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE)) { + (void) smb_mbc_encodef(&xa->rep_data_mb, "lll", 0, 0, 0); + return; + } + + (void) smb_mbc_encodef(&xa->rep_data_mb, + ((sr->session->native_os == NATIVE_OS_WIN95) ? "YYY" : "yyy"), + smb_gmt2local(sr, attr->sa_crtime.tv_sec), + smb_gmt2local(sr, attr->sa_vattr.va_atime.tv_sec), + smb_gmt2local(sr, attr->sa_vattr.va_mtime.tv_sec)); +} + +/* + * smb_encode_nt_times + * + * Encode timestamps in LARGE INTEGER format NT Times. + */ +void +smb_encode_nt_times(smb_request_t *sr, smb_xa_t *xa, smb_attr_t *attr) +{ + if ((sr->fid_ofile) && + (sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE)) { + (void) smb_mbc_encodef(&xa->rep_data_mb, "qqqq", 0, 0, 0, 0); + return; + } + + (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTT", + &attr->sa_crtime, + &attr->sa_vattr.va_atime, + &attr->sa_vattr.va_mtime, + &attr->sa_vattr.va_ctime); +}
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c Mon Jul 20 13:07:46 2009 -0400 @@ -322,6 +322,8 @@ #include <smbsrv/smb_fsops.h> int smb_query_all_info_filename(smb_tree_t *, smb_node_t *, char *, size_t); +extern void smb_encode_smb_datetimes(smb_request_t *, smb_xa_t *, smb_attr_t *); +extern void smb_encode_nt_times(smb_request_t *, smb_xa_t *, smb_attr_t *); /* * Function: int smb_com_trans2_query_path_information(struct smb_request *) @@ -340,11 +342,12 @@ char short_name[SMB_SHORTNAMELEN]; char name83[SMB_SHORTNAMELEN]; unsigned char is_dir; + unsigned char delete_on_close; int len; if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { - smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, - ERROR_ACCESS_DENIED); + smbsr_error(sr, NT_STATUS_INVALID_DEVICE_REQUEST, ERRDOS, + ERROR_INVALID_FUNCTION); return (SDRC_ERROR); } @@ -422,6 +425,18 @@ allocsz = ap->sa_vattr.va_nblocks * DEV_BSIZE; } + delete_on_close = + (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0; + + /* + * The number of links reported should be the number of + * non-deleted links. Thus if delete_on_close is set, + * decrement the link count. + */ + if (delete_on_close && ap->sa_vattr.va_nlink > 0) + --(ap->sa_vattr.va_nlink); + + switch (infolev) { case SMB_INFO_STANDARD: @@ -431,15 +446,9 @@ allocsz = UINT_MAX; (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); - (void) smb_mbc_encodef(&xa->rep_data_mb, - ((sr->session->native_os == NATIVE_OS_WIN95) - ? "YYYllw" : "yyyllw"), - smb_gmt2local(sr, ap->sa_crtime.tv_sec), - smb_gmt2local(sr, ap->sa_vattr.va_atime.tv_sec), - smb_gmt2local(sr, ap->sa_vattr.va_mtime.tv_sec), - (uint32_t)datasz, - (uint32_t)allocsz, - dattr); + smb_encode_smb_datetimes(sr, xa, ap); + (void) smb_mbc_encodef(&xa->rep_data_mb, "llw", + (uint32_t)datasz, (uint32_t)allocsz, dattr); break; case SMB_INFO_QUERY_EA_SIZE: @@ -449,15 +458,9 @@ allocsz = UINT_MAX; (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); - (void) smb_mbc_encodef(&xa->rep_data_mb, - ((sr->session->native_os == NATIVE_OS_WIN95) - ? "YYYllwl" : "yyyllwl"), - smb_gmt2local(sr, ap->sa_crtime.tv_sec), - smb_gmt2local(sr, ap->sa_vattr.va_atime.tv_sec), - smb_gmt2local(sr, ap->sa_vattr.va_mtime.tv_sec), - (uint32_t)datasz, - (uint32_t)allocsz, - dattr, 0); + smb_encode_smb_datetimes(sr, xa, ap); + (void) smb_mbc_encodef(&xa->rep_data_mb, "llwl", + (uint32_t)datasz, (uint32_t)allocsz, dattr, 0); break; case SMB_INFO_QUERY_EAS_FROM_LIST: @@ -477,12 +480,8 @@ * Similar change in smb_trans2_query_file_information.c. */ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); - (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.", - &ap->sa_crtime, - &ap->sa_vattr.va_atime, - &ap->sa_vattr.va_mtime, - &ap->sa_vattr.va_ctime, - dattr); + smb_encode_nt_times(sr, xa, ap); + (void) smb_mbc_encodef(&xa->rep_data_mb, "w6.", dattr); break; case SMB_QUERY_FILE_STANDARD_INFO: @@ -496,7 +495,7 @@ (uint64_t)allocsz, (uint64_t)datasz, ap->sa_vattr.va_nlink, - (node && (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0), + delete_on_close, (char)(ap->sa_vattr.va_type == VDIR)); break; @@ -520,19 +519,18 @@ case SMB_QUERY_FILE_ALL_INFO: case SMB_FILE_ALL_INFORMATION: + rc = smb_query_all_info_filename(sr->tid_tree, node, + name, MAXPATHLEN); + if (rc != 0) { + smbsr_errno(sr, rc); + smb_node_release(node); + kmem_free(name, MAXPATHLEN); + return (SDRC_ERROR); + } + /* - * The reply of this information level on the - * wire doesn't match with protocol specification. - * This is what spec. needs: "TTTTwqqlbbqllqqll" - * But this is actually is sent on the wire: - * "TTTTw6.qqlbb2.l" - * So, there is a 6-byte pad between Attributes and - * AllocationSize. Also there is a 2-byte pad After - * Directory field. Between Directory and FileNameLength - * there is just 4 bytes that it seems is AlignmentRequirement. - * There are 6 other fields between Directory and - * AlignmentRequirement in spec. that aren't sent - * on the wire. + * There is a 6-byte pad between Attributes and AllocationSize, + * and a 2-byte pad after the Directory field. */ rc = smb_query_all_info_filename(sr->tid_tree, node, name, MAXPATHLEN); @@ -544,11 +542,8 @@ } (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); - (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.qqlbb2.l", - &ap->sa_crtime, - &ap->sa_vattr.va_atime, - &ap->sa_vattr.va_mtime, - &ap->sa_vattr.va_ctime, + smb_encode_nt_times(sr, xa, ap); + (void) smb_mbc_encodef(&xa->rep_data_mb, "w6.qqlbb2.l", dattr, (uint64_t)allocsz, (uint64_t)datasz, @@ -564,14 +559,10 @@ case SMB_QUERY_FILE_ALT_NAME_INFO: case SMB_FILE_ALT_NAME_INFORMATION: /* - * Conform to the rule used by Windows NT/2003 servers. - * Shortname is created only if either the filename or - * extension portion of a file is made up of mixed case. - * - * If the shortname is generated, it will be returned as - * the alternative name. Otherwise, convert the original - * name to all upper-case and return it as the alternative - * name. + * If the shortname is generated by smb_mangle_name() + * it will be returned as the alternative name. + * Otherwise, convert the original name to upper-case + * and return it as the alternative name. */ (void) smb_mangle_name(ap->sa_vattr.va_nodeid, name, short_name, name83, 0); @@ -656,7 +647,7 @@ buflen -= len; if (SMB_IS_STREAM(node)) - vp = node->unnamed_stream_node->vp; + vp = node->n_unode->vp; else vp = node->vp;
--- a/usr/src/uts/common/fs/smbsrv/smb_tree.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/smbsrv/smb_tree.c Mon Jul 20 13:07:46 2009 -0400 @@ -193,8 +193,13 @@ static void smb_tree_get_flags(const smb_share_t *, vfs_t *, smb_tree_t *); static void smb_tree_log(smb_request_t *, const char *, const char *, ...); static void smb_tree_close_odirs(smb_tree_t *, uint16_t); +static smb_ofile_t *smb_tree_get_ofile(smb_tree_t *, smb_ofile_t *); static smb_odir_t *smb_tree_get_odir(smb_tree_t *, smb_odir_t *); static void smb_tree_set_execsub_info(smb_tree_t *, smb_execsub_info_t *); +static int smb_tree_enum_private(smb_tree_t *, smb_svcenum_t *); +static int smb_tree_netinfo_encode(smb_tree_t *, uint8_t *, size_t, uint32_t *); +static void smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *); +static void smb_tree_netinfo_fini(smb_netconnectinfo_t *); /* * Extract the share name and share type and connect as appropriate. @@ -362,8 +367,69 @@ return ((tree->t_flags & flags) == flags); } +/* + * If the enumeration request is for tree data, handle the request + * here. Otherwise, pass it on to the ofiles. + * + * This function should be called with a hold on the tree. + */ +int +smb_tree_enum(smb_tree_t *tree, smb_svcenum_t *svcenum) +{ + smb_ofile_t *of; + smb_ofile_t *next; + int rc; + + ASSERT(tree); + ASSERT(tree->t_magic == SMB_TREE_MAGIC); + + if (svcenum->se_type == SMB_SVCENUM_TYPE_TREE) + return (smb_tree_enum_private(tree, svcenum)); + + of = smb_tree_get_ofile(tree, NULL); + while (of) { + ASSERT(of->f_tree == tree); + + rc = smb_ofile_enum(of, svcenum); + if (rc != 0) { + smb_ofile_release(of); + break; + } + + next = smb_tree_get_ofile(tree, of); + smb_ofile_release(of); + of = next; + } + + return (rc); +} + +/* + * Close a file by its unique id. + */ +int +smb_tree_fclose(smb_tree_t *tree, uint32_t uniqid) +{ + smb_ofile_t *of; + + ASSERT(tree); + ASSERT(tree->t_magic == SMB_TREE_MAGIC); + + if ((of = smb_ofile_lookup_by_uniqid(tree, uniqid)) == NULL) + return (ENOENT); + + if (smb_ofile_disallow_fclose(of)) { + smb_ofile_release(of); + return (EACCES); + } + + smb_ofile_close(of, 0); + smb_ofile_release(of); + return (0); +} /* *************************** Static Functions ***************************** */ + #define SHARES_DIR ".zfs/shares/" static void smb_tree_acl_access(cred_t *cred, const char *sharename, vnode_t *pathvp, @@ -434,7 +500,7 @@ smb_tree_connect_disk(smb_request_t *sr, const char *sharename) { smb_user_t *user = sr->uid_user; - smb_node_t *dir_snode = NULL; + smb_node_t *dnode = NULL; smb_node_t *snode = NULL; char last_component[MAXNAMELEN]; smb_tree_t *tree; @@ -529,15 +595,15 @@ /* * Check that the shared directory exists. */ - rc = smb_pathname_reduce(sr, u_cred, si->shr_path, 0, 0, &dir_snode, + rc = smb_pathname_reduce(sr, u_cred, si->shr_path, 0, 0, &dnode, last_component); if (rc == 0) { rc = smb_fsop_lookup(sr, u_cred, SMB_FOLLOW_LINKS, - sr->sr_server->si_root_smb_node, dir_snode, last_component, + sr->sr_server->si_root_smb_node, dnode, last_component, &snode); - smb_node_release(dir_snode); + smb_node_release(dnode); } if (rc) { @@ -704,6 +770,7 @@ tree->t_state = SMB_TREE_STATE_CONNECTED; tree->t_magic = SMB_TREE_MAGIC; tree->t_access = access; + tree->t_connect_time = gethrestime_sec(); /* if FS is readonly, enforce that here */ if (tree->t_flags & SMB_TREE_READONLY) @@ -1080,6 +1147,44 @@ } /* + * Get the next open ofile in the list. A reference is taken on + * the ofile, which can be released later with smb_ofile_release(). + * + * If the specified ofile is NULL, search from the beginning of the + * list. Otherwise, the search starts just after that ofile. + * + * Returns NULL if there are no open files in the list. + */ +static smb_ofile_t * +smb_tree_get_ofile(smb_tree_t *tree, smb_ofile_t *of) +{ + smb_llist_t *ofile_list; + + ASSERT(tree); + ASSERT(tree->t_magic == SMB_TREE_MAGIC); + + ofile_list = &tree->t_ofile_list; + smb_llist_enter(ofile_list, RW_READER); + + if (of) { + ASSERT(of->f_magic == SMB_OFILE_MAGIC); + of = smb_llist_next(ofile_list, of); + } else { + of = smb_llist_head(ofile_list); + } + + while (of) { + if (smb_ofile_hold(of)) + break; + + of = smb_llist_next(ofile_list, of); + } + + smb_llist_exit(ofile_list); + return (of); +} + +/* * smb_tree_get_odir * * Find the next odir in the tree's list of odirs, and obtain a @@ -1157,3 +1262,96 @@ subs->e_cli_netbiosname = tree->t_session->workstation; subs->e_uid = tree->t_user->u_cred->cr_uid; } + +/* + * Private function to support smb_tree_enum. + */ +static int +smb_tree_enum_private(smb_tree_t *tree, smb_svcenum_t *svcenum) +{ + uint8_t *pb; + uint_t nbytes; + int rc; + + if (svcenum->se_nskip > 0) { + svcenum->se_nskip--; + return (0); + } + + if (svcenum->se_nitems >= svcenum->se_nlimit) { + svcenum->se_nitems = svcenum->se_nlimit; + return (0); + } + + pb = &svcenum->se_buf[svcenum->se_bused]; + rc = smb_tree_netinfo_encode(tree, pb, svcenum->se_bavail, &nbytes); + if (rc == 0) { + svcenum->se_bavail -= nbytes; + svcenum->se_bused += nbytes; + svcenum->se_nitems++; + } + + return (rc); +} + +/* + * Encode connection information into a buffer: connection information + * needed in user space to support RPC requests. + */ +static int +smb_tree_netinfo_encode(smb_tree_t *tree, uint8_t *buf, size_t buflen, + uint32_t *nbytes) +{ + smb_netconnectinfo_t info; + int rc; + + smb_tree_netinfo_init(tree, &info); + rc = smb_netconnectinfo_encode(&info, buf, buflen, nbytes); + smb_tree_netinfo_fini(&info); + + return (rc); +} + +/* + * Note: ci_numusers should be the number of users connected to + * the share rather than the number of references on the tree but + * we don't have a mechanism to track users/share in smbsrv yet. + */ +static void +smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *info) +{ + smb_user_t *user; + + ASSERT(tree); + + info->ci_id = tree->t_tid; + info->ci_type = tree->t_res_type; + info->ci_numopens = tree->t_open_files; + info->ci_numusers = tree->t_refcnt; + info->ci_time = gethrestime_sec() - tree->t_connect_time; + + info->ci_sharelen = strlen(tree->t_sharename) + 1; + info->ci_share = smb_kstrdup(tree->t_sharename, info->ci_sharelen); + + user = tree->t_user; + ASSERT(user); + + info->ci_namelen = user->u_domain_len + user->u_name_len + 2; + info->ci_username = kmem_alloc(info->ci_namelen, KM_SLEEP); + (void) snprintf(info->ci_username, info->ci_namelen, "%s\\%s", + user->u_domain, user->u_name); +} + +static void +smb_tree_netinfo_fini(smb_netconnectinfo_t *info) +{ + if (info == NULL) + return; + + if (info->ci_username) + kmem_free(info->ci_username, info->ci_namelen); + if (info->ci_share) + kmem_free(info->ci_share, info->ci_sharelen); + + bzero(info, sizeof (smb_netconnectinfo_t)); +}
--- a/usr/src/uts/common/fs/smbsrv/smb_user.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/smbsrv/smb_user.c Mon Jul 20 13:07:46 2009 -0400 @@ -171,6 +171,8 @@ static smb_sid_t *smb_admins_sid = NULL; +static boolean_t smb_user_is_logged_in(smb_user_t *); +static int smb_user_enum_private(smb_user_t *, smb_svcenum_t *); static void smb_user_delete(smb_user_t *user); static smb_tree_t *smb_user_get_tree(smb_llist_t *, smb_tree_t *); @@ -287,7 +289,8 @@ /* * smb_user_logoff * - * + * Change the user state and disconnect trees. + * The user list must not be entered or modified here. */ void smb_user_logoff( @@ -376,6 +379,27 @@ } /* + * Take a reference on a user. + */ +boolean_t +smb_user_hold(smb_user_t *user) +{ + ASSERT(user); + ASSERT(user->u_magic == SMB_USER_MAGIC); + + mutex_enter(&user->u_mutex); + + if (smb_user_is_logged_in(user)) { + user->u_refcnt++; + mutex_exit(&user->u_mutex); + return (B_TRUE); + } + + mutex_exit(&user->u_mutex); + return (B_FALSE); +} + +/* * smb_user_release * * @@ -434,29 +458,10 @@ ASSERT(user->u_magic == SMB_USER_MAGIC); ASSERT(user->u_session == session); if (user->u_uid == uid) { - mutex_enter(&user->u_mutex); - switch (user->u_state) { - - case SMB_USER_STATE_LOGGED_IN: - /* The user exists and is still logged in. */ - user->u_refcnt++; - mutex_exit(&user->u_mutex); + if (smb_user_hold(user)) { smb_llist_exit(&session->s_user_list); return (user); - - case SMB_USER_STATE_LOGGING_OFF: - case SMB_USER_STATE_LOGGED_OFF: - /* - * The user exists but has logged off or is in - * the process of logging off. - */ - mutex_exit(&user->u_mutex); - smb_llist_exit(&session->s_user_list); - return (NULL); - - default: - ASSERT(0); - mutex_exit(&user->u_mutex); + } else { smb_llist_exit(&session->s_user_list); return (NULL); } @@ -499,17 +504,11 @@ while (next) { ASSERT(next->u_magic == SMB_USER_MAGIC); ASSERT(next->u_session == session); - mutex_enter(&next->u_mutex); - if (next->u_state == SMB_USER_STATE_LOGGED_IN) { - next->u_refcnt++; - mutex_exit(&next->u_mutex); + + if (smb_user_hold(next)) break; - } else { - ASSERT((next->u_state == SMB_USER_STATE_LOGGING_OFF) || - (next->u_state == SMB_USER_STATE_LOGGED_OFF)); - mutex_exit(&next->u_mutex); - next = smb_llist_next(lst, next); - } + + next = smb_llist_next(lst, next); } smb_llist_exit(lst); @@ -712,6 +711,40 @@ } /* + * Close a file by its unique id. + */ +int +smb_user_fclose(smb_user_t *user, uint32_t uniqid) +{ + smb_llist_t *tree_list; + smb_tree_t *tree; + int rc = ENOENT; + + ASSERT(user); + ASSERT(user->u_magic == SMB_USER_MAGIC); + + tree_list = &user->u_tree_list; + ASSERT(tree_list); + + smb_llist_enter(tree_list, RW_READER); + tree = smb_llist_head(tree_list); + + while ((tree != NULL) && (rc == ENOENT)) { + ASSERT(tree->t_user == user); + + if (smb_tree_hold(tree)) { + rc = smb_tree_fclose(tree, uniqid); + smb_tree_release(tree); + } + + tree = smb_llist_next(tree_list, tree); + } + + smb_llist_exit(tree_list); + return (rc); +} + +/* * Determine whether or not the user is an administrator. * Members of the administrators group have administrative rights. */ @@ -734,9 +767,99 @@ return (B_FALSE); } +/* + * This function should be called with a hold on the user. + */ +boolean_t +smb_user_namecmp(smb_user_t *user, const char *name) +{ + char *fq_name; + boolean_t match; + + if (utf8_strcasecmp(name, user->u_name) == 0) + return (B_TRUE); + + fq_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); + + (void) snprintf(fq_name, MAXNAMELEN, "%s\\%s", + user->u_domain, user->u_name); + + match = (utf8_strcasecmp(name, fq_name) == 0); + if (!match) { + (void) snprintf(fq_name, MAXNAMELEN, "%s@%s", + user->u_name, user->u_domain); + + match = (utf8_strcasecmp(name, fq_name) == 0); + } + + kmem_free(fq_name, MAXNAMELEN); + return (match); +} + +/* + * If the enumeration request is for user data, handle the request + * here. Otherwise, pass it on to the trees. + * + * This function should be called with a hold on the user. + */ +int +smb_user_enum(smb_user_t *user, smb_svcenum_t *svcenum) +{ + smb_tree_t *tree; + smb_tree_t *next; + int rc; + + ASSERT(user); + ASSERT(user->u_magic == SMB_USER_MAGIC); + + if (svcenum->se_type == SMB_SVCENUM_TYPE_USER) + return (smb_user_enum_private(user, svcenum)); + + tree = smb_user_get_tree(&user->u_tree_list, NULL); + while (tree) { + ASSERT(tree->t_user == user); + + rc = smb_tree_enum(tree, svcenum); + if (rc != 0) { + smb_tree_release(tree); + break; + } + + next = smb_user_get_tree(&user->u_tree_list, tree); + smb_tree_release(tree); + tree = next; + } + + return (rc); +} + /* *************************** Static Functions ***************************** */ /* + * Determine whether or not a user is logged in. + * Typically, a reference can only be taken on a logged-in user. + * + * This is a private function and must be called with the user + * mutex held. + */ +static boolean_t +smb_user_is_logged_in(smb_user_t *user) +{ + switch (user->u_state) { + case SMB_USER_STATE_LOGGED_IN: + return (B_TRUE); + + case SMB_USER_STATE_LOGGING_OFF: + case SMB_USER_STATE_LOGGED_OFF: + return (B_FALSE); + + default: + ASSERT(0); + return (B_FALSE); + } +} + +/* * smb_user_delete */ static void @@ -821,3 +944,104 @@ { return ((user->u_privcred)? user->u_privcred : user->u_cred); } + +/* + * Private function to support smb_user_enum. + */ +static int +smb_user_enum_private(smb_user_t *user, smb_svcenum_t *svcenum) +{ + uint8_t *pb; + uint_t nbytes; + int rc; + + if (svcenum->se_nskip > 0) { + svcenum->se_nskip--; + return (0); + } + + if (svcenum->se_nitems >= svcenum->se_nlimit) { + svcenum->se_nitems = svcenum->se_nlimit; + return (0); + } + + pb = &svcenum->se_buf[svcenum->se_bused]; + rc = smb_user_netinfo_encode(user, pb, svcenum->se_bavail, &nbytes); + if (rc == 0) { + svcenum->se_bavail -= nbytes; + svcenum->se_bused += nbytes; + svcenum->se_nitems++; + } + + return (rc); +} + +/* + * Encode the NetInfo for a user into a buffer. NetInfo contains + * information that is often needed in user space to support RPC + * requests. + */ +int +smb_user_netinfo_encode(smb_user_t *user, uint8_t *buf, size_t buflen, + uint32_t *nbytes) +{ + smb_netuserinfo_t info; + int rc; + + smb_user_netinfo_init(user, &info); + rc = smb_netuserinfo_encode(&info, buf, buflen, nbytes); + smb_user_netinfo_fini(&info); + + return (rc); +} + +void +smb_user_netinfo_init(smb_user_t *user, smb_netuserinfo_t *info) +{ + smb_session_t *session; + char *buf; + + ASSERT(user); + ASSERT(user->u_domain); + ASSERT(user->u_name); + + session = user->u_session; + ASSERT(session); + ASSERT(session->workstation); + + info->ui_session_id = session->s_kid; + info->ui_native_os = session->native_os; + info->ui_ipaddr = session->ipaddr; + info->ui_numopens = session->s_file_cnt; + info->ui_uid = user->u_uid; + info->ui_logon_time = user->u_logon_time; + info->ui_flags = user->u_flags; + + info->ui_domain_len = user->u_domain_len; + info->ui_domain = smb_kstrdup(user->u_domain, info->ui_domain_len); + + info->ui_account_len = user->u_name_len; + info->ui_account = smb_kstrdup(user->u_name, info->ui_account_len); + + buf = kmem_alloc(MAXNAMELEN, KM_SLEEP); + smb_session_getclient(session, buf, MAXNAMELEN); + info->ui_workstation_len = strlen(buf) + 1; + info->ui_workstation = smb_kstrdup(buf, info->ui_workstation_len); + kmem_free(buf, MAXNAMELEN); +} + +void +smb_user_netinfo_fini(smb_netuserinfo_t *info) +{ + if (info == NULL) + return; + + if (info->ui_domain) + kmem_free(info->ui_domain, info->ui_domain_len); + if (info->ui_account) + kmem_free(info->ui_account, info->ui_account_len); + if (info->ui_workstation) + kmem_free(info->ui_workstation, info->ui_workstation_len); + + bzero(info, sizeof (smb_netuserinfo_t)); +}
--- a/usr/src/uts/common/fs/sockfs/sockcommon_sops.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/sockfs/sockcommon_sops.c Mon Jul 20 13:07:46 2009 -0400 @@ -1129,6 +1129,8 @@ so->so_proto_props.sopp_rcvthresh = soppp->sopp_rcvthresh; if (soppp->sopp_flags & SOCKOPT_MAXADDRLEN) so->so_proto_props.sopp_maxaddrlen = soppp->sopp_maxaddrlen; + if (soppp->sopp_flags & SOCKOPT_LOOPBACK) + so->so_proto_props.sopp_loopback = soppp->sopp_loopback; mutex_exit(&so->so_lock); @@ -1136,7 +1138,8 @@ soppp->sopp_flags &= ~(SOCKOPT_MAXBLK | SOCKOPT_WROFF | SOCKOPT_TAIL | SOCKOPT_RCVHIWAT | SOCKOPT_RCVLOWAT | SOCKOPT_MAXPSZ | SOCKOPT_ZCOPY | SOCKOPT_OOBINLINE | SOCKOPT_RCVTIMER | - SOCKOPT_RCVTHRESH | SOCKOPT_MAXADDRLEN | SOCKOPT_MINPSZ); + SOCKOPT_RCVTHRESH | SOCKOPT_MAXADDRLEN | SOCKOPT_MINPSZ | + SOCKOPT_LOOPBACK); ASSERT(soppp->sopp_flags == 0); #endif }
--- a/usr/src/uts/common/fs/sockfs/sodirect.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/sockfs/sodirect.c Mon Jul 20 13:07:46 2009 -0400 @@ -78,6 +78,7 @@ if (uiop->uio_resid >= uioasync.mincnt && sodp != NULL && sodp->sod_enabled && uioasync.enabled && !(flags & MSG_PEEK) && + !so->so_proto_props.sopp_loopback && !(so->so_state & SS_CANTRCVMORE)) { /* * Big enough I/O for uioa min setup and an sodirect socket
--- a/usr/src/uts/common/fs/zfs/spa.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/zfs/spa.c Mon Jul 20 13:07:46 2009 -0400 @@ -1574,9 +1574,12 @@ /* * If the config cache is stale, or we have uninitialized * metaslabs (see spa_vdev_add()), then update the config. + * + * If spa_load_verbatim is true, trust the current + * in-core spa_config and update the disk labels. */ if (config_cache_txg != spa->spa_config_txg || - state == SPA_LOAD_IMPORT) + state == SPA_LOAD_IMPORT || spa->spa_load_verbatim) need_update = B_TRUE; for (int c = 0; c < rvd->vdev_children; c++) @@ -2405,6 +2408,7 @@ spa = spa_add(pname, NULL); spa->spa_is_root = B_TRUE; + spa->spa_load_verbatim = B_TRUE; /* * Build up a vdev tree based on the boot device's label config. @@ -2493,7 +2497,7 @@ zpool_prop_to_name(ZPOOL_PROP_ALTROOT), &altroot); spa = spa_add(pool, altroot); - spa->spa_inactive_states_ok = B_TRUE; + spa->spa_load_verbatim = B_TRUE; VERIFY(nvlist_dup(config, &spa->spa_config, 0) == 0); @@ -2629,7 +2633,7 @@ /* * Update the config cache to include the newly-imported pool. */ - spa_config_update_common(spa, SPA_CONFIG_UPDATE_POOL, B_FALSE); + spa_config_update(spa, SPA_CONFIG_UPDATE_POOL); } /*
--- a/usr/src/uts/common/fs/zfs/spa_config.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/zfs/spa_config.c Mon Jul 20 13:07:46 2009 -0400 @@ -394,23 +394,12 @@ } /* - * For a pool that's not currently a booting rootpool, update all disk labels, - * generate a fresh config based on the current in-core state, and sync the - * global config cache. - */ -void -spa_config_update(spa_t *spa, int what) -{ - spa_config_update_common(spa, what, FALSE); -} - -/* * Update all disk labels, generate a fresh config based on the current * in-core state, and sync the global config cache (do not sync the config * cache if this is a booting rootpool). */ void -spa_config_update_common(spa_t *spa, int what, boolean_t isroot) +spa_config_update(spa_t *spa, int what) { vdev_t *rvd = spa->spa_root_vdev; uint64_t txg; @@ -447,9 +436,9 @@ /* * Update the global config cache to reflect the new mosconfig. */ - if (!isroot) + if (!spa->spa_is_root) spa_config_sync(spa, B_FALSE, what != SPA_CONFIG_UPDATE_POOL); if (what == SPA_CONFIG_UPDATE_POOL) - spa_config_update_common(spa, SPA_CONFIG_UPDATE_VDEVS, isroot); + spa_config_update(spa, SPA_CONFIG_UPDATE_VDEVS); }
--- a/usr/src/uts/common/fs/zfs/sys/spa_impl.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/zfs/sys/spa_impl.h Mon Jul 20 13:07:46 2009 -0400 @@ -105,7 +105,7 @@ int spa_inject_ref; /* injection references */ uint8_t spa_sync_on; /* sync threads are running */ spa_load_state_t spa_load_state; /* current load operation */ - boolean_t spa_inactive_states_ok; /* ok to open inactive state? */ + boolean_t spa_load_verbatim; /* load the given config? */ taskq_t *spa_zio_taskq[ZIO_TYPES][ZIO_TASKQ_TYPES]; dsl_pool_t *spa_dsl_pool; metaslab_class_t *spa_normal_class; /* normal data class */
--- a/usr/src/uts/common/fs/zfs/sys/zio.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/zfs/sys/zio.h Mon Jul 20 13:07:46 2009 -0400 @@ -143,6 +143,8 @@ #define ZIO_FLAG_GODFATHER 0x080000 #define ZIO_FLAG_TRYHARD 0x100000 +#define ZIO_FLAG_NODATA 0x200000 +#define ZIO_FLAG_OPTIONAL 0x400000 #define ZIO_FLAG_GANG_INHERIT \ (ZIO_FLAG_CANFAIL | \ @@ -161,7 +163,9 @@ ZIO_FLAG_IO_REPAIR | \ ZIO_FLAG_IO_RETRY | \ ZIO_FLAG_PROBE | \ - ZIO_FLAG_TRYHARD) + ZIO_FLAG_TRYHARD | \ + ZIO_FLAG_NODATA | \ + ZIO_FLAG_OPTIONAL) #define ZIO_FLAG_AGG_INHERIT \ (ZIO_FLAG_DONT_AGGREGATE | \
--- a/usr/src/uts/common/fs/zfs/vdev.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/zfs/vdev.c Mon Jul 20 13:07:46 2009 -0400 @@ -405,22 +405,26 @@ if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY, &nparity) == 0) { /* - * Currently, we can only support 2 parity devices. + * Currently, we can only support 3 parity devices. */ - if (nparity == 0 || nparity > 2) + if (nparity == 0 || nparity > 3) return (EINVAL); /* - * Older versions can only support 1 parity device. + * Previous versions could only support 1 or 2 parity + * device. */ - if (nparity == 2 && - spa_version(spa) < SPA_VERSION_RAID6) + if (nparity > 1 && + spa_version(spa) < SPA_VERSION_RAIDZ2) + return (ENOTSUP); + if (nparity > 2 && + spa_version(spa) < SPA_VERSION_RAIDZ3) return (ENOTSUP); } else { /* * We require the parity to be specified for SPAs that * support multiple parity levels. */ - if (spa_version(spa) >= SPA_VERSION_RAID6) + if (spa_version(spa) >= SPA_VERSION_RAIDZ2) return (EINVAL); /* * Otherwise, we default to 1 parity device for RAID-Z. @@ -1187,7 +1191,6 @@ nvlist_t *label; uint64_t guid, top_guid; uint64_t state; - boolean_t inactive_state; for (int c = 0; c < vd->vdev_children; c++) if (vdev_validate(vd->vdev_child[c]) != 0) @@ -1244,12 +1247,13 @@ nvlist_free(label); - inactive_state = (state == POOL_STATE_EXPORTED || - state == POOL_STATE_DESTROYED); - - if (spa->spa_load_state == SPA_LOAD_OPEN && - !(state == POOL_STATE_ACTIVE) && - !(spa->spa_inactive_states_ok && inactive_state)) + /* + * If spa->spa_load_verbatim is true, no need to check the + * state of the pool. + */ + if (!spa->spa_load_verbatim && + spa->spa_load_state == SPA_LOAD_OPEN && + state != POOL_STATE_ACTIVE) return (EBADF); /*
--- a/usr/src/uts/common/fs/zfs/vdev_label.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/zfs/vdev_label.c Mon Jul 20 13:07:46 2009 -0400 @@ -246,8 +246,10 @@ * into a crufty old storage pool. */ ASSERT(vd->vdev_nparity == 1 || - (vd->vdev_nparity == 2 && - spa_version(spa) >= SPA_VERSION_RAID6)); + (vd->vdev_nparity <= 2 && + spa_version(spa) >= SPA_VERSION_RAIDZ2) || + (vd->vdev_nparity <= 3 && + spa_version(spa) >= SPA_VERSION_RAIDZ3)); /* * Note that we'll add the nparity tag even on storage pools
--- a/usr/src/uts/common/fs/zfs/vdev_queue.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/zfs/vdev_queue.c Mon Jul 20 13:07:46 2009 -0400 @@ -24,7 +24,7 @@ */ #include <sys/zfs_context.h> -#include <sys/spa.h> +#include <sys/spa_impl.h> #include <sys/vdev_impl.h> #include <sys/zio.h> #include <sys/avl.h> @@ -48,11 +48,14 @@ int zfs_vdev_ramp_rate = 2; /* - * To reduce IOPs, we aggregate small adjacent i/os into one large i/o. - * For read i/os, we also aggregate across small adjacency gaps. + * To reduce IOPs, we aggregate small adjacent I/Os into one large I/O. + * For read I/Os, we also aggregate across small adjacency gaps; for writes + * we include spans of optional I/Os to aid aggregation at the disk even when + * they aren't able to help us aggregate at this level. */ int zfs_vdev_aggregation_limit = SPA_MAXBLOCKSIZE; int zfs_vdev_read_gap_limit = 32 << 10; +int zfs_vdev_write_gap_limit = 4 << 10; /* * Virtual device vector for disk I/O scheduling. @@ -172,12 +175,14 @@ static zio_t * vdev_queue_io_to_issue(vdev_queue_t *vq, uint64_t pending_limit) { - zio_t *fio, *lio, *aio, *dio, *nio; + zio_t *fio, *lio, *aio, *dio, *nio, *mio; avl_tree_t *t; int flags; uint64_t maxspan = zfs_vdev_aggregation_limit; uint64_t maxgap; + int stretch; +again: ASSERT(MUTEX_HELD(&vq->vq_lock)); if (avl_numnodes(&vq->vq_pending_tree) >= pending_limit || @@ -192,21 +197,88 @@ if (!(flags & ZIO_FLAG_DONT_AGGREGATE)) { /* - * We can aggregate I/Os that are adjacent and of the - * same flavor, as expressed by the AGG_INHERIT flags. - * The latter is necessary so that certain attributes - * of the I/O, such as whether it's a normal I/O or a - * scrub/resilver, can be preserved in the aggregate. + * We can aggregate I/Os that are sufficiently adjacent and of + * the same flavor, as expressed by the AGG_INHERIT flags. + * The latter requirement is necessary so that certain + * attributes of the I/O, such as whether it's a normal I/O + * or a scrub/resilver, can be preserved in the aggregate. + * We can include optional I/Os, but don't allow them + * to begin a range as they add no benefit in that situation. + */ + + /* + * We keep track of the last non-optional I/O. + */ + mio = (fio->io_flags & ZIO_FLAG_OPTIONAL) ? NULL : fio; + + /* + * Walk backwards through sufficiently contiguous I/Os + * recording the last non-option I/O. */ while ((dio = AVL_PREV(t, fio)) != NULL && (dio->io_flags & ZIO_FLAG_AGG_INHERIT) == flags && - IO_SPAN(dio, lio) <= maxspan && IO_GAP(dio, fio) <= maxgap) + IO_SPAN(dio, lio) <= maxspan && + IO_GAP(dio, fio) <= maxgap) { fio = dio; + if (mio == NULL && !(fio->io_flags & ZIO_FLAG_OPTIONAL)) + mio = fio; + } + /* + * Skip any initial optional I/Os. + */ + while ((fio->io_flags & ZIO_FLAG_OPTIONAL) && fio != lio) { + fio = AVL_NEXT(t, fio); + ASSERT(fio != NULL); + } + + /* + * Walk forward through sufficiently contiguous I/Os. + */ while ((dio = AVL_NEXT(t, lio)) != NULL && (dio->io_flags & ZIO_FLAG_AGG_INHERIT) == flags && - IO_SPAN(fio, dio) <= maxspan && IO_GAP(lio, dio) <= maxgap) + IO_SPAN(fio, dio) <= maxspan && + IO_GAP(lio, dio) <= maxgap) { lio = dio; + if (!(lio->io_flags & ZIO_FLAG_OPTIONAL)) + mio = lio; + } + + /* + * Now that we've established the range of the I/O aggregation + * we must decide what to do with trailing optional I/Os. + * For reads, there's nothing to do. While we are unable to + * aggregate further, it's possible that a trailing optional + * I/O would allow the underlying device to aggregate with + * subsequent I/Os. We must therefore determine if the next + * non-optional I/O is close enough to make aggregation + * worthwhile. + */ + stretch = B_FALSE; + if (t != &vq->vq_read_tree && mio != NULL) { + nio = lio; + while ((dio = AVL_NEXT(t, nio)) != NULL && + IO_GAP(nio, dio) == 0 && + IO_GAP(mio, dio) <= zfs_vdev_write_gap_limit) { + nio = dio; + if (!(nio->io_flags & ZIO_FLAG_OPTIONAL)) { + stretch = B_TRUE; + break; + } + } + } + + if (stretch) { + /* This may be a no-op. */ + VERIFY((dio = AVL_NEXT(t, lio)) != NULL); + dio->io_flags &= ~ZIO_FLAG_OPTIONAL; + } else { + while (lio != mio && lio != fio) { + ASSERT(lio->io_flags & ZIO_FLAG_OPTIONAL); + lio = AVL_PREV(t, lio); + ASSERT(lio != NULL); + } + } } if (fio != lio) { @@ -225,10 +297,15 @@ ASSERT(dio->io_type == aio->io_type); ASSERT(dio->io_vdev_tree == t); - if (dio->io_type == ZIO_TYPE_WRITE) + if (dio->io_flags & ZIO_FLAG_NODATA) { + ASSERT(dio->io_type == ZIO_TYPE_WRITE); + bzero((char *)aio->io_data + (dio->io_offset - + aio->io_offset), dio->io_size); + } else if (dio->io_type == ZIO_TYPE_WRITE) { bcopy(dio->io_data, (char *)aio->io_data + (dio->io_offset - aio->io_offset), dio->io_size); + } zio_add_child(dio, aio); vdev_queue_io_remove(vq, dio); @@ -244,6 +321,20 @@ ASSERT(fio->io_vdev_tree == t); vdev_queue_io_remove(vq, fio); + /* + * If the I/O is or was optional and therefore has no data, we need to + * simply discard it. We need to drop the vdev queue's lock to avoid a + * deadlock that we could encounter since this I/O will complete + * immediately. + */ + if (fio->io_flags & ZIO_FLAG_NODATA) { + mutex_exit(&vq->vq_lock); + zio_vdev_io_bypass(fio); + zio_execute(fio); + mutex_enter(&vq->vq_lock); + goto again; + } + avl_add(&vq->vq_pending_tree, fio); return (fio);
--- a/usr/src/uts/common/fs/zfs/vdev_raidz.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/fs/zfs/vdev_raidz.c Mon Jul 20 13:07:46 2009 -0400 @@ -35,12 +35,27 @@ /* * Virtual device vector for RAID-Z. * - * This vdev supports both single and double parity. For single parity, we - * use a simple XOR of all the data columns. For double parity, we use both - * the simple XOR as well as a technique described in "The mathematics of - * RAID-6" by H. Peter Anvin. This technique defines a Galois field, GF(2^8), - * over the integers expressable in a single byte. Briefly, the operations on - * the field are defined as follows: + * This vdev supports single, double, and triple parity. For single parity, + * we use a simple XOR of all the data columns. For double or triple parity, + * we use a special case of Reed-Solomon coding. This extends the + * technique described in "The mathematics of RAID-6" by H. Peter Anvin by + * drawing on the system described in "A Tutorial on Reed-Solomon Coding for + * Fault-Tolerance in RAID-like Systems" by James S. Plank on which the + * former is also based. The latter is designed to provide higher performance + * for writes. + * + * Note that the Plank paper claimed to support arbitrary N+M, but was then + * amended six years later identifying a critical flaw that invalidates its + * claims. Nevertheless, the technique can be adapted to work for up to + * triple parity. For additional parity, the amendment "Note: Correction to + * the 1997 Tutorial on Reed-Solomon Coding" by James S. Plank and Ying Ding + * is viable, but the additional complexity means that write performance will + * suffer. + * + * All of the methods above operate on a Galois field, defined over the + * integers mod 2^N. In our case we choose N=8 for GF(8) so that all elements + * can be expressed with a single byte. Briefly, the operations on the + * field are defined as follows: * * o addition (+) is represented by a bitwise XOR * o subtraction (-) is therefore identical to addition: A + B = A - B @@ -55,22 +70,32 @@ * (A * 2)_0 = A_7 * * In C, multiplying by 2 is therefore ((a << 1) ^ ((a & 0x80) ? 0x1d : 0)). + * As an aside, this multiplication is derived from the error correcting + * primitive polynomial x^8 + x^4 + x^3 + x^2 + 1. * * Observe that any number in the field (except for 0) can be expressed as a * power of 2 -- a generator for the field. We store a table of the powers of * 2 and logs base 2 for quick look ups, and exploit the fact that A * B can * be rewritten as 2^(log_2(A) + log_2(B)) (where '+' is normal addition rather - * than field addition). The inverse of a field element A (A^-1) is A^254. + * than field addition). The inverse of a field element A (A^-1) is therefore + * A ^ (255 - 1) = A^254. * - * The two parity columns, P and Q, over several data columns, D_0, ... D_n-1, - * can be expressed by field operations: + * The up-to-three parity columns, P, Q, R over several data columns, + * D_0, ... D_n-1, can be expressed by field operations: * * P = D_0 + D_1 + ... + D_n-2 + D_n-1 * Q = 2^n-1 * D_0 + 2^n-2 * D_1 + ... + 2^1 * D_n-2 + 2^0 * D_n-1 * = ((...((D_0) * 2 + D_1) * 2 + ...) * 2 + D_n-2) * 2 + D_n-1 + * R = 4^n-1 * D_0 + 4^n-2 * D_1 + ... + 4^1 * D_n-2 + 4^0 * D_n-1 + * = ((...((D_0) * 4 + D_1) * 4 + ...) * 4 + D_n-2) * 4 + D_n-1 * - * See the reconstruction code below for how P and Q can used individually or - * in concert to recover missing data columns. + * We chose 1, 2, and 4 as our generators because 1 corresponds to the trival + * XOR operation, and 2 and 4 can be computed quickly and generate linearly- + * independent coefficients. (There are no additional coefficients that have + * this property which is why the uncorrected Plank method breaks down.) + * + * See the reconstruction code below for how P, Q and R can used individually + * or in concert to recover missing data columns. */ typedef struct raidz_col { @@ -84,21 +109,49 @@ } raidz_col_t; typedef struct raidz_map { - uint64_t rm_cols; /* Column count */ + uint64_t rm_cols; /* Regular column count */ + uint64_t rm_scols; /* Count including skipped columns */ uint64_t rm_bigcols; /* Number of oversized columns */ uint64_t rm_asize; /* Actual total I/O size */ uint64_t rm_missingdata; /* Count of missing data devices */ uint64_t rm_missingparity; /* Count of missing parity devices */ uint64_t rm_firstdatacol; /* First data column/parity count */ + uint64_t rm_skipped; /* Skipped sectors for padding */ raidz_col_t rm_col[1]; /* Flexible array of I/O columns */ } raidz_map_t; #define VDEV_RAIDZ_P 0 #define VDEV_RAIDZ_Q 1 +#define VDEV_RAIDZ_R 2 +#define VDEV_RAIDZ_MAXPARITY 3 -#define VDEV_RAIDZ_MAXPARITY 2 +#define VDEV_RAIDZ_MUL_2(x) (((x) << 1) ^ (((x) & 0x80) ? 0x1d : 0)) +#define VDEV_RAIDZ_MUL_4(x) (VDEV_RAIDZ_MUL_2(VDEV_RAIDZ_MUL_2(x))) -#define VDEV_RAIDZ_MUL_2(a) (((a) << 1) ^ (((a) & 0x80) ? 0x1d : 0)) +/* + * We provide a mechanism to perform the field multiplication operation on a + * 64-bit value all at once rather than a byte at a time. This works by + * creating a mask from the top bit in each byte and using that to + * conditionally apply the XOR of 0x1d. + */ +#define VDEV_RAIDZ_64MUL_2(x, mask) \ +{ \ + (mask) = (x) & 0x8080808080808080ULL; \ + (mask) = ((mask) << 1) - ((mask) >> 7); \ + (x) = (((x) << 1) & 0xfefefefefefefefeULL) ^ \ + ((mask) & 0x1d1d1d1d1d1d1d1d); \ +} + +#define VDEV_RAIDZ_64MUL_4(x, mask) \ +{ \ + VDEV_RAIDZ_64MUL_2((x), mask); \ + VDEV_RAIDZ_64MUL_2((x), mask); \ +} + +/* + * Force reconstruction to use the general purpose method. + */ +int vdev_raidz_default_to_general; /* * These two tables represent powers and logs of 2 in the Galois field defined @@ -201,7 +254,7 @@ for (c = 0; c < rm->rm_firstdatacol; c++) zio_buf_free(rm->rm_col[c].rc_data, rm->rm_col[c].rc_size); - kmem_free(rm, offsetof(raidz_map_t, rm_col[rm->rm_cols])); + kmem_free(rm, offsetof(raidz_map_t, rm_col[rm->rm_scols])); } static raidz_map_t * @@ -213,24 +266,35 @@ uint64_t s = zio->io_size >> unit_shift; uint64_t f = b % dcols; uint64_t o = (b / dcols) << unit_shift; - uint64_t q, r, c, bc, col, acols, coff, devidx; + uint64_t q, r, c, bc, col, acols, scols, coff, devidx, asize, tot; q = s / (dcols - nparity); r = s - q * (dcols - nparity); bc = (r == 0 ? 0 : r + nparity); + tot = s + nparity * (q + (r == 0 ? 0 : 1)); - acols = (q == 0 ? bc : dcols); + if (q == 0) { + acols = bc; + scols = MIN(dcols, roundup(bc, nparity + 1)); + } else { + acols = dcols; + scols = dcols; + } - rm = kmem_alloc(offsetof(raidz_map_t, rm_col[acols]), KM_SLEEP); + ASSERT3U(acols, <=, scols); + + rm = kmem_alloc(offsetof(raidz_map_t, rm_col[scols]), KM_SLEEP); rm->rm_cols = acols; + rm->rm_scols = scols; rm->rm_bigcols = bc; - rm->rm_asize = 0; rm->rm_missingdata = 0; rm->rm_missingparity = 0; rm->rm_firstdatacol = nparity; - for (c = 0; c < acols; c++) { + asize = 0; + + for (c = 0; c < scols; c++) { col = f + c; coff = o; if (col >= dcols) { @@ -239,15 +303,26 @@ } rm->rm_col[c].rc_devidx = col; rm->rm_col[c].rc_offset = coff; - rm->rm_col[c].rc_size = (q + (c < bc)) << unit_shift; rm->rm_col[c].rc_data = NULL; rm->rm_col[c].rc_error = 0; rm->rm_col[c].rc_tried = 0; rm->rm_col[c].rc_skipped = 0; - rm->rm_asize += rm->rm_col[c].rc_size; + + if (c >= acols) + rm->rm_col[c].rc_size = 0; + else if (c < bc) + rm->rm_col[c].rc_size = (q + 1) << unit_shift; + else + rm->rm_col[c].rc_size = q << unit_shift; + + asize += rm->rm_col[c].rc_size; } - rm->rm_asize = roundup(rm->rm_asize, (nparity + 1) << unit_shift); + ASSERT3U(asize, ==, tot << unit_shift); + rm->rm_asize = roundup(asize, (nparity + 1) << unit_shift); + rm->rm_skipped = roundup(tot, nparity + 1) - tot; + ASSERT3U(rm->rm_asize - asize, ==, rm->rm_skipped << unit_shift); + ASSERT3U(rm->rm_skipped, <=, nparity); for (c = 0; c < rm->rm_firstdatacol; c++) rm->rm_col[c].rc_data = zio_buf_alloc(rm->rm_col[c].rc_size); @@ -305,12 +380,12 @@ if (c == rm->rm_firstdatacol) { ASSERT(ccount == pcount); - for (i = 0; i < ccount; i++, p++, src++) { + for (i = 0; i < ccount; i++, src++, p++) { *p = *src; } } else { ASSERT(ccount <= pcount); - for (i = 0; i < ccount; i++, p++, src++) { + for (i = 0; i < ccount; i++, src++, p++) { *p ^= *src; } } @@ -320,10 +395,10 @@ static void vdev_raidz_generate_parity_pq(raidz_map_t *rm) { - uint64_t *q, *p, *src, pcount, ccount, mask, i; + uint64_t *p, *q, *src, pcnt, ccnt, mask, i; int c; - pcount = rm->rm_col[VDEV_RAIDZ_P].rc_size / sizeof (src[0]); + pcnt = rm->rm_col[VDEV_RAIDZ_P].rc_size / sizeof (src[0]); ASSERT(rm->rm_col[VDEV_RAIDZ_P].rc_size == rm->rm_col[VDEV_RAIDZ_Q].rc_size); @@ -331,55 +406,138 @@ src = rm->rm_col[c].rc_data; p = rm->rm_col[VDEV_RAIDZ_P].rc_data; q = rm->rm_col[VDEV_RAIDZ_Q].rc_data; - ccount = rm->rm_col[c].rc_size / sizeof (src[0]); + + ccnt = rm->rm_col[c].rc_size / sizeof (src[0]); if (c == rm->rm_firstdatacol) { - ASSERT(ccount == pcount || ccount == 0); - for (i = 0; i < ccount; i++, p++, q++, src++) { - *q = *src; + ASSERT(ccnt == pcnt || ccnt == 0); + for (i = 0; i < ccnt; i++, src++, p++, q++) { *p = *src; + *q = *src; } - for (; i < pcount; i++, p++, q++, src++) { + for (; i < pcnt; i++, src++, p++, q++) { + *p = 0; *q = 0; - *p = 0; } } else { - ASSERT(ccount <= pcount); + ASSERT(ccnt <= pcnt); /* - * Rather than multiplying each byte individually (as - * described above), we are able to handle 8 at once - * by generating a mask based on the high bit in each - * byte and using that to conditionally XOR in 0x1d. + * Apply the algorithm described above by multiplying + * the previous result and adding in the new value. */ - for (i = 0; i < ccount; i++, p++, q++, src++) { - mask = *q & 0x8080808080808080ULL; - mask = (mask << 1) - (mask >> 7); - *q = ((*q << 1) & 0xfefefefefefefefeULL) ^ - (mask & 0x1d1d1d1d1d1d1d1dULL); + for (i = 0; i < ccnt; i++, src++, p++, q++) { + *p ^= *src; + + VDEV_RAIDZ_64MUL_2(*q, mask); *q ^= *src; - *p ^= *src; } /* * Treat short columns as though they are full of 0s. + * Note that there's therefore nothing needed for P. */ - for (; i < pcount; i++, q++) { - mask = *q & 0x8080808080808080ULL; - mask = (mask << 1) - (mask >> 7); - *q = ((*q << 1) & 0xfefefefefefefefeULL) ^ - (mask & 0x1d1d1d1d1d1d1d1dULL); + for (; i < pcnt; i++, q++) { + VDEV_RAIDZ_64MUL_2(*q, mask); } } } } static void -vdev_raidz_reconstruct_p(raidz_map_t *rm, int x) +vdev_raidz_generate_parity_pqr(raidz_map_t *rm) +{ + uint64_t *p, *q, *r, *src, pcnt, ccnt, mask, i; + int c; + + pcnt = rm->rm_col[VDEV_RAIDZ_P].rc_size / sizeof (src[0]); + ASSERT(rm->rm_col[VDEV_RAIDZ_P].rc_size == + rm->rm_col[VDEV_RAIDZ_Q].rc_size); + ASSERT(rm->rm_col[VDEV_RAIDZ_P].rc_size == + rm->rm_col[VDEV_RAIDZ_R].rc_size); + + for (c = rm->rm_firstdatacol; c < rm->rm_cols; c++) { + src = rm->rm_col[c].rc_data; + p = rm->rm_col[VDEV_RAIDZ_P].rc_data; + q = rm->rm_col[VDEV_RAIDZ_Q].rc_data; + r = rm->rm_col[VDEV_RAIDZ_R].rc_data; + + ccnt = rm->rm_col[c].rc_size / sizeof (src[0]); + + if (c == rm->rm_firstdatacol) { + ASSERT(ccnt == pcnt || ccnt == 0); + for (i = 0; i < ccnt; i++, src++, p++, q++, r++) { + *p = *src; + *q = *src; + *r = *src; + } + for (; i < pcnt; i++, src++, p++, q++, r++) { + *p = 0; + *q = 0; + *r = 0; + } + } else { + ASSERT(ccnt <= pcnt); + + /* + * Apply the algorithm described above by multiplying + * the previous result and adding in the new value. + */ + for (i = 0; i < ccnt; i++, src++, p++, q++, r++) { + *p ^= *src; + + VDEV_RAIDZ_64MUL_2(*q, mask); + *q ^= *src; + + VDEV_RAIDZ_64MUL_4(*r, mask); + *r ^= *src; + } + + /* + * Treat short columns as though they are full of 0s. + * Note that there's therefore nothing needed for P. + */ + for (; i < pcnt; i++, q++, r++) { + VDEV_RAIDZ_64MUL_2(*q, mask); + VDEV_RAIDZ_64MUL_4(*r, mask); + } + } + } +} + +/* + * Generate RAID parity in the first virtual columns according to the number of + * parity columns available. + */ +static void +vdev_raidz_generate_parity(raidz_map_t *rm) +{ + switch (rm->rm_firstdatacol) { + case 1: + vdev_raidz_generate_parity_p(rm); + break; + case 2: + vdev_raidz_generate_parity_pq(rm); + break; + case 3: + vdev_raidz_generate_parity_pqr(rm); + break; + default: + cmn_err(CE_PANIC, "invalid RAID-Z configuration"); + } +} + +static int +vdev_raidz_reconstruct_p(raidz_map_t *rm, int *tgts, int ntgts) { uint64_t *dst, *src, xcount, ccount, count, i; + int x = tgts[0]; int c; + ASSERT(ntgts == 1); + ASSERT(x >= rm->rm_firstdatacol); + ASSERT(x < rm->rm_cols); + xcount = rm->rm_col[x].rc_size / sizeof (src[0]); ASSERT(xcount <= rm->rm_col[VDEV_RAIDZ_P].rc_size / sizeof (src[0])); ASSERT(xcount > 0); @@ -404,15 +562,20 @@ *dst ^= *src; } } + + return (1 << VDEV_RAIDZ_P); } -static void -vdev_raidz_reconstruct_q(raidz_map_t *rm, int x) +static int +vdev_raidz_reconstruct_q(raidz_map_t *rm, int *tgts, int ntgts) { uint64_t *dst, *src, xcount, ccount, count, mask, i; uint8_t *b; + int x = tgts[0]; int c, j, exp; + ASSERT(ntgts == 1); + xcount = rm->rm_col[x].rc_size / sizeof (src[0]); ASSERT(xcount <= rm->rm_col[VDEV_RAIDZ_Q].rc_size / sizeof (src[0])); @@ -436,23 +599,13 @@ } } else { - /* - * For an explanation of this, see the comment in - * vdev_raidz_generate_parity_pq() above. - */ for (i = 0; i < count; i++, dst++, src++) { - mask = *dst & 0x8080808080808080ULL; - mask = (mask << 1) - (mask >> 7); - *dst = ((*dst << 1) & 0xfefefefefefefefeULL) ^ - (mask & 0x1d1d1d1d1d1d1d1dULL); + VDEV_RAIDZ_64MUL_2(*dst, mask); *dst ^= *src; } for (; i < xcount; i++, dst++) { - mask = *dst & 0x8080808080808080ULL; - mask = (mask << 1) - (mask >> 7); - *dst = ((*dst << 1) & 0xfefefefefefefefeULL) ^ - (mask & 0x1d1d1d1d1d1d1d1dULL); + VDEV_RAIDZ_64MUL_2(*dst, mask); } } } @@ -467,15 +620,20 @@ *b = vdev_raidz_exp2(*b, exp); } } + + return (1 << VDEV_RAIDZ_Q); } -static void -vdev_raidz_reconstruct_pq(raidz_map_t *rm, int x, int y) +static int +vdev_raidz_reconstruct_pq(raidz_map_t *rm, int *tgts, int ntgts) { uint8_t *p, *q, *pxy, *qxy, *xd, *yd, tmp, a, b, aexp, bexp; void *pdata, *qdata; uint64_t xsize, ysize, i; + int x = tgts[0]; + int y = tgts[1]; + ASSERT(ntgts == 2); ASSERT(x < y); ASSERT(x >= rm->rm_firstdatacol); ASSERT(y < rm->rm_cols); @@ -553,13 +711,554 @@ */ rm->rm_col[VDEV_RAIDZ_P].rc_data = pdata; rm->rm_col[VDEV_RAIDZ_Q].rc_data = qdata; + + return ((1 << VDEV_RAIDZ_P) | (1 << VDEV_RAIDZ_Q)); +} + +/* BEGIN CSTYLED */ +/* + * In the general case of reconstruction, we must solve the system of linear + * equations defined by the coeffecients used to generate parity as well as + * the contents of the data and parity disks. This can be expressed with + * vectors for the original data (D) and the actual data (d) and parity (p) + * and a matrix composed of the identity matrix (I) and a dispersal matrix (V): + * + * __ __ __ __ + * | | __ __ | p_0 | + * | V | | D_0 | | p_m-1 | + * | | x | : | = | d_0 | + * | I | | D_n-1 | | : | + * | | ~~ ~~ | d_n-1 | + * ~~ ~~ ~~ ~~ + * + * I is simply a square identity matrix of size n, and V is a vandermonde + * matrix defined by the coeffecients we chose for the various parity columns + * (1, 2, 4). Note that these values were chosen both for simplicity, speedy + * computation as well as linear separability. + * + * __ __ __ __ + * | 1 .. 1 1 1 | | p_0 | + * | 2^n-1 .. 4 2 1 | __ __ | : | + * | 4^n-1 .. 16 4 1 | | D_0 | | p_m-1 | + * | 1 .. 0 0 0 | | D_1 | | d_0 | + * | 0 .. 0 0 0 | x | D_2 | = | d_1 | + * | : : : : | | : | | d_2 | + * | 0 .. 1 0 0 | | D_n-1 | | : | + * | 0 .. 0 1 0 | ~~ ~~ | : | + * | 0 .. 0 0 1 | | d_n-1 | + * ~~ ~~ ~~ ~~ + * + * Note that I, V, d, and p are known. To compute D, we must invert the + * matrix and use the known data and parity values to reconstruct the unknown + * data values. We begin by removing the rows in V|I and d|p that correspond + * to failed or missing columns; we then make V|I square (n x n) and d|p + * sized n by removing rows corresponding to unused parity from the bottom up + * to generate (V|I)' and (d|p)'. We can then generate the inverse of (V|I)' + * using Gauss-Jordan elimination. In the example below we use m=3 parity + * columns, n=8 data columns, with errors in d_1, d_2, and p_1: + * __ __ + * | 1 1 1 1 1 1 1 1 | + * | 128 64 32 16 8 4 2 1 | <-----+-+-- missing disks + * | 19 205 116 29 64 16 4 1 | / / + * | 1 0 0 0 0 0 0 0 | / / + * | 0 1 0 0 0 0 0 0 | <--' / + * (V|I) = | 0 0 1 0 0 0 0 0 | <---' + * | 0 0 0 1 0 0 0 0 | + * | 0 0 0 0 1 0 0 0 | + * | 0 0 0 0 0 1 0 0 | + * | 0 0 0 0 0 0 1 0 | + * | 0 0 0 0 0 0 0 1 | + * ~~ ~~ + * __ __ + * | 1 1 1 1 1 1 1 1 | + * | 128 64 32 16 8 4 2 1 | + * | 19 205 116 29 64 16 4 1 | + * | 1 0 0 0 0 0 0 0 | + * | 0 1 0 0 0 0 0 0 | + * (V|I)' = | 0 0 1 0 0 0 0 0 | + * | 0 0 0 1 0 0 0 0 | + * | 0 0 0 0 1 0 0 0 | + * | 0 0 0 0 0 1 0 0 | + * | 0 0 0 0 0 0 1 0 | + * | 0 0 0 0 0 0 0 1 | + * ~~ ~~ + * + * Here we employ Gauss-Jordan elimination to find the inverse of (V|I)'. We + * have carefully chosen the seed values 1, 2, and 4 to ensure that this + * matrix is not singular. + * __ __ + * | 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 | + * | 19 205 116 29 64 16 4 1 0 1 0 0 0 0 0 0 | + * | 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 | + * | 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 | + * | 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 | + * | 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 | + * | 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 | + * | 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 | + * ~~ ~~ + * __ __ + * | 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 | + * | 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 | + * | 19 205 116 29 64 16 4 1 0 1 0 0 0 0 0 0 | + * | 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 | + * | 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 | + * | 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 | + * | 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 | + * | 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 | + * ~~ ~~ + * __ __ + * | 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 | + * | 0 1 1 0 0 0 0 0 1 0 1 1 1 1 1 1 | + * | 0 205 116 0 0 0 0 0 0 1 19 29 64 16 4 1 | + * | 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 | + * | 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 | + * | 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 | + * | 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 | + * | 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 | + * ~~ ~~ + * __ __ + * | 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 | + * | 0 1 1 0 0 0 0 0 1 0 1 1 1 1 1 1 | + * | 0 0 185 0 0 0 0 0 205 1 222 208 141 221 201 204 | + * | 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 | + * | 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 | + * | 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 | + * | 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 | + * | 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 | + * ~~ ~~ + * __ __ + * | 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 | + * | 0 1 1 0 0 0 0 0 1 0 1 1 1 1 1 1 | + * | 0 0 1 0 0 0 0 0 166 100 4 40 158 168 216 209 | + * | 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 | + * | 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 | + * | 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 | + * | 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 | + * | 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 | + * ~~ ~~ + * __ __ + * | 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 | + * | 0 1 0 0 0 0 0 0 167 100 5 41 159 169 217 208 | + * | 0 0 1 0 0 0 0 0 166 100 4 40 158 168 216 209 | + * | 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 | + * | 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 | + * | 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 | + * | 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 | + * | 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 | + * ~~ ~~ + * __ __ + * | 0 0 1 0 0 0 0 0 | + * | 167 100 5 41 159 169 217 208 | + * | 166 100 4 40 158 168 216 209 | + * (V|I)'^-1 = | 0 0 0 1 0 0 0 0 | + * | 0 0 0 0 1 0 0 0 | + * | 0 0 0 0 0 1 0 0 | + * | 0 0 0 0 0 0 1 0 | + * | 0 0 0 0 0 0 0 1 | + * ~~ ~~ + * + * We can then simply compute D = (V|I)'^-1 x (d|p)' to discover the values + * of the missing data. + * + * As is apparent from the example above, the only non-trivial rows in the + * inverse matrix correspond to the data disks that we're trying to + * reconstruct. Indeed, those are the only rows we need as the others would + * only be useful for reconstructing data known or assumed to be valid. For + * that reason, we only build the coefficients in the rows that correspond to + * targeted columns. + */ +/* END CSTYLED */ + +static void +vdev_raidz_matrix_init(raidz_map_t *rm, int n, int nmap, int *map, + uint8_t **rows) +{ + int i, j; + int pow; + + ASSERT(n == rm->rm_cols - rm->rm_firstdatacol); + + /* + * Fill in the missing rows of interest. + */ + for (i = 0; i < nmap; i++) { + ASSERT3S(0, <=, map[i]); + ASSERT3S(map[i], <=, 2); + + pow = map[i] * n; + if (pow > 255) + pow -= 255; + ASSERT(pow <= 255); + + for (j = 0; j < n; j++) { + pow -= map[i]; + if (pow < 0) + pow += 255; + rows[i][j] = vdev_raidz_pow2[pow]; + } + } } +static void +vdev_raidz_matrix_invert(raidz_map_t *rm, int n, int nmissing, int *missing, + uint8_t **rows, uint8_t **invrows, const uint8_t *used) +{ + int i, j, ii, jj; + uint8_t log; + + /* + * Assert that the first nmissing entries from the array of used + * columns correspond to parity columns and that subsequent entries + * correspond to data columns. + */ + for (i = 0; i < nmissing; i++) { + ASSERT3S(used[i], <, rm->rm_firstdatacol); + } + for (; i < n; i++) { + ASSERT3S(used[i], >=, rm->rm_firstdatacol); + } + + /* + * First initialize the storage where we'll compute the inverse rows. + */ + for (i = 0; i < nmissing; i++) { + for (j = 0; j < n; j++) { + invrows[i][j] = (i == j) ? 1 : 0; + } + } + + /* + * Subtract all trivial rows from the rows of consequence. + */ + for (i = 0; i < nmissing; i++) { + for (j = nmissing; j < n; j++) { + ASSERT3U(used[j], >=, rm->rm_firstdatacol); + jj = used[j] - rm->rm_firstdatacol; + ASSERT3S(jj, <, n); + invrows[i][j] = rows[i][jj]; + rows[i][jj] = 0; + } + } + + /* + * For each of the rows of interest, we must normalize it and subtract + * a multiple of it from the other rows. + */ + for (i = 0; i < nmissing; i++) { + for (j = 0; j < missing[i]; j++) { + ASSERT3U(rows[i][j], ==, 0); + } + ASSERT3U(rows[i][missing[i]], !=, 0); + + /* + * Compute the inverse of the first element and multiply each + * element in the row by that value. + */ + log = 255 - vdev_raidz_log2[rows[i][missing[i]]]; + + for (j = 0; j < n; j++) { + rows[i][j] = vdev_raidz_exp2(rows[i][j], log); + invrows[i][j] = vdev_raidz_exp2(invrows[i][j], log); + } + + for (ii = 0; ii < nmissing; ii++) { + if (i == ii) + continue; + + ASSERT3U(rows[ii][missing[i]], !=, 0); + + log = vdev_raidz_log2[rows[ii][missing[i]]]; + + for (j = 0; j < n; j++) { + rows[ii][j] ^= + vdev_raidz_exp2(rows[i][j], log); + invrows[ii][j] ^= + vdev_raidz_exp2(invrows[i][j], log); + } + } + } + + /* + * Verify that the data that is left in the rows are properly part of + * an identity matrix. + */ + for (i = 0; i < nmissing; i++) { + for (j = 0; j < n; j++) { + if (j == missing[i]) { + ASSERT3U(rows[i][j], ==, 1); + } else { + ASSERT3U(rows[i][j], ==, 0); + } + } + } +} + +static void +vdev_raidz_matrix_reconstruct(raidz_map_t *rm, int n, int nmissing, + int *missing, uint8_t **invrows, const uint8_t *used) +{ + int i, j, x, cc, c; + uint8_t *src; + uint64_t ccount; + uint8_t *dst[VDEV_RAIDZ_MAXPARITY]; + uint64_t dcount[VDEV_RAIDZ_MAXPARITY]; + uint8_t log, val; + int ll; + uint8_t *invlog[VDEV_RAIDZ_MAXPARITY]; + uint8_t *p, *pp; + size_t psize; + + psize = sizeof (invlog[0][0]) * n * nmissing; + p = kmem_alloc(psize, KM_SLEEP); + + for (pp = p, i = 0; i < nmissing; i++) { + invlog[i] = pp; + pp += n; + } + + for (i = 0; i < nmissing; i++) { + for (j = 0; j < n; j++) { + ASSERT3U(invrows[i][j], !=, 0); + invlog[i][j] = vdev_raidz_log2[invrows[i][j]]; + } + } + + for (i = 0; i < n; i++) { + c = used[i]; + ASSERT3U(c, <, rm->rm_cols); + + src = rm->rm_col[c].rc_data; + ccount = rm->rm_col[c].rc_size; + for (j = 0; j < nmissing; j++) { + cc = missing[j] + rm->rm_firstdatacol; + ASSERT3U(cc, >=, rm->rm_firstdatacol); + ASSERT3U(cc, <, rm->rm_cols); + ASSERT3U(cc, !=, c); + + dst[j] = rm->rm_col[cc].rc_data; + dcount[j] = rm->rm_col[cc].rc_size; + } + + ASSERT(ccount >= rm->rm_col[missing[0]].rc_size || i > 0); + + for (x = 0; x < ccount; x++, src++) { + if (*src != 0) + log = vdev_raidz_log2[*src]; + + for (cc = 0; cc < nmissing; cc++) { + if (x >= dcount[cc]) + continue; + + if (*src == 0) { + val = 0; + } else { + if ((ll = log + invlog[cc][i]) >= 255) + ll -= 255; + val = vdev_raidz_pow2[ll]; + } + + if (i == 0) + dst[cc][x] = val; + else + dst[cc][x] ^= val; + } + } + } + + kmem_free(p, psize); +} + +static int +vdev_raidz_reconstruct_general(raidz_map_t *rm, int *tgts, int ntgts) +{ + int n, i, c, t, tt; + int nmissing_rows; + int missing_rows[VDEV_RAIDZ_MAXPARITY]; + int parity_map[VDEV_RAIDZ_MAXPARITY]; + + uint8_t *p, *pp; + size_t psize; + + uint8_t *rows[VDEV_RAIDZ_MAXPARITY]; + uint8_t *invrows[VDEV_RAIDZ_MAXPARITY]; + uint8_t *used; + + int code = 0; + + + n = rm->rm_cols - rm->rm_firstdatacol; + + /* + * Figure out which data columns are missing. + */ + nmissing_rows = 0; + for (t = 0; t < ntgts; t++) { + if (tgts[t] >= rm->rm_firstdatacol) { + missing_rows[nmissing_rows++] = + tgts[t] - rm->rm_firstdatacol; + } + } + + /* + * Figure out which parity columns to use to help generate the missing + * data columns. + */ + for (tt = 0, c = 0, i = 0; i < nmissing_rows; c++) { + ASSERT(tt < ntgts); + ASSERT(c < rm->rm_firstdatacol); + + /* + * Skip any targeted parity columns. + */ + if (c == tgts[tt]) { + tt++; + continue; + } + + code |= 1 << c; + + parity_map[i] = c; + i++; + } + + ASSERT(code != 0); + ASSERT3U(code, <, 1 << VDEV_RAIDZ_MAXPARITY); + + psize = (sizeof (rows[0][0]) + sizeof (invrows[0][0])) * + nmissing_rows * n + sizeof (used[0]) * n; + p = kmem_alloc(psize, KM_SLEEP); + + for (pp = p, i = 0; i < nmissing_rows; i++) { + rows[i] = pp; + pp += n; + invrows[i] = pp; + pp += n; + } + used = pp; + + for (i = 0; i < nmissing_rows; i++) { + used[i] = parity_map[i]; + } + + for (tt = 0, c = rm->rm_firstdatacol; c < rm->rm_cols; c++) { + if (tt < nmissing_rows && + c == missing_rows[tt] + rm->rm_firstdatacol) { + tt++; + continue; + } + + ASSERT3S(i, <, n); + used[i] = c; + i++; + } + + /* + * Initialize the interesting rows of the matrix. + */ + vdev_raidz_matrix_init(rm, n, nmissing_rows, parity_map, rows); + + /* + * Invert the matrix. + */ + vdev_raidz_matrix_invert(rm, n, nmissing_rows, missing_rows, rows, + invrows, used); + + /* + * Reconstruct the missing data using the generated matrix. + */ + vdev_raidz_matrix_reconstruct(rm, n, nmissing_rows, missing_rows, + invrows, used); + + kmem_free(p, psize); + + return (code); +} + +static int +vdev_raidz_reconstruct(raidz_map_t *rm, int *t, int nt) +{ + int tgts[VDEV_RAIDZ_MAXPARITY], *dt; + int ntgts; + int i, c; + int code; + int nbadparity, nbaddata; + int parity_valid[VDEV_RAIDZ_MAXPARITY]; + + /* + * The tgts list must already be sorted. + */ + for (i = 1; i < nt; i++) { + ASSERT(t[i] > t[i - 1]); + } + + nbadparity = rm->rm_firstdatacol; + nbaddata = rm->rm_cols - nbadparity; + ntgts = 0; + for (i = 0, c = 0; c < rm->rm_cols; c++) { + if (c < rm->rm_firstdatacol) + parity_valid[c] = B_FALSE; + + if (i < nt && c == t[i]) { + tgts[ntgts++] = c; + i++; + } else if (rm->rm_col[c].rc_error != 0) { + tgts[ntgts++] = c; + } else if (c >= rm->rm_firstdatacol) { + nbaddata--; + } else { + parity_valid[c] = B_TRUE; + nbadparity--; + } + } + + ASSERT(ntgts >= nt); + ASSERT(nbaddata >= 0); + ASSERT(nbaddata + nbadparity == ntgts); + + dt = &tgts[nbadparity]; + + /* + * See if we can use any of our optimized reconstruction routines. + */ + if (!vdev_raidz_default_to_general) { + switch (nbaddata) { + case 1: + if (parity_valid[VDEV_RAIDZ_P]) + return (vdev_raidz_reconstruct_p(rm, dt, 1)); + + ASSERT(rm->rm_firstdatacol > 1); + + if (parity_valid[VDEV_RAIDZ_Q]) + return (vdev_raidz_reconstruct_q(rm, dt, 1)); + + ASSERT(rm->rm_firstdatacol > 2); + break; + + case 2: + ASSERT(rm->rm_firstdatacol > 1); + + if (parity_valid[VDEV_RAIDZ_P] && + parity_valid[VDEV_RAIDZ_Q]) + return (vdev_raidz_reconstruct_pq(rm, dt, 2)); + + ASSERT(rm->rm_firstdatacol > 2); + + break; + } + } + + code = vdev_raidz_reconstruct_general(rm, tgts, ntgts); + ASSERT(code < (1 << VDEV_RAIDZ_MAXPARITY)); + ASSERT(code > 0); + return (code); +} static int vdev_raidz_open(vdev_t *vd, uint64_t *asize, uint64_t *ashift) { + vdev_t *cvd; uint64_t nparity = vd->vdev_nparity; + int c; int lasterror = 0; int numerrors = 0; @@ -573,10 +1272,10 @@ vdev_open_children(vd); - for (int c = 0; c < vd->vdev_children; c++) { - vdev_t *cvd = vd->vdev_child[c]; + for (c = 0; c < vd->vdev_children; c++) { + cvd = vd->vdev_child[c]; - if (cvd->vdev_open_error) { + if (cvd->vdev_open_error != 0) { lasterror = cvd->vdev_open_error; numerrors++; continue; @@ -599,7 +1298,9 @@ static void vdev_raidz_close(vdev_t *vd) { - for (int c = 0; c < vd->vdev_children; c++) + int c; + + for (c = 0; c < vd->vdev_children; c++) vdev_close(vd->vdev_child[c]); } @@ -637,7 +1338,7 @@ blkptr_t *bp = zio->io_bp; raidz_map_t *rm; raidz_col_t *rc; - int c; + int c, i; rm = vdev_raidz_map_alloc(zio, tvd->vdev_ashift, vd->vdev_children, vd->vdev_nparity); @@ -645,13 +1346,7 @@ ASSERT3U(rm->rm_asize, ==, vdev_psize_to_asize(vd, zio->io_size)); if (zio->io_type == ZIO_TYPE_WRITE) { - /* - * Generate RAID parity in the first virtual columns. - */ - if (rm->rm_firstdatacol == 1) - vdev_raidz_generate_parity_p(rm); - else - vdev_raidz_generate_parity_pq(rm); + vdev_raidz_generate_parity(rm); for (c = 0; c < rm->rm_cols; c++) { rc = &rm->rm_col[c]; @@ -662,6 +1357,23 @@ vdev_raidz_child_done, rc)); } + /* + * Generate optional I/Os for any skipped sectors to improve + * aggregation contiguity. + */ + for (c = rm->rm_bigcols, i = 0; i < rm->rm_skipped; c++, i++) { + ASSERT(c <= rm->rm_scols); + if (c == rm->rm_scols) + c = 0; + rc = &rm->rm_col[c]; + cvd = vd->vdev_child[rc->rc_devidx]; + zio_nowait(zio_vdev_child_io(zio, NULL, cvd, + rc->rc_offset + rc->rc_size, NULL, + 1 << tvd->vdev_ashift, + zio->io_type, zio->io_priority, + ZIO_FLAG_NODATA | ZIO_FLAG_OPTIONAL, NULL, NULL)); + } + return (ZIO_PIPELINE_CONTINUE); } @@ -669,8 +1381,7 @@ /* * Iterate over the columns in reverse order so that we hit the parity - * last -- any errors along the way will force us to read the parity - * data. + * last -- any errors along the way will force us to read the parity. */ for (c = rm->rm_cols - 1; c >= 0; c--) { rc = &rm->rm_col[c]; @@ -746,10 +1457,7 @@ bcopy(rc->rc_data, orig[c], rc->rc_size); } - if (rm->rm_firstdatacol == 1) - vdev_raidz_generate_parity_p(rm); - else - vdev_raidz_generate_parity_pq(rm); + vdev_raidz_generate_parity(rm); for (c = 0; c < rm->rm_firstdatacol; c++) { rc = &rm->rm_col[c]; @@ -766,9 +1474,10 @@ return (ret); } -static uint64_t raidz_corrected_p; -static uint64_t raidz_corrected_q; -static uint64_t raidz_corrected_pq; +/* + * Keep statistics on all the ways that we used parity to correct data. + */ +static uint64_t raidz_corrected[1 << VDEV_RAIDZ_MAXPARITY]; static int vdev_raidz_worst_error(raidz_map_t *rm) @@ -781,19 +1490,176 @@ return (error); } +/* + * Iterate over all combinations of bad data and attempt a reconstruction. + * Note that the algorithm below is non-optimal because it doesn't take into + * account how reconstruction is actually performed. For example, with + * triple-parity RAID-Z the reconstruction procedure is the same if column 4 + * is targeted as invalid as if columns 1 and 4 are targeted since in both + * cases we'd only use parity information in column 0. + */ +static int +vdev_raidz_combrec(zio_t *zio, int total_errors, int data_errors) +{ + raidz_map_t *rm = zio->io_vsd; + raidz_col_t *rc; + void *orig[VDEV_RAIDZ_MAXPARITY]; + int tstore[VDEV_RAIDZ_MAXPARITY + 2]; + int *tgts = &tstore[1]; + int current, next, i, c, n; + int code, ret = 0; + + ASSERT(total_errors < rm->rm_firstdatacol); + + /* + * This simplifies one edge condition. + */ + tgts[-1] = -1; + + for (n = 1; n <= rm->rm_firstdatacol - total_errors; n++) { + /* + * Initialize the targets array by finding the first n columns + * that contain no error. + * + * If there were no data errors, we need to ensure that we're + * always explicitly attempting to reconstruct at least one + * data column. To do this, we simply push the highest target + * up into the data columns. + */ + for (c = 0, i = 0; i < n; i++) { + if (i == n - 1 && data_errors == 0 && + c < rm->rm_firstdatacol) { + c = rm->rm_firstdatacol; + } + + while (rm->rm_col[c].rc_error != 0) { + c++; + ASSERT3S(c, <, rm->rm_cols); + } + + tgts[i] = c++; + } + + /* + * Setting tgts[n] simplifies the other edge condition. + */ + tgts[n] = rm->rm_cols; + + /* + * These buffers were allocated in previous iterations. + */ + for (i = 0; i < n - 1; i++) { + ASSERT(orig[i] != NULL); + } + + orig[n - 1] = zio_buf_alloc(rm->rm_col[0].rc_size); + + current = 0; + next = tgts[current]; + + while (current != n) { + tgts[current] = next; + current = 0; + + /* + * Save off the original data that we're going to + * attempt to reconstruct. + */ + for (i = 0; i < n; i++) { + ASSERT(orig[i] != NULL); + c = tgts[i]; + ASSERT3S(c, >=, 0); + ASSERT3S(c, <, rm->rm_cols); + rc = &rm->rm_col[c]; + bcopy(rc->rc_data, orig[i], rc->rc_size); + } + + /* + * Attempt a reconstruction and exit the outer loop on + * success. + */ + code = vdev_raidz_reconstruct(rm, tgts, n); + if (zio_checksum_error(zio) == 0) { + atomic_inc_64(&raidz_corrected[code]); + + for (i = 0; i < n; i++) { + c = tgts[i]; + rc = &rm->rm_col[c]; + ASSERT(rc->rc_error == 0); + if (rc->rc_tried) + raidz_checksum_error(zio, rc); + rc->rc_error = ECKSUM; + } + + ret = code; + goto done; + } + + /* + * Restore the original data. + */ + for (i = 0; i < n; i++) { + c = tgts[i]; + rc = &rm->rm_col[c]; + bcopy(orig[i], rc->rc_data, rc->rc_size); + } + + do { + /* + * Find the next valid column after the current + * position.. + */ + for (next = tgts[current] + 1; + next < rm->rm_cols && + rm->rm_col[next].rc_error != 0; next++) + continue; + + ASSERT(next <= tgts[current + 1]); + + /* + * If that spot is available, we're done here. + */ + if (next != tgts[current + 1]) + break; + + /* + * Otherwise, find the next valid column after + * the previous position. + */ + for (c = tgts[current - 1] + 1; + rm->rm_col[c].rc_error != 0; c++) + continue; + + tgts[current] = c; + current++; + + } while (current != n); + } + } + n--; +done: + for (i = 0; i < n; i++) { + zio_buf_free(orig[i], rm->rm_col[0].rc_size); + } + + return (ret); +} + static void vdev_raidz_io_done(zio_t *zio) { vdev_t *vd = zio->io_vd; vdev_t *cvd; raidz_map_t *rm = zio->io_vsd; - raidz_col_t *rc, *rc1; + raidz_col_t *rc; int unexpected_errors = 0; int parity_errors = 0; int parity_untried = 0; int data_errors = 0; int total_errors = 0; - int n, c, c1; + int n, c; + int tgts[VDEV_RAIDZ_MAXPARITY]; + int code; ASSERT(zio->io_bp != NULL); /* XXX need to add code to enforce this */ @@ -857,8 +1723,7 @@ * any errors. */ if (total_errors <= rm->rm_firstdatacol - parity_untried) { - switch (data_errors) { - case 0: + if (data_errors == 0) { if (zio_checksum_error(zio) == 0) { /* * If we read parity information (unnecessarily @@ -878,9 +1743,7 @@ } goto done; } - break; - - case 1: + } else { /* * We either attempt to read all the parity columns or * none of them. If we didn't try to read parity, we @@ -892,45 +1755,38 @@ ASSERT(parity_errors < rm->rm_firstdatacol); /* - * Find the column that reported the error. + * Identify the data columns that reported an error. */ + n = 0; for (c = rm->rm_firstdatacol; c < rm->rm_cols; c++) { rc = &rm->rm_col[c]; - if (rc->rc_error != 0) - break; + if (rc->rc_error != 0) { + ASSERT(n < VDEV_RAIDZ_MAXPARITY); + tgts[n++] = c; + } } - ASSERT(c != rm->rm_cols); - ASSERT(!rc->rc_skipped || rc->rc_error == ENXIO || - rc->rc_error == ESTALE); - if (rm->rm_col[VDEV_RAIDZ_P].rc_error == 0) { - vdev_raidz_reconstruct_p(rm, c); - } else { - ASSERT(rm->rm_firstdatacol > 1); - vdev_raidz_reconstruct_q(rm, c); - } + ASSERT(rm->rm_firstdatacol >= n); + + code = vdev_raidz_reconstruct(rm, tgts, n); if (zio_checksum_error(zio) == 0) { - if (rm->rm_col[VDEV_RAIDZ_P].rc_error == 0) - atomic_inc_64(&raidz_corrected_p); - else - atomic_inc_64(&raidz_corrected_q); + atomic_inc_64(&raidz_corrected[code]); /* - * If there's more than one parity disk that - * was successfully read, confirm that the - * other parity disk produced the correct data. - * This routine is suboptimal in that it - * regenerates both the parity we wish to test - * as well as the parity we just used to - * perform the reconstruction, but this should - * be a relatively uncommon case, and can be - * optimized if it becomes a problem. - * We also regenerate parity when resilvering - * so we can write it out to the failed device - * later. + * If we read more parity disks than were used + * for reconstruction, confirm that the other + * parity disks produced correct data. This + * routine is suboptimal in that it regenerates + * the parity that we already used in addition + * to the parity that we're attempting to + * verify, but this should be a relatively + * uncommon case, and can be optimized if it + * becomes a problem. Note that we regenerate + * parity when resilvering so we can write it + * out to failed devices later. */ - if (parity_errors < rm->rm_firstdatacol - 1 || + if (parity_errors < rm->rm_firstdatacol - n || (zio->io_flags & ZIO_FLAG_RESILVER)) { n = raidz_parity_verify(zio, rm); unexpected_errors += n; @@ -940,46 +1796,6 @@ goto done; } - break; - - case 2: - /* - * Two data column errors require double parity. - */ - ASSERT(rm->rm_firstdatacol == 2); - - /* - * Find the two columns that reported errors. - */ - for (c = rm->rm_firstdatacol; c < rm->rm_cols; c++) { - rc = &rm->rm_col[c]; - if (rc->rc_error != 0) - break; - } - ASSERT(c != rm->rm_cols); - ASSERT(!rc->rc_skipped || rc->rc_error == ENXIO || - rc->rc_error == ESTALE); - - for (c1 = c++; c < rm->rm_cols; c++) { - rc = &rm->rm_col[c]; - if (rc->rc_error != 0) - break; - } - ASSERT(c != rm->rm_cols); - ASSERT(!rc->rc_skipped || rc->rc_error == ENXIO || - rc->rc_error == ESTALE); - - vdev_raidz_reconstruct_pq(rm, c1, c); - - if (zio_checksum_error(zio) == 0) { - atomic_inc_64(&raidz_corrected_pq); - goto done; - } - break; - - default: - ASSERT(rm->rm_firstdatacol <= 2); - ASSERT(0); } } @@ -1018,8 +1834,10 @@ * errors we detected, and we've attempted to read all columns. There * must, therefore, be one or more additional problems -- silent errors * resulting in invalid data rather than explicit I/O errors resulting - * in absent data. Before we attempt combinatorial reconstruction make - * sure we have a chance of coming up with the right answer. + * in absent data. We check if there is enough additional data to + * possibly reconstruct the data and then perform combinatorial + * reconstruction over all possible combinations. If that fails, + * we're cooked. */ if (total_errors >= rm->rm_firstdatacol) { zio->io_error = vdev_raidz_worst_error(rm); @@ -1030,133 +1848,30 @@ */ if (total_errors == rm->rm_firstdatacol) zio->io_error = zio_worst_error(zio->io_error, ECKSUM); - goto done; - } - - if (rm->rm_col[VDEV_RAIDZ_P].rc_error == 0) { - /* - * Attempt to reconstruct the data from parity P. - */ - for (c = rm->rm_firstdatacol; c < rm->rm_cols; c++) { - void *orig; - rc = &rm->rm_col[c]; - - orig = zio_buf_alloc(rc->rc_size); - bcopy(rc->rc_data, orig, rc->rc_size); - vdev_raidz_reconstruct_p(rm, c); - - if (zio_checksum_error(zio) == 0) { - zio_buf_free(orig, rc->rc_size); - atomic_inc_64(&raidz_corrected_p); - - /* - * If this child didn't know that it returned - * bad data, inform it. - */ - if (rc->rc_tried && rc->rc_error == 0) - raidz_checksum_error(zio, rc); - rc->rc_error = ECKSUM; - goto done; - } - - bcopy(orig, rc->rc_data, rc->rc_size); - zio_buf_free(orig, rc->rc_size); - } - } - - if (rm->rm_firstdatacol > 1 && rm->rm_col[VDEV_RAIDZ_Q].rc_error == 0) { - /* - * Attempt to reconstruct the data from parity Q. - */ - for (c = rm->rm_firstdatacol; c < rm->rm_cols; c++) { - void *orig; - rc = &rm->rm_col[c]; - - orig = zio_buf_alloc(rc->rc_size); - bcopy(rc->rc_data, orig, rc->rc_size); - vdev_raidz_reconstruct_q(rm, c); - - if (zio_checksum_error(zio) == 0) { - zio_buf_free(orig, rc->rc_size); - atomic_inc_64(&raidz_corrected_q); - - /* - * If this child didn't know that it returned - * bad data, inform it. - */ - if (rc->rc_tried && rc->rc_error == 0) - raidz_checksum_error(zio, rc); - rc->rc_error = ECKSUM; - goto done; - } - bcopy(orig, rc->rc_data, rc->rc_size); - zio_buf_free(orig, rc->rc_size); - } - } - - if (rm->rm_firstdatacol > 1 && - rm->rm_col[VDEV_RAIDZ_P].rc_error == 0 && - rm->rm_col[VDEV_RAIDZ_Q].rc_error == 0) { + } else if ((code = vdev_raidz_combrec(zio, total_errors, + data_errors)) != 0) { /* - * Attempt to reconstruct the data from both P and Q. + * If we didn't use all the available parity for the + * combinatorial reconstruction, verify that the remaining + * parity is correct. */ - for (c = rm->rm_firstdatacol; c < rm->rm_cols - 1; c++) { - void *orig, *orig1; - rc = &rm->rm_col[c]; - - orig = zio_buf_alloc(rc->rc_size); - bcopy(rc->rc_data, orig, rc->rc_size); - - for (c1 = c + 1; c1 < rm->rm_cols; c1++) { - rc1 = &rm->rm_col[c1]; - - orig1 = zio_buf_alloc(rc1->rc_size); - bcopy(rc1->rc_data, orig1, rc1->rc_size); - - vdev_raidz_reconstruct_pq(rm, c, c1); - - if (zio_checksum_error(zio) == 0) { - zio_buf_free(orig, rc->rc_size); - zio_buf_free(orig1, rc1->rc_size); - atomic_inc_64(&raidz_corrected_pq); + if (code != (1 << rm->rm_firstdatacol) - 1) + (void) raidz_parity_verify(zio, rm); + } else { + /* + * All combinations failed to checksum. Generate checksum + * ereports for all children. + */ + zio->io_error = ECKSUM; - /* - * If these children didn't know they - * returned bad data, inform them. - */ - if (rc->rc_tried && rc->rc_error == 0) - raidz_checksum_error(zio, rc); - if (rc1->rc_tried && rc1->rc_error == 0) - raidz_checksum_error(zio, rc1); - - rc->rc_error = ECKSUM; - rc1->rc_error = ECKSUM; - - goto done; - } - - bcopy(orig1, rc1->rc_data, rc1->rc_size); - zio_buf_free(orig1, rc1->rc_size); + if (!(zio->io_flags & ZIO_FLAG_SPECULATIVE)) { + for (c = 0; c < rm->rm_cols; c++) { + rc = &rm->rm_col[c]; + zfs_ereport_post(FM_EREPORT_ZFS_CHECKSUM, + zio->io_spa, vd->vdev_child[rc->rc_devidx], + zio, rc->rc_offset, rc->rc_size); } - - bcopy(orig, rc->rc_data, rc->rc_size); - zio_buf_free(orig, rc->rc_size); - } - } - - /* - * All combinations failed to checksum. Generate checksum ereports for - * all children. - */ - zio->io_error = ECKSUM; - - if (!(zio->io_flags & ZIO_FLAG_SPECULATIVE)) { - for (c = 0; c < rm->rm_cols; c++) { - rc = &rm->rm_col[c]; - zfs_ereport_post(FM_EREPORT_ZFS_CHECKSUM, - zio->io_spa, vd->vdev_child[rc->rc_devidx], zio, - rc->rc_offset, rc->rc_size); } }
--- a/usr/src/uts/common/inet/kssl/ksslrec.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/inet/kssl/ksslrec.c Mon Jul 20 13:07:46 2009 -0400 @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <sys/stream.h> #include <sys/strsubr.h> @@ -444,6 +442,15 @@ } +/* + * Minimum message length for a client hello = + * 2-byte client_version + + * 32-byte random + + * 1-byte session_id length + + * 2-byte cipher_suites length + + * 1-byte compression_methods length + + * 1-byte CompressionMethod.null + */ #define KSSL_SSL3_CH_MIN_MSGLEN (39) static int @@ -452,8 +459,7 @@ uchar_t *msgend; int err; SSL3AlertDescription desc = illegal_parameter; - uint_t sidlen; - uint_t nsuites; + uint_t sidlen, cslen, cmlen; uchar_t *suitesp; uint_t i, j; uint16_t suite; @@ -498,25 +504,35 @@ mp->b_rptr += SSL3_SESSIONID_BYTES; } - nsuites = ((uint_t)mp->b_rptr[0] << 8) + (uint_t)mp->b_rptr[1]; + cslen = ((uint_t)mp->b_rptr[0] << 8) + (uint_t)mp->b_rptr[1]; mp->b_rptr += 2; - ch_msglen += nsuites; - if (msglen != ch_msglen) { + ch_msglen += cslen; + + /* + * This check can't be a "!=" since there can be + * compression methods other than CompressionMethod.null. + * Also, there can be extra data (TLS extensions) after the + * compression methods field. We do not support any TLS + * extensions and hence ignore them. + */ + if (msglen < ch_msglen) { goto falert; } - if (nsuites & 0x1) { + + /* The length has to be even since a cipher suite is 2-byte long */ + if (cslen & 0x1) { goto falert; } suitesp = mp->b_rptr; if (ssl->sid.cached == B_TRUE) { suite = ssl->sid.cipher_suite; - for (j = 0; j < nsuites; j += 2) { + for (j = 0; j < cslen; j += 2) { if (suitesp[j] == ((suite >> 8) & 0xff) && suitesp[j + 1] == (suite & 0xff)) { break; } } - if (j < nsuites) { + if (j < cslen) { goto suite_found; } kssl_uncache_sid(&ssl->sid, ssl->kssl_entry); @@ -526,13 +542,13 @@ /* Check if this server is capable of the cipher suite */ for (i = 0; i < ssl->kssl_entry->kssl_cipherSuites_nentries; i++) { suite = ssl->kssl_entry->kssl_cipherSuites[i]; - for (j = 0; j < nsuites; j += 2) { + for (j = 0; j < cslen; j += 2) { if (suitesp[j] == ((suite >> 8) & 0xff) && suitesp[j + 1] == (suite & 0xff)) { break; } } - if (j < nsuites) { + if (j < cslen) { break; } } @@ -547,11 +563,27 @@ } suite_found: + mp->b_rptr += cslen; - mp->b_rptr += nsuites; - if (*mp->b_rptr++ != 1 || *mp->b_rptr++ != 0) { + /* + * Check for the mandatory CompressionMethod.null. We do not + * support any other compression methods. + */ + cmlen = *mp->b_rptr++; + ch_msglen += cmlen - 1; /* -1 accounts for the null method */ + if (msglen < ch_msglen) { + goto falert; + } + + while (cmlen >= 1) { + if (*mp->b_rptr++ == 0) + break; + cmlen--; + } + + if (cmlen == 0) { desc = handshake_failure; - DTRACE_PROBE(kssl_err__handshake_failure); + DTRACE_PROBE(kssl_err__no_null_method_failure); goto falert; } @@ -1352,8 +1384,10 @@ } } else { if (cipher_defs[ssl->pending_calg].bsize > 0) { + /* server_write_IV */ spec->cipher_mech.cm_param += spec->cipher_bsize; } + /* server_write_key */ spec->cipher_key.ck_data = &(ssl->pending_keyblock[2 * spec->mac_hashsz + @@ -1802,7 +1836,7 @@ SSL3AlertDescription desc = illegal_parameter; uint_t randlen; uint_t sidlen; - uint_t nsuites; + uint_t cslen; uchar_t *suitesp; uchar_t *rand; uint_t i, j; @@ -1829,11 +1863,11 @@ } mp->b_rptr += 3; - nsuites = ((uint_t)mp->b_rptr[0] << 8) + (uint_t)mp->b_rptr[1]; + cslen = ((uint_t)mp->b_rptr[0] << 8) + (uint_t)mp->b_rptr[1]; sidlen = ((uint_t)mp->b_rptr[2] << 8) + (uint_t)mp->b_rptr[3]; randlen = ((uint_t)mp->b_rptr[4] << 8) + (uint_t)mp->b_rptr[5]; - if (nsuites % 3 != 0) { - DTRACE_PROBE1(kssl_err__nsuites_error, uint_t, nsuites); + if (cslen % 3 != 0) { + DTRACE_PROBE1(kssl_err__cipher_suites_len_error, uint_t, cslen); goto falert; } if (randlen < SSL_MIN_CHALLENGE_BYTES || @@ -1843,12 +1877,12 @@ goto falert; } mp->b_rptr += 6; - ch_recsz += nsuites + sidlen + randlen; + ch_recsz += cslen + sidlen + randlen; if (recsz != ch_recsz) { goto falert; } suitesp = mp->b_rptr; - rand = suitesp + nsuites + sidlen; + rand = suitesp + cslen + sidlen; if (randlen < SSL3_RANDOM_LENGTH) { bzero(ssl->client_random, SSL3_RANDOM_LENGTH); } @@ -1857,7 +1891,7 @@ for (i = 0; i < ssl->kssl_entry->kssl_cipherSuites_nentries; i++) { suite = ssl->kssl_entry->kssl_cipherSuites[i]; - for (j = 0; j < nsuites; j += 3) { + for (j = 0; j < cslen; j += 3) { if (suitesp[j] != 0) { continue; } @@ -1867,7 +1901,7 @@ break; } } - if (j < nsuites) { + if (j < cslen) { break; } } @@ -1920,7 +1954,7 @@ /* * Call back routine for asynchronously submitted RSA decryption jobs. - * The routine retreived the pre-master secret, and proceeds to generate + * This routine retrieves the pre-master secret, and proceeds to generate * the remaining key materials. */ static void
--- a/usr/src/uts/common/inet/tcp/tcp.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/inet/tcp/tcp.c Mon Jul 20 13:07:46 2009 -0400 @@ -13633,6 +13633,20 @@ if (flags & TH_URG && urp >= 0) { if (!tcp->tcp_urp_last_valid || SEQ_GT(urp + seg_seq, tcp->tcp_urp_last)) { + /* + * Non-STREAMS sockets handle the urgent data a litte + * differently from STREAMS based sockets. There is no + * need to mark any mblks with the MSG{NOT,}MARKNEXT + * flags to keep SIOCATMARK happy. Instead a + * su_signal_oob upcall is made to update the mark. + * Neither is a T_EXDATA_IND mblk needed to be + * prepended to the urgent data. The urgent data is + * delivered using the su_recv upcall, where we set + * the MSG_OOB flag to indicate that it is urg data. + * + * Neither TH_SEND_URP_MARK nor TH_MARKNEXT_NEEDED + * are used by non-STREAMS sockets. + */ if (IPCL_IS_NONSTR(connp)) { if (!TCP_IS_DETACHED(tcp)) { (*connp->conn_upcalls->su_signal_oob) @@ -13858,26 +13872,34 @@ } else if (urp == seg_len) { /* * The urgent byte is the next byte after this sequence - * number. If there is data it is marked with - * MSGMARKNEXT and any tcp_urp_mark_mp is discarded - * since it is not needed. Otherwise, if the code - * above just allocated a zero-length tcp_urp_mark_mp - * message, that message is tagged with MSGMARKNEXT. - * Sending up these MSGMARKNEXT messages makes - * SIOCATMARK work correctly even though - * the T_EXDATA_IND will not be sent up until the - * urgent byte arrives. - */ - if (seg_len != 0) { - flags |= TH_MARKNEXT_NEEDED; - freemsg(tcp->tcp_urp_mark_mp); - tcp->tcp_urp_mark_mp = NULL; - flags &= ~TH_SEND_URP_MARK; - } else if (tcp->tcp_urp_mark_mp != NULL) { - flags |= TH_SEND_URP_MARK; - tcp->tcp_urp_mark_mp->b_flag &= - ~MSGNOTMARKNEXT; - tcp->tcp_urp_mark_mp->b_flag |= MSGMARKNEXT; + * number. If this endpoint is non-STREAMS, then there + * is nothing to do here since the socket has already + * been notified about the urg pointer by the + * su_signal_oob call above. + * + * In case of STREAMS, some more work might be needed. + * If there is data it is marked with MSGMARKNEXT and + * and any tcp_urp_mark_mp is discarded since it is not + * needed. Otherwise, if the code above just allocated + * a zero-length tcp_urp_mark_mp message, that message + * is tagged with MSGMARKNEXT. Sending up these + * MSGMARKNEXT messages makes SIOCATMARK work correctly + * even though the T_EXDATA_IND will not be sent up + * until the urgent byte arrives. + */ + if (!IPCL_IS_NONSTR(tcp->tcp_connp)) { + if (seg_len != 0) { + flags |= TH_MARKNEXT_NEEDED; + freemsg(tcp->tcp_urp_mark_mp); + tcp->tcp_urp_mark_mp = NULL; + flags &= ~TH_SEND_URP_MARK; + } else if (tcp->tcp_urp_mark_mp != NULL) { + flags |= TH_SEND_URP_MARK; + tcp->tcp_urp_mark_mp->b_flag &= + ~MSGNOTMARKNEXT; + tcp->tcp_urp_mark_mp->b_flag |= + MSGMARKNEXT; + } } #ifdef DEBUG (void) strlog(TCP_MOD_ID, 0, 1, SL_TRACE, @@ -14910,24 +14932,35 @@ } else { tcp_rcv_enqueue(tcp, mp, seg_len); } - } else { + } else if (IPCL_IS_NONSTR(connp)) { + /* + * Non-STREAMS socket + * + * Note that no KSSL processing is done here, because + * KSSL is not supported for non-STREAMS sockets. + */ + boolean_t push = flags & (TH_PUSH|TH_FIN); + int error; + + if ((*connp->conn_upcalls->su_recv)( + connp->conn_upper_handle, + mp, seg_len, 0, &error, &push) <= 0) { + /* + * We should never be in middle of a + * fallback, the squeue guarantees that. + */ + ASSERT(error != EOPNOTSUPP); + if (error == ENOSPC) + tcp->tcp_rwnd -= seg_len; + } else if (push) { + /* PUSH bit set and sockfs is not flow controlled */ + flags |= tcp_rwnd_reopen(tcp); + } + } else { + /* STREAMS socket */ if (mp->b_datap->db_type != M_DATA || (flags & TH_MARKNEXT_NEEDED)) { - if (IPCL_IS_NONSTR(connp)) { - int error; - - if ((*connp->conn_upcalls->su_recv) - (connp->conn_upper_handle, mp, - seg_len, 0, &error, NULL) <= 0) { - /* - * We should never be in middle of a - * fallback, the squeue guarantees that. - */ - ASSERT(error != EOPNOTSUPP); - if (error == ENOSPC) - tcp->tcp_rwnd -= seg_len; - } - } else if (tcp->tcp_rcv_list != NULL) { + if (tcp->tcp_rcv_list != NULL) { flags |= tcp_rcv_drain(tcp); } ASSERT(tcp->tcp_rcv_list == NULL || @@ -14950,8 +14983,7 @@ DTRACE_PROBE1(kssl_mblk__ksslinput_data1, mblk_t *, mp); tcp_kssl_input(tcp, mp); - } else if (!IPCL_IS_NONSTR(connp)) { - /* Already handled non-STREAMS case. */ + } else { putnext(tcp->tcp_rq, mp); if (!canputnext(tcp->tcp_rq)) tcp->tcp_rwnd -= seg_len; @@ -14961,28 +14993,6 @@ /* Does this need SSL processing first? */ DTRACE_PROBE1(kssl_mblk__ksslinput_data2, mblk_t *, mp); tcp_kssl_input(tcp, mp); - } else if (IPCL_IS_NONSTR(connp)) { - /* Non-STREAMS socket */ - boolean_t push = flags & (TH_PUSH|TH_FIN); - int error; - - if ((*connp->conn_upcalls->su_recv)( - connp->conn_upper_handle, - mp, seg_len, 0, &error, &push) <= 0) { - /* - * We should never be in middle of a - * fallback, the squeue guarantees that. - */ - ASSERT(error != EOPNOTSUPP); - if (error == ENOSPC) - tcp->tcp_rwnd -= seg_len; - } else if (push) { - /* - * PUSH bit set and sockfs is not - * flow controlled - */ - flags |= tcp_rwnd_reopen(tcp); - } } else if ((flags & (TH_PUSH|TH_FIN)) || tcp->tcp_rcv_cnt + seg_len >= tcp->tcp_recv_hiwater >> 3) { if (tcp->tcp_rcv_list != NULL) { @@ -15018,8 +15028,7 @@ * for a push bit. This provides resiliency against * implementations that do not correctly generate push bits. */ - if (!IPCL_IS_NONSTR(connp) && tcp->tcp_rcv_list != NULL && - tcp->tcp_push_tid == 0) { + if (tcp->tcp_rcv_list != NULL && tcp->tcp_push_tid == 0) { /* * The connection may be closed at this point, so don't * do anything for a detached tcp. @@ -17362,6 +17371,10 @@ sopp.sopp_tail = sopp_tail; sopp.sopp_zcopyflag = sopp_copyopt; } + if (tcp->tcp_loopback) { + sopp.sopp_flags |= SOCKOPT_LOOPBACK; + sopp.sopp_loopback = B_TRUE; + } (*connp->conn_upcalls->su_set_proto_props) (connp->conn_upper_handle, &sopp); } else { @@ -26454,6 +26467,16 @@ error = proto_tlitosyserr(-error); } } + + if (tcp->tcp_loopback) { + struct sock_proto_props sopp; + + sopp.sopp_flags = SOCKOPT_LOOPBACK; + sopp.sopp_loopback = B_TRUE; + + (*connp->conn_upcalls->su_set_proto_props)( + connp->conn_upper_handle, &sopp); + } done: squeue_synch_exit(sqp, connp);
--- a/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd.c Mon Jul 20 13:07:46 2009 -0400 @@ -762,7 +762,7 @@ sli->sli_data_order = SMS_DATA_ORDER; sli->sli_flags = BSWAP_32(sli->sli_flags); sli->sli_lu_size = BSWAP_64(sli->sli_lu_size); - sli->sli_meta_fname_offset = BSWAP_16(sli->sli_meta_fname_offset); + sli->sli_meta_fname_offset = BSWAP_64(sli->sli_meta_fname_offset); sli->sli_data_fname_offset = BSWAP_16(sli->sli_data_fname_offset); sli->sli_serial_offset = BSWAP_16(sli->sli_serial_offset); sli->sli_alias_offset = BSWAP_16(sli->sli_alias_offset); @@ -1066,6 +1066,9 @@ if (sl->sl_alias) { s += strlen(sl->sl_alias) + 1; } + if (sl->sl_mgmt_url) { + s += strlen(sl->sl_mgmt_url) + 1; + } sli = (sbd_lu_info_1_1_t *)kmem_zalloc(sizeof (*sli) + s, KM_SLEEP); p = sli->sli_buf; if ((sl->sl_flags & (SL_SHARED_META | SL_ZFS_META)) == 0) { @@ -1092,6 +1095,13 @@ sli->sli_flags |= SLI_ALIAS_VALID; p += strlen(sl->sl_alias) + 1; } + if (sl->sl_mgmt_url) { + (void) strcpy((char *)p, sl->sl_mgmt_url); + sli->sli_mgmt_url_offset = + (uintptr_t)p - (uintptr_t)sli->sli_buf; + sli->sli_flags |= SLI_MGMT_URL_VALID; + p += strlen(sl->sl_mgmt_url) + 1; + } if (sl->sl_flags & SL_WRITE_PROTECTED) { sli->sli_flags |= SLI_WRITE_PROTECTED; } @@ -1338,6 +1348,9 @@ if (sl->sl_alias_alloc_size) { kmem_free(sl->sl_alias, sl->sl_alias_alloc_size); } + if (sl->sl_mgmt_url_alloc_size) { + kmem_free(sl->sl_mgmt_url, sl->sl_mgmt_url_alloc_size); + } stmf_free(sl->sl_lu); return (ret); } @@ -1368,6 +1381,8 @@ (slu->slu_data_fname_off >= sz) || ((slu->slu_alias_valid) && (slu->slu_alias_off >= sz)) || + ((slu->slu_mgmt_url_valid) && + (slu->slu_mgmt_url_off >= sz)) || ((slu->slu_serial_valid) && ((slu->slu_serial_off + slu->slu_serial_size) >= sz))) { return (EINVAL); @@ -1385,6 +1400,9 @@ if (slu->slu_alias_valid) { alloc_sz += strlen(namebuf + slu->slu_alias_off) + 1; } + if (slu->slu_mgmt_url_valid) { + alloc_sz += strlen(namebuf + slu->slu_mgmt_url_off) + 1; + } if (slu->slu_serial_valid) { alloc_sz += slu->slu_serial_size; } @@ -1428,6 +1446,11 @@ (void) strcpy(p, namebuf + slu->slu_alias_off); p += strlen(sl->sl_alias) + 1; } + if (slu->slu_mgmt_url_valid) { + sl->sl_mgmt_url = p; + (void) strcpy(p, namebuf + slu->slu_mgmt_url_off); + p += strlen(sl->sl_mgmt_url) + 1; + } if (slu->slu_serial_valid) { sl->sl_serial_no = (uint8_t *)p; bcopy(namebuf + slu->slu_serial_off, sl->sl_serial_no, @@ -1784,6 +1807,8 @@ (sli->sli_meta_fname_offset > sli_buf_sz)) || ((sli->sli_flags & SLI_DATA_FNAME_VALID) && (sli->sli_data_fname_offset > sli_buf_sz)) || + ((sli->sli_flags & SLI_MGMT_URL_VALID) && + (sli->sli_mgmt_url_offset > sli_buf_sz)) || ((sli->sli_flags & SLI_SERIAL_VALID) && ((sli->sli_serial_offset + sli->sli_serial_size) > sli_buf_sz)) || ((sli->sli_flags & SLI_ALIAS_VALID) && @@ -1855,6 +1880,14 @@ (void) strcpy(sl->sl_alias, (char *)sli_buf_copy + sli->sli_alias_offset); } + if (sli->sli_flags & SLI_MGMT_URL_VALID) { + sl->sl_mgmt_url_alloc_size = strlen((char *)sli_buf_copy + + sli->sli_mgmt_url_offset) + 1; + sl->sl_mgmt_url = kmem_alloc(sl->sl_mgmt_url_alloc_size, + KM_SLEEP); + (void) strcpy(sl->sl_mgmt_url, (char *)sli_buf_copy + + sli->sli_mgmt_url_offset); + } if (sli->sli_flags & SLI_WRITE_PROTECTED) { sl->sl_flags |= SL_WRITE_PROTECTED; } @@ -1958,7 +1991,7 @@ sbd_modify_lu(sbd_modify_lu_t *mlu, int struct_sz, uint32_t *err_ret) { sbd_lu_t *sl = NULL; - int alias_sz; + uint16_t alias_sz; int ret = 0; sbd_it_data_t *it; sbd_status_t sret; @@ -1982,6 +2015,8 @@ /* Lets validate offsets */ if (((mlu->mlu_alias_valid) && (mlu->mlu_alias_off >= sz)) || + ((mlu->mlu_mgmt_url_valid) && + (mlu->mlu_mgmt_url_off >= sz)) || (mlu->mlu_by_fname) && (mlu->mlu_fname_off >= sz)) { return (EINVAL); @@ -2088,6 +2123,35 @@ mutex_exit(&sl->sl_lock); } + if (mlu->mlu_mgmt_url_valid) { + uint16_t url_sz; + + url_sz = strlen((char *)mlu->mlu_buf + mlu->mlu_mgmt_url_off); + if (url_sz > 0) + url_sz++; + + mutex_enter(&sl->sl_lock); + if (sl->sl_mgmt_url_alloc_size > 0 && + (url_sz == 0 || sl->sl_mgmt_url_alloc_size < url_sz)) { + kmem_free(sl->sl_mgmt_url, sl->sl_mgmt_url_alloc_size); + sl->sl_mgmt_url = NULL; + sl->sl_mgmt_url_alloc_size = 0; + } + if (url_sz > 0) { + if (sl->sl_mgmt_url_alloc_size == 0) { + sl->sl_mgmt_url = kmem_alloc(url_sz, KM_SLEEP); + sl->sl_mgmt_url_alloc_size = url_sz; + } + (void) strcpy(sl->sl_mgmt_url, (char *)mlu->mlu_buf + + mlu->mlu_mgmt_url_off); + } + for (it = sl->sl_it_list; it != NULL; + it = it->sbd_it_next) { + it->sbd_it_ua_conditions |= + SBD_UA_MODE_PARAMETERS_CHANGED; + } + mutex_exit(&sl->sl_lock); + } if (mlu->mlu_write_protected_valid) { mutex_enter(&sl->sl_lock); @@ -2368,6 +2432,9 @@ sz += strlen(sl->sl_alias) + 1; } + if (sl->sl_mgmt_url) { + sz += strlen(sl->sl_mgmt_url) + 1; + } bzero(oslp, sizeof (*oslp) - 8); oslp->slp_buf_size_needed = sz; @@ -2404,6 +2471,12 @@ (void) strcpy((char *)&oslp->slp_buf[off], sl->sl_alias); off += strlen(sl->sl_alias) + 1; } + if (sl->sl_mgmt_url) { + oslp->slp_mgmt_url_valid = 1; + oslp->slp_mgmt_url_off = off; + (void) strcpy((char *)&oslp->slp_buf[off], sl->sl_mgmt_url); + off += strlen(sl->sl_mgmt_url) + 1; + } if (sl->sl_serial_no_size) { oslp->slp_serial_off = off; bcopy(sl->sl_serial_no, &oslp->slp_buf[off],
--- a/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c Mon Jul 20 13:07:46 2009 -0400 @@ -138,7 +138,7 @@ if (iolen == 0) break; if (sbd_data_read(sl, laddr, (uint64_t)iolen, - dbuf->db_sglist[0].seg_addr) != STMF_SUCCESS) { + dbuf->db_sglist[ndx].seg_addr) != STMF_SUCCESS) { scmd->flags |= SBD_SCSI_CMD_XFER_FAIL; /* Do not need to do xfer anymore, just complete it */ dbuf->db_data_size = 0; @@ -401,7 +401,7 @@ if (iolen == 0) break; if (sbd_data_write(sl, laddr, (uint64_t)iolen, - dbuf->db_sglist[0].seg_addr) != STMF_SUCCESS) { + dbuf->db_sglist[ndx].seg_addr) != STMF_SUCCESS) { scmd->flags |= SBD_SCSI_CMD_XFER_FAIL; break; } @@ -1070,15 +1070,56 @@ STMF_SAA_INVALID_FIELD_IN_PARAM_LIST); } +/* + * This function parse through a string, passed to it as a pointer to a string, + * by adjusting the pointer to the first non-space character and returns + * the count/length of the first bunch of non-space characters. Multiple + * Management URLs are stored as a space delimited string in sl_mgmt_url + * field of sbd_lu_t. This function is used to retrieve one url at a time. + * + * i/p : pointer to pointer to a url string + * o/p : Adjust the pointer to the url to the first non white character + * and returns the length of the URL + */ +uint16_t +sbd_parse_mgmt_url(char **url_addr) { + uint16_t url_length = 0; + char *url; + url = *url_addr; + + while (*url != '\0') { + if (*url == ' ' || *url == '\t' || *url == '\n') { + (*url_addr)++; + url = *url_addr; + } else { + break; + } + } + + while (*url != '\0') { + if (*url == ' ' || *url == '\t' || + *url == '\n' || *url == '\0') { + break; + } + url++; + url_length++; + } + return (url_length); +} + void -sbd_handle_inquiry(struct scsi_task *task, struct stmf_data_buf *initial_dbuf, - uint8_t *p, int bsize) +sbd_handle_inquiry(struct scsi_task *task, struct stmf_data_buf *initial_dbuf) { sbd_lu_t *sl = (sbd_lu_t *)task->task_lu->lu_provider_private; uint8_t *cdbp = (uint8_t *)&task->task_cdb[0]; - uint32_t cmd_size; + uint8_t *p; + uint8_t byte0; uint8_t page_length; - uint8_t byte0; + uint16_t bsize = 512; + uint16_t cmd_size; + uint32_t xfer_size = 4; + uint32_t mgmt_url_size = 0; + byte0 = DTYPE_DIRECT; /* @@ -1096,7 +1137,7 @@ * return success. */ - cmd_size = (((uint32_t)cdbp[3]) << 8) | cdbp[4]; + cmd_size = (((uint16_t)cdbp[3]) << 8) | cdbp[4]; if (cmd_size == 0) { task->task_cmd_xfer_length = 0; @@ -1108,15 +1149,23 @@ return; } + if (sl->sl_mgmt_url) { + mgmt_url_size = strlen(sl->sl_mgmt_url); + } + /* * Standard inquiry */ if ((cdbp[1] & 1) == 0) { - struct scsi_inquiry *inq = (struct scsi_inquiry *)p; + int i; + struct scsi_inquiry *inq; - page_length = 31; - bzero(inq, page_length + 5); + p = (uint8_t *)kmem_zalloc(bsize, KM_SLEEP); + inq = (struct scsi_inquiry *)p; + + page_length = 69; + xfer_size = page_length + 5; inq->inq_dtype = DTYPE_DIRECT; inq->inq_ansi = 5; /* SPC-3 */ @@ -1124,7 +1173,7 @@ inq->inq_rdf = 2; /* Response data format for SPC-3 */ inq->inq_len = page_length; - inq->inq_tpgs = 1; + inq->inq_tpgs = TPGS_FAILOVER_IMPLICIT; inq->inq_cmdque = 1; if (sl->sl_flags & SL_VID_VALID) { @@ -1145,8 +1194,59 @@ bcopy(sbd_revision, inq->inq_revision, 4); } + /* Adding Version Descriptors */ + i = 0; + /* SAM-3 no version */ + inq->inq_vd[i].inq_vd_msb = 0x00; + inq->inq_vd[i].inq_vd_lsb = 0x60; + i++; + + /* transport */ + switch (task->task_lport->lport_id->protocol_id) { + case PROTOCOL_FIBRE_CHANNEL: + inq->inq_vd[i].inq_vd_msb = 0x09; + inq->inq_vd[i].inq_vd_lsb = 0x00; + i++; + break; + + case PROTOCOL_PARALLEL_SCSI: + case PROTOCOL_SSA: + case PROTOCOL_IEEE_1394: + /* Currently no claims of conformance */ + break; + + case PROTOCOL_SRP: + inq->inq_vd[i].inq_vd_msb = 0x09; + inq->inq_vd[i].inq_vd_lsb = 0x40; + i++; + break; + + case PROTOCOL_iSCSI: + inq->inq_vd[i].inq_vd_msb = 0x09; + inq->inq_vd[i].inq_vd_lsb = 0x60; + i++; + break; + + case PROTOCOL_SAS: + case PROTOCOL_ADT: + case PROTOCOL_ATAPI: + default: + /* Currently no claims of conformance */ + break; + } + + /* SPC-3 no version */ + inq->inq_vd[i].inq_vd_msb = 0x03; + inq->inq_vd[i].inq_vd_lsb = 0x00; + i++; + + /* SBC-2 no version */ + inq->inq_vd[i].inq_vd_msb = 0x03; + inq->inq_vd[i].inq_vd_lsb = 0x20; + sbd_handle_short_read_transfers(task, initial_dbuf, p, cmd_size, - min(cmd_size, page_length + 5)); + min(cmd_size, xfer_size)); + kmem_free(p, bsize); return; } @@ -1155,18 +1255,30 @@ * EVPD handling */ + /* Default 512 bytes may not be enough, increase bsize if necessary */ + if (cdbp[2] == 0x83 || cdbp[2] == 0x85) { + if (bsize < cmd_size) + bsize = cmd_size; + } + p = (uint8_t *)kmem_zalloc(bsize, KM_SLEEP); + switch (cdbp[2]) { case 0x00: - page_length = 4; - - bzero(p, page_length + 4); + page_length = 4 + (mgmt_url_size ? 1 : 0); p[0] = byte0; p[3] = page_length; - p[5] = 0x80; - p[6] = 0x83; - p[7] = 0x86; + /* Supported VPD pages in ascending order */ + { + uint8_t i = 5; + p[i++] = 0x80; + p[i++] = 0x83; + if (mgmt_url_size != 0) + p[i++] = 0x85; + p[i++] = 0x86; + } + xfer_size = page_length + 4; break; case 0x80: @@ -1174,25 +1286,74 @@ page_length = sl->sl_serial_no_size; bcopy(sl->sl_serial_no, p + 4, sl->sl_serial_no_size); } else { + /* if no serial num is specified set 4 spaces */ + page_length = 4; bcopy(" ", p + 4, 4); } p[0] = byte0; p[1] = 0x80; p[3] = page_length; + xfer_size = page_length + 4; break; case 0x83: - - page_length = stmf_scsilib_prepare_vpd_page83(task, p, + xfer_size = stmf_scsilib_prepare_vpd_page83(task, p, bsize, byte0, STMF_VPD_LU_ID|STMF_VPD_TARGET_ID| - STMF_VPD_TP_GROUP|STMF_VPD_RELATIVE_TP_ID) - 4; + STMF_VPD_TP_GROUP|STMF_VPD_RELATIVE_TP_ID); break; + case 0x85: + if (mgmt_url_size == 0) { + stmf_scsilib_send_status(task, STATUS_CHECK, + STMF_SAA_INVALID_FIELD_IN_CDB); + kmem_free(p, bsize); + return; + } + { + uint16_t idx, newidx, sz, url_size; + char *url; + + p[0] = byte0; + p[1] = 0x85; + + idx = 4; + url = sl->sl_mgmt_url; + url_size = sbd_parse_mgmt_url(&url); + /* Creating Network Service Descriptors */ + while (url_size != 0) { + /* Null terminated and 4 Byte aligned */ + sz = url_size + 1; + sz += (sz % 4) ? 4 - (sz % 4) : 0; + newidx = idx + sz + 4; + + if (newidx < bsize) { + /* + * SPC-3r23 : Table 320 (Sec 7.6.5) + * (Network service descriptor format + * + * Note: Hard coding service type as + * "Storage Configuration Service". + */ + p[idx] = 1; + SCSI_WRITE16(p + idx + 2, sz); + bcopy(url, p + idx + 4, url_size); + xfer_size = newidx + 4; + } + idx = newidx; + + /* skip to next mgmt url if any */ + url += url_size; + url_size = sbd_parse_mgmt_url(&url); + } + + /* Total descriptor length */ + SCSI_WRITE16(p + 2, idx - 4); + break; + } + case 0x86: page_length = 0x3c; - bzero(p, page_length + 4); - p[0] = byte0; p[1] = 0x86; /* Page 86 response */ p[3] = page_length; @@ -1204,17 +1365,19 @@ * to claim support only for Simple TA. */ p[5] = 1; - + xfer_size = page_length + 4; break; default: stmf_scsilib_send_status(task, STATUS_CHECK, STMF_SAA_INVALID_FIELD_IN_CDB); + kmem_free(p, bsize); return; } sbd_handle_short_read_transfers(task, initial_dbuf, p, cmd_size, - min(cmd_size, page_length + 4)); + min(cmd_size, xfer_size)); + kmem_free(p, bsize); } stmf_status_t @@ -1424,11 +1587,7 @@ cdb1 = task->task_cdb[1]; if (cdb0 == SCMD_INQUIRY) { /* Inquiry */ - uint8_t *p; - - p = (uint8_t *)kmem_zalloc(512, KM_SLEEP); - sbd_handle_inquiry(task, initial_dbuf, p, 512); - kmem_free(p, 512); + sbd_handle_inquiry(task, initial_dbuf); return; }
--- a/usr/src/uts/common/io/comstar/lu/stmf_sbd/stmf_sbd.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/comstar/lu/stmf_sbd/stmf_sbd.h Mon Jul 20 13:07:46 2009 -0400 @@ -130,7 +130,7 @@ * metadata is coming in from the correct zvol and not from a * clone. Has no meaning in any other case. */ - uint16_t sli_meta_fname_offset; + uint64_t sli_meta_fname_offset; /* * Data filename or the media filename when the metadata is in @@ -145,7 +145,8 @@ uint8_t sli_serial_size; uint8_t sli_rsvd1; uint8_t sli_device_id[20]; - uint8_t sli_rsvd2[256]; + uint64_t sli_mgmt_url_offset; + uint8_t sli_rsvd2[248]; /* * In case there is no separate meta, sli_meta_fname_offset wont @@ -169,6 +170,7 @@ #define SLI_ALIAS_VALID 0x0100 #define SLI_WRITEBACK_CACHE_DISABLE 0x0200 #define SLI_ZFS_META 0x0400 +#define SLI_MGMT_URL_VALID 0x0800 struct sbd_it_data; @@ -189,6 +191,7 @@ /* Metadata */ char *sl_alias; char *sl_meta_filename; /* If applicable */ + char *sl_mgmt_url; vnode_t *sl_meta_vp; vtype_t sl_meta_vtype; uint8_t sl_device_id[20]; /* 4(hdr) + 16(GUID) */ @@ -203,7 +206,8 @@ char sl_product_id[16]; char sl_revision[4]; uint32_t sl_data_fname_alloc_size; /* for an explicit alloc */ - uint32_t sl_alias_alloc_size; + uint16_t sl_alias_alloc_size; + uint16_t sl_mgmt_url_alloc_size; uint8_t sl_serial_no_alloc_size; uint64_t sl_meta_offset;
--- a/usr/src/uts/common/io/comstar/port/fct/discovery.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/comstar/port/fct/discovery.c Mon Jul 20 13:07:46 2009 -0400 @@ -2671,6 +2671,52 @@ rw_exit(&iport->iport_lock); } +void +fct_rls_cb(fct_i_cmd_t *icmd) +{ + fct_els_t *els = ICMD_TO_ELS(icmd); + uint8_t *resp; + fct_rls_cb_data_t *rls_cb_data = NULL; + fct_port_link_status_t *rls_resp; + fct_i_local_port_t *iport = ICMD_TO_IPORT(icmd); + + rls_cb_data = icmd->icmd_cb_private; + + if (!FCT_IS_ELS_ACC(icmd)) { + stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_rls_cb: " + "solicited RLS is not accepted - icmd/%p", icmd); + if (rls_cb_data) { + rls_cb_data->fct_els_res = FCT_FAILURE; + sema_v(&iport->iport_rls_sema); + } + return; + } + + if (!rls_cb_data) { + sema_v(&iport->iport_rls_sema); + return; + } + + resp = els->els_resp_payload; + + rls_cb_data = icmd->icmd_cb_private; + + /* Get the response and store it somewhere */ + rls_resp = (fct_port_link_status_t *)rls_cb_data->fct_link_status; + rls_resp->LinkFailureCount = BE_32(*((uint32_t *)(resp + 4))); + rls_resp->LossOfSyncCount = BE_32(*((uint32_t *)(resp + 8))); + rls_resp->LossOfSignalsCount = BE_32(*((uint32_t *)(resp + 12))); + rls_resp->PrimitiveSeqProtocolErrorCount = + BE_32(*((uint32_t *)(resp + 16))); + rls_resp->InvalidTransmissionWordCount = + BE_32(*((uint32_t *)(resp + 20))); + rls_resp->InvalidCRCCount = BE_32(*((uint32_t *)(resp + 24))); + + rls_cb_data->fct_els_res = FCT_SUCCESS; + sema_v(&iport->iport_rls_sema); + icmd->icmd_cb_private = NULL; +} + /* * For lookup functions, we move locking up one level */ @@ -2758,6 +2804,10 @@ page_format = 0x03 & page_buf[0]; page_portid = fct_netbuf_to_value(page_buf + 1, 3); + DTRACE_FC_2(rscn__receive, + fct_i_local_port_t, iport, + int, page_portid); + rw_enter(&iport->iport_lock, RW_READER); if (!page_format) { irp = fct_portid_to_portptr(iport, page_portid);
--- a/usr/src/uts/common/io/comstar/port/fct/fct.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/comstar/port/fct/fct.c Mon Jul 20 13:07:46 2009 -0400 @@ -53,6 +53,7 @@ static int fct_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *credp, int *rval); static int fct_fctiocmd(intptr_t data, int mode); +void fct_init_kstats(fct_i_local_port_t *iport); static dev_info_t *fct_dip; static struct cb_ops fct_cb_ops = { @@ -91,6 +92,7 @@ }; #define FCT_NAME "COMSTAR FCT" +#define FCT_MODULE_NAME "fct" extern struct mod_ops mod_driverops; static struct modldrv modldrv = { @@ -633,29 +635,111 @@ fct_get_port_stats(uint8_t *port_wwn, fc_tgt_hba_adapter_port_stats_t *port_stats, uint32_t *error_detail) { + int ret; fct_i_local_port_t *iport = fct_get_iport_per_wwn(port_wwn); + fct_port_link_status_t stat; + uint32_t buf_size = sizeof (fc_tgt_hba_adapter_port_stats_t); if (!iport) return (ENXIO); port_stats->version = FCT_HBA_ADAPTER_PORT_STATS_VERSION; + + if (iport->iport_port->port_info == NULL) { + *error_detail = FCTIO_FAILURE; + return (EIO); + } + ret = iport->iport_port->port_info(FC_TGT_PORT_RLS, + iport->iport_port, NULL, (uint8_t *)&stat, &buf_size); + if (ret != STMF_SUCCESS) { + *error_detail = FCTIO_FAILURE; + return (EIO); + } + + port_stats->SecondsSinceLastReset = 0; + port_stats->TxFrames = 0; + port_stats->TxWords = 0; + port_stats->RxFrames = 0; + port_stats->RxWords = 0; + port_stats->LIPCount = 0; + port_stats->NOSCount = 0; + port_stats->ErrorFrames = 0; + port_stats->DumpedFrames = 0; + port_stats->LinkFailureCount = stat.LinkFailureCount; + port_stats->LossOfSyncCount = stat.LossOfSyncCount; + port_stats->LossOfSignalCount = stat.LossOfSignalsCount; + port_stats->PrimitiveSeqProtocolErrCount = + stat.PrimitiveSeqProtocolErrorCount; + port_stats->InvalidTxWordCount = + stat.InvalidTransmissionWordCount; + port_stats->InvalidCRCCount = stat.InvalidCRCCount; + + return (ret); +} + +int +fct_get_link_status(uint8_t *port_wwn, uint64_t *dest_id, + fct_port_link_status_t *link_status, uint32_t *error_detail) +{ + fct_i_local_port_t *iport = fct_get_iport_per_wwn(port_wwn); + fct_i_remote_port_t *irp = NULL; + uint32_t buf_size = sizeof (fct_port_link_status_t); + stmf_status_t ret = 0; + int i; + fct_cmd_t *cmd = NULL; + + if (!iport) { + *error_detail = FCTIO_BADWWN; + return (ENXIO); + } + /* - * port_stats->SecondsSinceLastReset = ; - * port_stats->TxFrames = ; - * port_stats->TxWords = ; - * port_stats->RxFrames = ; - * port_stats->RxWords = ; - * port_stats->LIPCount = ; - * port_stats->NOSCount = ; - * port_stats->ErrorFrames = ; - * port_stats->DumpedFrames = ; - * port_stats->LinkFailureCount = ; - * port_stats->LossOfSyncCount = ; - * port_stats->LossOfSignalCount = ; - * port_stats->PrimitiveSeqProtocol = ; - * port_stats->InvalidTxWordCount = ; - * port_stats->InvalidCRCCount = ; + * If what we are requesting is zero or same as local port, + * then we use port_info() + */ + if (dest_id == NULL || *dest_id == iport->iport_link_info.portid) { + if (iport->iport_port->port_info == NULL) { + *error_detail = FCTIO_FAILURE; + return (EIO); + } + ret = iport->iport_port->port_info(FC_TGT_PORT_RLS, + iport->iport_port, NULL, + (uint8_t *)link_status, &buf_size); + if (ret == STMF_SUCCESS) { + return (0); + } else { + *error_detail = FCTIO_FAILURE; + return (EIO); + } + } + + /* + * For remote port, we will send RLS */ - return (0); + for (i = 0; i < rportid_table_size; i++) { + irp = iport->iport_rp_tb[i]; + while (irp) { + if (irp->irp_rp->rp_id == *dest_id && + irp->irp_flags & IRP_PLOGI_DONE) { + goto SEND_RLS_ELS; + } + irp = irp->irp_next; + } + } + return (ENXIO); + +SEND_RLS_ELS: + cmd = fct_create_solels(iport->iport_port, + irp->irp_rp, 0, ELS_OP_RLS, + 0, fct_rls_cb); + if (!cmd) + return (ENOMEM); + iport->iport_rls_cb_data.fct_link_status = link_status; + CMD_TO_ICMD(cmd)->icmd_cb_private = &iport->iport_rls_cb_data; + fct_post_to_solcmd_queue(iport->iport_port, cmd); + sema_p(&iport->iport_rls_sema); + if (iport->iport_rls_cb_data.fct_els_res != FCT_SUCCESS) + ret = EIO; + return (ret); } static int @@ -788,6 +872,19 @@ mutex_exit(&fct_global_mutex); break; } + case FCTIO_GET_LINK_STATUS: { + uint8_t *port_wwn = (uint8_t *)ibuf; + fct_port_link_status_t *link_status = + (fct_port_link_status_t *)obuf; + uint64_t *dest_id = abuf; + + mutex_enter(&fct_global_mutex); + ret = fct_get_link_status(port_wwn, dest_id, link_status, + &fctio->fctio_errno); + mutex_exit(&fct_global_mutex); + break; + } + default: break; } @@ -1018,6 +1115,7 @@ mutex_init(&iport->iport_worker_lock, NULL, MUTEX_DRIVER, NULL); cv_init(&iport->iport_worker_cv, NULL, CV_DRIVER, NULL); rw_init(&iport->iport_lock, NULL, RW_DRIVER, NULL); + sema_init(&iport->iport_rls_sema, 0, NULL, SEMA_DRIVER, NULL); /* Remote port mgmt */ iport->iport_rp_slots = (fct_i_remote_port_t **)kmem_zalloc( @@ -1088,6 +1186,8 @@ fct_iport_list = iport; mutex_exit(&fct_global_mutex); + fct_init_kstats(iport); + fct_log_local_port_event(port, ESC_SUNFC_PORT_ATTACH); return (FCT_SUCCESS); @@ -1169,6 +1269,7 @@ sizeof (fct_i_remote_port_t *)); rw_destroy(&iport->iport_lock); cv_destroy(&iport->iport_worker_cv); + sema_destroy(&iport->iport_rls_sema); mutex_destroy(&iport->iport_worker_lock); ddi_taskq_destroy(iport->iport_worker_taskq); if (iport->iport_rp_tb) { @@ -1176,6 +1277,10 @@ sizeof (fct_i_remote_port_t *)); } + if (iport->iport_kstat_portstat) { + kstat_delete(iport->iport_kstat_portstat); + } + fct_log_local_port_event(port, ESC_SUNFC_PORT_DETACH); return (FCT_SUCCESS); @@ -2275,6 +2380,16 @@ kmem_zalloc(els->els_req_size, KM_SLEEP); p[7] = FC_SCR_FULL_REGISTRATION; break; + case ELS_OP_RLS: + els->els_resp_alloc_size = els->els_resp_size = 28; + els->els_resp_payload = (uint8_t *) + kmem_zalloc(els->els_resp_size, KM_SLEEP); + els->els_req_alloc_size = els->els_req_size = 8; + p = els->els_req_payload = (uint8_t *) + kmem_zalloc(els->els_req_size, KM_SLEEP); + ptid = PORT_TO_IPORT(port)->iport_link_info.portid; + fct_value_to_netbuf(ptid, els->els_req_payload + 5, 3); + break; default: ASSERT(0); @@ -2737,6 +2852,12 @@ fct_queue_cmd_for_termination(cmd, FCT_NOT_LOGGED_IN); return; } + + DTRACE_FC_3(abts__receive, + fct_cmd_t, cmd, + fct_local_port_t, port, + fct_i_remote_port_t, irp); + cmd->cmd_rp = irp->irp_rp; /* @@ -3339,3 +3460,82 @@ from_ptr[0], from_ptr[1], from_ptr[2], from_ptr[3], from_ptr[4], from_ptr[5], from_ptr[6], from_ptr[7]); } + +static int +fct_update_stats(kstat_t *ks, int rw) +{ + fct_i_local_port_t *iport; + fct_port_stat_t *port_kstat; + fct_port_link_status_t stat; + uint32_t buf_size = sizeof (stat); + int ret; + + if (rw == KSTAT_WRITE) + return (EACCES); + + iport = (fct_i_local_port_t *)ks->ks_private; + port_kstat = (fct_port_stat_t *)ks->ks_data; + + if (iport->iport_port->port_info == NULL) { + return (EIO); + } + ret = iport->iport_port->port_info(FC_TGT_PORT_RLS, + iport->iport_port, NULL, (uint8_t *)&stat, &buf_size); + if (ret != STMF_SUCCESS) { + return (EIO); + } + + port_kstat->link_failure_cnt.value.ui32 = + stat.LinkFailureCount; + port_kstat->loss_of_sync_cnt.value.ui32 = + stat.LossOfSyncCount; + port_kstat->loss_of_signals_cnt.value.ui32 = + stat.LossOfSignalsCount; + port_kstat->prim_seq_protocol_err_cnt.value.ui32 = + stat.PrimitiveSeqProtocolErrorCount; + port_kstat->invalid_tx_word_cnt.value.ui32 = + stat.InvalidTransmissionWordCount; + port_kstat->invalid_crc_cnt.value.ui32 = + stat.InvalidCRCCount; + + return (0); +} + +void +fct_init_kstats(fct_i_local_port_t *iport) +{ + kstat_t *ks; + fct_port_stat_t *port_kstat; + char name[256]; + + if (iport->iport_alias) + (void) sprintf(name, "iport_%s", iport->iport_alias); + else + (void) sprintf(name, "iport_%"PRIxPTR"", (uintptr_t)iport); + ks = kstat_create(FCT_MODULE_NAME, 0, name, "rawdata", + KSTAT_TYPE_NAMED, sizeof (fct_port_stat_t) / sizeof (kstat_named_t), + 0); + + if (ks == NULL) { + return; + } + port_kstat = (fct_port_stat_t *)ks->ks_data; + + iport->iport_kstat_portstat = ks; + kstat_named_init(&port_kstat->link_failure_cnt, + "Link_failure_cnt", KSTAT_DATA_UINT32); + kstat_named_init(&port_kstat->loss_of_sync_cnt, + "Loss_of_sync_cnt", KSTAT_DATA_UINT32); + kstat_named_init(&port_kstat->loss_of_signals_cnt, + "Loss_of_signals_cnt", KSTAT_DATA_UINT32); + kstat_named_init(&port_kstat->prim_seq_protocol_err_cnt, + "Prim_seq_protocol_err_cnt", KSTAT_DATA_UINT32); + kstat_named_init(&port_kstat->invalid_tx_word_cnt, + "Invalid_tx_word_cnt", KSTAT_DATA_UINT32); + kstat_named_init(&port_kstat->invalid_crc_cnt, + "Invalid_crc_cnt", KSTAT_DATA_UINT32); + ks->ks_update = fct_update_stats; + ks->ks_private = (void *)iport; + kstat_install(ks); + +}
--- a/usr/src/uts/common/io/comstar/port/fct/fct_impl.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/comstar/port/fct/fct_impl.h Mon Jul 20 13:07:46 2009 -0400 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _FCT_IMPL_H @@ -154,6 +154,14 @@ } fct_i_remote_port_t; /* + * structure used for fct_rls_cb() callback private data + */ +typedef struct fct_rls_cb_data { + struct fct_port_link_status *fct_link_status; + fct_status_t fct_els_res; +} fct_rls_cb_data_t; + +/* * irp flags */ #define IRP_PLOGI_DONE 0x0001 @@ -266,7 +274,9 @@ /* rpwe = remote port with pending els(es) */ fct_i_remote_port_t *iport_rpwe_head; fct_i_remote_port_t *iport_rpwe_tail; - + kstat_t *iport_kstat_portstat; + ksema_t iport_rls_sema; + fct_rls_cb_data_t iport_rls_cb_data; } fct_i_local_port_t; #define IPORT_FLOGI_DONE(iport) PORT_FLOGI_DONE(&(iport)->iport_link_info) @@ -423,6 +433,7 @@ void fct_gcs_cb(fct_i_cmd_t *icmd); void fct_gft_cb(fct_i_cmd_t *icmd); void fct_gspn_cb(fct_i_cmd_t *icmd); +void fct_rls_cb(fct_i_cmd_t *icmd); disc_action_t fct_process_link_init(fct_i_local_port_t *iport); #ifdef __cplusplus
--- a/usr/src/uts/common/io/comstar/port/qlt/qlt.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/comstar/port/qlt/qlt.c Mon Jul 20 13:07:46 2009 -0400 @@ -888,6 +888,64 @@ FCHBA_MODEL_DESCRIPTION_LEN, "%s", qlt->nvram->model_name); } +/* ARGSUSED */ +fct_status_t +qlt_info(uint32_t cmd, fct_local_port_t *port, + void *arg, uint8_t *buf, uint32_t *bufsizep) +{ + qlt_state_t *qlt = (qlt_state_t *)port->port_fca_private; + mbox_cmd_t *mcp; + fct_status_t ret = FCT_SUCCESS; + uint8_t *p; + fct_port_link_status_t *link_status; + + switch (cmd) { + case FC_TGT_PORT_RLS: + if ((*bufsizep) < sizeof (fct_port_link_status_t)) { + ret = FCT_FAILURE; + break; + } + /* send mailbox command to get link status */ + mcp = qlt_alloc_mailbox_command(qlt, 156); + if (mcp == NULL) { + ret = FCT_ALLOC_FAILURE; + break; + } + + /* GET LINK STATUS count */ + mcp->to_fw[0] = 0x6d; + mcp->to_fw[8] = 156/4; + mcp->to_fw_mask |= BIT_1 | BIT_8; + mcp->from_fw_mask |= BIT_1 | BIT_2; + + ret = qlt_mailbox_command(qlt, mcp); + if (ret != QLT_SUCCESS) { + qlt_free_mailbox_command(qlt, mcp); + break; + } + qlt_dmem_dma_sync(mcp->dbuf, DDI_DMA_SYNC_FORCPU); + + p = mcp->dbuf->db_sglist[0].seg_addr; + link_status = (fct_port_link_status_t *)buf; + link_status->LinkFailureCount = LE_32(*((uint32_t *)p)); + link_status->LossOfSyncCount = LE_32(*((uint32_t *)(p + 4))); + link_status->LossOfSignalsCount = LE_32(*((uint32_t *)(p + 8))); + link_status->PrimitiveSeqProtocolErrorCount = + LE_32(*((uint32_t *)(p + 12))); + link_status->InvalidTransmissionWordCount = + LE_32(*((uint32_t *)(p + 16))); + link_status->InvalidCRCCount = + LE_32(*((uint32_t *)(p + 20))); + + qlt_free_mailbox_command(qlt, mcp); + break; + default: + ret = FCT_FAILURE; + break; + } + return (ret); +} + fct_status_t qlt_port_start(caddr_t arg) { @@ -940,6 +998,7 @@ port->port_ctl = qlt_ctl; port->port_flogi_xchg = qlt_do_flogi; port->port_populate_hba_details = qlt_populate_hba_fru_details; + port->port_info = qlt_info; if (fct_register_local_port(port) != FCT_SUCCESS) { goto qlt_pstart_fail_2_5;
--- a/usr/src/uts/common/io/fibre-channel/impl/fp.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/fibre-channel/impl/fp.c Mon Jul 20 13:07:46 2009 -0400 @@ -2940,7 +2940,8 @@ p2p_info.d_id, pd_recepient, KM_NOSLEEP); FP_DTRACE(FP_NHEAD1(2, 0), "Exiting fp_port_startup;" - " P2P port=%p pd=%p", port, pd); + " P2P port=%p pd=%p fp %x pd %x", port, pd, + port->fp_port_id.port_id, p2p_info.d_id); mutex_enter(&port->fp_mutex); return (FC_SUCCESS); } @@ -3292,7 +3293,9 @@ break; case FC_PKT_FS_RJT: - if (pkt->pkt_reason == FC_REASON_FS_LOGICAL_BUSY) { + if ((pkt->pkt_reason == FC_REASON_FS_LOGICAL_BUSY) || + ((pkt->pkt_reason == FC_REASON_FS_CMD_UNABLE) && + (pkt->pkt_expln == 0x00))) { cmd->cmd_retry_interval = fp_retry_delay; rval = fp_retry_cmd(pkt); } @@ -5888,6 +5891,8 @@ port->fp_port_id.port_id = s_id; mutex_exit(&port->fp_mutex); + FP_TRACE(FP_NHEAD1(1, 0), "fp_flogi_intr: fp %x" + "pd %x", port->fp_port_id.port_id, d_id); pd = fctl_create_remote_port(port, &nwwn, &dwwn, d_id, PD_PLOGI_INITIATOR, KM_NOSLEEP); @@ -6116,6 +6121,8 @@ if ((pd = pkt->pkt_pd) == NULL) { pd = fctl_get_remote_port_by_pwwn(port, &pwwn); if (pd == NULL) { + FP_TRACE(FP_NHEAD2(9, 0), "fp_plogi_intr: fp %x pd %x", + port->fp_port_id.port_id, d_id); pd = fctl_create_remote_port(port, &nwwn, &pwwn, d_id, PD_PLOGI_INITIATOR, KM_NOSLEEP); if (pd == NULL) { @@ -12091,6 +12098,8 @@ do_acc = (port->fp_statec_busy == 0) ? 1 : 0; mutex_exit(&port->fp_mutex); + FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_acc_init fp %x, pd %x", + port->fp_port_id.port_id, buf->ub_frame.s_id); pd = fctl_create_remote_port(port, &req->node_ww_name, &req->nport_ww_name, buf->ub_frame.s_id, PD_PLOGI_RECEPIENT, sleep); @@ -12774,6 +12783,11 @@ ASSERT(!MUTEX_HELD(&port->fp_mutex)); + if (ns_cmd->ns_cmd_code == NS_GA_NXT) { + FP_TRACE(FP_NHEAD1(1, 0), "fp_ns_query GA_NXT fp %x pd %x", + port->fp_port_id.port_id, ns_cmd->ns_gan_sid); + } + if (ns_cmd->ns_cmd_size == 0) { return (FC_FAILURE); } @@ -12958,8 +12972,11 @@ } - FP_TRACE(FP_NHEAD1(4, 0), "NS failure; pkt state=%x reason=%x", - pkt->pkt_state, pkt->pkt_reason); + FP_TRACE(FP_NHEAD2(9, 0), "%x NS failure pkt state=%x" + "reason=%x, expln=%x, NSCMD=%04X, NSRSP=%04X", + port->fp_port_id.port_id, pkt->pkt_state, + pkt->pkt_reason, pkt->pkt_expln, + cmd_hdr.ct_cmdrsp, resp_hdr.ct_cmdrsp); (void) fp_common_intr(pkt, 1); @@ -13046,9 +13063,8 @@ my_did = (d_id.port_id == port->fp_port_id.port_id) ? 1 : 0; mutex_exit(&port->fp_mutex); - FP_TRACE(FP_NHEAD1(1, 0), "GAN response; port=%p, d_id=%x", port, - d_id.port_id); - + FP_TRACE(FP_NHEAD1(1, 0), "GAN response; port=%p, fp %x pd %x", port, + port->fp_port_id.port_id, d_id.port_id); if (my_did == 0) { la_wwn_t pwwn; la_wwn_t nwwn; @@ -13086,6 +13102,8 @@ DDI_DEV_AUTOINCR); if (ns_cmd->ns_flags & FCTL_NS_CREATE_DEVICE && pd == NULL) { + FP_TRACE(FP_NHEAD1(1, 0), "fp %x gan_hander create" + "pd %x", port->fp_port_id.port_id, d_id.port_id); pd = fctl_create_remote_port(port, &nwwn, &pwwn, d_id.port_id, PD_PLOGI_INITIATOR, KM_NOSLEEP); }
--- a/usr/src/uts/common/io/fibre-channel/ulp/fcsm.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/fibre-channel/ulp/fcsm.c Mon Jul 20 13:07:46 2009 -0400 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -39,7 +39,7 @@ #include <sys/fibre-channel/ulp/fcsm.h> /* Definitions */ -#define FCSM_VERSION "1.26" +#define FCSM_VERSION "1.27" #define FCSM_NAME_VERSION "SunFC FCSM v" FCSM_VERSION @@ -1624,45 +1624,45 @@ } case FCSMIO_ADAPTER_LIST: { - fc_hba_list_t *list; - int count; - - if ((fcio->fcio_xfer != FCIO_XFER_RW) || + fc_hba_list_t *list; + int count; + + if ((fcio->fcio_xfer != FCIO_XFER_RW) || (fcio->fcio_olen == 0) || (fcio->fcio_obuf == 0)) { - retval = EINVAL; - break; - } - - list = kmem_zalloc(fcio->fcio_olen, KM_SLEEP); - - if (ddi_copyin(fcio->fcio_obuf, list, fcio->fcio_olen, mode)) { - retval = EFAULT; - break; - } - list->version = FC_HBA_LIST_VERSION; - - if (fcio->fcio_olen < MAXPATHLEN * list->numAdapters) { - retval = EFAULT; - break; - } - - count = fc_ulp_get_adapter_paths((char *)list->hbaPaths, - list->numAdapters); - if (count < 0) { /* Did something go wrong? */ - FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, - "Error fetching adapter list.")); - retval = ENXIO; + retval = EINVAL; + break; + } + + list = kmem_zalloc(fcio->fcio_olen, KM_SLEEP); + + if (ddi_copyin(fcio->fcio_obuf, list, fcio->fcio_olen, mode)) { + retval = EFAULT; + break; + } + list->version = FC_HBA_LIST_VERSION; + + if (fcio->fcio_olen < MAXPATHLEN * list->numAdapters) { + retval = EFAULT; + break; + } + + count = fc_ulp_get_adapter_paths((char *)list->hbaPaths, + list->numAdapters); + if (count < 0) { /* Did something go wrong? */ + FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, + "Error fetching adapter list.")); + retval = ENXIO; + kmem_free(list, fcio->fcio_olen); + break; + } + /* Sucess (or short buffer) */ + list->numAdapters = count; + if (ddi_copyout(list, fcio->fcio_obuf, + fcio->fcio_olen, mode)) { + retval = EFAULT; + } kmem_free(list, fcio->fcio_olen); break; - } - /* Sucess (or short buffer) */ - list->numAdapters = count; - if (ddi_copyout(list, fcio->fcio_obuf, - fcio->fcio_olen, mode)) { - retval = EFAULT; - } - kmem_free(list, fcio->fcio_olen); - break; } default: @@ -2752,10 +2752,10 @@ ASSERT(fcio != NULL); if (pkt->pkt_state != FC_PKT_SUCCESS) { - fcsm_display(CE_WARN, SM_LOG, cmd->cmd_fcsm, pkt, + FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, cmd->cmd_fcsm, pkt, "ct_intr: CT command <0x%x> to did 0x%x failed", ((fc_ct_aiu_t *)fcio->fcio_ibuf)->aiu_header.ct_cmdrsp, - pkt->pkt_cmd_fhdr.d_id); + pkt->pkt_cmd_fhdr.d_id)); } else { /* Get the CT response payload */ FCSM_REP_RD(pkt->pkt_resp_acc, fcio->fcio_obuf, @@ -3249,9 +3249,9 @@ fcsm = cmd->cmd_fcsm; ASSERT(fcsm != NULL); - fcsm_display(CE_WARN, SM_LOG, cmd->cmd_fcsm, pkt, + FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, cmd->cmd_fcsm, pkt, "fc packet to DID 0x%x failed for pkt 0x%p", - pkt->pkt_cmd_fhdr.d_id, pkt); + pkt->pkt_cmd_fhdr.d_id, pkt)); mutex_enter(&fcsm->sm_mutex); if (fcsm->sm_flags & FCSM_LINK_DOWN) {
--- a/usr/src/uts/common/io/hxge/hxge.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/hxge/hxge.h Mon Jul 20 13:07:46 2009 -0400 @@ -18,6 +18,7 @@ * * CDDL HEADER END */ + /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. @@ -397,6 +398,7 @@ uint32_t hxge_port_rcr_size; uint32_t hxge_port_tx_ring_size; + kmutex_t vmac_lock; kmutex_t pio_lock; hxge_timeout timeout;
--- a/usr/src/uts/common/io/hxge/hxge_hw.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/hxge/hxge_hw.c Mon Jul 20 13:07:46 2009 -0400 @@ -111,14 +111,13 @@ { p_hxge_ldv_t ldvp = (p_hxge_ldv_t)arg1; p_hxge_t hxgep = (p_hxge_t)arg2; - uint_t serviced = DDI_INTR_UNCLAIMED; uint8_t ldv; hpi_handle_t handle; p_hxge_ldgv_t ldgvp; p_hxge_ldg_t ldgp, t_ldgp; p_hxge_ldv_t t_ldvp; uint32_t vector0 = 0, vector1 = 0; - int i, j, nldvs, nintrs = 1; + int j, nldvs; hpi_status_t rs = HPI_SUCCESS; /* @@ -130,23 +129,20 @@ HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intr")); - if (!(hxgep->drv_state & STATE_HW_INITIALIZED)) { + if (hxgep->hxge_mac_state != HXGE_MAC_STARTED) { HXGE_ERROR_MSG((hxgep, INT_CTL, - "<== hxge_intr: not initialized 0x%x", serviced)); - return (serviced); + "<== hxge_intr: not initialized")); + return (DDI_INTR_UNCLAIMED); } ldgvp = hxgep->ldgvp; HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intr: ldgvp $%p", ldgvp)); - if (ldvp == NULL && ldgvp) { + if (ldvp == NULL && ldgvp) t_ldvp = ldvp = ldgvp->ldvp; - } - - if (ldvp) { + if (ldvp) ldgp = t_ldgp = ldvp->ldgp; - } HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intr: " "ldgvp $%p ldvp $%p ldgp $%p", ldgvp, ldvp, ldgp)); @@ -167,65 +163,62 @@ handle = HXGE_DEV_HPI_HANDLE(hxgep); t_ldgp = ldgp; t_ldvp = ldgp->ldvp; - nldvs = ldgp->nldvs; HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intr: #ldvs %d #intrs %d", nldvs, ldgvp->ldg_intrs)); - - serviced = DDI_INTR_CLAIMED; - for (i = 0; i < nintrs; i++, t_ldgp++) { - HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intr(%d): #ldvs %d " - " #intrs %d", i, nldvs, nintrs)); + HXGE_DEBUG_MSG((hxgep, INT_CTL, + "==> hxge_intr(%d): #ldvs %d", i, nldvs)); - /* Get this group's flag bits. */ - t_ldgp->interrupted = B_FALSE; - rs = hpi_ldsv_ldfs_get(handle, t_ldgp->ldg, &vector0, &vector1); - if (rs) { - continue; - } + /* + * Get this group's flag bits. + */ + t_ldgp->interrupted = B_FALSE; + rs = hpi_ldsv_ldfs_get(handle, t_ldgp->ldg, &vector0, &vector1); + if (rs != HPI_SUCCESS) + return (DDI_INTR_UNCLAIMED); - if (!vector0 && !vector1) { - HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intr: " - "no interrupts on group %d", t_ldgp->ldg)); - continue; - } + if (!vector0 && !vector1) { + HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intr: " + "no interrupts on group %d", t_ldgp->ldg)); + return (DDI_INTR_UNCLAIMED); + } - HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intr: " - "vector0 0x%llx vector1 0x%llx", vector0, vector1)); + HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intr: " + "vector0 0x%llx vector1 0x%llx", vector0, vector1)); - t_ldgp->interrupted = B_TRUE; - nldvs = t_ldgp->nldvs; + t_ldgp->interrupted = B_TRUE; + nldvs = t_ldgp->nldvs; - for (j = 0; j < nldvs; j++, t_ldvp++) { - /* - * Call device's handler if flag bits are on. - */ - ldv = t_ldvp->ldv; - if ((LDV_ON(ldv, vector0) | (LDV_ON(ldv, vector1)))) { - HXGE_DEBUG_MSG((hxgep, INT_CTL, - "==> hxge_intr: calling device %d" - " #ldvs %d #intrs %d", j, nldvs, nintrs)); - (void) (t_ldvp->ldv_intr_handler)( - (caddr_t)t_ldvp, arg2); - } + /* + * Process all devices that share this group. + */ + for (j = 0; j < nldvs; j++, t_ldvp++) { + /* + * Call device's handler if flag bits are on. + */ + ldv = t_ldvp->ldv; + if ((LDV_ON(ldv, vector0) | (LDV_ON(ldv, vector1)))) { + HXGE_DEBUG_MSG((hxgep, INT_CTL, + "==> hxge_intr: calling device %d" + " #ldvs %d #intrs %d", j, nldvs, nintrs)); + (void) (t_ldvp->ldv_intr_handler)( + (caddr_t)t_ldvp, arg2); } } - t_ldgp = ldgp; - for (i = 0; i < nintrs; i++, t_ldgp++) { - /* rearm group interrupts */ - if (t_ldgp->interrupted) { - HXGE_DEBUG_MSG((hxgep, INT_CTL, - "==> hxge_intr: arm group %d", t_ldgp->ldg)); - (void) hpi_intr_ldg_mgmt_set(handle, t_ldgp->ldg, - t_ldgp->arm, t_ldgp->ldg_timer); - } + /* + * Re-arm group interrupts + */ + if (t_ldgp->interrupted) { + HXGE_DEBUG_MSG((hxgep, INT_CTL, + "==> hxge_intr: arm group %d", t_ldgp->ldg)); + (void) hpi_intr_ldg_mgmt_set(handle, t_ldgp->ldg, + t_ldgp->arm, t_ldgp->ldg_timer); } - HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_intr: serviced 0x%x", - serviced)); - return (serviced); + HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_intr")); + return (DDI_INTR_CLAIMED); } hxge_status_t @@ -338,7 +331,6 @@ } HXGE_FM_REPORT_ERROR(hxgep, NULL, HXGE_FM_EREPORT_PEU_ERR); - return (HXGE_OK); } @@ -351,10 +343,9 @@ p_hxge_ldg_t ldgp = NULL; hpi_handle_t handle; dev_err_stat_t estat; - uint_t serviced = DDI_INTR_UNCLAIMED; if ((arg1 == NULL) && (arg2 == NULL)) { - return (serviced); + return (DDI_INTR_UNCLAIMED); } if ((arg2 == NULL) || @@ -375,12 +366,11 @@ "arg2 $%p arg1 $%p", hxgep, ldvp)); return (DDI_INTR_UNCLAIMED); } - /* - * Get the logical device state if the function uses interrupt. - */ } - /* This interrupt handler is for system error interrupts. */ + /* + * This interrupt handler is for system error interrupts. + */ handle = HXGE_DEV_HPI_HANDLE(hxgep); estat.value = 0; (void) hpi_fzc_sys_err_stat_get(handle, &estat); @@ -417,8 +407,6 @@ "==> hxge_syserr_intr: device error - unknown")); } - serviced = DDI_INTR_CLAIMED; - if ((ldgp != NULL) && (ldvp != NULL) && (ldgp->nldvs == 1) && !ldvp->use_timer) { (void) hpi_intr_ldg_mgmt_set(handle, ldgp->ldg, @@ -426,7 +414,7 @@ } HXGE_DEBUG_MSG((hxgep, SYSERR_CTL, "<== hxge_syserr_intr")); - return (serviced); + return (DDI_INTR_CLAIMED); } void
--- a/usr/src/uts/common/io/hxge/hxge_kstats.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/hxge/hxge_kstats.c Mon Jul 20 13:07:46 2009 -0400 @@ -1234,13 +1234,18 @@ val = 0; break; + case ETHER_STAT_ADV_CAP_10GFDX: + case ETHER_STAT_CAP_10GFDX: + case ETHER_STAT_LP_CAP_10GFDX: + val = 0; + break; + default: /* * Shouldn't reach here... */ cmn_err(CE_WARN, "hxge_m_stat: unrecognized parameter value = 0x%x", stat); - return (ENOTSUP); } *value = val;
--- a/usr/src/uts/common/io/hxge/hxge_main.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/hxge/hxge_main.c Mon Jul 20 13:07:46 2009 -0400 @@ -34,11 +34,7 @@ * (This PSARC case is limited to MSI-X vectors * and SPARC platforms only). */ -#if defined(_BIG_ENDIAN) uint32_t hxge_msi_enable = 2; -#else -uint32_t hxge_msi_enable = 2; -#endif /* * Globals: tunable parameters (/etc/system or adb) @@ -911,6 +907,8 @@ */ MUTEX_INIT(hxgep->genlock, NULL, MUTEX_DRIVER, (void *) hxgep->interrupt_cookie); + MUTEX_INIT(&hxgep->vmac_lock, NULL, + MUTEX_DRIVER, (void *) hxgep->interrupt_cookie); MUTEX_INIT(&hxgep->ouraddr_lock, NULL, MUTEX_DRIVER, (void *) hxgep->interrupt_cookie); RW_INIT(&hxgep->filter_lock, NULL, @@ -935,6 +933,7 @@ { HXGE_DEBUG_MSG((hxgep, DDI_CTL, "==> hxge_destroy_mutexes")); RW_DESTROY(&hxgep->filter_lock); + MUTEX_DESTROY(&hxgep->vmac_lock); MUTEX_DESTROY(&hxgep->ouraddr_lock); MUTEX_DESTROY(hxgep->genlock); MUTEX_DESTROY(&hxgep->pio_lock); @@ -2646,6 +2645,7 @@ * Fill in the handle for the transmit. */ MUTEX_ENTER(&ring->lock); + rhp->started = B_TRUE; ring->ring_handle = rhp->ring_handle; MUTEX_EXIT(&ring->lock); @@ -2667,6 +2667,7 @@ MUTEX_ENTER(&ring->lock); ring->ring_handle = (mac_ring_handle_t)NULL; + rhp->started = B_FALSE; MUTEX_EXIT(&ring->lock); }
--- a/usr/src/uts/common/io/hxge/hxge_rxdma.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/hxge/hxge_rxdma.c Mon Jul 20 13:07:46 2009 -0400 @@ -25,6 +25,8 @@ #include <hxge_impl.h> #include <hxge_rxdma.h> +#include <hpi.h> +#include <hpi_vir.h> /* * Number of blocks to accumulate before re-enabling DMA @@ -258,18 +260,20 @@ return (HXGE_ERROR | rs); } - /* Enable the DMA */ - rs = hpi_rxdma_cfg_rdc_enable(handle, channel); - if (rs != HPI_SUCCESS) { - return (HXGE_ERROR | rs); - } - /* Kick the DMA engine */ hpi_rxdma_rdc_rbr_kick(handle, channel, n_init_kick); /* Clear the rbr empty bit */ (void) hpi_rxdma_channel_rbr_empty_clear(handle, channel); + /* + * Enable the DMA + */ + rs = hpi_rxdma_cfg_rdc_enable(handle, channel); + if (rs != HPI_SUCCESS) { + return (HXGE_ERROR | rs); + } + HXGE_DEBUG_MSG((hxgep, DMA_CTL, "<== hxge_enable_rxdma_channel")); return (HXGE_OK); @@ -737,8 +741,10 @@ { HXGE_DEBUG_MSG((hxgep, RX_CTL, "==> hxge_rxdma_stop")); + MUTEX_ENTER(&hxgep->vmac_lock); (void) hxge_rx_vmac_disable(hxgep); (void) hxge_rxdma_hw_mode(hxgep, HXGE_DMA_STOP); + MUTEX_EXIT(&hxgep->vmac_lock); HXGE_DEBUG_MSG((hxgep, RX_CTL, "<== hxge_rxdma_stop")); } @@ -752,7 +758,9 @@ (void) hxge_uninit_rxdma_channels(hxgep); (void) hxge_init_rxdma_channels(hxgep); + MUTEX_ENTER(&hxgep->vmac_lock); (void) hxge_rx_vmac_enable(hxgep); + MUTEX_EXIT(&hxgep->vmac_lock); HXGE_DEBUG_MSG((hxgep, RX_CTL, "<== hxge_rxdma_stop_reinit")); } @@ -1132,7 +1140,6 @@ uint8_t channel; hpi_handle_t handle; rdc_stat_t cs; - uint_t serviced = DDI_INTR_UNCLAIMED; p_rx_rcr_ring_t ring; mblk_t *mp = NULL; @@ -1146,13 +1153,6 @@ hxgep = ldvp->hxgep; } - /* - * If the interface is not started, just swallow the interrupt - * for the logical device and don't rearm it. - */ - if (hxgep->hxge_mac_state != HXGE_MAC_STARTED) - return (DDI_INTR_CLAIMED); - HXGE_DEBUG_MSG((hxgep, RX_INT_CTL, "==> hxge_rx_intr: arg2 $%p arg1 $%p", hxgep, ldvp)); @@ -1175,71 +1175,61 @@ MUTEX_ENTER(&ring->lock); - /* - * If the channel is not started, then we are not - * ready to process packets. - */ - if (!rhp->started) { - MUTEX_EXIT(&ring->lock); - return (DDI_INTR_CLAIMED); - } - - RXDMA_REG_READ64(handle, RDC_STAT, channel, &cs.value); - cs.bits.ptrread = 0; - cs.bits.pktread = 0; - RXDMA_REG_WRITE64(handle, RDC_STAT, channel, cs.value); - - HXGE_DEBUG_MSG((hxgep, RX_INT_CTL, "==> hxge_rx_intr:channel %d " - "cs 0x%016llx rcrto 0x%x rcrthres %x", - channel, cs.value, cs.bits.rcr_to, cs.bits.rcr_thres)); - - /* - * Process packets, if we are not in polling mode. The MAC layer - * under load will be operating in polling mode for RX traffic. - */ - if (ring->poll_flag == 0) { - mp = hxge_rx_pkts(hxgep, ldvp->vdma_index, ldvp, ring, cs, -1); - } - serviced = DDI_INTR_CLAIMED; - - /* error events. */ - if (cs.value & RDC_STAT_ERROR) { - (void) hxge_rx_err_evnts(hxgep, ldvp->vdma_index, ldvp, cs); + if (!ring->poll_flag) { + RXDMA_REG_READ64(handle, RDC_STAT, channel, &cs.value); + cs.bits.ptrread = 0; + cs.bits.pktread = 0; + RXDMA_REG_WRITE64(handle, RDC_STAT, channel, cs.value); + + /* + * Process packets, if we are not in polling mode, the ring is + * started and the interface is started. The MAC layer under + * load will be operating in polling mode for RX traffic. + */ + if ((rhp->started) && + (hxgep->hxge_mac_state == HXGE_MAC_STARTED)) { + mp = hxge_rx_pkts(hxgep, ldvp->vdma_index, + ldvp, ring, cs, -1); + } + + /* Process error events. */ + if (cs.value & RDC_STAT_ERROR) { + MUTEX_EXIT(&ring->lock); + (void) hxge_rx_err_evnts(hxgep, channel, ldvp, cs); + MUTEX_ENTER(&ring->lock); + } + + /* + * Enable the mailbox update interrupt if we want to use + * mailbox. We probably don't need to use mailbox as it only + * saves us one pio read. Also write 1 to rcrthres and + * rcrto to clear these two edge triggered bits. + */ + cs.value &= RDC_STAT_WR1C; + cs.bits.mex = 1; + cs.bits.ptrread = 0; + cs.bits.pktread = 0; + RXDMA_REG_WRITE64(handle, RDC_STAT, channel, cs.value); + + if (ldgp->nldvs == 1) { + /* + * Re-arm the group. + */ + (void) hpi_intr_ldg_mgmt_set(handle, ldgp->ldg, B_TRUE, + ldgp->ldg_timer); + } + } else if ((ldgp->nldvs == 1) && (ring->poll_flag)) { + /* + * Disarm the group, if we are not a shared interrupt. + */ + (void) hpi_intr_ldg_mgmt_set(handle, ldgp->ldg, B_FALSE, 0); + } else if (ring->poll_flag) { + /* + * Mask-off this device from the group. + */ + (void) hpi_intr_mask_set(handle, ldvp->ldv, 1); } - /* - * Enable the mailbox update interrupt if we want to use mailbox. We - * probably don't need to use mailbox as it only saves us one pio read. - * Also write 1 to rcrthres and rcrto to clear these two edge triggered - * bits. - */ - cs.value &= RDC_STAT_WR1C; - cs.bits.mex = 1; - cs.bits.ptrread = 0; - cs.bits.pktread = 0; - RXDMA_REG_WRITE64(handle, RDC_STAT, channel, cs.value); - - /* - * Rearm this logical group if this is a single device group. - */ - if (ring->poll_flag) { - if (ldgp->nldvs == 1) { - ld_intr_mgmt_t mgm; - - mgm.value = 0; - mgm.bits.arm = 0; - HXGE_REG_WR32(handle, - LD_INTR_MGMT + LDSV_OFFSET(ldgp->ldg), mgm.value); - } - } else if (ldgp->nldvs == 1) { - ld_intr_mgmt_t mgm; - - mgm.value = 0; - mgm.bits.arm = 1; - mgm.bits.timer = ldgp->ldg_timer; - HXGE_REG_WR32(handle, - LD_INTR_MGMT + LDSV_OFFSET(ldgp->ldg), mgm.value); - } MUTEX_EXIT(&ring->lock); /* @@ -1250,9 +1240,8 @@ ring->rcr_gen_num); } - HXGE_DEBUG_MSG((hxgep, RX_INT_CTL, - "<== hxge_rx_intr: serviced %d", serviced)); - return (serviced); + HXGE_DEBUG_MSG((NULL, RX_INT_CTL, "<== hxge_rx_intr")); + return (DDI_INTR_CLAIMED); } /* @@ -1268,26 +1257,34 @@ p_hxge_ldg_t ldgp; if (ring_handle == NULL) { - return (0); + ASSERT(ring_handle != NULL); + return (1); } + hxgep = ring_handle->hxgep; ringp = hxgep->rx_rcr_rings->rcr_rings[ring_handle->index]; MUTEX_ENTER(&ringp->lock); + /* + * Are we already polling ? + */ + if (ringp->poll_flag) { + MUTEX_EXIT(&ringp->lock); + return (1); + } + ldgp = ringp->ldgp; if (ldgp == NULL) { MUTEX_EXIT(&ringp->lock); - return (0); + return (1); } /* * Enable polling */ - if (ringp->poll_flag == 0) { - ringp->poll_flag = 1; - } + ringp->poll_flag = B_TRUE; MUTEX_EXIT(&ringp->lock); return (0); @@ -1304,6 +1301,7 @@ p_hxge_t hxgep; if (ring_handle == NULL) { + ASSERT(ring_handle != NULL); return (0); } @@ -1318,26 +1316,12 @@ if (ringp->poll_flag) { hpi_handle_t handle; rdc_stat_t cs; - uint8_t channel; p_hxge_ldg_t ldgp; /* * Get the control and status for this channel. */ handle = HXGE_DEV_HPI_HANDLE(hxgep); - channel = ringp->rdc; - RXDMA_REG_READ64(handle, RDC_STAT, channel, &cs.value); - - /* - * Enable mailbox update - * Since packets were not read and the hardware uses - * bits pktread and ptrread to update the queue - * length, we need to set both bits to 0. - */ - cs.bits.pktread = 0; - cs.bits.ptrread = 0; - cs.bits.mex = 1; - RXDMA_REG_WRITE64(handle, RDC_STAT, channel, cs.value); /* * Rearm this logical group if this is a single device @@ -1345,21 +1329,37 @@ */ ldgp = ringp->ldgp; if (ldgp == NULL) { - ringp->poll_flag = 0; MUTEX_EXIT(&ringp->lock); - return (0); + return (1); } + ringp->poll_flag = B_FALSE; + + /* + * Enable mailbox update, to start interrupts again. + */ + cs.value = 0ULL; + cs.bits.mex = 1; + cs.bits.pktread = 0; + cs.bits.ptrread = 0; + RXDMA_REG_WRITE64(handle, RDC_STAT, ringp->rdc, cs.value); + if (ldgp->nldvs == 1) { - ld_intr_mgmt_t mgm; - - mgm.value = 0; - mgm.bits.arm = 1; - mgm.bits.timer = ldgp->ldg_timer; - HXGE_REG_WR32(handle, - LD_INTR_MGMT + LDSV_OFFSET(ldgp->ldg), mgm.value); + /* + * Re-arm the group, since it is the only member + * of the group. + */ + (void) hpi_intr_ldg_mgmt_set(handle, ldgp->ldg, B_TRUE, + ldgp->ldg_timer); + } else { + /* + * Mask-on interrupts for the device and re-arm + * the group. + */ + (void) hpi_intr_mask_set(handle, ringp->ldvp->ldv, 0); + (void) hpi_intr_ldg_mgmt_set(handle, ldgp->ldg, B_TRUE, + ldgp->ldg_timer); } - ringp->poll_flag = 0; } MUTEX_EXIT(&ringp->lock); return (0); @@ -1388,23 +1388,25 @@ ring = hxgep->rx_rcr_rings->rcr_rings[rhp->index]; MUTEX_ENTER(&ring->lock); - ASSERT(ring->poll_flag == 1); + ASSERT(ring->poll_flag == B_TRUE); ASSERT(rhp->started); - /* - * Make sure the ring is started and polling is - * started before processing packets. - */ - if ((!rhp->started) || (ring->poll_flag == 0)) { + if (!ring->poll_flag) { MUTEX_EXIT(&ring->lock); return ((mblk_t *)NULL); } + /* + * Get the control and status bits for the ring. + */ RXDMA_REG_READ64(handle, RDC_STAT, rhp->index, &cs.value); cs.bits.ptrread = 0; cs.bits.pktread = 0; RXDMA_REG_WRITE64(handle, RDC_STAT, rhp->index, cs.value); + /* + * Process packets. + */ mblk = hxge_rx_pkts(hxgep, ring->ldvp->vdma_index, ring->ldvp, ring, cs, bytes_to_pickup); ldvp = ring->ldvp; @@ -1413,9 +1415,23 @@ * Process Error Events. */ if (ldvp && (cs.value & RDC_STAT_ERROR)) { + /* + * Recovery routines will grab the RCR ring lock. + */ + MUTEX_EXIT(&ring->lock); (void) hxge_rx_err_evnts(hxgep, ldvp->vdma_index, ldvp, cs); + MUTEX_ENTER(&ring->lock); } + /* + * Clear any control and status bits and update + * the hardware. + */ + cs.value &= RDC_STAT_WR1C; + cs.bits.ptrread = 0; + cs.bits.pktread = 0; + RXDMA_REG_WRITE64(handle, RDC_STAT, rhp->index, cs.value); + MUTEX_EXIT(&ring->lock); return (mblk); } @@ -1445,10 +1461,6 @@ HXGE_DEBUG_MSG((hxgep, RX_INT_CTL, "==> hxge_rx_pkts:vindex %d " "channel %d", vindex, ldvp->channel)); - if (!(hxgep->drv_state & STATE_HW_INITIALIZED)) { - return (NULL); - } - handle = HXGE_DEV_HPI_HANDLE(hxgep); channel = rcrp->rdc; if (channel != ldvp->channel) { @@ -2276,6 +2288,7 @@ HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL, " hxge_rx_err_evnts: fatal error on Channel #%d\n", channel)); + MUTEX_ENTER(&rbrp->post_lock); /* This function needs to be inside the post_lock */ status = hxge_rxdma_fatal_err_recover(hxgep, channel); @@ -2284,8 +2297,8 @@ FM_SERVICE_RESTORED(hxgep); } } + HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_rx_err_evnts")); - return (status); } @@ -2762,6 +2775,8 @@ /* Map in the receive completion ring */ rcrp = (p_rx_rcr_ring_t)KMEM_ZALLOC(sizeof (rx_rcr_ring_t), KM_SLEEP); + MUTEX_INIT(&rcrp->lock, NULL, MUTEX_DRIVER, + (void *) hxgep->interrupt_cookie); rcrp->rdc = dma_channel; rcrp->hxgep = hxgep; @@ -2882,6 +2897,7 @@ HXGE_DEBUG_MSG((hxgep, MEM2_CTL, "==> hxge_unmap_rxdma_channel_cfg_ring: channel %d", rcr_p->rdc)); + MUTEX_DESTROY(&rcr_p->lock); KMEM_FREE(rcr_p, sizeof (rx_rcr_ring_t)); KMEM_FREE(rx_mbox_p, sizeof (rx_mbox_t)); @@ -3174,7 +3190,7 @@ * unmapped, so it may free <rbr_p> for us. */ rbr_p->rbr_state = RBR_UNMAPPED; - HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL, + HXGE_DEBUG_MSG((hxgep, MEM2_CTL, "unmap_rxdma_buf_ring: %d %s outstanding.", rbr_p->rbr_ref_cnt, rbr_p->rbr_ref_cnt == 1 ? "msg" : "msgs")); @@ -3468,7 +3484,6 @@ HXGE_DEBUG_MSG((hxgep, MEM2_CTL, "==> hxge_rxdma_start_channel: enable done")); HXGE_DEBUG_MSG((hxgep, MEM2_CTL, "<== hxge_rxdma_start_channel")); - return (HXGE_OK); } @@ -3621,7 +3636,6 @@ { hpi_handle_t handle; hpi_status_t rs = HPI_SUCCESS; - hxge_status_t status = HXGE_OK; p_rx_rbr_ring_t rbrp; p_rx_rcr_ring_t rcrp; p_rx_mbox_t mboxp; @@ -3635,8 +3649,6 @@ int n_init_kick = 0; HXGE_DEBUG_MSG((hxgep, RX_CTL, "==> hxge_rxdma_fatal_err_recover")); - HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL, - "Recovering from RxDMAChannel#%d error...", channel)); /* * Stop the dma channel waits for the stop done. If the stop done bit @@ -3648,6 +3660,10 @@ HXGE_DEBUG_MSG((hxgep, RX_CTL, "Rx DMA stop...")); ring_idx = hxge_rxdma_get_ring_index(hxgep, channel); + if (ring_idx < 0) { + return (HXGE_ERROR); + } + rbrp = (p_rx_rbr_ring_t)hxgep->rx_rbr_rings->rbr_rings[ring_idx]; rcrp = (p_rx_rcr_ring_t)hxgep->rx_rcr_rings->rcr_rings[ring_idx]; @@ -3728,11 +3744,8 @@ * owned by the hardware initially. The apps will post theirs * eventually. */ - status = hxge_rxdma_start_channel(hxgep, channel, rbrp, rcrp, mboxp, + (void) hxge_rxdma_start_channel(hxgep, channel, rbrp, rcrp, mboxp, n_init_kick); - if (status != HXGE_OK) { - goto fail; - } /* * The DMA channel may disable itself automatically. @@ -3745,20 +3758,26 @@ "hpi_rxdma_cfg_rdc_enable (channel %d)", channel)); } + /* + * Delay a bit of time by doing reads. + */ + for (i = 0; i < 1024; i++) { + uint64_t value; + RXDMA_REG_READ64(HXGE_DEV_HPI_HANDLE(hxgep), + RDC_INT_MASK, i & 3, &value); + } + MUTEX_EXIT(&rbrp->lock); MUTEX_EXIT(&rcrp->lock); - HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL, - "Recovery Successful, RxDMAChannel#%d Restored", channel)); HXGE_DEBUG_MSG((hxgep, RX_CTL, "<== hxge_rxdma_fatal_err_recover")); - return (HXGE_OK); fail: MUTEX_EXIT(&rbrp->lock); MUTEX_EXIT(&rcrp->lock); - HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL, "Recovery failed")); - + HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL, + "Error Recovery failed for channel(%d)", channel)); return (HXGE_ERROR | rs); } @@ -3784,6 +3803,7 @@ /* Disable RxMAC */ HXGE_DEBUG_MSG((hxgep, RX_CTL, "Disable RxMAC...\n")); + MUTEX_ENTER(&hxgep->vmac_lock); if (hxge_rx_vmac_disable(hxgep) != HXGE_OK) goto fail; @@ -3837,6 +3857,7 @@ "hxge_rx_port_fatal_err_recover: Failed to enable RxMAC")); goto fail; } + MUTEX_EXIT(&hxgep->vmac_lock); /* Reset the error mask since PEU reset cleared it */ HXGE_REG_WR64(hxgep->hpi_handle, RDC_FIFO_ERR_INT_MASK, 0x0); @@ -3844,10 +3865,12 @@ HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL, "Recovery Successful, RxPort Restored")); HXGE_DEBUG_MSG((hxgep, RX_CTL, "<== hxge_rx_port_fatal_err_recover")); - return (HXGE_OK); + fail: - HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL, "Recovery failed")); + MUTEX_EXIT(&hxgep->vmac_lock); + HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL, + "Error Recovery failed for hxge(%d)", hxgep->instance)); return (status); } @@ -3856,7 +3879,6 @@ { hpi_status_t hpi_status; hxge_status_t status; - int i; p_hxge_rx_ring_stats_t rdc_stats; rdc_stats = &hxgep->statsp->rdc_stats[rx_rbr_p->rdc]; @@ -3877,9 +3899,8 @@ * to 0, since there is a hardware bug when disabling * the vmac. */ - MUTEX_ENTER(hxgep->genlock); - (void) hpi_vmac_rx_set_framesize( - HXGE_DEV_HPI_HANDLE(hxgep), (uint16_t)0); + MUTEX_ENTER(&hxgep->vmac_lock); + (void) hxge_rx_vmac_disable(hxgep); hpi_status = hpi_rxdma_cfg_rdc_enable( HXGE_DEV_HPI_HANDLE(hxgep), rx_rbr_p->rdc); @@ -3895,16 +3916,9 @@ } } - for (i = 0; i < 1024; i++) { - uint64_t value; - RXDMA_REG_READ64(HXGE_DEV_HPI_HANDLE(hxgep), - RDC_STAT, i & 3, &value); - } - /* * Re-enable the RX VMAC. */ - (void) hpi_vmac_rx_set_framesize(HXGE_DEV_HPI_HANDLE(hxgep), - (uint16_t)hxgep->vmac.maxframesize); - MUTEX_EXIT(hxgep->genlock); + (void) hxge_rx_vmac_enable(hxgep); + MUTEX_EXIT(&hxgep->vmac_lock); }
--- a/usr/src/uts/common/io/i8042.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/i8042.c Mon Jul 20 13:07:46 2009 -0400 @@ -147,17 +147,10 @@ int rptr; int overruns; unsigned char buf[BUFSIZ]; - /* - * Used during i8042_rep_put8 to intercept the 8042 response in - * i8042_intr() + * has_glock is 1 if this child has the [put8] exclusive-access lock. */ - boolean_t intercept_complete; - boolean_t intr_intercept_enabled; - uint8_t intercept[2]; - uint8_t intercepted_byte; - kcondvar_t intercept_cv; - kmutex_t intercept_mutex; + volatile boolean_t has_glock; }; /* @@ -183,14 +176,16 @@ #ifdef __sparc timeout_id_t timeout_id; #endif -#ifdef DEBUG /* - * intr_thread is set to curthread in i8042_intr and is - * tested against curthread in i8402_rep_put8(). + * glock is 1 if any child has the [put8] exclusive-access lock + * glock_cv is associated with the condition `glock == 0' */ - kthread_t *intr_thread; -#endif - ddi_softint_handle_t intercept_sih; + volatile int glock; + /* + * Callers awaiting exclusive access in i8042_put8 sleep on glock_cv + * and are signaled when another child relinquishes exclusive access. + */ + kcondvar_t glock_cv; }; /* @@ -401,12 +396,8 @@ static uint8_t i8042_get8(ddi_acc_impl_t *handlep, uint8_t *addr); static void i8042_put8(ddi_acc_impl_t *handlep, uint8_t *addr, uint8_t value); -static void i8042_put8_nolock(ddi_acc_impl_t *handlep, uint8_t *addr, - uint8_t value); -static void i8042_rep_put8(ddi_acc_impl_t *handlep, uint8_t *haddr, - uint8_t *daddr, size_t repcount, uint_t flags); static void i8042_send(struct i8042 *global, int reg, unsigned char cmd); -static uint_t i8042_intercept_softint(caddr_t arg1, caddr_t arg2); +static uint8_t i8042_get8(ddi_acc_impl_t *handlep, uint8_t *addr); unsigned int i8042_unclaimed_interrupts = 0; @@ -492,8 +483,6 @@ } } - (void) ddi_intr_remove_softint(global->intercept_sih); - if (global->init_state & I8042_INIT_MUTEXES) { for (which_port = 0; which_port < NUM_PORTS; which_port++) { @@ -501,9 +490,8 @@ port = &global->i8042_ports[which_port]; mutex_destroy(&port->intr_mutex); #endif - mutex_destroy(&port->intercept_mutex); - cv_destroy(&port->intercept_cv); } + cv_destroy(&global->glock_cv); mutex_destroy(&global->i8042_out_mutex); mutex_destroy(&global->i8042_mutex); } @@ -685,20 +673,17 @@ mutex_init(&global->i8042_out_mutex, NULL, MUTEX_DRIVER, NULL); + cv_init(&global->glock_cv, NULL, CV_DRIVER, NULL); + for (which_port = 0; which_port < NUM_PORTS; ++which_port) { port = &global->i8042_ports[which_port]; port->initialized = B_FALSE; port->i8042_global = global; port->which = which_port; - port->intr_intercept_enabled = B_FALSE; - cv_init(&port->intercept_cv, NULL, CV_DRIVER, NULL); #if defined(USE_SOFT_INTRS) port->soft_hdl = 0; #else - mutex_init(&port->intercept_mutex, NULL, MUTEX_DRIVER, - (void *)DDI_INTR_SOFTPRI_DEFAULT); - /* * Assume that the interrupt block cookie for port <n> * is iblock_cookies[<n>] (a 1:1 mapping). If there are not @@ -714,8 +699,6 @@ } else { mutex_init(&port->intr_mutex, NULL, MUTEX_DRIVER, NULL); - mutex_init(&port->intercept_mutex, NULL, MUTEX_DRIVER, - NULL); } #endif @@ -746,11 +729,6 @@ goto fail; - if (ddi_intr_add_softint(dip, &global->intercept_sih, - DDI_INTR_SOFTPRI_DEFAULT, i8042_intercept_softint, global) - != DDI_SUCCESS) - goto fail; - /* * Assume the number of interrupts is less that the number of * bits in the variable used to keep track of which interrupt @@ -938,6 +916,7 @@ port->rptr = 0; port->dip = dip; port->inumber = 0; + port->has_glock = B_FALSE; port->initialized = B_TRUE; handle = mp->map_handlep; @@ -955,7 +934,7 @@ ap->ahi_get32 = NULL; ap->ahi_put64 = NULL; ap->ahi_get64 = NULL; - ap->ahi_rep_put8 = i8042_rep_put8; + ap->ahi_rep_put8 = NULL; ap->ahi_rep_get8 = NULL; ap->ahi_rep_put16 = NULL; ap->ahi_rep_get16 = NULL; @@ -1030,9 +1009,6 @@ int new_wptr; struct i8042_port *port; -#ifdef DEBUG - global->intr_thread = curthread; -#endif mutex_enter(&global->i8042_mutex); stat = ddi_get8(global->io_handle, global->io_addr + I8042_STAT); @@ -1040,9 +1016,6 @@ if (! (stat & I8042_STAT_OUTBF)) { ++i8042_unclaimed_interrupts; mutex_exit(&global->i8042_mutex); -#ifdef DEBUG - global->intr_thread = NULL; -#endif return (DDI_INTR_UNCLAIMED); } @@ -1054,27 +1027,6 @@ if (! port->initialized) { mutex_exit(&global->i8042_mutex); -#ifdef DEBUG - global->intr_thread = NULL; -#endif - return (DDI_INTR_CLAIMED); - } - - /* - * If interception is enabled, and the byte matches what is being - * waited for, clear the interception flag and trigger a softintr - * that will signal the waiter, then exit the interrupt handler - * without passing the byte to the child's interrupt handler. - */ - if (port->intr_intercept_enabled && (port->intercept[0] == byte || - port->intercept[1] == byte)) { - port->intercepted_byte = byte; - port->intr_intercept_enabled = B_FALSE; - (void) ddi_intr_trigger_softint(global->intercept_sih, port); - mutex_exit(&global->i8042_mutex); -#ifdef DEBUG - global->intr_thread = NULL; -#endif return (DDI_INTR_CLAIMED); } @@ -1089,10 +1041,6 @@ #endif mutex_exit(&global->i8042_mutex); - -#ifdef DEBUG - global->intr_thread = NULL; -#endif return (DDI_INTR_CLAIMED); } @@ -1114,9 +1062,6 @@ mutex_exit(&port->intr_mutex); #endif -#ifdef DEBUG - global->intr_thread = NULL; -#endif return (DDI_INTR_CLAIMED); } @@ -1204,6 +1149,37 @@ global = port->i8042_global; switch ((uintptr_t)addr) { + case I8042_LOCK: + ASSERT(port->has_glock != B_TRUE); /* No reentrancy */ + mutex_enter(&global->i8042_out_mutex); + /* + * Block other children requesting exclusive access here until + * the child possessing it relinquishes the lock. + */ + while (global->glock) { + cv_wait(&global->glock_cv, &global->i8042_out_mutex); + } + port->has_glock = B_TRUE; + global->glock = 1; + mutex_exit(&global->i8042_out_mutex); + ret = 0; + break; + + case I8042_UNLOCK: + mutex_enter(&global->i8042_out_mutex); + ASSERT(global->glock != 0); + ASSERT(port->has_glock == B_TRUE); + port->has_glock = B_FALSE; + global->glock = 0; + /* + * Signal anyone waiting for exclusive access that it is now + * available. + */ + cv_signal(&global->glock_cv); + mutex_exit(&global->i8042_out_mutex); + ret = 0; + break; + case I8042_INT_INPUT_AVAIL: mutex_enter(&global->i8042_mutex); ret = port->rptr != port->wptr; @@ -1311,211 +1287,14 @@ return (ret); } -/* - * Send the byte specified and wait for a reply -- either the retry response, - * or another response (assumed to be an acknowledgement). If the retry - * response is received within the timeout period, the initial byte is resent - * to the 8042. - */ -static int -i8042_do_intercept(ddi_acc_impl_t *handlep, struct i8042_port *port, - uint8_t *oaddr, uint8_t byte, uint8_t retry_response) +static void +i8042_put8(ddi_acc_impl_t *handlep, uint8_t *addr, uint8_t value) { - int timedout = 0; - struct i8042 *global; - clock_t tval; - - global = port->i8042_global; - - /* - * Intercept the command response so that the 8042 interrupt handler - * does not call the port's interrupt handler. - */ - port->intercept_complete = B_FALSE; - port->intr_intercept_enabled = B_TRUE; - - /* Maximum time to wait: */ - tval = ddi_get_lbolt() + drv_usectohz(MAX_WAIT_ITERATIONS * - USECS_PER_WAIT); - - do { - i8042_put8_nolock(handlep, oaddr, byte); - - /* - * Wait for the command response - */ - while (!port->intercept_complete) { - if (cv_timedwait(&port->intercept_cv, - &port->intercept_mutex, tval) < 0 && - !port->intercept_complete) { - timedout = 1; - break; - } - } - - /* - * If the intercepted byte is the retry response, keep retrying - * until we time out, or until the success response is received. - */ - if (port->intercept_complete && - port->intercepted_byte == retry_response) - port->intercept_complete = B_FALSE; - - } while (!timedout && !port->intercept_complete); - - port->intr_intercept_enabled = B_FALSE; - - if (timedout && !port->intercept_complete) { - /* - * Some keyboard controllers don't trigger an interrupt, - * so check the status bits to see if there's input available - */ - if (ddi_get8(global->io_handle, global->io_addr + I8042_STAT) & - I8042_STAT_OUTBF) { - byte = ddi_get8(global->io_handle, - global->io_addr + I8042_DATA); - - port->intercepted_byte = byte; - - if (byte == retry_response) - return (B_TRUE); /* Timed out */ - else if (port->intercept[0] == byte) { - port->intercept_complete = B_TRUE; - return (B_FALSE); /* Response OK */ - } - } - } - - return (timedout); -} - -/* - * The _rep_put8() operation is designed to allow child drivers to - * execute commands that have responses or that have responses plus an - * option byte. These commands need to be executed atomically with respect - * to commands from other children (some 8042 implementations get confused - * when other child devices intersperse their commands while a command - * to a different 8042-connected device is in flight). - * - * haddr points to a buffer with either 3 or 4 bytes. Three bytes if a - * command (byte 0) is being sent for which we expect a response code (byte 1) - * (this function blocks until we either read a response code (or the retry - * code (byte 2)) or until a timer expires). - * Four if the command (byte 0) requires a response (byte 1) and then an - * option byte (byte 3). The option byte is only sent iff the response code - * expected is received before the timeout. As with the 3-byte request, byte - * 2 is the retry response. - * - * While this function may technically called in interrupt context, it may - * block (depending on the IPL of the i8042 interrupt handler vs. the handler - * executing) for as long as the timeout (and fail if i8042_intr cannot run). - * - * flags are ignored. - * - */ -/*ARGSUSED*/ -static void -i8042_rep_put8(ddi_acc_impl_t *handlep, uint8_t *haddr, uint8_t *daddr, - size_t repcount, uint_t flags) -{ + struct i8042 *global; struct i8042_port *port; - struct i8042 *global; - uint8_t *oaddr; - uintptr_t devaddr = (uintptr_t)daddr; - int timedout = 0; - boolean_t polled; ddi_acc_hdl_t *h; h = (ddi_acc_hdl_t *)handlep; - - port = (struct i8042_port *)h->ah_bus_private; - global = port->i8042_global; - - /* - * If this function is called, somehow, while we're in i8042_intr, - * the logic below will not work. That situation should never be - * possible. - */ - ASSERT(global->intr_thread != curthread); - - /* - * Only support the main port for now - */ - if (port->which != MAIN_PORT || (devaddr != I8042_INT_CMD_PLUS_PARAM && - devaddr != I8042_POLL_CMD_PLUS_PARAM)) { -#ifdef DEBUG - prom_printf("WARNING: i8042_rep_put8(): port or address " - "invalid\n"); -#endif - return; - } - - /* - * Only support commands with MAX one parameter. The format of the - * buffer supplied must be { <CMD>, <CMD_OK_RESPONSE>[, <PARAMETER>] } - */ - if (repcount != 3 && repcount != 4) { -#ifdef DEBUG - prom_printf("WARNING: i8042_rep_put8(): Invalid repetition " - "count (%d)\n", (int)repcount); -#endif - return; - } - - polled = (devaddr == I8042_POLL_CMD_PLUS_PARAM); - - if (polled) { - oaddr = (uint8_t *)I8042_POLL_OUTPUT_DATA; - } else { - oaddr = (uint8_t *)I8042_INT_OUTPUT_DATA; - /* - * Mutexes are only required for the non-polled (polled - * via the virtual registers, NOT via the polling mechanism - * used for systems without 8042 interrupts) case, because - * when polling is used, the system is single-threaded - * with interrupts disabled. - */ - mutex_enter(&global->i8042_out_mutex); - } - - /* Initialize the response and retry bytes from the caller */ - port->intercept[0] = haddr[1]; - port->intercept[1] = haddr[2]; - - mutex_enter(&port->intercept_mutex); - - timedout = i8042_do_intercept(handlep, port, oaddr, haddr[0], haddr[2]); - - /* - * If the first byte was processed before the timeout period, and - * there's an option byte, send it now. - */ - if (!timedout && repcount == 4) { - timedout = i8042_do_intercept(handlep, port, oaddr, haddr[3], - haddr[2]); - } - - mutex_exit(&port->intercept_mutex); - -#ifdef DEBUG - if (timedout && i8042_debug) - prom_printf("WARNING: i8042_rep_put8(): timed out waiting for " - "command response\n"); -#endif - - if (!polled) - mutex_exit(&global->i8042_out_mutex); -} - -static void -i8042_put8_nolock(ddi_acc_impl_t *handlep, uint8_t *addr, uint8_t value) -{ - struct i8042_port *port; - struct i8042 *global; - ddi_acc_hdl_t *h; - - h = (ddi_acc_hdl_t *)handlep; - port = (struct i8042_port *)h->ah_bus_private; global = port->i8042_global; @@ -1523,43 +1302,33 @@ case I8042_INT_OUTPUT_DATA: case I8042_POLL_OUTPUT_DATA: + if ((uintptr_t)addr == I8042_INT_OUTPUT_DATA) { + mutex_enter(&global->i8042_out_mutex); + + /* + * If no child has exclusive access, then proceed with + * the put8 below. If a child (not the one making the + * call) has exclusive access, wait for it to be + * relinquished. The use of i8042_out_mutex prevents + * children seeking exclusive access from getting it + * while a child is writing to the 8042. + */ + while (global->glock && !port->has_glock) { + cv_wait(&global->glock_cv, + &global->i8042_out_mutex); + } + } + if (port->which == AUX_PORT) i8042_send(global, I8042_CMD, I8042_CMD_WRITE_AUX); i8042_send(global, I8042_DATA, value); - break; - } -} - -static void -i8042_put8(ddi_acc_impl_t *handlep, uint8_t *addr, uint8_t value) -{ - struct i8042 *global; - ddi_acc_hdl_t *h; - - h = (ddi_acc_hdl_t *)handlep; - global = ((struct i8042_port *)h->ah_bus_private)->i8042_global; - - switch ((uintptr_t)addr) { - case I8042_INT_OUTPUT_DATA: - case I8042_POLL_OUTPUT_DATA: - - if ((uintptr_t)addr == I8042_INT_OUTPUT_DATA) - mutex_enter(&global->i8042_out_mutex); - - i8042_put8_nolock(handlep, addr, value); - if ((uintptr_t)addr == I8042_INT_OUTPUT_DATA) mutex_exit(&global->i8042_out_mutex); break; - case I8042_INT_CMD_PLUS_PARAM: - case I8042_POLL_CMD_PLUS_PARAM: - - break; - #if defined(DEBUG) case I8042_INT_INPUT_AVAIL: case I8042_INT_INPUT_DATA: @@ -1915,25 +1684,3 @@ return (B_FALSE); } #endif - -/* - * arg1 is the global i8042 state pointer (not used) - * arg2 is the port pointer for the intercepted port - */ -/*ARGSUSED*/ -static uint_t -i8042_intercept_softint(caddr_t arg1, caddr_t arg2) -{ - struct i8042_port *port = (struct i8042_port *)arg2; - ASSERT(port != NULL); - - mutex_enter(&port->intercept_mutex); - if (!port->intercept_complete) { - port->intercept_complete = B_TRUE; - cv_signal(&port->intercept_cv); - mutex_exit(&port->intercept_mutex); - return (DDI_INTR_CLAIMED); - } - mutex_exit(&port->intercept_mutex); - return (DDI_INTR_UNCLAIMED); -}
--- a/usr/src/uts/common/io/ib/adapters/hermon/hermon.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/ib/adapters/hermon/hermon.c Mon Jul 20 13:07:46 2009 -0400 @@ -1171,6 +1171,7 @@ } else if (HERMON_IS_MAINTENANCE_MODE(state->hs_dip)) { HERMON_FMANOTE(state, HERMON_FMA_MAINT); state->hs_operational_mode = HERMON_MAINTENANCE_MODE; + state->hs_fm_degraded_reason = HCA_FW_MISC; /* not fw reason */ return (DDI_FAILURE); } else { @@ -1626,6 +1627,7 @@ state->hs_fw.fw_rev_subminor); } state->hs_operational_mode = HERMON_MAINTENANCE_MODE; + state->hs_fm_degraded_reason = HCA_FW_MISMATCH; hermon_hw_fini(state, cleanup); HERMON_ATTACH_MSG(state->hs_attach_buf, "hw_init_checkfwver_fail"); @@ -1696,6 +1698,7 @@ cmn_err(CE_NOTE, "RUN_FW command failed: 0x%08x\n", status); if (status == HERMON_CMD_BAD_NVMEM) { state->hs_operational_mode = HERMON_MAINTENANCE_MODE; + state->hs_fm_degraded_reason = HCA_FW_CORRUPT; } hermon_hw_fini(state, cleanup); HERMON_ATTACH_MSG(state->hs_attach_buf, "hw_init_run_fw_fail");
--- a/usr/src/uts/common/io/ib/adapters/hermon/hermon_cmd.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/ib/adapters/hermon/hermon_cmd.c Mon Jul 20 13:07:46 2009 -0400 @@ -265,9 +265,11 @@ break; case HERMON_CMD_BAD_NVMEM: + /* + * No need of an ereport here since this case + * is treated as a degradation later. + */ HERMON_FMANOTE(state, HERMON_FMA_NVMEM); - hermon_fm_ereport(state, HCA_IBA_ERR, - HCA_ERR_NON_FATAL); break; default: @@ -1820,9 +1822,11 @@ #ifdef FMA_TEST if (hermon_test_num == -2) { status = HERMON_CMD_BAD_NVMEM; + /* + * No need of an ereport here since this case + * is treated as a degradation later. + */ HERMON_FMANOTE(state, HERMON_FMA_BADNVMEM); - hermon_fm_ereport(state, HCA_IBA_ERR, - HCA_ERR_NON_FATAL); } #endif return (status);
--- a/usr/src/uts/common/io/ib/adapters/hermon/hermon_fm.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/ib/adapters/hermon/hermon_fm.c Mon Jul 20 13:07:46 2009 -0400 @@ -1008,6 +1008,21 @@ DDI_SERVICE_LOST); break; case HCA_ERR_DEGRADED: + switch (state->hs_fm_degraded_reason) { + case HCA_FW_CORRUPT: + i_hca_fm_ereport(state->hs_dip, type, + DDI_FM_DEVICE_FW_CORRUPT); + break; + case HCA_FW_MISMATCH: + i_hca_fm_ereport(state->hs_dip, type, + DDI_FM_DEVICE_FW_MISMATCH); + break; + case HCA_FW_MISC: + default: + i_hca_fm_ereport(state->hs_dip, type, + DDI_FM_DEVICE_INTERN_UNCORR); + break; + } ddi_fm_service_impact(state->hs_dip, DDI_SERVICE_DEGRADED); break; @@ -1035,8 +1050,21 @@ "error. type = %d, detail = %d\n.", type, detail); break; case HCA_ERR_DEGRADED: - i_hca_fm_ereport(state->hs_dip, type, - DDI_FM_DEVICE_INTERN_UNCORR); + switch (state->hs_fm_degraded_reason) { + case HCA_FW_CORRUPT: + i_hca_fm_ereport(state->hs_dip, type, + DDI_FM_DEVICE_FW_CORRUPT); + break; + case HCA_FW_MISMATCH: + i_hca_fm_ereport(state->hs_dip, type, + DDI_FM_DEVICE_FW_MISMATCH); + break; + case HCA_FW_MISC: + default: + i_hca_fm_ereport(state->hs_dip, type, + DDI_FM_DEVICE_INTERN_UNCORR); + break; + } ddi_fm_service_impact(state->hs_dip, DDI_SERVICE_DEGRADED); break;
--- a/usr/src/uts/common/io/ib/clients/iser/iser_cq.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/ib/clients/iser/iser_cq.c Mon Jul 20 13:07:46 2009 -0400 @@ -54,24 +54,30 @@ iser_chan = (iser_chan_t *)arg; - /* Poll completions until the CQ is empty */ + /* + * Poll for work request completion while successful. If the + * queue empties or otherwise becomes invalid, stop polling. + */ do { status = iser_ib_poll_send_completions(cq_hdl, iser_chan); - } while (status != IBT_CQ_EMPTY); + } while (status == IBT_SUCCESS); - /* We've emptied the CQ, rearm it before we're done here */ - status = ibt_enable_cq_notify(cq_hdl, IBT_NEXT_COMPLETION); - if (status != IBT_SUCCESS) { - /* Unexpected error */ - ISER_LOG(CE_NOTE, "iser_ib_sendcq_handler: " - "ibt_enable_cq_notify error (%d)", status); - return; + if (status == IBT_CQ_EMPTY) { + /* We've emptied the CQ, rearm it before we're done here */ + status = ibt_enable_cq_notify(cq_hdl, IBT_NEXT_COMPLETION); + if (status != IBT_SUCCESS) { + /* Unexpected error */ + ISER_LOG(CE_NOTE, "iser_ib_sendcq_handler: " + "ibt_enable_cq_notify error (%d)", status); + return; + } + + /* Now, check for more completions after the rearm */ + do { + status = iser_ib_poll_send_completions( + cq_hdl, iser_chan); + } while (status == IBT_SUCCESS); } - - /* Now, check for more completions after the rearm */ - do { - status = iser_ib_poll_send_completions(cq_hdl, iser_chan); - } while (status != IBT_CQ_EMPTY); } static int @@ -91,16 +97,14 @@ iser_conn = iser_chan->ic_conn; - /* - * Poll ISER_IB_SCQ_POLL_MAX completions from the CQ. - */ + /* Poll ISER_IB_SCQ_POLL_MAX completions from the CQ */ status = ibt_poll_cq(cq_hdl, wc, ISER_IB_SCQ_POLL_MAX, &npoll); if (status != IBT_SUCCESS) { if (status != IBT_CQ_EMPTY) { /* Unexpected error */ ISER_LOG(CE_NOTE, "iser_ib_sendcq_handler: ibt_poll_cq " - "error (%d)", status); + "unexpected error (%d)", status); } /* CQ is empty. Either way, move along... */ return (status); @@ -313,24 +317,30 @@ iser_chan = (iser_chan_t *)arg; - /* Poll completions until the CQ is empty */ + /* + * Poll for work request completion while successful. If the + * queue empties or otherwise becomes invalid, stop polling. + */ do { status = iser_ib_poll_recv_completions(cq_hdl, iser_chan); - } while (status != IBT_CQ_EMPTY); + } while (status == IBT_SUCCESS); - /* We've emptied the CQ, rearm it before we're done here */ - status = ibt_enable_cq_notify(cq_hdl, IBT_NEXT_COMPLETION); - if (status != IBT_SUCCESS) { - /* Unexpected error */ - ISER_LOG(CE_NOTE, "iser_ib_recvcq_handler: " - "ibt_enable_cq_notify error (%d)", status); - return; + if (status == IBT_CQ_EMPTY) { + /* We've emptied the CQ, rearm it before we're done here */ + status = ibt_enable_cq_notify(cq_hdl, IBT_NEXT_COMPLETION); + if (status != IBT_SUCCESS) { + /* Unexpected error */ + ISER_LOG(CE_NOTE, "iser_ib_recvcq_handler: " + "ibt_enable_cq_notify error (%d)", status); + return; + } + + /* Now, check for more completions after the rearm */ + do { + status = iser_ib_poll_recv_completions( + cq_hdl, iser_chan); + } while (status == IBT_SUCCESS); } - - /* Now, check for more completions after the rearm */ - do { - status = iser_ib_poll_recv_completions(cq_hdl, iser_chan); - } while (status != IBT_CQ_EMPTY); } static int
--- a/usr/src/uts/common/io/ib/clients/iser/iser_ib.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/ib/clients/iser/iser_ib.c Mon Jul 20 13:07:46 2009 -0400 @@ -187,7 +187,14 @@ /* * iser_ib_bind_service * - * This function binds a given iSER service on all available HCA ports + * This function binds a given iSER service on all available HCA ports. The + * current specification does not allow user to specify transport bindings + * for each iscsi target. The ULP invokes this function to bind the target + * to all available iser ports after checking for the presence of an IB HCA. + * iSER is "configured" whenever an IB-capable IP address exists. The lack + * of active IB ports is a less-fatal condition, and sockets would be used + * as the transport even though an Infiniband HCA is configured but unusable. + * */ int iser_ib_bind_service(idm_svc_t *idm_svc) @@ -196,6 +203,7 @@ ib_gid_t gid; int num_ports = 0; int num_binds = 0; + int num_inactive_binds = 0; /* if HCA ports inactive */ int status; int i; @@ -218,6 +226,7 @@ * in our async handler if the port comes up * at a later time. */ + num_inactive_binds++; continue; } @@ -246,6 +255,14 @@ ISER_LOG(CE_NOTE, "iser_ib_bind_service: Service available on " "(%d) of (%d) ports", num_binds, num_ports); return (ISER_STATUS_SUCCESS); + } else if (num_inactive_binds) { + ISER_LOG(CE_NOTE, "iser_ib_bind_service: Could not bind " + "service, HCA ports are not active."); + /* + * still considered success, the async handler will bind + * the service when the port comes up at a later time + */ + return (ISER_STATUS_SUCCESS); } else { ISER_LOG(CE_NOTE, "iser_ib_bind_service: Did not bind service"); return (ISER_STATUS_FAIL);
--- a/usr/src/uts/common/io/ib/clients/iser/iser_xfer.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/ib/clients/iser/iser_xfer.c Mon Jul 20 13:07:46 2009 -0400 @@ -95,21 +95,28 @@ wr.wr_nds = 1; wr.wr_sgl = &msg->msg_ds; - status = ibt_post_send(chan->ic_chanhdl, &wr, 1, NULL); - if (status != IBT_SUCCESS) { - ISER_LOG(CE_NOTE, "iser_xfer_hello_msg: ibt_post_send " - "failure (%d)", status); - iser_msg_free(msg); - iser_wr_free(iser_wr); - return (ISER_STATUS_FAIL); - } - /* Increment this channel's SQ posted count */ + /* + * Avoid race condition by incrementing this channel's + * SQ posted count prior to calling ibt_post_send + */ mutex_enter(&chan->ic_sq_post_lock); chan->ic_sq_post_count++; if (chan->ic_sq_post_count > chan->ic_sq_max_post_count) chan->ic_sq_max_post_count = chan->ic_sq_post_count; mutex_exit(&chan->ic_sq_post_lock); + status = ibt_post_send(chan->ic_chanhdl, &wr, 1, NULL); + if (status != IBT_SUCCESS) { + ISER_LOG(CE_NOTE, "iser_xfer_hello_msg: ibt_post_send " + "failure (%d)", status); + mutex_enter(&chan->ic_sq_post_lock); + chan->ic_sq_post_count--; + mutex_exit(&chan->ic_sq_post_lock); + iser_msg_free(msg); + iser_wr_free(iser_wr); + return (ISER_STATUS_FAIL); + } + ISER_LOG(CE_NOTE, "Posting iSER Hello message: chan (0x%p): " "IP [%x to %x]", (void *)chan, chan->ic_localip.un.ip4addr, chan->ic_remoteip.un.ip4addr); @@ -176,21 +183,24 @@ wr.wr_nds = 1; wr.wr_sgl = &msg->msg_ds; + mutex_enter(&chan->ic_sq_post_lock); + chan->ic_sq_post_count++; + if (chan->ic_sq_post_count > chan->ic_sq_max_post_count) + chan->ic_sq_max_post_count = chan->ic_sq_post_count; + + mutex_exit(&chan->ic_sq_post_lock); + status = ibt_post_send(chan->ic_chanhdl, &wr, 1, NULL); if (status != IBT_SUCCESS) { ISER_LOG(CE_NOTE, "iser_xfer_helloreply_msg: ibt_post_send " "failure (%d)", status); + mutex_enter(&chan->ic_sq_post_lock); + chan->ic_sq_post_count--; + mutex_exit(&chan->ic_sq_post_lock); iser_msg_free(msg); iser_wr_free(iser_wr); return (ISER_STATUS_FAIL); } - /* Increment this channel's SQ posted count */ - mutex_enter(&chan->ic_sq_post_lock); - chan->ic_sq_post_count++; - if (chan->ic_sq_post_count > chan->ic_sq_max_post_count) - chan->ic_sq_max_post_count = chan->ic_sq_post_count; - mutex_exit(&chan->ic_sq_post_lock); - ISER_LOG(CE_NOTE, "Posting iSER HelloReply message: chan (0x%p): " "IP [%x to %x]", (void *)chan, chan->ic_localip.un.ip4addr, chan->ic_remoteip.un.ip4addr); @@ -228,6 +238,14 @@ ASSERT(chan != NULL); + mutex_enter(&chan->ic_conn->ic_lock); + /* Bail out if the connection is closed */ + if ((chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSING) || + (chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSED)) { + mutex_exit(&chan->ic_conn->ic_lock); + return (ISER_STATUS_FAIL); + } + /* * All SCSI command PDU (except SCSI Read and SCSI Write) and the SCSI * Response PDU are sent to the remote end using the SendSE Message. @@ -238,6 +256,7 @@ hca = (iser_hca_t *)chan->ic_hca; if (hca == NULL) { ISER_LOG(CE_NOTE, "iser_xfer_ctrlpdu: no hca handle found"); + mutex_exit(&chan->ic_conn->ic_lock); return (ISER_STATUS_FAIL); } @@ -245,15 +264,14 @@ if (msg == NULL) { ISER_LOG(CE_NOTE, "iser_xfer_ctrlpdu: iser message cache " "alloc failed"); + mutex_exit(&chan->ic_conn->ic_lock); return (ISER_STATUS_FAIL); } /* Pull the BHS out of the PDU handle */ bhs = (iscsi_data_hdr_t *)pdu->isp_hdr; - ASSERT(chan->ic_conn != NULL && chan->ic_conn->ic_idmc != NULL); ic = chan->ic_conn->ic_idmc; - ASSERT(ic != NULL); hdr = (iser_ctrl_hdr_t *)(uintptr_t)msg->msg_ds.ds_va; @@ -330,6 +348,7 @@ ISER_LOG(CE_NOTE, "iser_xfer_ctrlpdu: unable to allocate " "iser wr handle"); iser_msg_free(msg); + mutex_exit(&chan->ic_conn->ic_lock); return (ISER_STATUS_FAIL); } iser_wr->iw_pdu = pdu; @@ -346,6 +365,13 @@ wr.wr_nds = 1; wr.wr_sgl = &msg->msg_ds; + /* Increment this channel's SQ posted count */ + mutex_enter(&chan->ic_sq_post_lock); + chan->ic_sq_post_count++; + if (chan->ic_sq_post_count > chan->ic_sq_max_post_count) + chan->ic_sq_max_post_count = chan->ic_sq_post_count; + mutex_exit(&chan->ic_sq_post_lock); + /* Post Send Work Request on the specified channel */ status = ibt_post_send(chan->ic_chanhdl, &wr, 1, NULL); if (status != IBT_SUCCESS) { @@ -353,15 +379,14 @@ "failure (%d)", status); iser_msg_free(msg); iser_wr_free(iser_wr); + mutex_enter(&chan->ic_sq_post_lock); + chan->ic_sq_post_count--; + mutex_exit(&chan->ic_sq_post_lock); + mutex_exit(&chan->ic_conn->ic_lock); return (ISER_STATUS_FAIL); } - /* Increment this channel's SQ posted count */ - mutex_enter(&chan->ic_sq_post_lock); - chan->ic_sq_post_count++; - if (chan->ic_sq_post_count > chan->ic_sq_max_post_count) - chan->ic_sq_max_post_count = chan->ic_sq_post_count; - mutex_exit(&chan->ic_sq_post_lock); + mutex_exit(&chan->ic_conn->ic_lock); return (ISER_STATUS_SUCCESS); } @@ -388,6 +413,15 @@ /* Grab the iSER resources from the task and buf handles */ iser_conn = (iser_conn_t *)idt->idt_ic->ic_transport_private; iser_chan = iser_conn->ic_chan; + + mutex_enter(&iser_chan->ic_conn->ic_lock); + /* Bail out if the connection is closed */ + if ((iser_chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSING) || + (iser_chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSED)) { + mutex_exit(&iser_chan->ic_conn->ic_lock); + return (ISER_STATUS_FAIL); + } + iser_buf = (iser_buf_t *)buf->idb_buf_private; iser_hdr = (iser_ctrl_hdr_t *)idt->idt_transport_hdr; @@ -408,6 +442,7 @@ if (iser_wr == NULL) { ISER_LOG(CE_NOTE, "iser_xfer_buf_to_ini: unable to allocate " "iser wr handle"); + mutex_exit(&iser_chan->ic_conn->ic_lock); return (ISER_STATUS_FAIL); } iser_wr->iw_buf = buf; @@ -433,13 +468,6 @@ uint32_t, reg_rkey, uint32_t, buf->idb_xfer_len, int, XFER_BUF_TX_TO_INI); - status = ibt_post_send(iser_chan->ic_chanhdl, &wr, 1, NULL); - if (status != IBT_SUCCESS) { - ISER_LOG(CE_NOTE, "iser_xfer_buf_to_ini: ibt_post_send " - "failure (%d)", status); - iser_wr_free(iser_wr); - return (ISER_STATUS_FAIL); - } /* Increment this channel's SQ posted count */ mutex_enter(&iser_chan->ic_sq_post_lock); iser_chan->ic_sq_post_count++; @@ -447,6 +475,19 @@ iser_chan->ic_sq_max_post_count = iser_chan->ic_sq_post_count; mutex_exit(&iser_chan->ic_sq_post_lock); + status = ibt_post_send(iser_chan->ic_chanhdl, &wr, 1, NULL); + if (status != IBT_SUCCESS) { + ISER_LOG(CE_NOTE, "iser_xfer_buf_to_ini: ibt_post_send " + "failure (%d)", status); + iser_wr_free(iser_wr); + mutex_enter(&iser_chan->ic_sq_post_lock); + iser_chan->ic_sq_post_count--; + mutex_exit(&iser_chan->ic_sq_post_lock); + mutex_exit(&iser_chan->ic_conn->ic_lock); + return (ISER_STATUS_FAIL); + } + + mutex_exit(&iser_chan->ic_conn->ic_lock); return (ISER_STATUS_SUCCESS); } @@ -474,6 +515,15 @@ /* Grab the iSER resources from the task and buf handles */ iser_conn = (iser_conn_t *)idt->idt_ic->ic_transport_private; iser_chan = iser_conn->ic_chan; + + mutex_enter(&iser_chan->ic_conn->ic_lock); + /* Bail out if the connection is closed */ + if ((iser_chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSING) || + (iser_chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSED)) { + mutex_exit(&iser_chan->ic_conn->ic_lock); + return (ISER_STATUS_FAIL); + } + iser_buf = (iser_buf_t *)buf->idb_buf_private; iser_hdr = (iser_ctrl_hdr_t *)idt->idt_transport_hdr; @@ -494,6 +544,7 @@ if (iser_wr == NULL) { ISER_LOG(CE_NOTE, "iser_xfer_buf_from_ini: unable to allocate " "iser wr handle"); + mutex_exit(&iser_chan->ic_conn->ic_lock); return (ISER_STATUS_FAIL); } iser_wr->iw_buf = buf; @@ -519,13 +570,6 @@ uint32_t, reg_rkey, uint32_t, buf->idb_xfer_len, int, XFER_BUF_RX_FROM_INI); - status = ibt_post_send(iser_chan->ic_chanhdl, &wr, 1, NULL); - if (status != IBT_SUCCESS) { - ISER_LOG(CE_NOTE, "iser_xfer_buf_from_ini: ibt_post_send " - "failure (%d)", status); - iser_wr_free(iser_wr); - return (ISER_STATUS_FAIL); - } /* Increment this channel's SQ posted count */ mutex_enter(&iser_chan->ic_sq_post_lock); iser_chan->ic_sq_post_count++; @@ -533,5 +577,18 @@ iser_chan->ic_sq_max_post_count = iser_chan->ic_sq_post_count; mutex_exit(&iser_chan->ic_sq_post_lock); + status = ibt_post_send(iser_chan->ic_chanhdl, &wr, 1, NULL); + if (status != IBT_SUCCESS) { + ISER_LOG(CE_NOTE, "iser_xfer_buf_from_ini: ibt_post_send " + "failure (%d)", status); + iser_wr_free(iser_wr); + mutex_enter(&iser_chan->ic_sq_post_lock); + iser_chan->ic_sq_post_count--; + mutex_exit(&iser_chan->ic_sq_post_lock); + mutex_exit(&iser_chan->ic_conn->ic_lock); + return (ISER_STATUS_FAIL); + } + + mutex_exit(&iser_chan->ic_conn->ic_lock); return (ISER_STATUS_SUCCESS); }
--- a/usr/src/uts/common/io/ib/ibnex/ibnex.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/ib/ibnex/ibnex.c Mon Jul 20 13:07:46 2009 -0400 @@ -54,6 +54,7 @@ #include <sys/ib/ibtl/impl/ibtl_ibnex.h> #include <sys/file.h> #include <sys/hwconf.h> +#include <sys/fs/dv_node.h> /* Function prototypes */ static int ibnex_attach(dev_info_t *, ddi_attach_cmd_t); @@ -1633,8 +1634,6 @@ (void) ibnex_commsvc_initnode(parent, port_attr, idx, IBNEX_VPPA_COMMSVC_NODE, pkey, &rval, IBNEX_CFGADM_ENUMERATE); - IBTF_DPRINTF_L5("ibnex", "\tcreate_vppa_nodes: " - "commsvc_initnode failed rval %x", rval); } } } @@ -2948,6 +2947,7 @@ char hca_guid[IBNEX_HCAGUID_STRSZ]; ibdm_ioc_info_t *ioc_list, *ioc; ibnex_node_data_t *node_data; + dev_info_t *phci; IBTF_DPRINTF_L4("ibnex", "\tdm_callback: attr %p event %x", arg, flag); @@ -2987,6 +2987,16 @@ } mutex_exit(&ibnex.ibnex_mutex); ibdm_ibnex_free_ioc_list(ioc); + break; + + case IBDM_EVENT_PORT_UP: + case IBDM_EVENT_PORT_PKEY_CHANGE: + phci = ibtl_ibnex_hcaguid2dip(*(longlong_t *)arg); + devfs_clean(phci, NULL, 0); + break; + default: + break; + } }
--- a/usr/src/uts/common/io/ib/ibnex/ibnex_ioctl.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/ib/ibnex/ibnex_ioctl.c Mon Jul 20 13:07:46 2009 -0400 @@ -2880,6 +2880,72 @@ return (rv); } +#define IBNEX_CTL_CP_HCA_INFO(x, y, driver_name, instance, device_path, \ + device_path_alloc_sz, device_path_len) \ +{ \ + (x)->hca_node_guid = (y)->hca_node_guid; \ + (x)->hca_si_guid = (y)->hca_si_guid; \ + (x)->hca_nports = (y)->hca_nports; \ + (x)->hca_flags = (y)->hca_flags; \ + (x)->hca_flags2 = (y)->hca_flags2; \ + (x)->hca_vendor_id = (y)->hca_vendor_id; \ + (x)->hca_device_id = (y)->hca_device_id; \ + (x)->hca_version_id = (y)->hca_version_id; \ + (x)->hca_max_chans = (y)->hca_max_chans; \ + (x)->hca_max_chan_sz = (y)->hca_max_chan_sz; \ + (x)->hca_max_sgl = (y)->hca_max_sgl; \ + (x)->hca_max_cq = (y)->hca_max_cq; \ + (x)->hca_max_cq_sz = (y)->hca_max_cq_sz; \ + (x)->hca_page_sz = (y)->hca_page_sz; \ + (x)->hca_max_memr = (y)->hca_max_memr; \ + (x)->hca_max_memr_len = (y)->hca_max_memr_len; \ + (x)->hca_max_mem_win = (y)->hca_max_mem_win; \ + (x)->hca_max_rsc = (y)->hca_max_rsc; \ + (x)->hca_max_rdma_in_chan = (y)->hca_max_rdma_in_chan; \ + (x)->hca_max_rdma_out_chan = (y)->hca_max_rdma_out_chan; \ + (x)->hca_max_ipv6_chan = (y)->hca_max_ipv6_chan; \ + (x)->hca_max_ether_chan = (y)->hca_max_ether_chan; \ + (x)->hca_max_mcg_chans = (y)->hca_max_mcg_chans; \ + (x)->hca_max_mcg = (y)->hca_max_mcg; \ + (x)->hca_max_chan_per_mcg = (y)->hca_max_chan_per_mcg; \ + (x)->hca_max_partitions = (y)->hca_max_partitions; \ + (x)->hca_local_ack_delay = (y)->hca_local_ack_delay; \ + (x)->hca_max_port_sgid_tbl_sz = (y)->hca_max_port_sgid_tbl_sz; \ + (x)->hca_max_port_pkey_tbl_sz = (y)->hca_max_port_pkey_tbl_sz; \ + (x)->hca_max_pd = (y)->hca_max_pd; \ + (x)->hca_max_ud_dest = (y)->hca_max_ud_dest; \ + (x)->hca_max_srqs = (y)->hca_max_srqs; \ + (x)->hca_max_srqs_sz = (y)->hca_max_srqs_sz; \ + (x)->hca_max_srq_sgl = (y)->hca_max_srq_sgl; \ + (x)->hca_max_cq_handlers = (y)->hca_max_cq_handlers; \ + (x)->hca_reserved_lkey = (y)->hca_reserved_lkey; \ + (x)->hca_max_fmrs = (y)->hca_max_fmrs; \ + (x)->hca_max_lso_size = (y)->hca_max_lso_size; \ + (x)->hca_max_lso_hdr_size = (y)->hca_max_lso_hdr_size; \ + (x)->hca_max_inline_size = (y)->hca_max_inline_size; \ + (x)->hca_max_cq_mod_count = (y)->hca_max_cq_mod_count; \ + (x)->hca_max_cq_mod_usec = (y)->hca_max_cq_mod_usec; \ + (x)->hca_fw_major_version = (y)->hca_fw_major_version; \ + (x)->hca_fw_minor_version = (y)->hca_fw_minor_version; \ + (x)->hca_fw_micro_version = (y)->hca_fw_micro_version; \ + (x)->hca_ud_send_inline_sz = (y)->hca_ud_send_inline_sz; \ + (x)->hca_conn_send_inline_sz = (y)->hca_conn_send_inline_sz; \ + (x)->hca_conn_rdmaw_inline_overhead = \ + (y)->hca_conn_rdmaw_inline_overhead; \ + (x)->hca_recv_sgl_sz = (y)->hca_recv_sgl_sz; \ + (x)->hca_ud_send_sgl_sz = (y)->hca_ud_send_sgl_sz; \ + (x)->hca_conn_send_sgl_sz = (y)->hca_conn_send_sgl_sz; \ + (x)->hca_conn_rdma_sgl_overhead = (y)->hca_conn_rdma_sgl_overhead; \ + \ + (void) strlcpy((x)->hca_driver_name, (driver_name), \ + MAX_HCA_DRVNAME_LEN); \ + (x)->hca_driver_instance = (instance); \ + \ + (x)->hca_device_path = ((device_path_alloc_sz) >= (device_path_len)) \ + ? (device_path) : NULL; \ + (x)->hca_device_path_len = (device_path_len); \ +} + /* * IOCTL implementation to query HCA attributes */ @@ -2888,110 +2954,121 @@ cred_t *credp, int *rvalp) { int rv = 0; - ibnex_ctl_hca_info_t *hca_info; - ibnex_ctl_query_hca_t *query_hca; - ibt_hca_attr_t *hca_attr; + ibnex_ctl_query_hca_t *query_hca = NULL; + ibnex_ctl_query_hca_32_t *query_hca_32 = NULL; + ibt_hca_attr_t *hca_attr = NULL; char driver_name[MAX_HCA_DRVNAME_LEN]; int instance; + ib_guid_t hca_guid; + char *device_path; + uint_t device_path_alloc_sz, hca_device_path_len; + char *hca_device_path = NULL; IBTF_DPRINTF_L4("ibnex", "\tctl_query_hca: cmd=%x, arg=%p, " "mode=%x, cred=%p, rval=%p, dev=0x%x", cmd, arg, mode, credp, rvalp, dev); - /* - * NOTE: 32-bit versions of the structures for ibnex_ctl_query_hca_t - * and ibnex_ctl_hca_info_t are not defined because the alignment - * of fields for these structures happen to be the same for both - * 64-bit and 32-bit cases. - */ - - query_hca = kmem_zalloc(sizeof (ibnex_ctl_query_hca_t), KM_SLEEP); +#ifdef _MULTI_DATAMODEL + if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { + query_hca_32 = kmem_zalloc( + sizeof (ibnex_ctl_query_hca_32_t), KM_SLEEP); + + if (ddi_copyin((void *)arg, query_hca_32, + sizeof (ibnex_ctl_query_hca_32_t), mode) != 0) { + IBTF_DPRINTF_L2("ibnex", + "\tctl_query_hca: ddi_copyin err 1"); + rv = EFAULT; + goto out; + } + + hca_guid = query_hca_32->hca_guid; + device_path = (char *)(uintptr_t)query_hca_32->hca_device_path; + device_path_alloc_sz = query_hca_32->hca_device_path_alloc_sz; + } else +#endif + { + query_hca = kmem_zalloc(sizeof (ibnex_ctl_query_hca_t), + KM_SLEEP); + + if (ddi_copyin((void *)arg, query_hca, + sizeof (ibnex_ctl_query_hca_t), mode) != 0) { + IBTF_DPRINTF_L2("ibnex", + "\tctl_query_hca: ddi_copyin err 2"); + rv = EFAULT; + goto out; + } + + hca_guid = query_hca->hca_guid; + device_path = query_hca->hca_device_path; + device_path_alloc_sz = query_hca->hca_device_path_alloc_sz; + } + hca_attr = kmem_zalloc(sizeof (ibt_hca_attr_t), KM_SLEEP); - - if (ddi_copyin((void *)arg, query_hca, - sizeof (ibnex_ctl_query_hca_t), mode) != 0) { - IBTF_DPRINTF_L2("ibnex", "\tctl_query_hca: ddi_copyin err"); - rv = EFAULT; - goto out; - } - - if (ibtl_ibnex_query_hca_byguid(query_hca->hca_guid, hca_attr, - driver_name, sizeof (driver_name), &instance) != IBT_SUCCESS) { + hca_device_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP); + + if (ibtl_ibnex_query_hca_byguid(hca_guid, hca_attr, + driver_name, sizeof (driver_name), &instance, hca_device_path) + != IBT_SUCCESS) { rv = ENXIO; goto out; } - hca_info = &query_hca->hca_info; - - hca_info->hca_node_guid = hca_attr->hca_node_guid; - hca_info->hca_si_guid = hca_attr->hca_si_guid; - hca_info->hca_nports = hca_attr->hca_nports; - hca_info->hca_flags = hca_attr->hca_flags; - hca_info->hca_flags2 = hca_attr->hca_flags2; - hca_info->hca_vendor_id = hca_attr->hca_vendor_id; - hca_info->hca_device_id = hca_attr->hca_device_id; - hca_info->hca_version_id = hca_attr->hca_version_id; - hca_info->hca_max_chans = hca_attr->hca_max_chans; - hca_info->hca_max_chan_sz = hca_attr->hca_max_chan_sz; - hca_info->hca_max_sgl = hca_attr->hca_max_sgl; - hca_info->hca_max_cq = hca_attr->hca_max_cq; - hca_info->hca_max_cq_sz = hca_attr->hca_max_cq_sz; - hca_info->hca_page_sz = hca_attr->hca_page_sz; - hca_info->hca_max_memr = hca_attr->hca_max_memr; - hca_info->hca_max_memr_len = hca_attr->hca_max_memr_len; - hca_info->hca_max_mem_win = hca_attr->hca_max_mem_win; - hca_info->hca_max_rsc = hca_attr->hca_max_rsc; - hca_info->hca_max_rdma_in_chan = hca_attr->hca_max_rdma_in_chan; - hca_info->hca_max_rdma_out_chan = hca_attr->hca_max_rdma_out_chan; - hca_info->hca_max_ipv6_chan = hca_attr->hca_max_ipv6_chan; - hca_info->hca_max_ether_chan = hca_attr->hca_max_ether_chan; - hca_info->hca_max_mcg_chans = hca_attr->hca_max_mcg_chans; - hca_info->hca_max_mcg = hca_attr->hca_max_mcg; - hca_info->hca_max_chan_per_mcg = hca_attr->hca_max_chan_per_mcg; - hca_info->hca_max_partitions = hca_attr->hca_max_partitions; - hca_info->hca_local_ack_delay = hca_attr->hca_local_ack_delay; - hca_info->hca_max_port_sgid_tbl_sz = hca_attr->hca_max_port_sgid_tbl_sz; - hca_info->hca_max_port_pkey_tbl_sz = hca_attr->hca_max_port_pkey_tbl_sz; - hca_info->hca_max_pd = hca_attr->hca_max_pd; - hca_info->hca_max_ud_dest = hca_attr->hca_max_ud_dest; - hca_info->hca_max_srqs = hca_attr->hca_max_srqs; - hca_info->hca_max_srqs_sz = hca_attr->hca_max_srqs_sz; - hca_info->hca_max_srq_sgl = hca_attr->hca_max_srq_sgl; - hca_info->hca_max_cq_handlers = hca_attr->hca_max_cq_handlers; - hca_info->hca_reserved_lkey = hca_attr->hca_reserved_lkey; - hca_info->hca_max_fmrs = hca_attr->hca_max_fmrs; - hca_info->hca_max_lso_size = hca_attr->hca_max_lso_size; - hca_info->hca_max_lso_hdr_size = hca_attr->hca_max_lso_hdr_size; - hca_info->hca_max_inline_size = hca_attr->hca_max_inline_size; - hca_info->hca_max_cq_mod_count = hca_attr->hca_max_cq_mod_count; - hca_info->hca_max_cq_mod_usec = hca_attr->hca_max_cq_mod_usec; - hca_info->hca_fw_major_version = hca_attr->hca_fw_major_version; - hca_info->hca_fw_minor_version = hca_attr->hca_fw_minor_version; - hca_info->hca_fw_micro_version = hca_attr->hca_fw_micro_version; - hca_info->hca_ud_send_inline_sz = hca_attr->hca_ud_send_inline_sz; - hca_info->hca_conn_send_inline_sz = hca_attr->hca_conn_send_inline_sz; - hca_info->hca_conn_rdmaw_inline_overhead = - hca_attr->hca_conn_rdmaw_inline_overhead; - hca_info->hca_recv_sgl_sz = hca_attr->hca_recv_sgl_sz; - hca_info->hca_ud_send_sgl_sz = hca_attr->hca_ud_send_sgl_sz; - hca_info->hca_conn_send_sgl_sz = hca_attr->hca_conn_send_sgl_sz; - hca_info->hca_conn_rdma_sgl_overhead = - hca_attr->hca_conn_rdma_sgl_overhead; - - (void) strlcpy(hca_info->hca_driver_name, driver_name, - MAX_HCA_DRVNAME_LEN); - hca_info->hca_driver_instance = instance; - - /* copy hca information to the user space */ - if (ddi_copyout(hca_info, &((ibnex_ctl_query_hca_t *)arg)->hca_info, - sizeof (ibnex_ctl_hca_info_t), mode) != 0) { - IBTF_DPRINTF_L2("ibnex", "\tctl_query_hca: ddi_copyout err"); - rv = EFAULT; + hca_device_path_len = strlen(hca_device_path) + 1; + +#ifdef _MULTI_DATAMODEL + if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { + + IBNEX_CTL_CP_HCA_INFO(&query_hca_32->hca_info, hca_attr, + driver_name, instance, query_hca_32->hca_device_path, + device_path_alloc_sz, hca_device_path_len); + + /* copy hca information to the user space */ + if (ddi_copyout(&query_hca_32->hca_info, + &((ibnex_ctl_query_hca_32_t *)arg)->hca_info, + sizeof (ibnex_ctl_hca_info_32_t), mode) != 0) { + IBTF_DPRINTF_L2("ibnex", + "\tctl_query_hca: ddi_copyout err 1"); + rv = EFAULT; + goto out; + } + } else +#endif + { + IBNEX_CTL_CP_HCA_INFO(&query_hca->hca_info, hca_attr, + driver_name, instance, device_path, + device_path_alloc_sz, hca_device_path_len); + + /* copy hca information to the user space */ + if (ddi_copyout(&query_hca->hca_info, + &((ibnex_ctl_query_hca_t *)arg)->hca_info, + sizeof (ibnex_ctl_hca_info_t), mode) != 0) { + IBTF_DPRINTF_L2("ibnex", + "\tctl_query_hca: ddi_copyout err 2"); + rv = EFAULT; + goto out; + } + } + + if (device_path_alloc_sz >= hca_device_path_len) { + if (ddi_copyout(hca_device_path, + device_path, + hca_device_path_len, mode) != 0) { + IBTF_DPRINTF_L2("ibnex", "\tctl_query_hca: " + "ddi_copyout err copying device path"); + rv = EFAULT; + } } out: - kmem_free(query_hca, sizeof (ibnex_ctl_query_hca_t)); - kmem_free(hca_attr, sizeof (ibt_hca_attr_t)); + if (query_hca) + kmem_free(query_hca, sizeof (ibnex_ctl_query_hca_t)); + if (query_hca_32) + kmem_free(query_hca_32, sizeof (ibnex_ctl_query_hca_32_t)); + if (hca_attr) + kmem_free(hca_attr, sizeof (ibt_hca_attr_t)); + if (hca_device_path) + kmem_free(hca_device_path, MAXPATHLEN); + return (rv); } @@ -3056,7 +3133,7 @@ if (ddi_copyin((void *)arg, query_hca_port_32, sizeof (ibnex_ctl_query_hca_port_32_t), mode) != 0) { IBTF_DPRINTF_L2("ibnex", - "\tctl_query_hca_port: ddi_copyin err 2"); + "\tctl_query_hca_port: ddi_copyin err 1"); rv = EFAULT; goto out; }
--- a/usr/src/uts/common/io/ib/ibtl/ibtl_ibnex.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/ib/ibtl/ibtl_ibnex.c Mon Jul 20 13:07:46 2009 -0400 @@ -635,6 +635,8 @@ * driver_name - caller allocated buffer which will contain * HCA driver name upon success * driver_instance - HCA driver instance + * hca_device_path - caller allocated buffer of size MAXPATHLEN which + * will contain hca device path upon success. * Returns: * IBT_SUCCESS/IBT_FAILURE * Description: @@ -643,7 +645,8 @@ */ ibt_status_t ibtl_ibnex_query_hca_byguid(ib_guid_t hca_guid, ibt_hca_attr_t *hca_attrs, - char *driver_name, size_t driver_name_size, int *driver_instance) + char *driver_name, size_t driver_name_size, int *driver_instance, + char *hca_device_path) { ibtl_hca_devinfo_t *hca_devp; @@ -667,6 +670,7 @@ return (IBT_INSUFF_KERNEL_RESOURCE); } + (void) ddi_pathname(hca_devp->hd_hca_dip, hca_device_path); *driver_instance = ddi_get_instance(hca_devp->hd_hca_dip); bcopy(hca_devp->hd_hca_attr, hca_attrs, sizeof (ibt_hca_attr_t));
--- a/usr/src/uts/common/io/ib/mgt/ibdm/ibdm.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/ib/mgt/ibdm/ibdm.c Mon Jul 20 13:07:46 2009 -0400 @@ -41,6 +41,7 @@ #include <sys/taskq.h> #include <sys/ib/mgt/ibdm/ibdm_impl.h> #include <sys/ib/mgt/ibmf/ibmf_impl.h> +#include <sys/ib/ibtl/impl/ibtl_ibnex.h> #include <sys/modctl.h> /* Function Prototype declarations */ @@ -87,6 +88,7 @@ static void ibdm_alloc_send_buffers(ibmf_msg_t *); static void ibdm_free_send_buffers(ibmf_msg_t *); static void ibdm_handle_hca_detach(ib_guid_t); +static void ibdm_handle_port_change_event(ibt_async_event_t *); static int ibdm_fini_port(ibdm_port_attr_t *); static int ibdm_uninit_hca(ibdm_hca_list_t *); static void ibdm_handle_setclassportinfo(ibmf_handle_t, ibmf_msg_t *, @@ -553,6 +555,14 @@ hca_list->hl_nports_active++; cv_broadcast(&ibdm.ibdm_port_settle_cv); mutex_exit(&ibdm.ibdm_hl_mutex); + + /* Inform IB nexus driver */ + mutex_enter(&ibdm.ibdm_ibnex_mutex); + if (ibdm.ibdm_ibnex_callback != NULL) { + (*ibdm.ibdm_ibnex_callback)((void *) + &event->ev_hca_guid, IBDM_EVENT_PORT_UP); + } + mutex_exit(&ibdm.ibdm_ibnex_mutex); break; case IBT_ERROR_PORT_DOWN: @@ -576,19 +586,8 @@ case IBT_PORT_CHANGE_EVENT: IBTF_DPRINTF_L4("ibdm", "\tevent_hdlr: PORT_CHANGE"); - if (event->ev_port_flags & IBT_PORT_CHANGE_PKEY) { - mutex_enter(&ibdm.ibdm_hl_mutex); - port = ibdm_get_port_attr(event, &hca_list); - if (port == NULL) { - IBTF_DPRINTF_L2("ibdm", - "\tevent_hdlr: HCA not present"); - mutex_exit(&ibdm.ibdm_hl_mutex); - break; - } - ibdm_update_port_pkeys(port); - cv_broadcast(&ibdm.ibdm_port_settle_cv); - mutex_exit(&ibdm.ibdm_hl_mutex); - } + if (event->ev_port_flags & IBT_PORT_CHANGE_PKEY) + ibdm_handle_port_change_event(event); break; default: /* Ignore all other events/errors */ @@ -596,6 +595,33 @@ } } +static void +ibdm_handle_port_change_event(ibt_async_event_t *event) +{ + ibdm_port_attr_t *port; + ibdm_hca_list_t *hca_list; + + IBTF_DPRINTF_L2("ibdm", "\tibdm_handle_port_change_event:" + " HCA guid %llx", event->ev_hca_guid); + mutex_enter(&ibdm.ibdm_hl_mutex); + port = ibdm_get_port_attr(event, &hca_list); + if (port == NULL) { + IBTF_DPRINTF_L2("ibdm", "\tevent_hdlr: HCA not present"); + mutex_exit(&ibdm.ibdm_hl_mutex); + return; + } + ibdm_update_port_pkeys(port); + cv_broadcast(&ibdm.ibdm_port_settle_cv); + mutex_exit(&ibdm.ibdm_hl_mutex); + + /* Inform IB nexus driver */ + mutex_enter(&ibdm.ibdm_ibnex_mutex); + if (ibdm.ibdm_ibnex_callback != NULL) { + (*ibdm.ibdm_ibnex_callback)((void *) + &event->ev_hca_guid, IBDM_EVENT_PORT_PKEY_CHANGE); + } + mutex_exit(&ibdm.ibdm_ibnex_mutex); +} /* * ibdm_update_port_pkeys() @@ -1106,8 +1132,11 @@ } } if (head->hl_hca_hdl) - if (ibt_close_hca(head->hl_hca_hdl) != IBT_SUCCESS) + if (ibt_close_hca(head->hl_hca_hdl) != IBT_SUCCESS) { + IBTF_DPRINTF_L2("ibdm", "uninit_hca: " + "ibt_close_hca() failed"); return (IBDM_FAILURE); + } kmem_free(head->hl_port_attr, head->hl_nports * sizeof (ibdm_port_attr_t)); kmem_free(head->hl_hca_port_attr, sizeof (ibdm_port_attr_t)); @@ -1151,7 +1180,7 @@ ibmf_status = ibmf_unregister(&port_attr->pa_ibmf_hdl, 0); if (ibmf_status != IBMF_SUCCESS) { - IBTF_DPRINTF_L4("ibdm", "\tfini_port: " + IBTF_DPRINTF_L2("ibdm", "\tfini_port: " "ibmf_unregister failed %d", ibmf_status); return (IBDM_FAILURE); } @@ -1162,7 +1191,7 @@ if (port_attr->pa_sa_hdl) { ibmf_status = ibmf_sa_session_close(&port_attr->pa_sa_hdl, 0); if (ibmf_status != IBMF_SUCCESS) { - IBTF_DPRINTF_L4("ibdm", "\tfini_port: " + IBTF_DPRINTF_L2("ibdm", "\tfini_port: " "ibmf_sa_session_close failed %d", ibmf_status); return (IBDM_FAILURE); } @@ -5404,7 +5433,7 @@ */ if (ibmf_alloc_msg(gid_info->gl_ibmf_hdl, IBMF_ALLOC_SLEEP, &msg) != IBMF_SUCCESS) { - IBTF_DPRINTF_L4("ibdm", "\tsend_ioc_profile: pkt alloc fail"); + IBTF_DPRINTF_L2("ibdm", "\tsend_ioc_profile: pkt alloc fail"); return (IBDM_FAILURE); }
--- a/usr/src/uts/common/io/kb8042/at_keyprocess.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/kb8042/at_keyprocess.c Mon Jul 20 13:07:46 2009 -0400 @@ -33,29 +33,12 @@ #include "kb8042.h" /* - * Debugging for this module is enabled by the kb8042_debug flag - * defined in kb8042.c. See that module for details. This flag is - * hotkey enabled by F10 if the kb8042_enable_debug_hotkey flag is set. - */ - -#if defined(DEBUG) || defined(lint) -#define KD_DEBUG -#endif - -/* * A note on the use of prom_printf here: Most of these routines can be * called from "polled mode", where we're servicing I/O requests from kmdb. * Normal system services are not available from polled mode; cmn_err will * not work. prom_printf is the only safe output mechanism. */ -#if defined(KD_DEBUG) -extern boolean_t kb8042_debug; -#define DEBUG_KD(f) { if (kb8042_debug) prom_printf f; } -#else -#define DEBUG_KD(f) /* nothing */ -#endif - #define KEYBAD 0xff /* should generate an error */ #define KEYIGN 0xfe /* ignore this sequence */ @@ -748,8 +731,6 @@ enum keystate *state, boolean_t *synthetic_release_needed) { - DEBUG_KD(("KeyboardConvertScan_set1: 0x%02x ", scan)); - *synthetic_release_needed = B_FALSE; *state = KEY_PRESSED; @@ -763,7 +744,6 @@ * Perhaps we should reset state here, * since we no longer know what's going on. */ - DEBUG_KD(("-> overrun\n")); return (B_FALSE); case KB_POST_FAIL: /* @@ -776,7 +756,6 @@ * Reset to idle */ kb8042->parse_scan_state = STATE_IDLE; - DEBUG_KD(("-> POST %s\n", scan == KB_POST_OK ? "OK" : "FAIL")); return (B_FALSE); case KXT_EXTEND: @@ -809,12 +788,10 @@ switch (scan) { case KXT_EXTEND: kb8042->parse_scan_state = STATE_E0; - DEBUG_KD(("-> state E0\n")); return (B_FALSE); case KXT_EXTEND2: kb8042->parse_scan_state = STATE_E1; - DEBUG_KD(("-> state E1\n")); return (B_FALSE); /* @@ -857,7 +834,6 @@ switch (scan) { case 0x1d: kb8042->parse_scan_state = STATE_E1_1D; - DEBUG_KD(("-> state E1 1D\n")); return (B_FALSE); default: *keynum = INVALID; @@ -888,11 +864,9 @@ switch (*keynum) { case KEYIGN: /* not a key, nor an error */ - DEBUG_KD(("-> hole -> ignored\n")); return (B_FALSE); /* also not a final keycode */ case KEYBAD: /* not part of a legit sequence? */ - DEBUG_KD(("-> bad -> ignored\n")); return (B_FALSE); /* and return not a final keycode */ default: @@ -900,11 +874,6 @@ * If we're here, it's a valid keycode. We've already * filled in the return values; return success. */ - - DEBUG_KD(("-> %s keypos %d\n", - *state == KEY_RELEASED ? "released" : "pressed", - *keynum)); - return (B_TRUE); /* resolved to a key */ } } @@ -930,8 +899,6 @@ enum keystate *state, boolean_t *synthetic_release_needed) { - DEBUG_KD(("KeyboardConvertScan_set2: 0x%02x ", scan)); - *synthetic_release_needed = B_FALSE; *state = KEY_PRESSED; @@ -949,7 +916,6 @@ case KAT_BREAK: /* Switch states so we can recognize the code that follows */ kb8042->break_received = 1; - DEBUG_KD(("-> break prefix\n")); return (B_FALSE); /* not a final keycode */ case KB_ERROR: @@ -957,7 +923,6 @@ * Perhaps we should reset state here, * since we no longer know what's going on. */ - DEBUG_KD(("-> overrun\n")); return (B_FALSE); case KB_POST_OK: @@ -972,7 +937,6 @@ * Reset to idle */ kb8042->parse_scan_state = STATE_IDLE; - DEBUG_KD(("-> POST %s\n", scan == KB_POST_OK ? "OK" : "FAIL")); return (B_FALSE); } @@ -986,12 +950,10 @@ switch (scan) { case KXT_EXTEND: kb8042->parse_scan_state = STATE_E0; - DEBUG_KD(("-> state E0\n")); return (B_FALSE); case KXT_EXTEND2: kb8042->parse_scan_state = STATE_E1; - DEBUG_KD(("-> state E1\n")); return (B_FALSE); /* @@ -1034,7 +996,6 @@ switch (scan) { case 0x14: kb8042->parse_scan_state = STATE_E1_14; - DEBUG_KD(("-> state E1 14\n")); return (B_FALSE); default: *keynum = INVALID; @@ -1112,11 +1073,9 @@ switch (*keynum) { case KEYIGN: /* not a key, nor an error */ - DEBUG_KD(("-> hole -> ignored\n")); return (B_FALSE); /* also not a final keycode */ case KEYBAD: /* not part of a legit sequence? */ - DEBUG_KD(("-> bad -> ignored\n")); return (B_FALSE); /* and return not a final keycode */ default: @@ -1124,11 +1083,6 @@ * If we're here, it's a valid keycode. We've already * filled in the return values; return success. */ - - DEBUG_KD(("-> %s keypos %d\n", - *state == KEY_RELEASED ? "released" : "pressed", - *keynum)); - return (B_TRUE); /* resolved to a key */ } }
--- a/usr/src/uts/common/io/kb8042/kb8042.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/kb8042/kb8042.c Mon Jul 20 13:07:46 2009 -0400 @@ -103,32 +103,6 @@ /* 248 */ 0, 0, 0, 0 }; -/* - * DEBUG (or KD_DEBUG for just this module) turns on a flag called - * kb8042_enable_debug_hotkey. If kb8042_enable_debug_hotkey is true, - * then the following hotkeys are enabled: - * F10 - turn on debugging "normal" translations - * F9 - turn on debugging "getchar" translations - * F8 - turn on "low level" debugging - * F7 - turn on terse press/release debugging - * F1 - turn off all debugging - * The default value for kb8042_enable_debug_hotkey is false, disabling - * these hotkeys. - */ - -#if defined(DEBUG) || defined(lint) -#define KD_DEBUG -#endif - -#ifdef KD_DEBUG -boolean_t kb8042_enable_debug_hotkey = B_FALSE; -boolean_t kb8042_debug = B_FALSE; -boolean_t kb8042_getchar_debug = B_FALSE; -boolean_t kb8042_low_level_debug = B_FALSE; -boolean_t kb8042_pressrelease_debug = B_FALSE; -static void kb8042_debug_hotkey(int scancode); -#endif - #ifdef __sparc #define USECS_PER_WAIT 100 #define MAX_WAIT_USECS 100000 /* in usecs = 100 ms */ @@ -139,6 +113,9 @@ #endif +#define MAX_KB8042_WAIT_MAX_MS 500 /* 500ms total */ +#define MAX_KB8042_RETRIES 5 + enum state_return { STATE_NORMAL, STATE_INTERNAL }; static void kb8042_init(struct kb8042 *kb8042, boolean_t from_resume); @@ -312,21 +289,24 @@ } } +/* + * kb8042_send_and_expect does all its I/O via polling interfaces + */ static boolean_t kb8042_send_and_expect(struct kb8042 *kb8042, uint8_t send, uint8_t expect, - boolean_t polled, int timeout, int *error, uint8_t *got) + int timeout, int *error, uint8_t *got) { - int port = (polled == B_TRUE) ? I8042_POLL_INPUT_DATA : - I8042_INT_INPUT_DATA; uint8_t datab; int err; boolean_t rval; - kb8042_send_to_keyboard(kb8042, send, polled); + ddi_put8(kb8042->handle, + kb8042->addr + I8042_POLL_OUTPUT_DATA, send); - if (kb8042_is_input_avail(kb8042, timeout, polled)) { + if (kb8042_is_input_avail(kb8042, timeout, B_TRUE)) { err = 0; - datab = ddi_get8(kb8042->handle, kb8042->addr + port); + datab = ddi_get8(kb8042->handle, + kb8042->addr + I8042_POLL_INPUT_DATA); rval = ((datab == expect) ? B_TRUE : B_FALSE); } else { err = EAGAIN; @@ -351,12 +331,16 @@ } } +/* + * kb8042_read_scanset works properly because it is called before ddi_add_intr + * (if it is called after ddi_add_intr, i8042_intr would call kb8042_intr + * instead of just storing the data that comes in from the keyboard, which + * would prevent the code here from getting it.) + */ static int -kb8042_read_scanset(struct kb8042 *kb8042, boolean_t polled) +kb8042_read_scanset(struct kb8042 *kb8042) { int scanset = -1; - int port = (polled == B_TRUE) ? I8042_POLL_INPUT_DATA : - I8042_INT_INPUT_DATA; int err; uint8_t got; @@ -366,8 +350,8 @@ * Send a "change scan code set" command to the keyboard. * It should respond with an ACK. */ - if (kb8042_send_and_expect(kb8042, KB_SET_SCAN, KB_ACK, polled, - MAX_WAIT_USECS, &err, &got) != B_TRUE) { + if (kb8042_send_and_expect(kb8042, KB_SET_SCAN, KB_ACK, MAX_WAIT_USECS, + &err, &got) != B_TRUE) { goto fail_read_scanset; } @@ -375,8 +359,8 @@ * Send a 0. The keyboard should ACK the 0, then it should send the * scan code set in use. */ - if (kb8042_send_and_expect(kb8042, 0, KB_ACK, polled, - MAX_WAIT_USECS, &err, &got) != B_TRUE) { + if (kb8042_send_and_expect(kb8042, 0, KB_ACK, MAX_WAIT_USECS, &err, + &got) != B_TRUE) { goto fail_read_scanset; } @@ -386,11 +370,11 @@ * just for fun, so blow past those to get the keyboard scan code. */ while (kb8042_is_input_avail(kb8042, MAX_WAIT_USECS, B_TRUE) && - (scanset = ddi_get8(kb8042->handle, kb8042->addr + port)) - == KB_ACK) + (scanset = ddi_get8(kb8042->handle, + kb8042->addr + I8042_POLL_INPUT_DATA)) == KB_ACK) ; -#ifdef KD_DEBUG +#ifdef DEBUG cmn_err(CE_NOTE, "!Scan code set from keyboard is `%d'.", scanset); #endif @@ -398,7 +382,7 @@ return (scanset); fail_read_scanset: -#ifdef KD_DEBUG +#ifdef DEBUG if (err == 0) cmn_err(CE_NOTE, "Could not read current scan set from " "keyboard: %s. (Expected 0x%x, but got 0x%x).", @@ -473,7 +457,7 @@ rc = ddi_regs_map_setup(devi, 0, (caddr_t *)&kb8042->addr, (offset_t)0, (offset_t)0, &attr, &kb8042->handle); if (rc != DDI_SUCCESS) { -#if defined(KD_DEBUG) +#ifdef DEBUG cmn_err(CE_WARN, "kb8042_attach: can't map registers"); #endif goto failure; @@ -490,13 +474,14 @@ mutex_init(&kb8042->w_hw_mutex, NULL, MUTEX_DRIVER, kb8042->w_iblock); cv_init(&kb8042->ops_cv, NULL, CV_DRIVER, NULL); cv_init(&kb8042->suspend_cv, NULL, CV_DRIVER, NULL); + cv_init(&kb8042->cmd_cv, NULL, CV_DRIVER, NULL); kb8042->init_state |= KB8042_HW_MUTEX_INITTED; kb8042_init(kb8042, B_FALSE); #ifdef __sparc /* Detect the scan code set currently in use */ - scanset = kb8042_read_scanset(kb8042, B_TRUE); + scanset = kb8042_read_scanset(kb8042); if (scanset < 0 && kb8042_warn_unknown_scanset) { @@ -542,7 +527,7 @@ ddi_report_dev(devi); -#ifdef KD_DEBUG +#ifdef DEBUG cmn_err(CE_CONT, "?%s instance #%d READY\n", DRIVER_NAME(devi), ddi_get_instance(devi)); #endif @@ -620,15 +605,16 @@ { ASSERT(kb8042_dip != NULL); + if (kb8042->init_state & KB8042_INTR_ADDED) + ddi_remove_intr(kb8042_dip, 0, kb8042->w_iblock); + if (kb8042->init_state & KB8042_HW_MUTEX_INITTED) { + cv_destroy(&kb8042->cmd_cv); cv_destroy(&kb8042->suspend_cv); cv_destroy(&kb8042->ops_cv); mutex_destroy(&kb8042->w_hw_mutex); } - if (kb8042->init_state & KB8042_INTR_ADDED) - ddi_remove_intr(kb8042_dip, 0, kb8042->w_iblock); - if (kb8042->init_state & KB8042_REGS_MAPPED) ddi_regs_map_free(&kb8042->handle); @@ -657,8 +643,15 @@ kb8042->kb_old_key_pos = 0; + /* + * Explicitly grab and release the 8042 lock outside of + * kb8042_send_to_keyboard, because this is the only situation + * where a polling interface is used with locking required. + */ + (void) ddi_get8(kb8042->handle, kb8042->addr + I8042_LOCK); /* Set up the command state machine and start it running. */ - kb8042_send_to_keyboard(kb8042, KB_ENABLE, B_FALSE); + kb8042_send_to_keyboard(kb8042, KB_ENABLE, B_TRUE); + (void) ddi_get8(kb8042->handle, kb8042->addr + I8042_UNLOCK); kb8042->w_init++; @@ -1013,9 +1006,23 @@ enum keystate state; boolean_t synthetic_release_needed; -#ifdef KD_DEBUG - kb8042_debug_hotkey(scancode); -#endif + /* + * Intercept ACK and RESEND and signal the condition that + * kb8042_send_and_wait is waiting for. + */ + if (scancode == KB_ACK) { + mutex_enter(&kb8042->w_hw_mutex); + kb8042->acked = 1; + cv_signal(&kb8042->cmd_cv); + mutex_exit(&kb8042->w_hw_mutex); + return; + } else if (scancode == KB_RESEND) { + mutex_enter(&kb8042->w_hw_mutex); + kb8042->need_retry = 1; + cv_signal(&kb8042->cmd_cv); + mutex_exit(&kb8042->w_hw_mutex); + return; + } if (!kb8042->w_init) /* can't do anything anyway */ return; @@ -1025,48 +1032,23 @@ if (legit == 0) { /* Eaten by translation */ -#ifdef KD_DEBUG - if (kb8042_debug) - prom_printf("kb8042_intr: 0x%x -> ignored\n", scancode); -#endif return; } -#ifdef KD_DEBUG - if (kb8042_debug) { - prom_printf("kb8042_intr: 0x%x -> %s %d", - scancode, - state == KEY_RELEASED ? "released" : "pressed", - key_pos); - } -#endif - /* * Don't know if we want this permanently, but it seems interesting * for the moment. */ if (key_pos == kb8042->debugger.mod1) { -#ifdef KD_DEBUG - if (kb8042_debug) - prom_printf(" -> debug mod1"); -#endif kb8042->debugger.mod1_down = (state == KEY_PRESSED); } if (key_pos == kb8042->debugger.mod2) { -#ifdef KD_DEBUG - if (kb8042_debug) - prom_printf(" -> debug mod2"); -#endif kb8042->debugger.mod2_down = (state == KEY_PRESSED); } if (kb8042->debugger.enabled && key_pos == kb8042->debugger.trigger && kb8042->debugger.mod1_down && kb8042->debugger.mod2_down) { -#ifdef KD_DEBUG - if (kb8042_debug) - prom_printf(" -> debugger\n"); -#endif /* * Require new presses of the modifiers. */ @@ -1083,10 +1065,6 @@ * Ctrl-Alt-D still works. */ if (kb8042->w_qp == NULL) { -#ifdef KD_DEBUG - if (kb8042_debug) - prom_printf(" -> nobody home\n"); -#endif return; } @@ -1097,27 +1075,11 @@ * Don't think so.) */ if (kb8042_autorepeat_detect(kb8042, key_pos, state)) { -#ifdef KD_DEBUG - if (kb8042_debug) - prom_printf(" -> autorepeat ignored\n"); -#endif return; } -#ifdef KD_DEBUG - if (kb8042_debug) - prom_printf(" -> OK\n"); -#endif -#if defined(KD_DEBUG) - if (kb8042_pressrelease_debug) { - prom_printf(" %s%d ", - state == KEY_PRESSED ? "+" : "-", - key_pos); - } -#endif - - kb8042_process_key(kb8042, key_pos, state); + kb8042_process_key(kb8042, key_pos, state); /* * This is a total hack. For some stupid reason, the two additional @@ -1125,12 +1087,6 @@ * only. We synthesize a release immediately. */ if (synthetic_release_needed) { -#if defined(KD_DEBUG) - if (kb8042_debug) - prom_printf("synthetic release %d\n", key_pos); - if (kb8042_pressrelease_debug) - prom_printf(" -%d(s) ", key_pos); -#endif (void) kb8042_autorepeat_detect(kb8042, key_pos, KEY_RELEASED); kb8042_process_key(kb8042, key_pos, state); } @@ -1179,11 +1135,6 @@ scancode = ddi_get8(kb8042->handle, kb8042->addr + I8042_INT_INPUT_DATA); -#if defined(KD_DEBUG) - if (kb8042_low_level_debug) - prom_printf(" <K:%x ", scancode); -#endif - kb8042_received_byte(kb8042, scancode); } @@ -1223,10 +1174,6 @@ *key = kb8042->polled_synthetic_release_key; *state = KEY_RELEASED; kb8042->polled_synthetic_release_pending = B_FALSE; -#if defined(KD_DEBUG) - if (kb8042_getchar_debug) - prom_printf("synthetic release 0x%x\n", *key); -#endif (void) kb8042_autorepeat_detect(kb8042, *key, *state); return (B_TRUE); } @@ -1240,33 +1187,11 @@ scancode = ddi_get8(kb8042->handle, kb8042->addr + I8042_POLL_INPUT_DATA); -#if defined(KD_DEBUG) - if (kb8042_low_level_debug) - prom_printf(" g<%x ", scancode); -#endif - -#ifdef KD_DEBUG - kb8042_debug_hotkey(scancode); - if (kb8042_getchar_debug) - prom_printf("polled 0x%x", scancode); -#endif - legit = KeyboardConvertScan(kb8042, scancode, key, state, &synthetic_release_needed); if (!legit) { -#ifdef KD_DEBUG - if (kb8042_getchar_debug) - prom_printf(" -> ignored\n"); -#endif continue; } -#ifdef KD_DEBUG - if (kb8042_getchar_debug) { - prom_printf(" -> %s %d\n", - *state == KEY_PRESSED ? "pressed" : "released", - *key); - } -#endif /* * For the moment at least, we rely on hardware autorepeat * for polled I/O autorepeat. However, for coordination @@ -1324,55 +1249,141 @@ kb8042_setled(kb8042, led_state, B_FALSE); } + +static int +kb8042_send_and_wait(struct kb8042 *kb8042, uint8_t u8, boolean_t polled) +{ + uint8_t *outp = kb8042->addr + + (polled ? I8042_POLL_OUTPUT_DATA : I8042_INT_OUTPUT_DATA); + uint8_t *inavp = kb8042->addr + + (polled ? I8042_POLL_INPUT_AVAIL : I8042_INT_INPUT_AVAIL); + uint8_t *inp = kb8042->addr + + (polled ? I8042_POLL_INPUT_DATA : I8042_INT_INPUT_DATA); + uint8_t b; + int ms_waited; + int timedout; + int expire; + int retries = 0; + + do { + kb8042->acked = 0; + kb8042->need_retry = 0; + ms_waited = 0; /* Zero it whether polled or not */ + timedout = 0; + + ddi_put8(kb8042->handle, outp, u8); + + while (!kb8042->acked && !kb8042->need_retry && !timedout) { + + if (polled) { + if (ddi_get8(kb8042->handle, inavp)) { + b = ddi_get8(kb8042->handle, inp); + switch (b) { + case KB_ACK: + kb8042->acked = 1; + break; + case KB_RESEND: + kb8042->need_retry = 1; + break; + default: + /* + * drop it: We should never + * get scancodes while + * we're in the middle of a + * command anyway. + */ +#ifdef DEBUG + cmn_err(CE_WARN, "!Unexpected " + " byte 0x%x", b); +#endif + break; + } + } + + /* + * Wait 1ms if an ACK wasn't received yet + */ + if (!kb8042->acked) { + drv_usecwait(1000); + ms_waited++; + if (ms_waited >= MAX_KB8042_WAIT_MAX_MS) + timedout = B_TRUE; + } + } else { + /* Interrupt-driven */ + expire = ddi_get_lbolt() + + drv_usectohz(MAX_KB8042_WAIT_MAX_MS * 1000); + + /* + * If cv_timedwait returned -1 and we neither + * received an ACK nor a RETRY response, then + * we timed out. + */ + if (cv_timedwait(&kb8042->cmd_cv, + &kb8042->w_hw_mutex, expire) == -1 && + !kb8042->acked && !kb8042->need_retry) { + timedout = B_TRUE; + } + } + + } + } while ((kb8042->need_retry || timedout) && + ++retries < MAX_KB8042_RETRIES); + + return (kb8042->acked); +} + +/* + * kb8042_send_to_keyboard should be called with w_hw_mutex held if + * polled is FALSE. + */ static void kb8042_send_to_keyboard(struct kb8042 *kb8042, int byte, boolean_t polled) { - uint8_t led_cmd[4]; /* - * KB_SET_LED and KB_ENABLE are special commands for which the nexus - * driver is requested to wait for responses before proceeding. - * KB_SET_LED also provides an option byte for the nexus to send to - * the keyboard after the acknowledgement. + * KB_SET_LED and KB_ENABLE are special commands which require blocking + * other 8042 consumers while executing. * * Other commands/data are sent using the single put8 I/O access * function. */ if (byte == KB_SET_LED) { - /* - * Initialize the buffer used with _rep_put8. We - * expect an ACK after the SET_LED command, at which point - * the LED byte should be sent to the keyboard. - */ - led_cmd[0] = KB_SET_LED; - led_cmd[1] = KB_ACK; - led_cmd[2] = KB_RESEND; - led_cmd[3] = kb8042_xlate_leds(kb8042->leds.desired); - if (polled) { - ddi_rep_put8(kb8042->handle, &led_cmd[0], - kb8042->addr + I8042_POLL_CMD_PLUS_PARAM, 4, 0); - } else { - ddi_rep_put8(kb8042->handle, &led_cmd[0], - kb8042->addr + I8042_INT_CMD_PLUS_PARAM, 4, 0); + + if (!polled) { + (void) ddi_get8(kb8042->handle, kb8042->addr + + I8042_LOCK); + } + + if (kb8042_send_and_wait(kb8042, KB_SET_LED, polled)) { + /* + * Ignore return value, as there's nothing we can + * do about it if the SET LED command fails. + */ + (void) kb8042_send_and_wait(kb8042, + kb8042_xlate_leds(kb8042->leds.desired), polled); + } + + if (!polled) { + (void) ddi_get8(kb8042->handle, kb8042->addr + + I8042_UNLOCK); } kb8042->leds.commanded = kb8042->leds.desired; } else if (byte == KB_ENABLE) { - /* - * Initialize the buffer used with _rep_put8. We - * expect an ACK after the KB_ENABLE command. - */ - led_cmd[0] = KB_ENABLE; - led_cmd[1] = KB_ACK; - led_cmd[2] = KB_RESEND; - if (polled) { - ddi_rep_put8(kb8042->handle, &led_cmd[0], - kb8042->addr + I8042_POLL_CMD_PLUS_PARAM, 3, 0); - } else { - ddi_rep_put8(kb8042->handle, &led_cmd[0], - kb8042->addr + I8042_INT_CMD_PLUS_PARAM, 3, 0); + if (!polled) { + (void) ddi_get8(kb8042->handle, kb8042->addr + + I8042_LOCK); } + + (void) kb8042_send_and_wait(kb8042, KB_ENABLE, polled); + + if (!polled) { + (void) ddi_get8(kb8042->handle, kb8042->addr + + I8042_UNLOCK); + } + } else { /* All other commands use the "normal" virtual output port */ if (polled) { @@ -1383,11 +1394,6 @@ kb8042->addr + I8042_INT_OUTPUT_DATA, byte); } } - -#if defined(KD_DEBUG) - if (kb8042_low_level_debug) - prom_printf(" >K:%x ", byte); -#endif } /* @@ -1404,7 +1410,6 @@ { int cnt; int ready; - unsigned char byt; /* wait for up to 250 ms for a response */ for (cnt = 0; cnt < 250; cnt++) { @@ -1421,12 +1426,8 @@ * already. (On a PC, the BIOS almost certainly did.) */ if (ready != 0) { - byt = ddi_get8(kb8042->handle, + (void) ddi_get8(kb8042->handle, kb8042->addr + I8042_INT_INPUT_DATA); -#if defined(KD_DEBUG) - if (kb8042_low_level_debug) - prom_printf(" <K:%x ", byt); -#endif } } @@ -1474,55 +1475,6 @@ #endif } -#if defined(KD_DEBUG) -static void -kb8042_debug_hotkey(int scancode) -{ - if (!kb8042_enable_debug_hotkey) - return; - - switch (scancode) { - case 0x44: /* F10 in Scan Set 1 code. (Set 2 code is 0x09) */ - if (!kb8042_debug) { - prom_printf("\nKeyboard: normal debugging on\n"); - kb8042_debug = B_TRUE; - } - break; - case 0x43: /* F9 in Scan Set 1 code. (Set 2 code is 0x01) */ - if (!kb8042_getchar_debug) { - prom_printf("\nKeyboard: getchar debugging on\n"); - kb8042_getchar_debug = B_TRUE; - } - break; - case 0x42: /* F8 in Scan Set 1 code. (Set 2 code is 0x0a) */ - if (!kb8042_low_level_debug) { - prom_printf("\nKeyboard: low-level debugging on\n"); - kb8042_low_level_debug = B_TRUE; - } - break; - case 0x41: /* F7 in Scan Set 1 code. (Set 2 code is 0x83) */ - if (!kb8042_pressrelease_debug) { - prom_printf( - "\nKeyboard: press/release debugging on\n"); - kb8042_pressrelease_debug = B_TRUE; - } - break; - case 0x3b: /* F1 in Scan Set 1 code. (Set 2 code is 0x05) */ - if (kb8042_debug || - kb8042_getchar_debug || - kb8042_low_level_debug || - kb8042_pressrelease_debug) { - prom_printf("\nKeyboard: all debugging off\n"); - kb8042_debug = B_FALSE; - kb8042_getchar_debug = B_FALSE; - kb8042_low_level_debug = B_FALSE; - kb8042_pressrelease_debug = B_FALSE; - } - break; - } -} -#endif - static boolean_t kb8042_autorepeat_detect( struct kb8042 *kb8042,
--- a/usr/src/uts/common/io/kb8042/kb8042.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/kb8042/kb8042.h Mon Jul 20 13:07:46 2009 -0400 @@ -24,7 +24,7 @@ /* All Rights Reserved */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -112,6 +112,9 @@ int ops; kcondvar_t suspend_cv; kcondvar_t ops_cv; + int acked; + int need_retry; + kcondvar_t cmd_cv; }; extern boolean_t KeyboardConvertScan(struct kb8042 *, unsigned char scan,
--- a/usr/src/uts/common/io/lvm/mirror/mirror_resync.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/lvm/mirror/mirror_resync.c Mon Jul 20 13:07:46 2009 -0400 @@ -20,7 +20,7 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -3808,7 +3808,7 @@ rw_enter(&un->un_pernode_dirty_mx[node], RW_WRITER); if (un->un_pernode_dirty_bm[node] == NULL) { un->un_pernode_dirty_bm[node] = (uchar_t *)kmem_zalloc( - un->un_rrd_num, KM_SLEEP); + howmany(un->un_rrd_num, NBBY), KM_SLEEP); } rw_exit(&un->un_pernode_dirty_mx[node]);
--- a/usr/src/uts/common/io/mouse8042.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/mouse8042.c Mon Jul 20 13:07:46 2009 -0400 @@ -23,7 +23,7 @@ /* All Rights Reserved */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -42,6 +42,7 @@ #include <sys/stream.h> #include <sys/stropts.h> #include <sys/strtty.h> +#include <sys/strsun.h> #include <sys/debug.h> #include <sys/ddi.h> #include <sys/stat.h> @@ -53,17 +54,16 @@ #include <sys/i8042.h> #include <sys/note.h> +#include <sys/mouse.h> #define DRIVER_NAME(dip) ddi_driver_name(dip) -#ifdef DEBUG -#define MOUSE8042_DEBUG -#endif - #define MOUSE8042_INTERNAL_OPEN(minor) (((minor) & 0x1) == 1) #define MOUSE8042_MINOR_TO_INSTANCE(minor) ((minor) / 2) #define MOUSE8042_INTERNAL_MINOR(minor) ((minor) + 1) +#define MOUSE8042_RESET_TIMEOUT_USECS 500000 /* 500 ms */ + extern int ddi_create_internal_pathname(dev_info_t *, char *, int, minor_t); extern void consconfig_link(major_t major, minor_t minor); extern int consconfig_unlink(major_t major, minor_t minor); @@ -85,6 +85,17 @@ */ static dev_info_t *mouse8042_dip; +/* + * RESET states + */ +typedef enum { + MSE_RESET_IDLE, /* No reset in progress */ + MSE_RESET_PRE, /* Send reset, waiting for ACK */ + MSE_RESET_ACK, /* Got ACK, waiting for 0xAA */ + MSE_RESET_AA, /* Got 0xAA, waiting for 0x00 */ + MSE_RESET_FAILED +} mouse8042_reset_state_e; + struct mouse_state { queue_t *ms_rqp; queue_t *ms_wqp; @@ -95,18 +106,19 @@ minor_t ms_minor; boolean_t ms_opened; + kmutex_t reset_mutex; + mouse8042_reset_state_e reset_state; + timeout_id_t reset_tid; + int ready; + mblk_t *reply_mp; + bufcall_id_t bc_id; }; -#if defined(MOUSE8042_DEBUG) -int mouse8042_debug = 0; -int mouse8042_debug_minimal = 0; -#endif - static uint_t mouse8042_intr(caddr_t arg); static int mouse8042_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *cred_p); static int mouse8042_close(queue_t *q, int flag, cred_t *cred_p); -static int mouse8042_wput(queue_t *q, mblk_t *mp); +static int mouse8042_wsrv(queue_t *qp); static int mouse8042_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result); @@ -137,8 +149,8 @@ }; static struct qinit mouse8042_winit = { - mouse8042_wput, /* put */ - NULL, /* service */ + putq, /* put */ + mouse8042_wsrv, /* service */ NULL, /* open */ NULL, /* close */ NULL, /* admin */ @@ -254,15 +266,12 @@ int rc; -#ifdef MOUSE8042_DEBUG - if (mouse8042_debug) { - cmn_err(CE_CONT, MODULE_NAME "_attach entry\n"); - } -#endif - if (cmd == DDI_RESUME) { state = (struct mouse_state *)ddi_get_driver_private(dip); + /* Ready to handle inbound data from mouse8042_intr */ + state->ready = 1; + /* * Send a 0xaa 0x00 upstream. * This causes the vuid module to reset the mouse. @@ -289,6 +298,9 @@ /* allocate and initialize state structure */ state = kmem_zalloc(sizeof (struct mouse_state), KM_SLEEP); state->ms_opened = B_FALSE; + state->reset_state = MSE_RESET_IDLE; + state->reset_tid = 0; + state->bc_id = 0; ddi_set_driver_private(dip, state); /* @@ -310,10 +322,6 @@ rc = ddi_create_minor_node(dip, "mouse", S_IFCHR, instance * 2, DDI_NT_MOUSE, NULL); if (rc != DDI_SUCCESS) { -#if defined(MOUSE8042_DEBUG) - cmn_err(CE_CONT, - MODULE_NAME "_attach: ddi_create_minor_node failed\n"); -#endif goto fail_1; } @@ -325,41 +333,33 @@ rc = ddi_regs_map_setup(dip, 0, (caddr_t *)&state->ms_addr, (offset_t)0, (offset_t)0, &attr, &state->ms_handle); if (rc != DDI_SUCCESS) { -#if defined(MOUSE8042_DEBUG) - cmn_err(CE_WARN, MODULE_NAME "_attach: can't map registers"); -#endif goto fail_2; } rc = ddi_get_iblock_cookie(dip, 0, &state->ms_iblock_cookie); if (rc != DDI_SUCCESS) { -#if defined(MOUSE8042_DEBUG) - cmn_err(CE_WARN, - MODULE_NAME "_attach: Can't get iblock cookie"); -#endif goto fail_3; } mutex_init(&state->ms_mutex, NULL, MUTEX_DRIVER, state->ms_iblock_cookie); + mutex_init(&state->reset_mutex, NULL, MUTEX_DRIVER, + state->ms_iblock_cookie); rc = ddi_add_intr(dip, 0, (ddi_iblock_cookie_t *)NULL, (ddi_idevice_cookie_t *)NULL, mouse8042_intr, (caddr_t)state); if (rc != DDI_SUCCESS) { -#if defined(MOUSE8042_DEBUG) - cmn_err(CE_WARN, MODULE_NAME "_attach: cannot add interrupt"); -#endif goto fail_3; } mouse8042_dip = dip; + /* Ready to handle inbound data from mouse8042_intr */ + state->ready = 1; + /* Now that we're attached, announce our presence to the world. */ ddi_report_dev(dip); -#if defined(MOUSE8042_DEBUG) - cmn_err(CE_CONT, "?%s #%d\n", DRIVER_NAME(dip), ddi_get_instance(dip)); -#endif return (DDI_SUCCESS); fail_3: @@ -383,11 +383,14 @@ switch (cmd) { case DDI_SUSPEND: + /* Ignore all data from mouse8042_intr until we fully resume */ + state->ready = 0; return (DDI_SUCCESS); case DDI_DETACH: ddi_remove_intr(dip, 0, state->ms_iblock_cookie); mouse8042_dip = NULL; + mutex_destroy(&state->reset_mutex); mutex_destroy(&state->ms_mutex); ddi_prop_remove_all(dip); ddi_regs_map_free(&state->ms_handle); @@ -396,12 +399,6 @@ return (DDI_SUCCESS); default: -#ifdef MOUSE8042_DEBUG - if (mouse8042_debug) { - cmn_err(CE_CONT, - "mouse8042_detach: cmd = %d unknown\n", cmd); - } -#endif return (DDI_FAILURE); } } @@ -419,10 +416,6 @@ minor_t minor = getminor(dev); int instance = MOUSE8042_MINOR_TO_INSTANCE(minor); -#ifdef MOUSE8042_DEBUG - if (mouse8042_debug) - cmn_err(CE_CONT, "mouse8042_getinfo: call\n"); -#endif switch (infocmd) { case DDI_INFO_DEVT2DEVINFO: if (mouse8042_dip == NULL) @@ -457,11 +450,6 @@ state = ddi_get_driver_private(mouse8042_dip); -#ifdef MOUSE8042_DEBUG - if (mouse8042_debug) - cmn_err(CE_CONT, "mouse8042_open:entered\n"); -#endif - mutex_enter(&state->ms_mutex); if (state->ms_opened) { @@ -545,15 +533,23 @@ state = (struct mouse_state *)q->q_ptr; -#ifdef MOUSE8042_DEBUG - if (mouse8042_debug) - cmn_err(CE_CONT, "mouse8042_close:entered\n"); -#endif - mutex_enter(&state->ms_mutex); qprocsoff(q); + if (state->reset_tid != 0) { + (void) quntimeout(q, state->reset_tid); + state->reset_tid = 0; + } + if (state->bc_id != 0) { + (void) qunbufcall(q, state->bc_id); + state->bc_id = 0; + } + if (state->reply_mp != NULL) { + freemsg(state->reply_mp); + state->reply_mp = NULL; + } + q->q_ptr = NULL; WR(q)->q_ptr = NULL; state->ms_rqp = NULL; @@ -600,78 +596,267 @@ qreply(qp, mp); } +static void +mouse8042_reset_timeout(void *argp) +{ + struct mouse_state *state = (struct mouse_state *)argp; + mblk_t *mp; + + mutex_enter(&state->reset_mutex); + + /* + * If the interrupt handler hasn't completed the reset handling + * (reset_state would be IDLE or FAILED in that case), then + * drop the 8042 lock, and send a faked retry reply upstream, + * then enable the queue for further message processing. + */ + if (state->reset_state != MSE_RESET_IDLE && + state->reset_state != MSE_RESET_FAILED) { + + state->reset_tid = 0; + state->reset_state = MSE_RESET_IDLE; + + (void) ddi_get8(state->ms_handle, state->ms_addr + + I8042_UNLOCK); + + mp = state->reply_mp; + *mp->b_wptr++ = MSERESEND; + state->reply_mp = NULL; + + if (state->ms_rqp != NULL) + putnext(state->ms_rqp, mp); + else + freemsg(mp); + + ASSERT(state->ms_wqp != NULL); + + enableok(state->ms_wqp); + qenable(state->ms_wqp); + } + + mutex_exit(&state->reset_mutex); +} + +/* + * Returns 1 if the caller should put the message (bp) back on the queue + */ static int -mouse8042_wput(queue_t *q, mblk_t *mp) +mouse8042_process_reset(queue_t *q, mblk_t *mp, struct mouse_state *state) { - struct iocblk *iocbp; + mutex_enter(&state->reset_mutex); + /* + * If we're in the middle of a reset, put the message back on the queue + * for processing later. + */ + if (state->reset_state != MSE_RESET_IDLE) { + /* + * We noenable the queue again here in case it was backenabled + * by an upper-level module. + */ + noenable(q); + + mutex_exit(&state->reset_mutex); + return (1); + } + + /* + * Drop the reset state lock before allocating the response message and + * grabbing the 8042 exclusive-access lock (since those operations + * may take an extended period of time to complete). + */ + mutex_exit(&state->reset_mutex); + + state->reply_mp = allocb(3, BPRI_MED); + if (state->reply_mp == NULL) { + /* + * Allocation failed -- set up a bufcall to enable the queue + * whenever there is enough memory to allocate the response + * message. + */ + state->bc_id = qbufcall(q, 3, BPRI_MED, + (void (*)(void *))qenable, q); + + if (state->bc_id == 0) { + /* + * If the qbufcall failed, we cannot proceed, so use the + * message we were sent to respond with an error. + */ + *mp->b_rptr = MSEERROR; + mp->b_wptr = mp->b_rptr + 1; + qreply(q, mp); + return (0); + } + + return (1); + } + + /* + * Gain exclusive access to the 8042 for the duration of the reset. + * The unlock will occur when the reset has either completed or timed + * out. + */ + (void) ddi_get8(state->ms_handle, + state->ms_addr + I8042_LOCK); + + mutex_enter(&state->reset_mutex); + + state->reset_state = MSE_RESET_PRE; + noenable(q); + + state->reset_tid = qtimeout(q, + mouse8042_reset_timeout, + state, + drv_usectohz( + MOUSE8042_RESET_TIMEOUT_USECS)); + + ddi_put8(state->ms_handle, + state->ms_addr + + I8042_INT_OUTPUT_DATA, MSERESET); + + mp->b_rptr++; + + mutex_exit(&state->reset_mutex); + return (1); +} + +/* + * Returns 1 if the caller should stop processing messages + */ +static int +mouse8042_process_data_msg(queue_t *q, mblk_t *mp, struct mouse_state *state) +{ mblk_t *bp; mblk_t *next; - struct mouse_state *state; + + bp = mp; + do { + while (bp->b_rptr < bp->b_wptr) { + /* + * Detect an attempt to reset the mouse. Lock out any + * further mouse writes until the reset has completed. + */ + if (*bp->b_rptr == MSERESET) { - state = (struct mouse_state *)q->q_ptr; + /* + * If we couldn't allocate memory and we + * we couldn't register a bufcall, + * mouse8042_process_reset returns 0 and + * has already used the message to send an + * error reply back upstream, so there is no + * need to deallocate or put this message back + * on the queue. + */ + if (mouse8042_process_reset(q, bp, state) == 0) + return (1); -#ifdef MOUSE8042_DEBUG - if (mouse8042_debug) - cmn_err(CE_CONT, "mouse8042_wput:entered\n"); -#endif + /* + * If there's no data remaining in this block, + * free this block and put the following blocks + * of this message back on the queue. If putting + * the rest of the message back on the queue + * fails, free the the message. + */ + if (MBLKL(bp) == 0) { + next = bp->b_cont; + freeb(bp); + bp = next; + } + if (bp != NULL) { + if (!putbq(q, bp)) + freemsg(bp); + } + + return (1); + + } + ddi_put8(state->ms_handle, + state->ms_addr + I8042_INT_OUTPUT_DATA, + *bp->b_rptr++); + } + next = bp->b_cont; + freeb(bp); + } while ((bp = next) != NULL); + + return (0); +} + +static int +mouse8042_process_msg(queue_t *q, mblk_t *mp, struct mouse_state *state) +{ + struct iocblk *iocbp; + int rv = 0; + iocbp = (struct iocblk *)mp->b_rptr; + switch (mp->b_datap->db_type) { case M_FLUSH: -#ifdef MOUSE8042_DEBUG - if (mouse8042_debug) - cmn_err(CE_CONT, "mouse8042_wput:M_FLUSH\n"); -#endif - - if (*mp->b_rptr & FLUSHW) + if (*mp->b_rptr & FLUSHW) { flushq(q, FLUSHDATA); - qreply(q, mp); + *mp->b_rptr &= ~FLUSHW; + } + if (*mp->b_rptr & FLUSHR) { + qreply(q, mp); + } else + freemsg(mp); break; case M_IOCTL: -#ifdef MOUSE8042_DEBUG - if (mouse8042_debug) - cmn_err(CE_CONT, "mouse8042_wput:M_IOCTL\n"); -#endif mouse8042_iocnack(q, mp, iocbp, EINVAL, 0); break; case M_IOCDATA: -#ifdef MOUSE8042_DEBUG - if (mouse8042_debug) - cmn_err(CE_CONT, "mouse8042_wput:M_IOCDATA\n"); -#endif mouse8042_iocnack(q, mp, iocbp, EINVAL, 0); break; case M_DATA: - bp = mp; - do { - while (bp->b_rptr < bp->b_wptr) { -#if defined(MOUSE8042_DEBUG) - if (mouse8042_debug) { - cmn_err(CE_CONT, - "mouse8042: send %2x\n", - *bp->b_rptr); - } - if (mouse8042_debug_minimal) { - cmn_err(CE_CONT, ">a:%2x ", - *bp->b_rptr); - } -#endif - ddi_put8(state->ms_handle, - state->ms_addr + I8042_INT_OUTPUT_DATA, - *bp->b_rptr++); - } - next = bp->b_cont; - freeb(bp); - } while ((bp = next) != NULL); + rv = mouse8042_process_data_msg(q, mp, state); break; default: freemsg(mp); break; } -#ifdef MOUSE8042_DEBUG - if (mouse8042_debug) - cmn_err(CE_CONT, "mouse8042_wput:leaving\n"); -#endif - return (0); /* ignored */ + + return (rv); +} + +static int +mouse8042_wsrv(queue_t *qp) +{ + mblk_t *mp; + struct mouse_state *state; + state = (struct mouse_state *)qp->q_ptr; + + while ((mp = getq(qp)) != NULL) { + if (mouse8042_process_msg(qp, mp, state) != 0) + break; + } + + return (0); +} + +/* + * Returns the next reset state, given the current state and the byte + * received from the mouse. Error and Resend codes are handled by the + * caller. + */ +static mouse8042_reset_state_e +mouse8042_reset_fsm(mouse8042_reset_state_e reset_state, uint8_t mdata) +{ + switch (reset_state) { + case MSE_RESET_PRE: /* RESET sent, now we expect an ACK */ + if (mdata == MSE_ACK) /* Got the ACK */ + return (MSE_RESET_ACK); + break; + + case MSE_RESET_ACK: /* ACK received; now we expect 0xAA */ + if (mdata == MSE_AA) /* Got the 0xAA */ + return (MSE_RESET_AA); + break; + + case MSE_RESET_AA: /* 0xAA received; now we expect 0x00 */ + if (mdata == MSE_00) + return (MSE_RESET_IDLE); + break; + } + + return (reset_state); } static uint_t @@ -684,10 +869,6 @@ mutex_enter(&state->ms_mutex); -#if defined(MOUSE8042_DEBUG) - if (mouse8042_debug) - cmn_err(CE_CONT, "mouse8042_intr()\n"); -#endif rc = DDI_INTR_UNCLAIMED; for (;;) { @@ -700,24 +881,81 @@ mdata = ddi_get8(state->ms_handle, state->ms_addr + I8042_INT_INPUT_DATA); -#if defined(MOUSE8042_DEBUG) - if (mouse8042_debug) - cmn_err(CE_CONT, "mouse8042_intr: got %2x\n", mdata); - if (mouse8042_debug_minimal) - cmn_err(CE_CONT, "<A:%2x ", mdata); -#endif + rc = DDI_INTR_CLAIMED; + + /* + * If we're not ready for this data, discard it. + */ + if (!state->ready) + continue; + + mutex_enter(&state->reset_mutex); + if (state->reset_state != MSE_RESET_IDLE) { + + if (mdata == MSEERROR || mdata == MSERESET) { + state->reset_state = MSE_RESET_FAILED; + } else { + state->reset_state = + mouse8042_reset_fsm(state->reset_state, + mdata); + } + + /* + * If we transitioned back to the idle reset state (or + * the reset failed), disable the timeout, release the + * 8042 exclusive-access lock, then send the response + * the the upper-level modules. Finally, enable the + * queue and schedule queue service procedures so that + * upper-level modules can process the response. + * Otherwise, if we're still in the middle of the + * reset sequence, do not send the data up (since the + * response is sent at the end of the sequence, or + * on timeout/error). + */ + if (state->reset_state == MSE_RESET_IDLE || + state->reset_state == MSE_RESET_FAILED) { - rc = DDI_INTR_CLAIMED; + mutex_exit(&state->reset_mutex); + (void) quntimeout(state->ms_wqp, + state->reset_tid); + mutex_enter(&state->reset_mutex); + + (void) ddi_get8(state->ms_handle, + state->ms_addr + I8042_UNLOCK); + + state->reset_tid = 0; + mp = state->reply_mp; + if (state->reset_state == MSE_RESET_FAILED) { + *mp->b_wptr++ = mdata; + } else { + *mp->b_wptr++ = MSE_ACK; + *mp->b_wptr++ = MSE_AA; + *mp->b_wptr++ = MSE_00; + } + state->reply_mp = NULL; + + state->reset_state = MSE_RESET_IDLE; + + if (state->ms_rqp != NULL) + putnext(state->ms_rqp, mp); + else + freemsg(mp); + + enableok(state->ms_wqp); + qenable(state->ms_wqp); + } + + mutex_exit(&state->reset_mutex); + mutex_exit(&state->ms_mutex); + return (rc); + } + mutex_exit(&state->reset_mutex); if (state->ms_rqp != NULL && (mp = allocb(1, BPRI_MED))) { *mp->b_wptr++ = mdata; putnext(state->ms_rqp, mp); } } -#ifdef MOUSE8042_DEBUG - if (mouse8042_debug) - cmn_err(CE_CONT, "mouse8042_intr() ok\n"); -#endif mutex_exit(&state->ms_mutex); return (rc);
--- a/usr/src/uts/common/io/rwn/rt2860.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/rwn/rt2860.c Mon Jul 20 13:07:46 2009 -0400 @@ -79,10 +79,10 @@ #include "fw-rt2860/rt2860.ucode" }; -static const struct ieee80211_rateset rt2560_rateset_11b = +static const struct ieee80211_rateset rt2860_rateset_11b = { 4, { 2, 4, 11, 22 } }; -static const struct ieee80211_rateset rt2560_rateset_11g = +static const struct ieee80211_rateset rt2860_rateset_11g = { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } }; static const struct { @@ -224,7 +224,7 @@ static struct modldrv rwn_modldrv = { &mod_driverops, /* Type of module. This one is a driver */ - "Ralink RT2700/2800 driver v1.1", /* short description */ + "Ralink RT2700/2800 driver v1.2", /* short description */ &rwn_dev_ops /* driver specific ops */ }; @@ -1116,7 +1116,7 @@ m = allocb(msgdsize(mp) + 32, BPRI_MED); if (m == NULL) { RWN_DEBUG(RT2860_DBG_TX, "rwn: rt2860_send():" - "rt2560_mgmt_send: can't alloc mblk.\n"); + "rt2860_mgmt_send: can't alloc mblk.\n"); err = DDI_FAILURE; goto fail1; } @@ -1697,6 +1697,7 @@ sc->sc_tx_timer = 0; mutex_exit(&sc->sc_txlock); } + static void rt2860_rx_intr(struct rt2860_softc *sc) { @@ -1769,7 +1770,7 @@ } ant = rt2860_maxrssi_chain(sc, rxwi); - rssi = rxwi->rssi[ant]; + rssi = RT2860_RSSI_OFFSET - rxwi->rssi[ant]; /* grab a reference to the source node */ ni = ieee80211_find_rxnode(ic, wh); @@ -2886,6 +2887,9 @@ RWN_DEBUG(RT2860_DBG_MSG, "rwn: rt2860_attach(): " "PCI configuration is done successfully\n"); + sc->amrr.amrr_min_success_threshold = 1; + sc->amrr.amrr_max_success_threshold = 15; + /* wait for NIC to initialize */ for (ntries = 0; ntries < 100; ntries++) { sc->mac_rev = RT2860_READ(sc, RT2860_ASIC_VER_ID); @@ -2958,8 +2962,8 @@ ic->ic_caps |= IEEE80211_C_WPA; /* Support WPA/WPA2 */ /* set supported .11b and .11g rates */ - ic->ic_sup_rates[IEEE80211_MODE_11B] = rt2560_rateset_11b; - ic->ic_sup_rates[IEEE80211_MODE_11G] = rt2560_rateset_11g; + ic->ic_sup_rates[IEEE80211_MODE_11B] = rt2860_rateset_11b; + ic->ic_sup_rates[IEEE80211_MODE_11G] = rt2860_rateset_11g; /* set supported .11b and .11g channels (1 through 14) */ for (i = 1; i <= 14; i++) { @@ -2970,6 +2974,7 @@ IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; } + ic->ic_maxrssi = 63; ic->ic_xmit = rt2860_send; ieee80211_attach(ic); @@ -3070,7 +3075,6 @@ fail4: while (--qid >= 0) rt2860_free_tx_ring(sc, &sc->txq[qid]); - fail3: ddi_regs_map_free(&sc->sc_io_handle); fail2:
--- a/usr/src/uts/common/io/rwn/rt2860_var.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/rwn/rt2860_var.h Mon Jul 20 13:07:46 2009 -0400 @@ -48,6 +48,8 @@ #define RT2860_MAX_SCATTER ((RT2860_TX_RING_COUNT * 2) - 1) +#define RT2860_RSSI_OFFSET 92 + /* HW supports up to 255 STAs */ #define RT2860_WCID_MAX 254 #define RT2860_AID2WCID(aid) ((aid) & 0xff)
--- a/usr/src/uts/common/io/sata/adapters/ahci/ahci.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/sata/adapters/ahci/ahci.c Mon Jul 20 13:07:46 2009 -0400 @@ -345,9 +345,9 @@ * End of global tunable variable definition */ +uint32_t ahci_debug_flags = (AHCIDBG_ERRS|AHCIDBG_TIMEOUT); + #if AHCI_DEBUG -uint32_t ahci_debug_flags = 0; - /* The following is needed for ahci_log() */ static kmutex_t ahci_log_mutex; static char ahci_log_buf[512]; @@ -439,7 +439,7 @@ static int ahci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) { - ahci_ctl_t *ahci_ctlp; + ahci_ctl_t *ahci_ctlp = NULL; int instance = ddi_get_instance(dip); int status; int attach_state; @@ -453,7 +453,8 @@ int speed; #endif - AHCIDBG0(AHCIDBG_INIT|AHCIDBG_ENTRY, NULL, "ahci_attach enter"); + AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp, "ahci_attach enter", + NULL); switch (cmd) { case DDI_ATTACH: @@ -486,9 +487,9 @@ * suspend/resume. */ if (ahci_initialize_controller(ahci_ctlp) != AHCI_SUCCESS) { - AHCIDBG0(AHCIDBG_ERRS|AHCIDBG_PM, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS|AHCIDBG_PM, ahci_ctlp, "Failed to initialize the controller " - "during DDI_RESUME"); + "during DDI_RESUME", NULL); return (DDI_FAILURE); } @@ -559,7 +560,7 @@ goto err_out; } - AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "rnumber = %d", rnumber); + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "rnumber = %d", rnumber); status = ddi_regs_map_setup(dip, rnumber, @@ -596,21 +597,21 @@ cap_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, (uint32_t *)AHCI_GLOBAL_CAP(ahci_ctlp)); - AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "hba capabilites = 0x%x", + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "hba capabilites = 0x%x", cap_status); #if AHCI_DEBUG /* Get the interface speed supported by the HBA */ speed = (cap_status & AHCI_HBA_CAP_ISS) >> AHCI_HBA_CAP_ISS_SHIFT; if (speed == 0x01) { - AHCIDBG0(AHCIDBG_INIT, ahci_ctlp, - "hba interface speed support: Gen 1 (1.5Gbps)"); + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, + "hba interface speed support: Gen 1 (1.5Gbps)", NULL); } else if (speed == 0x10) { - AHCIDBG0(AHCIDBG_INIT, ahci_ctlp, - "hba interface speed support: Gen 2 (3 Gbps)"); + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, + "hba interface speed support: Gen 2 (3 Gbps)", NULL); } else if (speed == 0x11) { - AHCIDBG0(AHCIDBG_INIT, ahci_ctlp, - "hba interface speed support: Gen 3 (6 Gbps)"); + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, + "hba interface speed support: Gen 3 (6 Gbps)", NULL); } #endif @@ -619,7 +620,7 @@ ((cap_status & AHCI_HBA_CAP_NCS) >> AHCI_HBA_CAP_NCS_SHIFT) + 1; - AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "hba number of cmd slots: %d", + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "hba number of cmd slots: %d", ahci_ctlp->ahcictl_num_cmd_slots); /* Get the bit map which indicates ports implemented by the HBA */ @@ -627,7 +628,7 @@ ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, (uint32_t *)AHCI_GLOBAL_PI(ahci_ctlp)); - AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "hba implementation of ports: 0x%x", + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "hba implementation of ports: 0x%x", ahci_ctlp->ahcictl_ports_implemented); /* @@ -642,7 +643,7 @@ (cap_status & AHCI_HBA_CAP_NP) + 1, ddi_fls(ahci_ctlp->ahcictl_ports_implemented)); - AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "hba number of ports: %d", + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "hba number of ports: %d", ahci_ctlp->ahcictl_num_ports); /* Get the number of implemented ports by the HBA */ @@ -650,7 +651,7 @@ ahci_get_num_implemented_ports( ahci_ctlp->ahcictl_ports_implemented); - AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "hba number of implemented ports: %d", ahci_ctlp->ahcictl_num_implemented_ports); @@ -658,15 +659,15 @@ if (!(cap_status & AHCI_HBA_CAP_S64A)) { ahci_ctlp->ahcictl_cap |= AHCI_CAP_BUF_32BIT_DMA; ahci_ctlp->ahcictl_cap |= AHCI_CAP_COMMU_32BIT_DMA; - AHCIDBG0(AHCIDBG_INIT, ahci_ctlp, - "hba does not support 64-bit addressing"); + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, + "hba does not support 64-bit addressing", NULL); } /* Checking for Support Command List Override */ if (cap_status & AHCI_HBA_CAP_SCLO) { ahci_ctlp->ahcictl_cap |= AHCI_CAP_SCLO; - AHCIDBG0(AHCIDBG_INIT, ahci_ctlp, - "hba supports command list override."); + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, + "hba supports command list override.", NULL); } if (pci_config_setup(dip, &ahci_ctlp->ahcictl_pci_conf_handle) @@ -705,7 +706,7 @@ goto err_out; } - AHCIDBG1(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp, + AHCIDBG(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp, "ddi_intr_get_supported_types() returned: 0x%x", intr_types); @@ -716,27 +717,27 @@ if (ahci_add_intrs(ahci_ctlp, DDI_INTR_TYPE_MSI) == DDI_SUCCESS) { ahci_ctlp->ahcictl_intr_type = DDI_INTR_TYPE_MSI; - AHCIDBG0(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp, - "Using MSI interrupt type"); + AHCIDBG(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp, + "Using MSI interrupt type", NULL); goto intr_done; } - AHCIDBG0(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp, + AHCIDBG(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp, "MSI registration failed, " - "trying FIXED interrupts"); + "trying FIXED interrupts", NULL); } if (intr_types & DDI_INTR_TYPE_FIXED) { if (ahci_add_intrs(ahci_ctlp, DDI_INTR_TYPE_FIXED) == DDI_SUCCESS) { ahci_ctlp->ahcictl_intr_type = DDI_INTR_TYPE_FIXED; - AHCIDBG0(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp, - "Using FIXED interrupt type"); + AHCIDBG(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp, + "Using FIXED interrupt type", NULL); goto intr_done; } - AHCIDBG0(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp, - "FIXED interrupt registration failed"); + AHCIDBG(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp, + "FIXED interrupt registration failed", NULL); } cmn_err(CE_WARN, "!ahci%d: Interrupt registration failed", instance); @@ -763,7 +764,7 @@ (ahci_dma_prdt_number - AHCI_PRDT_NUMBER) * sizeof (ahci_prdt_item_t)); - AHCIDBG2(AHCIDBG_INIT, ahci_ctlp, + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "ahci_attach: ahci_dma_prdt_number set by user is 0x%x," " ahci_cmd_table_size is 0x%x", ahci_dma_prdt_number, ahci_cmd_table_size); @@ -830,7 +831,7 @@ ahci_ctlp->ahcictl_flags &= ~AHCI_ATTACH; - AHCIDBG0(AHCIDBG_INIT, ahci_ctlp, "ahci_attach success!"); + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "ahci_attach success!", NULL); return (DDI_SUCCESS); @@ -886,7 +887,7 @@ instance = ddi_get_instance(dip); ahci_ctlp = ddi_get_soft_state(ahci_statep, instance); - AHCIDBG0(AHCIDBG_ENTRY, ahci_ctlp, "ahci_detach enter"); + AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_detach enter", NULL); switch (cmd) { case DDI_DETACH: @@ -1023,8 +1024,8 @@ { struct sata_hba_tran *sata_hba_tran; - AHCIDBG0(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp, - "ahci_register_sata_hba_tran enter"); + AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp, + "ahci_register_sata_hba_tran enter", NULL); mutex_enter(&ahci_ctlp->ahcictl_mutex); @@ -1046,8 +1047,8 @@ /* Get the data transfer capability for PIO command by the HBA */ if (cap_status & AHCI_HBA_CAP_PMD) { ahci_ctlp->ahcictl_cap |= AHCI_CAP_PIO_MDRQ; - AHCIDBG0(AHCIDBG_INFO, ahci_ctlp, "HBA supports multiple " - "DRQ block data transfer for PIO command protocol"); + AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "HBA supports multiple " + "DRQ block data transfer for PIO command protocol", NULL); } /* @@ -1069,8 +1070,8 @@ !(ahci_ctlp->ahcictl_cap & AHCI_CAP_NO_MCMDLIST_NONQUEUE)) { sata_hba_tran->sata_tran_hba_features_support |= SATA_CTLF_NCQ; ahci_ctlp->ahcictl_cap |= AHCI_CAP_NCQ; - AHCIDBG0(AHCIDBG_INFO, ahci_ctlp, "HBA supports Native " - "Command Queuing"); + AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "HBA supports Native " + "Command Queuing", NULL); } /* Report the number of command slots */ @@ -1114,8 +1115,8 @@ static int ahci_unregister_sata_hba_tran(ahci_ctl_t *ahci_ctlp) { - AHCIDBG0(AHCIDBG_ENTRY, ahci_ctlp, - "ahci_unregister_sata_hba_tran enter"); + AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, + "ahci_unregister_sata_hba_tran enter", NULL); /* Detach from the SATA framework. */ if (sata_hba_detach(ahci_ctlp->ahcictl_dip, DDI_DETACH) != @@ -1150,10 +1151,8 @@ ahci_ctl_t *ahci_ctlp; ahci_port_t *ahci_portp; uint8_t cport = sd->satadev_addr.cport; -#if AHCI_DEBUG uint8_t pmport = sd->satadev_addr.pmport; uint8_t qual = sd->satadev_addr.qual; -#endif uint8_t device_type; uint32_t port_state; uint8_t port; @@ -1161,7 +1160,7 @@ ahci_ctlp = ddi_get_soft_state(ahci_statep, ddi_get_instance(dip)); port = ahci_ctlp->ahcictl_cport_to_port[cport]; - AHCIDBG3(AHCIDBG_ENTRY, ahci_ctlp, + AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_tran_probe_port enter: cport: %d, " "pmport: %d, qual: %d", cport, pmport, qual); @@ -1174,31 +1173,31 @@ case SATA_PSTATE_FAILED: sd->satadev_state = SATA_PSTATE_FAILED; - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_tran_probe_port: port %d PORT FAILED", port); goto out; case SATA_PSTATE_SHUTDOWN: sd->satadev_state = SATA_PSTATE_SHUTDOWN; - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_tran_probe_port: port %d PORT SHUTDOWN", port); goto out; case SATA_PSTATE_PWROFF: sd->satadev_state = SATA_PSTATE_PWROFF; - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_tran_probe_port: port %d PORT PWROFF", port); goto out; case SATA_PSTATE_PWRON: sd->satadev_state = SATA_PSTATE_PWRON; - AHCIDBG1(AHCIDBG_INFO, ahci_ctlp, + AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "ahci_tran_probe_port: port %d PORT PWRON", port); break; default: sd->satadev_state = port_state; - AHCIDBG2(AHCIDBG_INFO, ahci_ctlp, + AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "ahci_tran_probe_port: port %d PORT NORMAL %x", port, port_state); break; @@ -1210,7 +1209,7 @@ case SATA_DTYPE_ATADISK: sd->satadev_type = SATA_DTYPE_ATADISK; - AHCIDBG1(AHCIDBG_INFO, ahci_ctlp, + AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "ahci_tran_probe_port: port %d DISK found", port); break; @@ -1222,27 +1221,27 @@ * DEVICE data */ sd->satadev_type = SATA_DTYPE_ATAPI; - AHCIDBG1(AHCIDBG_INFO, ahci_ctlp, + AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "ahci_tran_probe_port: port %d ATAPI found", port); break; case SATA_DTYPE_PMULT: sd->satadev_type = SATA_DTYPE_PMULT; - AHCIDBG1(AHCIDBG_INFO, ahci_ctlp, + AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "ahci_tran_probe_port: port %d Port Multiplier found", port); break; case SATA_DTYPE_UNKNOWN: sd->satadev_type = SATA_DTYPE_UNKNOWN; - AHCIDBG1(AHCIDBG_INFO, ahci_ctlp, + AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "ahci_tran_probe_port: port %d Unknown device found", port); break; default: /* we don't support any other device types */ sd->satadev_type = SATA_DTYPE_NONE; - AHCIDBG1(AHCIDBG_INFO, ahci_ctlp, + AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "ahci_tran_probe_port: port %d No device found", port); break; } @@ -1294,7 +1293,7 @@ ahci_ctlp = ddi_get_soft_state(ahci_statep, ddi_get_instance(dip)); port = ahci_ctlp->ahcictl_cport_to_port[cport]; - AHCIDBG2(AHCIDBG_ENTRY, ahci_ctlp, + AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_tran_start enter: cport %d satapkt 0x%p", cport, (void *)spkt); @@ -1315,7 +1314,7 @@ ahci_portp->ahciport_port_state; ahci_update_sata_registers(ahci_ctlp, port, &spkt->satapkt_device); - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_tran_start returning PORT_ERROR while " "port in FAILED/SHUTDOWN/PWROFF state: " "port: %d", port); @@ -1334,7 +1333,7 @@ ahci_portp->ahciport_port_state; ahci_update_sata_registers(ahci_ctlp, port, &spkt->satapkt_device); - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_tran_start returning PORT_ERROR while " "no device attached: port: %d", port); mutex_exit(&ahci_portp->ahciport_mutex); @@ -1354,7 +1353,7 @@ */ if (spkt->satapkt_cmd.satacmd_flags.sata_clear_dev_reset) { ahci_portp->ahciport_reset_in_progress = 0; - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_tran_start clearing the " "reset_in_progress for port: %d", port); } @@ -1363,7 +1362,7 @@ ! spkt->satapkt_cmd.satacmd_flags.sata_ignore_dev_reset && ! ddi_in_panic()) { spkt->satapkt_reason = SATA_PKT_BUSY; - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_tran_start returning BUSY while " "reset in progress: port: %d", port); mutex_exit(&ahci_portp->ahciport_mutex); @@ -1372,7 +1371,7 @@ if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) { spkt->satapkt_reason = SATA_PKT_BUSY; - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_tran_start returning BUSY while " "mopping in progress: port: %d", port); mutex_exit(&ahci_portp->ahciport_mutex); @@ -1388,7 +1387,7 @@ if (!(spkt->satapkt_op_mode & SATA_OPMODE_POLLING) && servicing_interrupt()) { spkt->satapkt_reason = SATA_PKT_BUSY; - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_tran_start returning BUSY while " "sending SYNC mode under interrupt context: " "port : %d", port); @@ -1399,7 +1398,7 @@ /* We need to do the sync start now */ if (ahci_do_sync_start(ahci_ctlp, ahci_portp, port, spkt) == AHCI_FAILURE) { - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_tran_start " + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_tran_start " "return QUEUE_FULL: port %d", port); mutex_exit(&ahci_portp->ahciport_mutex); return (SATA_TRAN_QUEUE_FULL); @@ -1409,14 +1408,14 @@ if (ahci_deliver_satapkt(ahci_ctlp, ahci_portp, port, spkt) == AHCI_FAILURE) { spkt->satapkt_reason = SATA_PKT_QUEUE_FULL; - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_tran_start " + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_tran_start " "returning QUEUE_FULL: port %d", port); mutex_exit(&ahci_portp->ahciport_mutex); return (SATA_TRAN_QUEUE_FULL); } } - AHCIDBG1(AHCIDBG_INFO, ahci_ctlp, "ahci_tran_start " + AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "ahci_tran_start " "sata tran accepted: port %d", port); mutex_exit(&ahci_portp->ahciport_mutex); @@ -1441,7 +1440,7 @@ int rval; int instance = ddi_get_instance(ahci_ctlp->ahcictl_dip); - AHCIDBG2(AHCIDBG_ENTRY, ahci_ctlp, "ahci_do_sync_start enter: " + AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_do_sync_start enter: " "port %d spkt 0x%p", port, spkt); if (spkt->satapkt_op_mode & SATA_OPMODE_POLLING) { @@ -1549,7 +1548,7 @@ uint32_t free_slots; int slot; - AHCIDBG2(AHCIDBG_ENTRY, ahci_ctlp, "ahci_claim_free_slot enter " + AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_claim_free_slot enter " "ahciport_pending_tags = 0x%x " "ahciport_pending_ncq_tags = 0x%x", ahci_portp->ahciport_pending_tags, @@ -1563,18 +1562,19 @@ if (command_type == AHCI_NON_NCQ_CMD) { /* Non-NCQ command request */ if (NCQ_CMD_IN_PROGRESS(ahci_portp)) { - AHCIDBG0(AHCIDBG_INFO|AHCIDBG_NCQ, ahci_ctlp, + AHCIDBG(AHCIDBG_INFO|AHCIDBG_NCQ, ahci_ctlp, "ahci_claim_free_slot: there is still pending " "queued command(s) in the command list, " "so no available slot for the non-queued " - "command"); + "command", NULL); return (AHCI_FAILURE); } if ((ahci_ctlp->ahcictl_cap & AHCI_CAP_NO_MCMDLIST_NONQUEUE) && NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) { - AHCIDBG0(AHCIDBG_INFO, ahci_ctlp, + AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "ahci_claim_free_slot: HBA cannot support multiple-" - "use of the command list for non-queued commands"); + "use of the command list for non-queued commands", + NULL); return (AHCI_FAILURE); } free_slots = (~ahci_portp->ahciport_pending_tags) & @@ -1582,27 +1582,28 @@ } else if (command_type == AHCI_NCQ_CMD) { /* NCQ command request */ if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) { - AHCIDBG0(AHCIDBG_INFO|AHCIDBG_NCQ, ahci_ctlp, + AHCIDBG(AHCIDBG_INFO|AHCIDBG_NCQ, ahci_ctlp, "ahci_claim_free_slot: there is still pending " "non-queued command(s) in the command list, " - "so no available slot for the queued command"); + "so no available slot for the queued command", + NULL); return (AHCI_FAILURE); } free_slots = (~ahci_portp->ahciport_pending_ncq_tags) & AHCI_NCQ_SLOT_MASK(ahci_portp); } else if (command_type == AHCI_ERR_RETRI_CMD) { /* Error retrieval command request */ - AHCIDBG0(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_claim_free_slot: slot 0 is allocated for REQUEST " - "SENSE or READ LOG EXT command"); + "SENSE or READ LOG EXT command", NULL); slot = 0; goto out; } slot = ddi_ffs(free_slots) - 1; if (slot == -1) { - AHCIDBG0(AHCIDBG_VERBOSE, ahci_ctlp, - "ahci_claim_free_slot: no empty slots"); + AHCIDBG(AHCIDBG_VERBOSE, ahci_ctlp, + "ahci_claim_free_slot: no empty slots", NULL); return (AHCI_FAILURE); } @@ -1620,7 +1621,7 @@ ahci_portp->ahciport_pending_tags |= (0x1 << slot); out: - AHCIDBG1(AHCIDBG_VERBOSE, ahci_ctlp, + AHCIDBG(AHCIDBG_VERBOSE, ahci_ctlp, "ahci_claim_free_slot: found slot: 0x%x", slot); return (slot); @@ -1680,7 +1681,7 @@ */ if (ahci_portp->ahciport_max_ncq_tags == 0) { ahci_portp->ahciport_max_ncq_tags = ncq_qdepth; - AHCIDBG2(AHCIDBG_NCQ, ahci_ctlp, + AHCIDBG(AHCIDBG_NCQ, ahci_ctlp, "ahci_deliver_satapkt: port %d the max tags for " "NCQ command is %d", port, ncq_qdepth); } else { @@ -1705,11 +1706,11 @@ /* Check if there is an empty command slot */ cmd_slot = ahci_claim_free_slot(ahci_ctlp, ahci_portp, command_type); if (cmd_slot == AHCI_FAILURE) { - AHCIDBG0(AHCIDBG_INFO, ahci_ctlp, "no free command slot"); + AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "no free command slot", NULL); return (AHCI_FAILURE); } - AHCIDBG4(AHCIDBG_ENTRY|AHCIDBG_INFO, ahci_ctlp, + AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_INFO, ahci_ctlp, "ahci_deliver_satapkt enter: cmd_reg: 0x%x, cmd_slot: 0x%x, " "port: %d, satapkt: 0x%p", scmd->satacmd_cmd_reg, cmd_slot, port, (void *)spkt); @@ -1818,7 +1819,7 @@ } ncookies = scmd->satacmd_num_dma_cookies; - AHCIDBG2(AHCIDBG_PRDT, ahci_ctlp, + AHCIDBG(AHCIDBG_PRDT, ahci_ctlp, "ncookies = 0x%x, ahci_dma_prdt_number = 0x%x", ncookies, ahci_dma_prdt_number); @@ -1837,7 +1838,7 @@ scmd->satacmd_dma_cookie_list[i].dmac_size; } - AHCIDBG2(AHCIDBG_PRDT, ahci_ctlp, + AHCIDBG(AHCIDBG_PRDT, ahci_ctlp, "ahciport_prd_bytecounts 0x%x for cmd_slot 0x%x", ahci_portp->ahciport_prd_bytecounts[cmd_slot], cmd_slot); @@ -1858,7 +1859,7 @@ /* Set the length of the command in the CFIS area */ SET_COMMAND_FIS_LENGTH(cmd_header, AHCI_H2D_REGISTER_FIS_LENGTH); - AHCIDBG1(AHCIDBG_INFO, ahci_ctlp, "command data direction is " + AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "command data direction is " "sata_data_direction = 0x%x", scmd->satacmd_flags.sata_data_direction); @@ -1957,7 +1958,7 @@ (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port), (0x1 << cmd_slot)); - AHCIDBG1(AHCIDBG_INFO, ahci_ctlp, "ahci_deliver_satapkt " + AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "ahci_deliver_satapkt " "exit: port %d", port); return (cmd_slot); @@ -1984,7 +1985,7 @@ ahci_ctlp = ddi_get_soft_state(ahci_statep, instance); port = ahci_ctlp->ahcictl_cport_to_port[cport]; - AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp, + AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_tran_abort enter: port %d", port); ahci_portp = ahci_ctlp->ahcictl_ports[port]; @@ -1995,7 +1996,7 @@ * commands are being mopped, therefore there is nothing else to do */ if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) { - AHCIDBG1(AHCIDBG_INFO, ahci_ctlp, + AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "ahci_tran_abort: port %d is in " "mopping process, so just return directly ", port); mutex_exit(&ahci_portp->ahciport_mutex); @@ -2015,7 +2016,7 @@ ahci_portp->ahciport_port_state; ahci_update_sata_registers(ahci_ctlp, port, &spkt->satapkt_device); - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_tran_abort returning SATA_FAILURE while " "port in FAILED/SHUTDOWN/PWROFF state: " "port: %d", port); @@ -2034,7 +2035,7 @@ ahci_portp->ahciport_port_state; ahci_update_sata_registers(ahci_ctlp, port, &spkt->satapkt_device); - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_tran_abort returning SATA_FAILURE while " "no device attached: port: %d", port); mutex_exit(&ahci_portp->ahciport_mutex); @@ -2065,7 +2066,7 @@ if (aborted_tags == 0xffffffff) { /* request packet is not on the pending list */ - AHCIDBG1(AHCIDBG_INFO, ahci_ctlp, + AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "Cannot find the aborting pkt 0x%p on the " "pending list", (void *)spkt); ahci_update_sata_registers(ahci_ctlp, port, @@ -2146,7 +2147,7 @@ sata_device_t sdevice; int ret; - AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp, + AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_reset_device_reject_pkts on port: %d", port); /* @@ -2154,7 +2155,7 @@ * commands are being mopped, therefore there is nothing else to do */ if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) { - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_reset_device_reject_pkts: port %d is in " "mopping process, so return directly ", port); return (SATA_SUCCESS); @@ -2172,12 +2173,12 @@ if (ahci_software_reset(ahci_ctlp, ahci_portp, port) != AHCI_SUCCESS) { - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "Try to do a port reset after software " "reset failed", port); ret = ahci_port_reset(ahci_ctlp, ahci_portp, port); if (ret != AHCI_SUCCESS) { - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_reset_device_reject_pkts: port %d " "failed", port); return (SATA_FAILURE); @@ -2204,7 +2205,7 @@ SATA_EVNT_DEVICE_RESET); mutex_enter(&ahci_portp->ahciport_mutex); - AHCIDBG1(AHCIDBG_EVENT, ahci_ctlp, + AHCIDBG(AHCIDBG_EVENT, ahci_ctlp, "port %d sending event up: SATA_EVNT_RESET", port); /* Next try to mop the pending commands */ @@ -2242,7 +2243,7 @@ uint32_t reset_tags = 0; uint32_t finished_tags = 0; - AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp, + AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_reset_port_reject_pkts on port: %d", port); /* @@ -2250,7 +2251,7 @@ * commands are being mopped, therefore there is nothing else to do */ if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) { - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_reset_port_reject_pkts: port %d is in " "mopping process, so return directly ", port); return (SATA_SUCCESS); @@ -2308,8 +2309,8 @@ uint8_t port; int ret = SATA_SUCCESS; - AHCIDBG0(AHCIDBG_ENTRY, ahci_ctlp, - "ahci_reset_hba_reject_pkts enter"); + AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, + "ahci_reset_hba_reject_pkts enter", NULL); for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) { if (!AHCI_PORT_IMPLEMENTED(ahci_ctlp, port)) { @@ -2353,7 +2354,7 @@ * check AHCI_PORT_FLAG_MOPPING flag. */ if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) { - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_reset_hba_reject_pkts: port %d is in " "mopping process, so return directly ", port); mutex_exit(&ahci_portp->ahciport_mutex); @@ -2403,7 +2404,7 @@ ahci_ctlp = ddi_get_soft_state(ahci_statep, instance); port = ahci_ctlp->ahcictl_cport_to_port[cport]; - AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp, + AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_tran_reset_port enter: cport: %d", cport); switch (sd->satadev_addr.qual) { @@ -2436,7 +2437,7 @@ */ sd->satadev_state = ahci_portp->ahciport_port_state; ahci_update_sata_registers(ahci_ctlp, port, sd); - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_tran_reset_dport returning SATA_FAILURE " "while port in FAILED/SHUTDOWN/PWROFF state: " "port: %d", port); @@ -2453,7 +2454,7 @@ sd->satadev_type = SATA_DTYPE_NONE; sd->satadev_state = ahci_portp->ahciport_port_state; ahci_update_sata_registers(ahci_ctlp, port, sd); - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_tran_reset_dport returning SATA_FAILURE " "while no device attached: port: %d", port); mutex_exit(&ahci_portp->ahciport_mutex); @@ -2475,9 +2476,9 @@ case SATA_ADDR_PMPORT: case SATA_ADDR_DPMPORT: - AHCIDBG0(AHCIDBG_INFO, ahci_ctlp, + AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "ahci_tran_reset_dport: port multiplier will be " - "supported later"); + "supported later", NULL); /* FALLTHRU */ default: ret = SATA_FAILURE; @@ -2503,7 +2504,7 @@ ahci_ctlp = ddi_get_soft_state(ahci_statep, instance); port = ahci_ctlp->ahcictl_cport_to_port[cport]; - AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp, + AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_tran_hotplug_port_activate cport %d enter", cport); ahci_portp = ahci_ctlp->ahcictl_ports[port]; @@ -2557,7 +2558,7 @@ ahci_ctlp = ddi_get_soft_state(ahci_statep, instance); port = ahci_ctlp->ahcictl_cport_to_port[cport]; - AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp, + AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_tran_hotplug_port_deactivate cport %d enter", cport); ahci_portp = ahci_ctlp->ahcictl_ports[port]; @@ -2610,7 +2611,7 @@ uint32_t slot_status = 0; uint32_t abort_tags = 0; - AHCIDBG1(AHCIDBG_ENTRY|AHCIDBG_INTR, ahci_ctlp, + AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_INTR, ahci_ctlp, "ahci_reject_all_abort_pkts on port: %d", port); /* @@ -2625,7 +2626,7 @@ abort_tags = 0x1; goto out; } else { - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_reject_all_abort_pkts return directly " "port %d no needs to reject any outstanding " "commands", port); @@ -2675,15 +2676,15 @@ { int port, cport = 0; - AHCIDBG0(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp, - "ahci_alloc_ports_state enter"); + AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp, + "ahci_alloc_ports_state enter", NULL); mutex_enter(&ahci_ctlp->ahcictl_mutex); /* Allocate structures only for the implemented ports */ for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) { if (!AHCI_PORT_IMPLEMENTED(ahci_ctlp, port)) { - AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "hba port %d not implemented", port); continue; } @@ -2769,8 +2770,8 @@ uint32_t ghc_control; int port; - AHCIDBG0(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp, - "ahci_initialize_controller enter"); + AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp, + "ahci_initialize_controller enter", NULL); mutex_enter(&ahci_ctlp->ahcictl_mutex); @@ -2803,7 +2804,7 @@ */ if (ahci_initialize_port(ahci_ctlp, ahci_portp, port) != AHCI_SUCCESS) { - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_initialize_controller: failed to " "initialize port %d", port); /* @@ -2835,8 +2836,8 @@ ahci_port_t *ahci_portp; int port; - AHCIDBG0(AHCIDBG_INIT, ahci_ctlp, - "ahci_uninitialize_controller enter"); + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, + "ahci_uninitialize_controller enter", NULL); /* disable all the interrupts. */ mutex_enter(&ahci_ctlp->ahcictl_mutex); @@ -2884,7 +2885,7 @@ port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port)); - AHCIDBG2(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp, + AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp, "ahci_initialize_port: port %d " "port_cmd_status = 0x%x", port, port_cmd_status); /* @@ -2924,7 +2925,7 @@ /* Does port reset succeed on HBA port? */ if (ret != AHCI_SUCCESS) { - AHCIDBG1(AHCIDBG_INIT|AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_INIT|AHCIDBG_ERRS, ahci_ctlp, "ahci_initialize_port:" "port reset faild at port %d", port); return (AHCI_FAILURE); @@ -2932,7 +2933,7 @@ /* Is port failed? */ if (ahci_portp->ahciport_port_state & SATA_PSTATE_FAILED) { - AHCIDBG2(AHCIDBG_INIT|AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_INIT|AHCIDBG_ERRS, ahci_ctlp, "ahci_initialize_port: port %d state 0x%x", port, ahci_portp->ahciport_port_state); return (AHCI_FAILURE); @@ -2941,7 +2942,7 @@ ahci_portp->ahciport_port_state = SATA_STATE_READY; - AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "port %d is ready now.", port); + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "port %d is ready now.", port); /* * At the time being, only probe ports/devices and get the types of @@ -2963,12 +2964,12 @@ * and PxFBU registers in case these registers were cleared * during the suspend. */ - AHCIDBG1(AHCIDBG_PM, ahci_ctlp, + AHCIDBG(AHCIDBG_PM, ahci_ctlp, "ahci_initialize_port: port %d " "reset the port during resume", port); (void) ahci_port_reset(ahci_ctlp, ahci_portp, port); - AHCIDBG1(AHCIDBG_PM, ahci_ctlp, + AHCIDBG(AHCIDBG_PM, ahci_ctlp, "ahci_initialize_port: port %d " "set PxCLB, PxCLBU, PxFB and PxFBU " "during resume", port); @@ -2986,7 +2987,7 @@ /* Return directly if no device connected */ if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) { - AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "No device connected to port %d", port); goto out; } @@ -2994,7 +2995,7 @@ /* Try to start the port */ if (ahci_start_port(ahci_ctlp, ahci_portp, port) != AHCI_SUCCESS) { - AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "failed to start port %d", port); return (AHCI_FAILURE); } @@ -3039,18 +3040,18 @@ if (venid == VIA_VENID) { revision = pci_config_get8(ahci_ctlp->ahcictl_pci_conf_handle, PCI_CONF_REVID); - AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "revision id = 0x%x", revision); if (revision == 0x00) { ahci_ctlp->ahcictl_buffer_dma_attr.dma_attr_align = 0x4; - AHCIDBG0(AHCIDBG_INIT, ahci_ctlp, - "change ddi_attr_align to 0x4"); + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, + "change ddi_attr_align to 0x4", NULL); } ahci_ctlp->ahcictl_cap = AHCI_CAP_NO_MCMDLIST_NONQUEUE; - AHCIDBG0(AHCIDBG_INIT, ahci_ctlp, + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "VT8251 cannot use multiple command lists for " - "non-queued commands"); + "non-queued commands", NULL); } /* @@ -3059,10 +3060,10 @@ * though S64A bit of CAP register declares the support. */ if (venid == 0x1002 && devid == 0x4380) { - AHCIDBG0(AHCIDBG_INIT, ahci_ctlp, + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "ATI SB600 cannot do 64-bit DMA for both data buffer " "and communication memory descriptors though CAP indicates " - "support, so force it to use 32-bit DMA"); + "support, so force it to use 32-bit DMA", NULL); ahci_ctlp->ahcictl_cap |= AHCI_CAP_BUF_32BIT_DMA; ahci_ctlp->ahcictl_cap |= AHCI_CAP_COMMU_32BIT_DMA; } @@ -3074,10 +3075,10 @@ * 64-bit DMA for data buffer. */ if (venid == 0x1002 && devid == 0x4391) { - AHCIDBG0(AHCIDBG_INIT, ahci_ctlp, + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "ATI SB700/750 cannot do 64-bit DMA for communication " "memory descriptors though CAP indicates support, " - "so force it to use 32-bit DMA"); + "so force it to use 32-bit DMA", NULL); ahci_ctlp->ahcictl_cap |= AHCI_CAP_COMMU_32BIT_DMA; } @@ -3087,9 +3088,9 @@ * on most Nvidia boards) is fixed. */ if (venid == 0x10de && devid == 0x0ad4) { - AHCIDBG0(AHCIDBG_INIT, ahci_ctlp, + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "Force nVidia MCP78 AHCI controller to use " - "fixed interrupts"); + "fixed interrupts", NULL); ahci_msi_enabled = B_FALSE; } @@ -3116,12 +3117,12 @@ * capabilities and that the pointer is in a valid range. */ if (++cap_count > PCI_CAP_MAX_PTR) { - AHCIDBG0(AHCIDBG_ERRS, ahci_ctlp, - "too many device capabilities"); + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, + "too many device capabilities", NULL); return (AHCI_FAILURE); } if (caps_ptr < PCI_CAP_PTR_OFF) { - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "capabilities pointer 0x%x out of range", caps_ptr); return (AHCI_FAILURE); @@ -3149,13 +3150,13 @@ pmcsr = pci_config_get16( ahci_ctlp->ahcictl_pci_conf_handle, ahci_ctlp->ahcictl_pmcsr_offset); - AHCIDBG2(AHCIDBG_PM, ahci_ctlp, + AHCIDBG(AHCIDBG_PM, ahci_ctlp, "Power Management capability found PCI_PMCAP " "= 0x%x PCI_PMCSR = 0x%x", pmcap, pmcsr); if ((pmcap & 0x3) == 0x3) - AHCIDBG0(AHCIDBG_PM, ahci_ctlp, + AHCIDBG(AHCIDBG_PM, ahci_ctlp, "PCI Power Management Interface " - "spec 1.2 compliant"); + "spec 1.2 compliant", NULL); #endif break; @@ -3164,41 +3165,41 @@ msimc = pci_config_get16( ahci_ctlp->ahcictl_pci_conf_handle, caps_ptr + PCI_MSI_CTRL); - AHCIDBG1(AHCIDBG_MSI, ahci_ctlp, + AHCIDBG(AHCIDBG_MSI, ahci_ctlp, "Message Signaled Interrupt capability found " "MSICAP_MC.MMC = 0x%x", (msimc & 0xe) >> 1); #endif - AHCIDBG0(AHCIDBG_MSI, ahci_ctlp, - "MSI capability found"); + AHCIDBG(AHCIDBG_MSI, ahci_ctlp, + "MSI capability found", NULL); break; case PCI_CAP_ID_PCIX: - AHCIDBG0(AHCIDBG_PM, ahci_ctlp, - "PCI-X capability found"); + AHCIDBG(AHCIDBG_PM, ahci_ctlp, + "PCI-X capability found", NULL); break; case PCI_CAP_ID_PCI_E: - AHCIDBG0(AHCIDBG_PM, ahci_ctlp, - "PCI Express capability found"); + AHCIDBG(AHCIDBG_PM, ahci_ctlp, + "PCI Express capability found", NULL); break; case PCI_CAP_ID_MSI_X: - AHCIDBG0(AHCIDBG_PM, ahci_ctlp, - "MSI-X capability found"); + AHCIDBG(AHCIDBG_PM, ahci_ctlp, + "MSI-X capability found", NULL); break; case PCI_CAP_ID_SATA: - AHCIDBG0(AHCIDBG_PM, ahci_ctlp, - "SATA capability found"); + AHCIDBG(AHCIDBG_PM, ahci_ctlp, + "SATA capability found", NULL); break; case PCI_CAP_ID_VS: - AHCIDBG0(AHCIDBG_PM, ahci_ctlp, - "Vendor Specific capability found"); + AHCIDBG(AHCIDBG_PM, ahci_ctlp, + "Vendor Specific capability found", NULL); break; default: - AHCIDBG1(AHCIDBG_PM, ahci_ctlp, + AHCIDBG(AHCIDBG_PM, ahci_ctlp, "unrecognized capability 0x%x", cap); break; } @@ -3239,13 +3240,13 @@ int slot, loop_count; int rval = AHCI_FAILURE; - AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp, + AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "Port %d device resetting", port); /* First clear PxCMD.ST (AHCI v1.2 10.4.1) */ if (ahci_put_port_into_notrunning_state(ahci_ctlp, ahci_portp, port) != AHCI_SUCCESS) { - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_software_reset: cannot stop HBA port %d.", port); goto out; } @@ -3257,7 +3258,7 @@ if (port_task_file & AHCI_TFD_STS_BSY || port_task_file & AHCI_TFD_STS_DRQ) { if (!(ahci_ctlp->ahcictl_cap & AHCI_CAP_SCLO)) { - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "PxTFD.STS.BSY/DRQ is set (PxTFD=0x%x), " "cannot issue a software reset.", port_task_file); goto out; @@ -3268,8 +3269,8 @@ * set), PxCMD.CLO bit should be set before set PxCMD.ST, in * order to clear PxTFD.STS.BSY and PxTFD.STS.DRQ. */ - AHCIDBG0(AHCIDBG_ERRS, ahci_ctlp, - "PxTFD.STS.BSY/DRQ is set, try SCLO.") + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, + "PxTFD.STS.BSY/DRQ is set, try SCLO.", NULL) port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port)); @@ -3285,7 +3286,7 @@ /* We are effectively timing out after 1 sec. */ if (loop_count++ > 100) { - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "SCLO time out. port %d is busy.", port); goto out; } @@ -3300,7 +3301,7 @@ (uint32_t *)AHCI_PORT_PxTFD(ahci_ctlp, port)); if (port_task_file & AHCI_TFD_STS_BSY || port_task_file & AHCI_TFD_STS_DRQ) { - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "SCLO cannot clear PxTFD.STS.BSY/DRQ (PxTFD=0x%x)", port_task_file); goto out; @@ -3310,7 +3311,7 @@ /* Then start port */ if (ahci_start_port(ahci_ctlp, ahci_portp, port) != AHCI_SUCCESS) { - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_software_reset: cannot start AHCI port %d.", port); goto out; } @@ -3369,7 +3370,7 @@ /* We are effectively timing out after 1 sec. */ if (loop_count++ > AHCI_POLLRATE_PORT_SOFTRESET) { - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "the first SRST FIS is timed out, " "loop_count = %d", loop_count); goto out; @@ -3379,7 +3380,7 @@ delay(AHCI_10MS_TICKS); } while (port_cmd_issue & AHCI_SLOT_MASK(ahci_ctlp) & (0x1 << slot)); - AHCIDBG3(AHCIDBG_POLL_LOOP, ahci_ctlp, + AHCIDBG(AHCIDBG_POLL_LOOP, ahci_ctlp, "ahci_software_reset: 1st loop count: %d, " "port_cmd_issue = 0x%x, slot = 0x%x", loop_count, port_cmd_issue, slot); @@ -3428,7 +3429,7 @@ /* We are effectively timing out after 1 sec. */ if (loop_count++ > AHCI_POLLRATE_PORT_SOFTRESET) { - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "the second SRST FIS is timed out, " "loop_count = %d", loop_count); goto out; @@ -3438,7 +3439,7 @@ delay(AHCI_10MS_TICKS); } while (port_cmd_issue & AHCI_SLOT_MASK(ahci_ctlp) & (0x1 << slot)); - AHCIDBG3(AHCIDBG_POLL_LOOP, ahci_ctlp, + AHCIDBG(AHCIDBG_POLL_LOOP, ahci_ctlp, "ahci_software_reset: 2nd loop count: %d, " "port_cmd_issue = 0x%x, slot = 0x%x", loop_count, port_cmd_issue, slot); @@ -3447,7 +3448,7 @@ rval = AHCI_SUCCESS; out: - AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_software_reset: %s at port %d", rval == AHCI_SUCCESS ? "succeed" : "failed", port); @@ -3485,7 +3486,7 @@ int loop_count; int instance = ddi_get_instance(ahci_ctlp->ahcictl_dip); - AHCIDBG1(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp, + AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp, "Port %d port resetting...", port); ahci_portp->ahciport_port_state = 0; @@ -3503,7 +3504,7 @@ if (!(port_cmd_status & AHCI_CMD_STATUS_SUD)) { if (!(ahci_portp->ahciport_flags & AHCI_PORT_FLAG_SPINUP)) { - AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "Port %d PxCMD.SUD is zero, force " "it to do spin-up", port); ahci_portp->ahciport_flags |= @@ -3517,9 +3518,9 @@ */ if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_SPINUP) { - AHCIDBG0(AHCIDBG_INIT, ahci_ctlp, + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "HBA does not support staggered spin-up " - "force it to do normal COMRESET"); + "force it to do normal COMRESET", NULL); ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_SPINUP; } @@ -3527,7 +3528,7 @@ if (!(ahci_portp->ahciport_flags & AHCI_PORT_FLAG_SPINUP)) { /* Do normal COMRESET */ - AHCIDBG1(AHCIDBG_INFO, ahci_ctlp, + AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "ahci_port_reset: do normal COMRESET", port); /* @@ -3537,7 +3538,7 @@ */ #if AHCI_DEBUG if (!(port_cmd_status & AHCI_CMD_STATUS_SUD)) - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "port %d SUD bit not set", port) #endif @@ -3641,7 +3642,7 @@ delay(AHCI_10MS_TICKS); } while (SSTATUS_GET_DET(port_sstatus) != SSTATUS_DET_DEVPRE_PHYCOM); - AHCIDBG3(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp, + AHCIDBG(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp, "ahci_port_reset: 1st loop count: %d, " "port_sstatus = 0x%x port %d", loop_count, port_sstatus, port); @@ -3687,7 +3688,7 @@ port_task_file = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, (uint32_t *)AHCI_PORT_PxTFD(ahci_ctlp, port)); if (!(port_task_file & AHCI_TFD_STS_BSY)) { - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_port_reset: " + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_port_reset: " "port %d BSY bit is not set after COMINIT signal " "is received", port); } @@ -3720,7 +3721,7 @@ "the power-up diagnostics failed", instance, port); - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_port_reset: " + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_port_reset: " "port %d PxTFD.STS.ERR is not set, we need another " "software reset.", port); @@ -3752,7 +3753,7 @@ } while (((port_task_file & AHCI_TFD_ERR_MASK) >> AHCI_TFD_ERR_SHIFT) != AHCI_TFD_ERR_SGS); - AHCIDBG3(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp, + AHCIDBG(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp, "ahci_port_reset: 2nd loop count: %d, " "port_task_file = 0x%x port %d", loop_count, port_task_file, port); @@ -3765,7 +3766,7 @@ /* Set port as ready */ ahci_portp->ahciport_port_state |= SATA_STATE_READY; - AHCIDBG1(AHCIDBG_INFO|AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_INFO|AHCIDBG_ERRS, ahci_ctlp, "ahci_port_reset: succeed at port %d.", port); return (AHCI_SUCCESS); } @@ -3793,7 +3794,8 @@ int loop_count; int rval = AHCI_SUCCESS; - AHCIDBG0(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp, "HBA resetting"); + AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp, "HBA resetting", + NULL); mutex_enter(&ahci_ctlp->ahcictl_mutex); @@ -3814,7 +3816,7 @@ (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp)); if (loop_count++ > AHCI_POLLRATE_HBA_RESET) { - AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "ahci hba reset is timing out, " "ghc_control = 0x%x", ghc_control); /* We are effectively timing out after 1 sec. */ @@ -3825,14 +3827,14 @@ delay(AHCI_10MS_TICKS); } while (ghc_control & AHCI_HBA_GHC_HR); - AHCIDBG2(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp, + AHCIDBG(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp, "ahci_hba_reset: 1st loop count: %d, " "ghc_control = 0x%x", loop_count, ghc_control); if (ghc_control & AHCI_HBA_GHC_HR) { /* The hba is not reset for some reasons */ - AHCIDBG0(AHCIDBG_INIT, ahci_ctlp, - "hba reset failed: HBA in a hung or locked state"); + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, + "hba reset failed: HBA in a hung or locked state", NULL); mutex_exit(&ahci_ctlp->ahcictl_mutex); return (AHCI_FAILURE); } @@ -3849,7 +3851,7 @@ if (ahci_port_reset(ahci_ctlp, ahci_portp, port) != AHCI_SUCCESS) { rval = AHCI_FAILURE; - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_hba_reset: port %d failed", port); } @@ -3890,7 +3892,7 @@ { uint32_t signature; - AHCIDBG1(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp, + AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp, "ahci_find_dev_signature enter: port %d", port); ahci_portp->ahciport_device_type = SATA_DTYPE_UNKNOWN; @@ -3898,7 +3900,7 @@ /* Issue a software reset to get the signature */ if (ahci_software_reset(ahci_ctlp, ahci_portp, port) != AHCI_SUCCESS) { - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_find_dev_signature: software reset failed " "at port %d, cannot get signature.", port); ahci_portp->ahciport_port_state = SATA_PSTATE_FAILED; @@ -3911,7 +3913,7 @@ */ if (ahci_put_port_into_notrunning_state(ahci_ctlp, ahci_portp, port) != AHCI_SUCCESS) { - AHCIDBG1(AHCIDBG_INFO, ahci_ctlp, + AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "ahci_find_dev_signature: cannot stop port %d.", port); ahci_portp->ahciport_port_state = SATA_PSTATE_FAILED; return; @@ -3921,7 +3923,7 @@ signature = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, (uint32_t *)AHCI_PORT_PxSIG(ahci_ctlp, port)); - AHCIDBG2(AHCIDBG_INIT|AHCIDBG_INFO, ahci_ctlp, + AHCIDBG(AHCIDBG_INIT|AHCIDBG_INFO, ahci_ctlp, "ahci_find_dev_signature: port %d signature = 0x%x", port, signature); @@ -3929,25 +3931,25 @@ case AHCI_SIGNATURE_DISK: ahci_portp->ahciport_device_type = SATA_DTYPE_ATADISK; - AHCIDBG1(AHCIDBG_INFO, ahci_ctlp, + AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "Disk is found at port: %d", port); break; case AHCI_SIGNATURE_ATAPI: ahci_portp->ahciport_device_type = SATA_DTYPE_ATAPI; - AHCIDBG1(AHCIDBG_INFO, ahci_ctlp, + AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "ATAPI device is found at port: %d", port); break; case AHCI_SIGNATURE_PORT_MULTIPLIER: ahci_portp->ahciport_device_type = SATA_DTYPE_PMULT; - AHCIDBG1(AHCIDBG_INFO, ahci_ctlp, + AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "Port Multiplier is found at port: %d", port); break; default: ahci_portp->ahciport_device_type = SATA_DTYPE_UNKNOWN; - AHCIDBG1(AHCIDBG_INFO, ahci_ctlp, + AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "Unknown device is found at port: %d", port); } } @@ -4004,17 +4006,17 @@ { uint32_t port_cmd_status; - AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp, "ahci_start_port: %d enter", port); + AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_start_port: %d enter", port); if (ahci_portp->ahciport_port_state & SATA_PSTATE_FAILED) { - AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp, "ahci_start_port failed " + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_start_port failed " "the state for port %d is 0x%x", port, ahci_portp->ahciport_port_state); return (AHCI_FAILURE); } if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) { - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_start_port failed " + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_start_port failed " "no device is attached at port %d", port); return (AHCI_FAILURE); } @@ -4041,7 +4043,7 @@ ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_STARTED; - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_start_port: " + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_start_port: " "PxCMD.ST set to '1' at port %d", port); return (AHCI_SUCCESS); @@ -4183,8 +4185,8 @@ NULL, &ahci_portp->ahciport_rcvd_fis_dma_handle) != DDI_SUCCESS) { - AHCIDBG0(AHCIDBG_INIT, ahci_ctlp, - "rcvd FIS dma handle alloc failed"); + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, + "rcvd FIS dma handle alloc failed", NULL); return (AHCI_FAILURE); } @@ -4199,8 +4201,8 @@ &ret_len, &ahci_portp->ahciport_rcvd_fis_acc_handle) != NULL) { - AHCIDBG0(AHCIDBG_INIT, ahci_ctlp, - "rcvd FIS dma mem alloc fail"); + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, + "rcvd FIS dma mem alloc fail", NULL); /* error.. free the dma handle. */ ddi_dma_free_handle(&ahci_portp->ahciport_rcvd_fis_dma_handle); return (AHCI_FAILURE); @@ -4216,8 +4218,8 @@ &ahci_portp->ahciport_rcvd_fis_dma_cookie, &cookie_count) != DDI_DMA_MAPPED) { - AHCIDBG0(AHCIDBG_INIT, ahci_ctlp, - "rcvd FIS dma handle bind fail"); + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, + "rcvd FIS dma handle bind fail", NULL); /* error.. free the dma handle & free the memory. */ ddi_dma_mem_free(&ahci_portp->ahciport_rcvd_fis_acc_handle); ddi_dma_free_handle(&ahci_portp->ahciport_rcvd_fis_dma_handle); @@ -4231,9 +4233,9 @@ (uint64_t *)AHCI_PORT_PxFB(ahci_ctlp, port), ahci_portp->ahciport_rcvd_fis_dma_cookie.dmac_laddress); - AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "64-bit, dma address: 0x%llx", + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "64-bit, dma address: 0x%llx", ahci_portp->ahciport_rcvd_fis_dma_cookie.dmac_laddress); - AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "32-bit, dma address: 0x%x", + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "32-bit, dma address: 0x%x", ahci_portp->ahciport_rcvd_fis_dma_cookie.dmac_address); return (AHCI_SUCCESS); @@ -4284,8 +4286,8 @@ NULL, &ahci_portp->ahciport_cmd_list_dma_handle) != DDI_SUCCESS) { - AHCIDBG0(AHCIDBG_INIT, ahci_ctlp, - "cmd list dma handle alloc failed"); + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, + "cmd list dma handle alloc failed", NULL); return (AHCI_FAILURE); } @@ -4299,8 +4301,8 @@ &ret_len, &ahci_portp->ahciport_cmd_list_acc_handle) != NULL) { - AHCIDBG0(AHCIDBG_INIT, ahci_ctlp, - "cmd list dma mem alloc fail"); + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, + "cmd list dma mem alloc fail", NULL); /* error.. free the dma handle. */ ddi_dma_free_handle(&ahci_portp->ahciport_cmd_list_dma_handle); return (AHCI_FAILURE); @@ -4316,8 +4318,8 @@ &ahci_portp->ahciport_cmd_list_dma_cookie, &cookie_count) != DDI_DMA_MAPPED) { - AHCIDBG0(AHCIDBG_INIT, ahci_ctlp, - "cmd list dma handle bind fail"); + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, + "cmd list dma handle bind fail", NULL); /* error.. free the dma handle & free the memory. */ ddi_dma_mem_free(&ahci_portp->ahciport_cmd_list_acc_handle); ddi_dma_free_handle(&ahci_portp->ahciport_cmd_list_dma_handle); @@ -4331,10 +4333,10 @@ (uint64_t *)AHCI_PORT_PxCLB(ahci_ctlp, port), ahci_portp->ahciport_cmd_list_dma_cookie.dmac_laddress); - AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "64-bit, dma address: 0x%llx", + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "64-bit, dma address: 0x%llx", ahci_portp->ahciport_cmd_list_dma_cookie.dmac_laddress); - AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "32-bit, dma address: 0x%x", + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "32-bit, dma address: 0x%x", ahci_portp->ahciport_cmd_list_dma_cookie.dmac_address); if (ahci_alloc_cmd_tables(ahci_ctlp, ahci_portp) != AHCI_SUCCESS) { @@ -4393,7 +4395,7 @@ uint_t cookie_count; int slot; - AHCIDBG1(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp, + AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp, "ahci_alloc_cmd_tables: port %d enter", ahci_portp->ahciport_port_num); @@ -4406,8 +4408,8 @@ &ahci_portp->ahciport_cmd_tables_dma_handle[slot]) != DDI_SUCCESS) { - AHCIDBG0(AHCIDBG_INIT, ahci_ctlp, - "cmd table dma handle alloc failed"); + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, + "cmd table dma handle alloc failed", NULL); goto err_out; } @@ -4424,8 +4426,8 @@ &ahci_portp->ahciport_cmd_tables_acc_handle[slot]) != NULL) { - AHCIDBG0(AHCIDBG_INIT, ahci_ctlp, - "cmd table dma mem alloc fail"); + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, + "cmd table dma mem alloc fail", NULL); /* error.. free the dma handle. */ ddi_dma_free_handle( @@ -4444,8 +4446,8 @@ &cmd_table_dma_cookie, &cookie_count) != DDI_DMA_MAPPED) { - AHCIDBG0(AHCIDBG_INIT, ahci_ctlp, - "cmd table dma handle bind fail"); + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, + "cmd table dma handle bind fail", NULL); /* error.. free the dma handle & free the memory. */ ddi_dma_mem_free( &ahci_portp->ahciport_cmd_tables_acc_handle[slot]); @@ -4500,7 +4502,7 @@ { int slot; - AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp, + AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_dealloc_cmd_tables: %d enter", ahci_portp->ahciport_port_num); @@ -4550,7 +4552,7 @@ uint32_t port_intr_status; uint32_t port_intr_enable; - AHCIDBG1(AHCIDBG_INTR|AHCIDBG_ENTRY, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR|AHCIDBG_ENTRY, ahci_ctlp, "ahci_port_intr enter: port %d", port); mutex_enter(&ahci_portp->ahciport_mutex); @@ -4588,7 +4590,7 @@ port_intr_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, (uint32_t *)AHCI_PORT_PxIS(ahci_ctlp, port)); - AHCIDBG3(AHCIDBG_INTR, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR, ahci_ctlp, "ahci_port_intr: port %d, port_intr_status = 0x%x, " "port_intr_enable = 0x%x", port, port_intr_status, port_intr_enable); @@ -4785,7 +4787,7 @@ if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp)) { /* Slot 0 is always used during error recovery */ finished_tags = 0x1 & ~port_cmd_issue; - AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_intr_cmd_cmplt: port %d the sata pkt for error " "retrieval is finished, and finished_tags = 0x%x", port, finished_tags); @@ -4794,7 +4796,7 @@ ~port_cmd_issue & AHCI_SLOT_MASK(ahci_ctlp); } - AHCIDBG3(AHCIDBG_INTR, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR, ahci_ctlp, "ahci_intr_cmd_cmplt: pending_tags = 0x%x, " "port_cmd_issue = 0x%x finished_tags = 0x%x", ahci_portp->ahciport_pending_tags, port_cmd_issue, @@ -4805,7 +4807,7 @@ satapkt = ahci_portp->ahciport_err_retri_pkt; ASSERT(satapkt != NULL); - AHCIDBG1(AHCIDBG_INTR, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR, ahci_ctlp, "ahci_intr_cmd_cmplt: sending up pkt 0x%p " "with SATA_PKT_COMPLETED", (void *)satapkt); @@ -4850,7 +4852,7 @@ if (cmd_dmacount) { cmd_header = &ahci_portp->ahciport_cmd_list[finished_slot]; - AHCIDBG3(AHCIDBG_INTR|AHCIDBG_PRDT, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR|AHCIDBG_PRDT, ahci_ctlp, "ahci_intr_cmd_cmplt: port %d, " "PRD Byte Count = 0x%x, " "ahciport_prd_bytecounts = 0x%x", port, @@ -4858,7 +4860,7 @@ cmd_dmacount); if (cmd_header->ahcich_prd_byte_count != cmd_dmacount) { - AHCIDBG1(AHCIDBG_UNDERFLOW, ahci_ctlp, + AHCIDBG(AHCIDBG_UNDERFLOW, ahci_ctlp, "ahci_intr_cmd_cmplt: port %d, " "an underflow occurred", port); } @@ -4887,7 +4889,7 @@ ahci_copy_out_regs(&satapkt->satapkt_cmd, rcvd_fisp); } - AHCIDBG1(AHCIDBG_INTR, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR, ahci_ctlp, "ahci_intr_cmd_cmplt: sending up pkt 0x%p " "with SATA_PKT_COMPLETED", (void *)satapkt); @@ -4898,7 +4900,7 @@ SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_COMPLETED); } out: - AHCIDBG1(AHCIDBG_PKTCOMP, ahci_ctlp, + AHCIDBG(AHCIDBG_PKTCOMP, ahci_ctlp, "ahci_intr_cmd_cmplt: pending_tags = 0x%x", ahci_portp->ahciport_pending_tags); @@ -4939,7 +4941,7 @@ int finished_slot; sata_pkt_t *satapkt; - AHCIDBG1(AHCIDBG_ENTRY|AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp, + AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp, "ahci_intr_set_device_bits enter: port %d", port); mutex_enter(&ahci_portp->ahciport_mutex); @@ -4958,12 +4960,12 @@ finished_tags = ahci_portp->ahciport_pending_ncq_tags & ~port_sactive & AHCI_NCQ_SLOT_MASK(ahci_portp); - AHCIDBG3(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp, "ahci_intr_set_device_bits: port %d pending_ncq_tags = 0x%x " "port_sactive = 0x%x", port, ahci_portp->ahciport_pending_ncq_tags, port_sactive); - AHCIDBG1(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp, "ahci_intr_set_device_bits: finished_tags = 0x%x", finished_tags); /* @@ -4976,12 +4978,12 @@ issued_tags = ahci_portp->ahciport_pending_tags & ~port_cmd_issue & AHCI_SLOT_MASK(ahci_ctlp); - AHCIDBG3(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp, "ahci_intr_set_device_bits: port %d pending_tags = 0x%x " "port_cmd_issue = 0x%x", port, ahci_portp->ahciport_pending_tags, port_cmd_issue); - AHCIDBG1(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp, "ahci_intr_set_device_bits: issued_tags = 0x%x", issued_tags); /* @@ -5011,7 +5013,7 @@ satapkt = ahci_portp->ahciport_slot_pkts[finished_slot]; ASSERT(satapkt != NULL); - AHCIDBG1(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp, "ahci_intr_set_device_bits: sending up pkt 0x%p " "with SATA_PKT_COMPLETED", (void *)satapkt); @@ -5022,7 +5024,7 @@ SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_COMPLETED); } out: - AHCIDBG3(AHCIDBG_PKTCOMP|AHCIDBG_NCQ, ahci_ctlp, + AHCIDBG(AHCIDBG_PKTCOMP|AHCIDBG_NCQ, ahci_ctlp, "ahci_intr_set_device_bits: port %d " "pending_ncq_tags = 0x%x pending_tags = 0x%x", port, ahci_portp->ahciport_pending_ncq_tags, @@ -5065,7 +5067,7 @@ port_serror = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, (uint32_t *)AHCI_PORT_PxSERR(ahci_ctlp, port)); - AHCIDBG2(AHCIDBG_INTR|AHCIDBG_ENTRY, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR|AHCIDBG_ENTRY, ahci_ctlp, "ahci_intr_port_connect_change: port %d, " "port_serror = 0x%x", port, port_serror); #endif @@ -5098,7 +5100,7 @@ { uint32_t cap_status, port_cmd_status; - AHCIDBG1(AHCIDBG_INTR|AHCIDBG_ENTRY, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR|AHCIDBG_ENTRY, ahci_ctlp, "ahci_intr_device_mechanical_presence_status enter, " "port %d", port); @@ -5111,7 +5113,7 @@ if (!(cap_status & AHCI_HBA_CAP_SMPS) || !(port_cmd_status & AHCI_CMD_STATUS_MPSP)) { - AHCIDBG2(AHCIDBG_INTR, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR, ahci_ctlp, "CAP.SMPS or PxCMD.MPSP is not set, so just ignore " "the interrupt: cap_status = 0x%x, " "port_cmd_status = 0x%x", cap_status, port_cmd_status); @@ -5122,12 +5124,12 @@ #if AHCI_DEBUG if (port_cmd_status & AHCI_CMD_STATUS_MPSS) { - AHCIDBG2(AHCIDBG_INTR, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR, ahci_ctlp, "The mechanical presence switch is open: " "port %d, port_cmd_status = 0x%x", port, port_cmd_status); } else { - AHCIDBG2(AHCIDBG_INTR, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR, ahci_ctlp, "The mechanical presence switch is close: " "port %d, port_cmd_status = 0x%x", port, port_cmd_status); @@ -5167,7 +5169,7 @@ int dev_exists_now = 0; int dev_existed_previously = 0; - AHCIDBG1(AHCIDBG_INTR|AHCIDBG_ENTRY, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR|AHCIDBG_ENTRY, ahci_ctlp, "ahci_intr_phyrdy_change enter, port %d", port); /* Clear PxSERR.DIAG.N to clear the interrupt bit */ @@ -5202,7 +5204,7 @@ if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_NODEV) { ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_NODEV; - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_intr_phyrdy_change: port %d " "AHCI_PORT_FLAG_NODEV is cleared", port); if (dev_exists_now == 0) @@ -5219,7 +5221,7 @@ if (dev_exists_now) { if (dev_existed_previously) { /* Things are fine now. The loss was temporary. */ - AHCIDBG1(AHCIDBG_EVENT, ahci_ctlp, + AHCIDBG(AHCIDBG_EVENT, ahci_ctlp, "ahci_intr_phyrdy_change port %d " "device link lost/established", port); @@ -5231,7 +5233,7 @@ mutex_enter(&ahci_portp->ahciport_mutex); } else { - AHCIDBG1(AHCIDBG_EVENT, ahci_ctlp, + AHCIDBG(AHCIDBG_EVENT, ahci_ctlp, "ahci_intr_phyrdy_change: port %d " "device link established", port); @@ -5243,7 +5245,7 @@ if (ahci_start_port(ahci_ctlp, ahci_portp, port) != AHCI_SUCCESS) { sdevice.satadev_state |= SATA_PSTATE_FAILED; - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_intr_phyrdy_change: port %d failed " "at start port", port); } @@ -5262,7 +5264,7 @@ } else { /* No device exists now */ if (dev_existed_previously) { - AHCIDBG1(AHCIDBG_EVENT, ahci_ctlp, + AHCIDBG(AHCIDBG_EVENT, ahci_ctlp, "ahci_intr_phyrdy_change: port %d " "device link lost", port); @@ -5345,14 +5347,14 @@ port_serror = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, (uint32_t *)AHCI_PORT_PxSERR(ahci_ctlp, port)); - AHCIDBG2(AHCIDBG_INTR|AHCIDBG_ENTRY|AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR|AHCIDBG_ENTRY|AHCIDBG_ERRS, ahci_ctlp, "ahci_intr_non_fatal_error: port %d, " "port_serror = 0x%x", port, port_serror); ahci_log_serror_message(ahci_ctlp, port, port_serror, 1); if (intr_status & AHCI_INTR_STATUS_UFS) { - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci port %d has unknown FIS error", port); /* Clear the interrupt bit by clearing PxSERR.DIAG.F */ @@ -5363,12 +5365,12 @@ #if AHCI_DEBUG if (intr_status & AHCI_INTR_STATUS_OFS) { - AHCIDBG1(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp, "ahci port %d has overflow error", port); } if (intr_status & AHCI_INTR_STATUS_INFS) { - AHCIDBG1(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp, "ahci port %d has interface non fatal error", port); } @@ -5392,12 +5394,12 @@ } if (satapkt != NULL) { - AHCIDBG2(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp, "ahci_intr_non_fatal_error: pending_tags = 0x%x " "cmd 0x%x", ahci_portp->ahciport_pending_tags, satapkt->satapkt_cmd.satacmd_cmd_reg); - AHCIDBG2(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp, "ahci_intr_non_fatal_error: port %d, " "satapkt 0x%p is being processed when error occurs", port, (void *)satapkt); @@ -5413,7 +5415,7 @@ if (cmd_dmacount) { cmd_header = &ahci_portp-> ahciport_cmd_list[current_slot]; - AHCIDBG3(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp, "ahci_intr_non_fatal_error: port %d, " "PRD Byte Count = 0x%x, " "ahciport_prd_bytecounts = 0x%x", port, @@ -5432,7 +5434,7 @@ port_cmd_issue = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port)); - AHCIDBG3(AHCIDBG_INTR|AHCIDBG_NCQ|AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR|AHCIDBG_NCQ|AHCIDBG_ERRS, ahci_ctlp, "ahci_intr_non_fatal_error: pending_ncq_tags = 0x%x " "port_sactive = 0x%x port_cmd_issue = 0x%x", ahci_portp->ahciport_pending_ncq_tags, @@ -5449,7 +5451,7 @@ } satapkt = ahci_portp->ahciport_slot_pkts[current_slot]; - AHCIDBG2(AHCIDBG_INTR|AHCIDBG_NCQ|AHCIDBG_ERRS, + AHCIDBG(AHCIDBG_INTR|AHCIDBG_NCQ|AHCIDBG_ERRS, ahci_ctlp, "ahci_intr_non_fatal_error: " "port %d, satapkt 0x%p is outstanding when " "error occurs", port, (void *)satapkt); @@ -5564,7 +5566,7 @@ * SATA_DTYPE_NONE. */ if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) { - AHCIDBG1(AHCIDBG_ENTRY|AHCIDBG_INTR, ahci_ctlp, + AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_INTR, ahci_ctlp, "ahci_intr_fatal_error: port %d no device attached, " "and just return without doing anything", port); goto out0; @@ -5573,7 +5575,7 @@ if (intr_status & AHCI_INTR_STATUS_TFES) { task_file_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, (uint32_t *)AHCI_PORT_PxTFD(ahci_ctlp, port)); - AHCIDBG2(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp, "ahci_intr_fatal_error: port %d " "task_file_status = 0x%x", port, task_file_status); } @@ -5589,7 +5591,7 @@ AHCI_CMD_STATUS_CCS_SHIFT; spkt = ahci_portp->ahciport_slot_pkts[failed_slot]; - AHCIDBG2(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp, "ahci_intr_fatal_error: spkt 0x%p is being processed when " "fatal error occurred for port %d", spkt, port); @@ -5670,7 +5672,7 @@ uint32_t port_cmd_status; sata_device_t sdevice; - AHCIDBG1(AHCIDBG_INTR, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR, ahci_ctlp, "ahci_intr_cold_port_detect enter, port %d", port); mutex_enter(&ahci_portp->ahciport_mutex); @@ -5678,14 +5680,14 @@ port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port)); if (!(port_cmd_status & AHCI_CMD_STATUS_CPD)) { - AHCIDBG1(AHCIDBG_INTR, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR, ahci_ctlp, "port %d does not support cold presence detect, so " "we just ignore this interrupt", port); mutex_exit(&ahci_portp->ahciport_mutex); return (AHCI_SUCCESS); } - AHCIDBG1(AHCIDBG_INTR, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR, ahci_ctlp, "port %d device status has changed", port); bzero((void *)&sdevice, sizeof (sata_device_t)); @@ -5695,7 +5697,7 @@ sdevice.satadev_state = SATA_PSTATE_PWRON; if (port_cmd_status & AHCI_CMD_STATUS_CPS) { - AHCIDBG1(AHCIDBG_INTR, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR, ahci_ctlp, "port %d: a device is hot plugged", port); mutex_exit(&ahci_portp->ahciport_mutex); sata_hba_event_notify( @@ -5705,7 +5707,7 @@ mutex_enter(&ahci_portp->ahciport_mutex); } else { - AHCIDBG1(AHCIDBG_INTR, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR, ahci_ctlp, "port %d: a device is hot unplugged", port); mutex_exit(&ahci_portp->ahciport_mutex); sata_hba_event_notify( @@ -5729,7 +5731,7 @@ static void ahci_enable_port_intrs(ahci_ctl_t *ahci_ctlp, uint8_t port) { - AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp, + AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_enable_port_intrs enter, port %d", port); /* @@ -5788,7 +5790,7 @@ { uint32_t ghc_control; - AHCIDBG0(AHCIDBG_ENTRY, ahci_ctlp, "ahci_enable_all_intrs enter"); + AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_enable_all_intrs enter", NULL); ghc_control = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp)); @@ -5808,7 +5810,7 @@ static void ahci_disable_port_intrs(ahci_ctl_t *ahci_ctlp, uint8_t port) { - AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp, + AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_disable_port_intrs enter, port %d", port); ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle, @@ -5829,7 +5831,8 @@ { uint32_t ghc_control; - AHCIDBG0(AHCIDBG_ENTRY, ahci_ctlp, "ahci_disable_all_intrs enter"); + AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_disable_all_intrs enter", + NULL); ghc_control = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp)); @@ -5887,13 +5890,13 @@ int count, avail, actual; int i, rc; - AHCIDBG1(AHCIDBG_ENTRY|AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp, + AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp, "ahci_add_intrs enter interrupt type 0x%x", intr_type); /* get number of interrupts. */ rc = ddi_intr_get_nintrs(dip, intr_type, &count); if ((rc != DDI_SUCCESS) || (count == 0)) { - AHCIDBG2(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp, "ddi_intr_get_nintrs() failed, " "rc %d count %d\n", rc, count); return (DDI_FAILURE); @@ -5902,7 +5905,7 @@ /* get number of available interrupts. */ rc = ddi_intr_get_navail(dip, intr_type, &avail); if ((rc != DDI_SUCCESS) || (avail == 0)) { - AHCIDBG2(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp, "ddi_intr_get_navail() failed, " "rc %d avail %d\n", rc, avail); return (DDI_FAILURE); @@ -5910,7 +5913,7 @@ #if AHCI_DEBUG if (avail < count) { - AHCIDBG2(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp, "ddi_intr_get_nintrs returned %d, navail() returned %d", count, avail); } @@ -5925,7 +5928,7 @@ * performance. */ if ((intr_type == DDI_INTR_TYPE_MSI) && (count > 1)) { - AHCIDBG1(AHCIDBG_INTR, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR, ahci_ctlp, "force to use one interrupt routine though the " "HBA supports %d interrupt", count); count = 1; @@ -5941,7 +5944,7 @@ intr_type, 0, count, &actual, DDI_INTR_ALLOC_NORMAL); if ((rc != DDI_SUCCESS) || (actual == 0)) { - AHCIDBG4(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp, "ddi_intr_alloc() failed, rc %d count %d actual %d " "avail %d\n", rc, count, actual, avail); kmem_free(ahci_ctlp->ahcictl_intr_htable, @@ -5952,7 +5955,7 @@ /* use interrupt count returned */ #if AHCI_DEBUG if (actual < count) { - AHCIDBG2(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp, "Requested: %d, Received: %d", count, actual); } #endif @@ -5964,8 +5967,8 @@ */ if (ddi_intr_get_pri(ahci_ctlp->ahcictl_intr_htable[0], &ahci_ctlp->ahcictl_intr_pri) != DDI_SUCCESS) { - AHCIDBG0(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp, - "ddi_intr_get_pri() failed"); + AHCIDBG(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp, + "ddi_intr_get_pri() failed", NULL); /* Free already allocated intr. */ for (i = 0; i < actual; i++) { @@ -5979,8 +5982,8 @@ /* Test for high level interrupt. */ if (ahci_ctlp->ahcictl_intr_pri >= ddi_intr_get_hilevel_pri()) { - AHCIDBG0(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp, - "ahci_add_intrs: Hi level intr not supported"); + AHCIDBG(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp, + "ahci_add_intrs: Hi level intr not supported", NULL); /* Free already allocated intr. */ for (i = 0; i < actual; i++) { @@ -5997,8 +6000,8 @@ for (i = 0; i < actual; i++) { if (ddi_intr_add_handler(ahci_ctlp->ahcictl_intr_htable[i], ahci_intr, (caddr_t)ahci_ctlp, NULL) != DDI_SUCCESS) { - AHCIDBG0(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp, - "ddi_intr_add_handler() failed"); + AHCIDBG(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp, + "ddi_intr_add_handler() failed", NULL); /* Free already allocated intr. */ for (i = 0; i < actual; i++) { @@ -6014,8 +6017,8 @@ if (ddi_intr_get_cap(ahci_ctlp->ahcictl_intr_htable[0], &ahci_ctlp->ahcictl_intr_cap) != DDI_SUCCESS) { - AHCIDBG0(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp, - "ddi_intr_get_cap() failed"); + AHCIDBG(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp, + "ddi_intr_get_cap() failed", NULL); /* Free already allocated intr. */ for (i = 0; i < actual; i++) { @@ -6055,7 +6058,7 @@ { int x; - AHCIDBG0(AHCIDBG_ENTRY, ahci_ctlp, "ahci_rem_intrs entered"); + AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_rem_intrs entered", NULL); /* Disable all interrupts. */ if ((ahci_ctlp->ahcictl_intr_type == DDI_INTR_TYPE_MSI) && @@ -6095,7 +6098,7 @@ uint32_t port_cmd_status; int loop_count; - AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp, + AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_put_port_into_notrunning_state enter: port %d", port); port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, @@ -6113,7 +6116,7 @@ (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port)); if (loop_count++ > AHCI_POLLRATE_PORT_IDLE) { - AHCIDBG2(AHCIDBG_INIT, ahci_ctlp, + AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "clearing port %d CMD.CR timeout, " "port_cmd_status = 0x%x", port, port_cmd_status); @@ -6131,13 +6134,13 @@ ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_STARTED; if (port_cmd_status & AHCI_CMD_STATUS_CR) { - AHCIDBG2(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp, + AHCIDBG(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp, "ahci_put_port_into_notrunning_state: failed to clear " "PxCMD.CR to '0' after loop count: %d, and " "port_cmd_status = 0x%x", loop_count, port_cmd_status); return (AHCI_FAILURE); } else { - AHCIDBG2(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp, + AHCIDBG(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp, "ahci_put_port_into_notrunning_state: succeeded to clear " "PxCMD.CR to '0' after loop count: %d, and " "port_cmd_status = 0x%x", loop_count, port_cmd_status); @@ -6189,7 +6192,7 @@ int dev_exists_begin = 0; int dev_exists_end = 0; - AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp, + AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_restart_port_wait_till_ready: port %d enter", port); if (ahci_portp->ahciport_device_type != SATA_DTYPE_NONE) @@ -6257,7 +6260,7 @@ mutex_enter(&ahci_portp->ahciport_mutex); } - AHCIDBG1(AHCIDBG_EVENT, ahci_ctlp, + AHCIDBG(AHCIDBG_EVENT, ahci_ctlp, "port %d sending event up: SATA_EVNT_RESET", port); } else { ahci_portp->ahciport_reset_in_progress = 0; @@ -6277,11 +6280,11 @@ /* Check whether a hot plug event happened */ if (dev_exists_begin == 1 && dev_exists_end == 0) { - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_restart_port_wait_till_ready: port %d " "device is removed", port); ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_NODEV; - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_restart_port_wait_till_ready: port %d " "AHCI_PORT_FLAG_NODEV flag is set", port); mutex_exit(&ahci_portp->ahciport_mutex); @@ -6320,11 +6323,11 @@ int ncq_cmd_in_progress = 0; int err_retri_cmd_in_progress = 0; - AHCIDBG2(AHCIDBG_ERRS|AHCIDBG_ENTRY, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS|AHCIDBG_ENTRY, ahci_ctlp, "ahci_mop_commands entered: port: %d slot_status: 0x%x", ahci_portp->ahciport_port_num, slot_status); - AHCIDBG4(AHCIDBG_ERRS|AHCIDBG_ENTRY, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS|AHCIDBG_ENTRY, ahci_ctlp, "ahci_mop_commands: failed_tags: 0x%x, " "timeout_tags: 0x%x aborted_tags: 0x%x, " "reset_tags: 0x%x", failed_tags, @@ -6367,7 +6370,7 @@ * Please note that the command is always sent down in Slot 0 */ err_retri_cmd_in_progress = 1; - AHCIDBG2(AHCIDBG_ERRS|AHCIDBG_NCQ, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS|AHCIDBG_NCQ, ahci_ctlp, "ahci_mop_commands is called for port %d while " "REQUEST SENSE or READ LOG EXT for error retrieval " "is being executed slot_status = 0x%x", @@ -6386,7 +6389,7 @@ satapkt = ahci_portp->ahciport_slot_pkts[tmp_slot]; ASSERT(satapkt != NULL); - AHCIDBG1(AHCIDBG_INFO, ahci_ctlp, "ahci_mop_commands: " + AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "ahci_mop_commands: " "sending up pkt 0x%p with SATA_PKT_COMPLETED", (void *)satapkt); @@ -6418,7 +6421,7 @@ ASSERT(satapkt != NULL); ASSERT(failed_tags == 0x1); - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: " + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: " "sending up pkt 0x%p with SATA_PKT_DEV_ERROR", (void *)satapkt); SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_DEV_ERROR); @@ -6433,7 +6436,7 @@ satapkt = ahci_portp->ahciport_slot_pkts[tmp_slot]; ASSERT(satapkt != NULL); - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: " + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: " "sending up pkt 0x%p with SATA_PKT_DEV_ERROR", (void *)satapkt); @@ -6454,7 +6457,7 @@ ASSERT(satapkt != NULL); ASSERT(timeout_tags == 0x1); - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: " + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: " "sending up pkt 0x%p with SATA_PKT_TIMEOUT", (void *)satapkt); SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_TIMEOUT); @@ -6469,7 +6472,7 @@ satapkt = ahci_portp->ahciport_slot_pkts[tmp_slot]; ASSERT(satapkt != NULL); - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: " + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: " "sending up pkt 0x%p with SATA_PKT_TIMEOUT", (void *)satapkt); @@ -6490,7 +6493,7 @@ ASSERT(satapkt != NULL); ASSERT(aborted_tags == 0x1); - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: " + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: " "sending up pkt 0x%p with SATA_PKT_ABORTED", (void *)satapkt); SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_ABORTED); @@ -6505,7 +6508,7 @@ satapkt = ahci_portp->ahciport_slot_pkts[tmp_slot]; ASSERT(satapkt != NULL); - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: " + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: " "sending up pkt 0x%p with SATA_PKT_ABORTED", (void *)satapkt); @@ -6529,7 +6532,7 @@ satapkt = ahci_portp->ahciport_slot_pkts[tmp_slot]; ASSERT(satapkt != NULL); - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: " + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: " "sending up pkt 0x%p with SATA_PKT_RESET", (void *)satapkt); @@ -6553,7 +6556,7 @@ satapkt = ahci_portp->ahciport_slot_pkts[tmp_slot]; ASSERT(satapkt != NULL); - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: " + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: " "sending up pkt 0x%p with SATA_PKT_RESET", (void *)satapkt); @@ -6592,7 +6595,7 @@ uint32_t failed_tags = 0; struct sata_ncq_error_recovery_page *ncq_err_page; - AHCIDBG1(AHCIDBG_ENTRY|AHCIDBG_NCQ, ahci_ctlp, + AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_NCQ, ahci_ctlp, "ahci_get_rdlogext_data enter: port %d", port); /* Prepare the sdevice data */ @@ -6616,7 +6619,7 @@ goto loop; } /* Timed out after 1s */ - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "failed to get rdlog spkt for port %d", port); return (failed_tags); } @@ -6653,23 +6656,23 @@ /* Get the failed tag */ failed_slot = ncq_err_page->ncq_tag; - AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_get_rdlogext_data: port %d " "failed slot %d", port, failed_slot); if (failed_slot & NQ) { - AHCIDBG0(AHCIDBG_ERRS, ahci_ctlp, - "the failed slot is not a valid tag"); + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, + "the failed slot is not a valid tag", NULL); goto out; } failed_slot &= NCQ_TAG_MASK; spkt = ahci_portp->ahciport_slot_pkts[failed_slot]; - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_get_rdlogext_data: failed spkt 0x%p", (void *)spkt); if (spkt == NULL) { - AHCIDBG0(AHCIDBG_ERRS, ahci_ctlp, - "the failed slot spkt is NULL") + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, + "the failed slot spkt is NULL", NULL); goto out; } @@ -6707,7 +6710,7 @@ struct scsi_extended_sense *rqsense; #endif - AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp, + AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_get_rqsense_data enter: port %d", port); /* Prepare the sdevice data */ @@ -6734,7 +6737,7 @@ } /* Timed out after 1s */ - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "failed to get rs spkt for port %d", port); return; } @@ -6774,11 +6777,11 @@ sata_cmd->satacmd_rqsense; /* Dump the sense data */ - AHCIDBG0(AHCIDBG_SENSEDATA, ahci_ctlp, "\n"); - AHCIDBG2(AHCIDBG_SENSEDATA, ahci_ctlp, + AHCIDBG(AHCIDBG_SENSEDATA, ahci_ctlp, "\n", NULL); + AHCIDBG(AHCIDBG_SENSEDATA, ahci_ctlp, "Sense data for satapkt %p ATAPI cmd 0x%x", spkt, sata_cmd->satacmd_acdb[0]); - AHCIDBG5(AHCIDBG_SENSEDATA, ahci_ctlp, + AHCIDBG(AHCIDBG_SENSEDATA, ahci_ctlp, " es_code 0x%x es_class 0x%x " "es_key 0x%x es_add_code 0x%x " "es_qual_code 0x%x", @@ -6832,7 +6835,7 @@ ahci_cmd_header_t *cmd_header; #endif - AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp, + AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_fatal_error_recovery_handler enter: port %d", port); if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp) || @@ -6869,7 +6872,7 @@ if (ahci_portp->ahciport_prd_bytecounts[failed_slot]) { cmd_header = &ahci_portp->ahciport_cmd_list[failed_slot]; - AHCIDBG3(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp, "ahci_fatal_error_recovery_handler: port %d, " "PRD Byte Count = 0x%x, " "ahciport_prd_bytecounts = 0x%x", port, @@ -6913,7 +6916,7 @@ * supposed to be REQUEST SENSE command or READ LOG EXT command. */ if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp)) { - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_fatal_error_recovery_handler: port %d REQUEST SENSE " "command or READ LOG EXT command for error data retrieval " "failed", port); @@ -6964,7 +6967,7 @@ if (spkt && ahci_portp->ahciport_device_type == SATA_DTYPE_ATAPI) ahci_get_rqsense_data(ahci_ctlp, ahci_portp, port, spkt); out: - AHCIDBG5(AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_fatal_error_recovery_handler: port %d fatal error " "occurred slot_status = 0x%x, pending_tags = 0x%x, " "pending_ncq_tags = 0x%x failed_tags = 0x%x", @@ -6999,7 +7002,7 @@ event = ahci_event_arg->ahciea_event; port = ahci_portp->ahciport_port_num; - AHCIDBG2(AHCIDBG_ENTRY|AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp, + AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp, "ahci_events_handler enter: port %d intr_status = 0x%x", port, event); @@ -7010,7 +7013,7 @@ * SATA_DTYPE_NONE. */ if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) { - AHCIDBG1(AHCIDBG_ENTRY|AHCIDBG_INTR, ahci_ctlp, + AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_INTR, ahci_ctlp, "ahci_events_handler: port %d no device attached, " "and just return without doing anything", port); goto out; @@ -7039,7 +7042,7 @@ uint32_t finished_tags = 0; uint32_t timeout_tags = 0; - AHCIDBG1(AHCIDBG_TIMEOUT|AHCIDBG_ENTRY, ahci_ctlp, + AHCIDBG(AHCIDBG_TIMEOUT|AHCIDBG_ENTRY, ahci_ctlp, "ahci_timeout_pkts enter: port %d", port); mutex_enter(&ahci_portp->ahciport_mutex); @@ -7064,7 +7067,7 @@ * supposed to be REQUEST SENSE command or READ LOG EXT command. */ if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp)) { - AHCIDBG4(AHCIDBG_ERRS|AHCIDBG_TIMEOUT, ahci_ctlp, + AHCIDBG(AHCIDBG_ERRS|AHCIDBG_TIMEOUT, ahci_ctlp, "ahci_timeout_pkts called while REQUEST SENSE " "command or READ LOG EXT command for error recovery " "timed out timeout_tags = 0x%x, slot_status = 0x%x, " @@ -7091,7 +7094,7 @@ ~slot_status & AHCI_SLOT_MASK(ahci_ctlp); timeout_tags = tmp_timeout_tags & ~finished_tags; - AHCIDBG5(AHCIDBG_TIMEOUT, ahci_ctlp, + AHCIDBG(AHCIDBG_TIMEOUT, ahci_ctlp, "ahci_timeout_pkts: port %d, finished_tags = 0x%x, " "timeout_tags = 0x%x, port_cmd_issue = 0x%x, " "pending_tags = 0x%x ", @@ -7102,7 +7105,7 @@ ~slot_status & AHCI_NCQ_SLOT_MASK(ahci_portp); timeout_tags = tmp_timeout_tags & ~finished_tags; - AHCIDBG5(AHCIDBG_TIMEOUT|AHCIDBG_NCQ, ahci_ctlp, + AHCIDBG(AHCIDBG_TIMEOUT|AHCIDBG_NCQ, ahci_ctlp, "ahci_timeout_pkts: port %d, finished_tags = 0x%x, " "timeout_tags = 0x%x, port_sactive = 0x%x, " "pending_ncq_tags = 0x%x ", @@ -7149,8 +7152,8 @@ mutex_enter(&ahci_ctlp->ahcictl_mutex); - AHCIDBG0(AHCIDBG_ENTRY, ahci_ctlp, - "ahci_watchdog_handler entered"); + AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, + "ahci_watchdog_handler entered", NULL); for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) { if (!AHCI_PORT_IMPLEMENTED(ahci_ctlp, port)) { @@ -7231,11 +7234,11 @@ #if AHCI_DEBUG if (NCQ_CMD_IN_PROGRESS(ahci_portp)) { - AHCIDBG1(AHCIDBG_ERRS|AHCIDBG_TIMEOUT, + AHCIDBG(AHCIDBG_ERRS|AHCIDBG_TIMEOUT, ahci_ctlp, "watchdog: the current " "tags is 0x%x", current_tags); } else { - AHCIDBG1(AHCIDBG_ERRS|AHCIDBG_TIMEOUT, + AHCIDBG(AHCIDBG_ERRS|AHCIDBG_TIMEOUT, ahci_ctlp, "watchdog: the current " "slot is %d", current_slot); } @@ -7473,14 +7476,22 @@ if (debug_only) { (void) sprintf(err_msg_header, "port %d", port); - AHCIDBG0(AHCIDBG_ERRS, ahci_ctlp, err_msg_header); - AHCIDBG0(AHCIDBG_ERRS, ahci_ctlp, err_msg); + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, err_msg_header, NULL); + AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, err_msg, NULL); } else if (ahci_ctlp) { cmn_err(CE_WARN, "!ahci%d: %s %s", ddi_get_instance(ahci_ctlp->ahcictl_dip), err_msg_header, err_msg); + + /* sata trace debug */ + sata_trace_debug(ahci_ctlp->ahcictl_dip, + "ahci%d: %s %s", ddi_get_instance(ahci_ctlp->ahcictl_dip), + err_msg_header, err_msg); } else { cmn_err(CE_WARN, "!ahci: %s %s", err_msg_header, err_msg); + + /* sata trace debug */ + sata_trace_debug(NULL, "ahci: %s %s", err_msg_header, err_msg); } }
--- a/usr/src/uts/common/io/sata/impl/sata.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/sata/impl/sata.c Mon Jul 20 13:07:46 2009 -0400 @@ -102,7 +102,7 @@ sata_save_atapi_trace(spx, count); #else -#define SATA_LOG_D(arg) +#define SATA_LOG_D(args) sata_trace_log args #define SATAATAPITRACE(spx, count) #endif @@ -189,29 +189,30 @@ static int sata_txlt_start_stop_unit(sata_pkt_txlate_t *); static int sata_txlt_read_capacity(sata_pkt_txlate_t *); static int sata_txlt_request_sense(sata_pkt_txlate_t *); -static int sata_txlt_read(sata_pkt_txlate_t *); -static int sata_txlt_write(sata_pkt_txlate_t *); -static int sata_txlt_log_sense(sata_pkt_txlate_t *); -static int sata_txlt_log_select(sata_pkt_txlate_t *); -static int sata_txlt_mode_sense(sata_pkt_txlate_t *); -static int sata_txlt_mode_select(sata_pkt_txlate_t *); -static int sata_txlt_synchronize_cache(sata_pkt_txlate_t *); -static int sata_txlt_write_buffer(sata_pkt_txlate_t *); -static int sata_txlt_nodata_cmd_immediate(sata_pkt_txlate_t *); - -static int sata_hba_start(sata_pkt_txlate_t *, int *); +static int sata_txlt_read(sata_pkt_txlate_t *); +static int sata_txlt_write(sata_pkt_txlate_t *); +static int sata_txlt_log_sense(sata_pkt_txlate_t *); +static int sata_txlt_log_select(sata_pkt_txlate_t *); +static int sata_txlt_mode_sense(sata_pkt_txlate_t *); +static int sata_txlt_mode_select(sata_pkt_txlate_t *); +static int sata_txlt_synchronize_cache(sata_pkt_txlate_t *); +static int sata_txlt_write_buffer(sata_pkt_txlate_t *); +static int sata_txlt_nodata_cmd_immediate(sata_pkt_txlate_t *); + +static int sata_hba_start(sata_pkt_txlate_t *, int *); static int sata_txlt_invalid_command(sata_pkt_txlate_t *); +static int sata_txlt_check_condition(sata_pkt_txlate_t *, uchar_t, uchar_t); static int sata_txlt_lba_out_of_range(sata_pkt_txlate_t *); -static void sata_txlt_rw_completion(sata_pkt_t *); -static void sata_txlt_nodata_cmd_completion(sata_pkt_t *); -static void sata_txlt_download_mcode_cmd_completion(sata_pkt_t *); -static int sata_emul_rw_completion(sata_pkt_txlate_t *); -static struct scsi_extended_sense *sata_immediate_error_response( +static void sata_txlt_rw_completion(sata_pkt_t *); +static void sata_txlt_nodata_cmd_completion(sata_pkt_t *); +static void sata_txlt_download_mcode_cmd_completion(sata_pkt_t *); +static int sata_emul_rw_completion(sata_pkt_txlate_t *); +static struct scsi_extended_sense *sata_immediate_error_response( sata_pkt_txlate_t *, int); static struct scsi_extended_sense *sata_arq_sense(sata_pkt_txlate_t *); -static int sata_txlt_atapi(sata_pkt_txlate_t *); -static void sata_txlt_atapi_completion(sata_pkt_t *); +static int sata_txlt_atapi(sata_pkt_txlate_t *); +static void sata_txlt_atapi_completion(sata_pkt_t *); /* * Local functions for ioctl @@ -291,11 +292,13 @@ static int sata_build_msense_page_8(sata_drive_info_t *, int, uint8_t *); static int sata_build_msense_page_1a(sata_drive_info_t *, int, uint8_t *); static int sata_build_msense_page_1c(sata_drive_info_t *, int, uint8_t *); +static int sata_build_msense_page_30(sata_drive_info_t *, int, uint8_t *); static int sata_mode_select_page_8(sata_pkt_txlate_t *, struct mode_cache_scsi3 *, int, int *, int *, int *); +static int sata_mode_select_page_1a(sata_pkt_txlate_t *, + struct mode_info_power_cond *, int, int *, int *, int *); static int sata_mode_select_page_1c(sata_pkt_txlate_t *, struct mode_info_excpt_page *, int, int *, int *, int *); -static int sata_build_msense_page_30(sata_drive_info_t *, int, uint8_t *); static int sata_mode_select_page_30(sata_pkt_txlate_t *, struct mode_acoustic_management *, int, int *, int *, int *); @@ -306,9 +309,18 @@ sata_hba_inst_t *); static int sata_build_lsense_page_30(sata_drive_info_t *, uint8_t *, sata_hba_inst_t *); +static int sata_build_lsense_page_0e(sata_drive_info_t *, uint8_t *, + sata_pkt_txlate_t *); + +static void sata_set_arq_data(sata_pkt_t *); +static void sata_build_read_verify_cmd(sata_cmd_t *, uint16_t, uint64_t); +static void sata_build_generic_cmd(sata_cmd_t *, uint8_t); +static uint8_t sata_get_standby_timer(uint8_t *timer); + static void sata_save_drive_settings(sata_drive_info_t *); static void sata_show_drive_info(sata_hba_inst_t *, sata_drive_info_t *); static void sata_log(sata_hba_inst_t *, uint_t, char *fmt, ...); +static void sata_trace_log(sata_hba_inst_t *, uint_t, const char *fmt, ...); static int sata_fetch_smart_return_status(sata_hba_inst_t *, sata_drive_info_t *); static int sata_fetch_smart_data(sata_hba_inst_t *, sata_drive_info_t *, @@ -411,6 +423,17 @@ static char sata_log_buf[256]; +/* + * sata trace debug + */ +static sata_trace_rbuf_t *sata_debug_rbuf; +static sata_trace_dmsg_t *sata_trace_dmsg_alloc(void); +static void sata_trace_dmsg_free(void); +static void sata_trace_rbuf_alloc(void); +static void sata_trace_rbuf_free(void); + +int dmsg_ring_size = DMSG_RING_SIZE; + /* Default write cache setting for SATA hard disks */ int sata_write_cache = 1; /* enabled */ @@ -543,10 +566,12 @@ mutex_init(&sata_event_mutex, NULL, MUTEX_DRIVER, NULL); mutex_init(&sata_log_mutex, NULL, MUTEX_DRIVER, NULL); cv_init(&sata_event_cv, NULL, CV_DRIVER, NULL); + sata_trace_rbuf_alloc(); if ((rval = mod_install(&modlinkage)) != 0) { #ifdef SATA_DEBUG cmn_err(CE_WARN, "sata: _init: mod_install failed\n"); #endif + sata_trace_rbuf_free(); mutex_destroy(&sata_log_mutex); cv_destroy(&sata_event_cv); mutex_destroy(&sata_event_mutex); @@ -563,6 +588,7 @@ if ((rval = mod_remove(&modlinkage)) != 0) return (rval); + sata_trace_rbuf_free(); mutex_destroy(&sata_log_mutex); cv_destroy(&sata_event_cv); mutex_destroy(&sata_event_mutex); @@ -1794,8 +1820,11 @@ sata_hba_inst_t *sata_hba_inst = (sata_hba_inst_t *)(sd->sd_address.a_hba_tran->tran_hba_private); int rval; + uint32_t pm_cap; rval = scsi_hba_probe(sd, callback); + pm_cap = SATA_CAP_POWER_CONDITON | SATA_CAP_SMART_PAGE | + SATA_CAP_LOG_SENSE; if (rval == SCSIPROBE_EXISTS) { /* @@ -1804,7 +1833,7 @@ * before enabling device power-management. */ if ((ddi_prop_update_int(DDI_DEV_T_NONE, sd->sd_dev, - "pm-capable", 1)) != DDI_PROP_SUCCESS) { + "pm-capable", pm_cap)) != DDI_PROP_SUCCESS) { sata_log(sata_hba_inst, CE_WARN, "SATA device at port %d: " "will not be power-managed ", @@ -2148,6 +2177,20 @@ } mutex_exit(&(SATA_CPORT_MUTEX(sata_hba_inst, cport))); + /* + * Checking for power state, if it was on + * STOPPED state, then the drive is not capable + * of processing media access command. And + * TEST_UNIT_READY, REQUEST_SENSE has special handling + * in the function for different power state. + */ + if (((sdinfo->satadrv_power_level == SATA_POWER_STANDBY) || + (sdinfo->satadrv_power_level == SATA_POWER_STOPPED)) && + (SATA_IS_MEDIUM_ACCESS_CMD(pkt->pkt_cdbp[0]))) { + return (sata_txlt_check_condition(spx, KEY_NOT_READY, + SD_SCSI_ASC_LU_NOT_READY)); + } + /* ATA Disk commands processing starts here */ bp = spx->txlt_sata_pkt->satapkt_cmd.satacmd_bp; @@ -3012,12 +3055,53 @@ } /* + * Scsi response set up for check condition with special sense key + * and additional sense code. + * + * Returns TRAN_ACCEPT and appropriate values in scsi_pkt fields. + */ +static int +sata_txlt_check_condition(sata_pkt_txlate_t *spx, uchar_t key, uchar_t code) +{ + sata_hba_inst_t *shi = SATA_TXLT_HBA_INST(spx); + int cport = SATA_TXLT_CPORT(spx); + struct scsi_pkt *scsipkt = spx->txlt_scsi_pkt; + struct scsi_extended_sense *sense; + + mutex_enter(&SATA_CPORT_MUTEX(shi, cport)); + scsipkt->pkt_reason = CMD_CMPLT; + scsipkt->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET | + STATE_SENT_CMD | STATE_GOT_STATUS; + + *scsipkt->pkt_scbp = STATUS_CHECK; + + sense = sata_arq_sense(spx); + sense->es_key = key; + sense->es_add_code = code; + + mutex_exit(&SATA_CPORT_MUTEX(shi, cport)); + + SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst, + "Scsi_pkt completion reason %x\n", scsipkt->pkt_reason); + + if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0) + /* scsi callback required */ + if (taskq_dispatch(SATA_TXLT_TASKQ(spx), + (task_func_t *)scsi_hba_pkt_comp, + (void *)spx->txlt_scsi_pkt, + TQ_SLEEP) == NULL) + /* Scheduling the callback failed */ + return (TRAN_BUSY); + return (TRAN_ACCEPT); +} + +/* * Scsi response setup for * emulated non-data command that requires no action/return data * * Returns TRAN_ACCEPT and appropriate values in scsi_pkt fields. */ -static int +static int sata_txlt_nodata_cmd_immediate(sata_pkt_txlate_t *spx) { int rval; @@ -3274,10 +3358,10 @@ /* * SATA translate command: Request Sense. - * Emulated command (ATA version for SATA hard disks) - * Always NO SENSE, because any sense data should be reported by ARQ sense. * * Returns TRAN_ACCEPT and appropriate values in scsi_pkt fields. + * At the moment this is an emulated command (ATA version for SATA hard disks). + * May be translated into Check Power Mode command in the future. * * Note: There is a mismatch between already implemented Informational * Exception Mode Select page 0x1C and this function. @@ -3291,7 +3375,9 @@ struct scsi_pkt *scsipkt = spx->txlt_scsi_pkt; struct scsi_extended_sense sense; struct buf *bp = spx->txlt_sata_pkt->satapkt_cmd.satacmd_bp; - int rval, reason; + sata_drive_info_t *sdinfo; + sata_cmd_t *scmd = &spx->txlt_sata_pkt->satapkt_cmd; + int rval, reason, power_state = 0; mutex_enter(&(SATA_TXLT_CPORT_MUTEX(spx))); @@ -3300,14 +3386,68 @@ mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx))); return (rval); } - mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx))); - scsipkt->pkt_reason = CMD_CMPLT; scsipkt->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD | STATE_GOT_STATUS; *scsipkt->pkt_scbp = STATUS_GOOD; + /* + * when CONTROL field's NACA bit == 1 + * return ILLEGAL_REQUEST + */ + if (scsipkt->pkt_cdbp[5] & CTL_BYTE_NACA_MASK) { + mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx))); + return (sata_txlt_check_condition(spx, KEY_ILLEGAL_REQUEST, + SD_SCSI_ASC_CMD_SEQUENCE_ERR)); + } + + sdinfo = sata_get_device_info(spx->txlt_sata_hba_inst, + &spx->txlt_sata_pkt->satapkt_device); + ASSERT(sdinfo != NULL); + + spx->txlt_sata_pkt->satapkt_op_mode = SATA_OPMODE_SYNCH; + + sata_build_generic_cmd(scmd, SATAC_CHECK_POWER_MODE); + scmd->satacmd_flags.sata_copy_out_sec_count_lsb = B_TRUE; + scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE; + if (sata_hba_start(spx, &rval) != 0) { + mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx))); + return (rval); + } else { + if (scmd->satacmd_error_reg != 0) { + mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx))); + return (sata_txlt_check_condition(spx, KEY_NO_SENSE, + SD_SCSI_ASC_NO_ADD_SENSE)); + } + } + + switch (scmd->satacmd_sec_count_lsb) { + case SATA_PWRMODE_STANDBY: /* device in standby mode */ + if (sdinfo->satadrv_power_level == SATA_POWER_STOPPED) + power_state = SATA_POWER_STOPPED; + else { + power_state = SATA_POWER_STANDBY; + sdinfo->satadrv_power_level = SATA_POWER_STANDBY; + } + break; + case SATA_PWRMODE_IDLE: /* device in idle mode */ + power_state = SATA_POWER_IDLE; + sdinfo->satadrv_power_level = SATA_POWER_IDLE; + break; + case SATA_PWRMODE_ACTIVE: /* device in active or idle mode */ + default: /* 0x40, 0x41 active mode */ + if (sdinfo->satadrv_power_level == SATA_POWER_IDLE) + power_state = SATA_POWER_IDLE; + else { + power_state = SATA_POWER_ACTIVE; + sdinfo->satadrv_power_level = SATA_POWER_ACTIVE; + } + break; + } + + mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx))); + if (bp != NULL && bp->b_un.b_addr && bp->b_bcount) { /* * Because it is fully emulated command storing data @@ -3327,17 +3467,29 @@ bcopy(&sense, bp->b_un.b_addr, count); scsipkt->pkt_state |= STATE_XFERRED_DATA; scsipkt->pkt_resid = 0; + switch (power_state) { + case SATA_POWER_IDLE: + case SATA_POWER_STANDBY: + sense.es_add_code = + SD_SCSI_ASC_LOW_POWER_CONDITION_ON; + break; + case SATA_POWER_STOPPED: + sense.es_add_code = SD_SCSI_ASC_NO_ADD_SENSE; + break; + case SATA_POWER_ACTIVE: + default: + break; + } } SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst, "Scsi_pkt completion reason %x\n", scsipkt->pkt_reason); - if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0 && - scsipkt->pkt_comp != NULL) + if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0) /* scsi callback required */ if (taskq_dispatch(SATA_TXLT_TASKQ(spx), - (task_func_t *)scsipkt->pkt_comp, (void *) scsipkt, + (task_func_t *)scsi_hba_pkt_comp, (void *) scsipkt, TQ_SLEEP) == NULL) /* Scheduling the callback failed */ return (TRAN_BUSY); @@ -3356,6 +3508,8 @@ { struct scsi_pkt *scsipkt = spx->txlt_scsi_pkt; struct scsi_extended_sense *sense; + sata_cmd_t *scmd = &spx->txlt_sata_pkt->satapkt_cmd; + sata_drive_info_t *sdinfo; int power_state; int rval, reason; @@ -3366,37 +3520,59 @@ mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx))); return (rval); } - mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx))); - - /* At this moment, emulate it rather than execute anything */ - power_state = SATA_PWRMODE_ACTIVE; + + sdinfo = sata_get_device_info(spx->txlt_sata_hba_inst, + &spx->txlt_sata_pkt->satapkt_device); + ASSERT(sdinfo != NULL); + + spx->txlt_sata_pkt->satapkt_op_mode = SATA_OPMODE_SYNCH; + + /* send CHECK POWER MODE command */ + sata_build_generic_cmd(scmd, SATAC_CHECK_POWER_MODE); + scmd->satacmd_flags.sata_copy_out_sec_count_lsb = B_TRUE; + scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE; + if (sata_hba_start(spx, &rval) != 0) { + mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx))); + return (rval); + } else { + if (scmd->satacmd_error_reg != 0) { + mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx))); + return (sata_txlt_check_condition(spx, KEY_NOT_READY, + SD_SCSI_ASC_LU_NOT_RESPONSE)); + } + } + + power_state = scmd->satacmd_sec_count_lsb; + + /* + * return NOT READY when device in STOPPED mode + */ + if (power_state == SATA_PWRMODE_STANDBY && + sdinfo->satadrv_power_level == SATA_POWER_STOPPED) { + *scsipkt->pkt_scbp = STATUS_CHECK; + sense = sata_arq_sense(spx); + sense->es_key = KEY_NOT_READY; + sense->es_add_code = SD_SCSI_ASC_LU_NOT_READY; + } else { + /* + * For other power mode, return GOOD status + */ + *scsipkt->pkt_scbp = STATUS_GOOD; + } scsipkt->pkt_reason = CMD_CMPLT; scsipkt->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD | STATE_GOT_STATUS; - switch (power_state) { - case SATA_PWRMODE_ACTIVE: - case SATA_PWRMODE_IDLE: - *scsipkt->pkt_scbp = STATUS_GOOD; - break; - default: - /* PWR mode standby */ - *scsipkt->pkt_scbp = STATUS_CHECK; - sense = sata_arq_sense(spx); - sense->es_key = KEY_NOT_READY; - sense->es_add_code = SD_SCSI_ASC_LU_NOT_READY; - break; - } + mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx))); SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst, "Scsi_pkt completion reason %x\n", scsipkt->pkt_reason); - if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0 && - scsipkt->pkt_comp != NULL) + if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0) /* scsi callback required */ if (taskq_dispatch(SATA_TXLT_TASKQ(spx), - (task_func_t *)scsipkt->pkt_comp, (void *) scsipkt, + (task_func_t *)scsi_hba_pkt_comp, (void *) scsipkt, TQ_SLEEP) == NULL) /* Scheduling the callback failed */ return (TRAN_BUSY); @@ -3404,16 +3580,26 @@ return (TRAN_ACCEPT); } - /* * SATA translate command: Start Stop Unit * Translation depends on a command: - * Start Unit translated into Idle Immediate - * Stop Unit translated into Standby Immediate + * + * Power condition bits will be supported + * and the power level should be maintained by SATL, + * When SATL received a command, it will check the + * power level firstly, and return the status according + * to SAT2 v2.6 and SAT-2 Standby Modifications + * + * SPC-4/SBC-3 SATL ATA power condition SATL SPC/SBC + * ----------------------------------------------------------------------- + * SSU_PC1 Active <==> ATA Active <==> SSU:start_bit =1 + * SSU_PC2 Idle <==> ATA Idle <==> N/A + * SSU_PC3 Standby <==> ATA Standby <==> N/A + * SSU_PC4 Stopped <==> ATA Standby <==> SSU:start_bit = 0 + * * Unload Media / NOT SUPPORTED YET * Load Media / NOT SUPPROTED YET - * Power condition bits are ignored, so is Immediate bit - * Requesting synchronous execution. + * Immediate bit / NOT SUPPORTED YET (deferred error) * * Returns TRAN_ACCEPT or code returned by sata_hba_start() and * appropriate values in scsi_pkt fields. @@ -3423,11 +3609,11 @@ { struct scsi_pkt *scsipkt = spx->txlt_scsi_pkt; sata_cmd_t *scmd = &spx->txlt_sata_pkt->satapkt_cmd; - struct scsi_extended_sense *sense; sata_hba_inst_t *shi = SATA_TXLT_HBA_INST(spx); int cport = SATA_TXLT_CPORT(spx); int rval, reason; - int synch; + sata_drive_info_t *sdinfo; + sata_id_t *sata_id; SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst, "sata_txlt_start_stop_unit: %d\n", scsipkt->pkt_scbp[4] & 1); @@ -3440,81 +3626,304 @@ return (rval); } - if (scsipkt->pkt_cdbp[4] & 2) { - /* Load/Unload Media - invalid request */ - *scsipkt->pkt_scbp = STATUS_CHECK; - sense = sata_arq_sense(spx); - sense->es_key = KEY_ILLEGAL_REQUEST; - sense->es_add_code = SD_SCSI_ASC_INVALID_FIELD_IN_CDB; - mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx))); - - SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst, - "Scsi_pkt completion reason %x\n", scsipkt->pkt_reason); - - if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0 && - scsipkt->pkt_comp != NULL) - /* scsi callback required */ - if (taskq_dispatch(SATA_TXLT_TASKQ(spx), - (task_func_t *)scsipkt->pkt_comp, (void *) scsipkt, - TQ_SLEEP) == NULL) - /* Scheduling the callback failed */ - return (TRAN_BUSY); - - return (TRAN_ACCEPT); - } - scmd->satacmd_addr_type = 0; - scmd->satacmd_sec_count_lsb = 0; - scmd->satacmd_lba_low_lsb = 0; - scmd->satacmd_lba_mid_lsb = 0; - scmd->satacmd_lba_high_lsb = 0; - scmd->satacmd_features_reg = 0; - scmd->satacmd_device_reg = 0; - scmd->satacmd_status_reg = 0; - if (scsipkt->pkt_cdbp[4] & 1) { - /* Start Unit */ - scmd->satacmd_cmd_reg = SATAC_IDLE_IM; - } else { - /* Stop Unit */ - scmd->satacmd_cmd_reg = SATAC_STANDBY_IM; - } - - if (!(spx->txlt_sata_pkt->satapkt_op_mode & SATA_OPMODE_SYNCH)) { - /* Need to set-up a callback function */ - spx->txlt_sata_pkt->satapkt_comp = - sata_txlt_nodata_cmd_completion; - synch = FALSE; - } else { - spx->txlt_sata_pkt->satapkt_op_mode = SATA_OPMODE_SYNCH; - synch = TRUE; - } - - /* Transfer command to HBA */ - if (sata_hba_start(spx, &rval) != 0) { - /* Pkt not accepted for execution */ + if (scsipkt->pkt_cdbp[1] & START_STOP_IMMED_MASK) { + /* IMMED bit - not supported */ mutex_exit(&SATA_CPORT_MUTEX(shi, cport)); - return (rval); - } - - /* - * If execution is non-synchronous, - * a callback function will handle potential errors, translate - * the response and will do a callback to a target driver. - * If it was synchronous, check execution status using the same - * framework callback. + return (sata_txlt_check_condition(spx, KEY_ILLEGAL_REQUEST, + SD_SCSI_ASC_INVALID_FIELD_IN_CDB)); + } + + spx->txlt_sata_pkt->satapkt_op_mode = SATA_OPMODE_SYNCH; + spx->txlt_sata_pkt->satapkt_comp = NULL; + + sdinfo = sata_get_device_info(spx->txlt_sata_hba_inst, + &spx->txlt_sata_pkt->satapkt_device); + ASSERT(sdinfo != NULL); + sata_id = &sdinfo->satadrv_id; + + switch ((scsipkt->pkt_cdbp[4] & START_STOP_POWER_COND_MASK) >> 4) { + case 0: + if (scsipkt->pkt_cdbp[4] & START_STOP_LOEJ_MASK) { + /* Load/Unload Media - invalid request */ + goto err_out; + } + if (scsipkt->pkt_cdbp[4] & START_STOP_START_MASK) { + /* Start Unit */ + sata_build_read_verify_cmd(scmd, 1, 5); + scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE; + /* Transfer command to HBA */ + if (sata_hba_start(spx, &rval) != 0) { + /* Pkt not accepted for execution */ + mutex_exit(&SATA_CPORT_MUTEX(shi, cport)); + return (rval); + } else { + if (scmd->satacmd_error_reg != 0) { + goto err_out; + } + } + sdinfo->satadrv_power_level = SATA_POWER_ACTIVE; + } else { + /* Stop Unit */ + sata_build_generic_cmd(scmd, SATAC_FLUSH_CACHE); + scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE; + if (sata_hba_start(spx, &rval) != 0) { + mutex_exit(&SATA_CPORT_MUTEX(shi, cport)); + return (rval); + } else { + if (scmd->satacmd_error_reg != 0) { + goto err_out; + } + } + /* ata standby immediate command */ + sata_build_generic_cmd(scmd, SATAC_STANDBY_IM); + scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE; + if (sata_hba_start(spx, &rval) != 0) { + mutex_exit(&SATA_CPORT_MUTEX(shi, cport)); + return (rval); + } else { + if (scmd->satacmd_error_reg != 0) { + goto err_out; + } + } + sdinfo->satadrv_power_level = SATA_POWER_STOPPED; + } + break; + case 0x1: + sata_build_generic_cmd(scmd, SATAC_IDLE); + scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE; + if (sata_hba_start(spx, &rval) != 0) { + mutex_exit(&SATA_CPORT_MUTEX(shi, cport)); + return (rval); + } else { + if (scmd->satacmd_error_reg != 0) { + goto err_out; + } + } + sata_build_read_verify_cmd(scmd, 1, 5); + scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE; + /* Transfer command to HBA */ + if (sata_hba_start(spx, &rval) != 0) { + /* Pkt not accepted for execution */ + mutex_exit(&SATA_CPORT_MUTEX(shi, cport)); + return (rval); + } else { + if (scmd->satacmd_error_reg != 0) { + goto err_out; + } + } + sdinfo->satadrv_power_level = SATA_POWER_ACTIVE; + break; + case 0x2: + sata_build_generic_cmd(scmd, SATAC_FLUSH_CACHE); + scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE; + if (!(scsipkt->pkt_cdbp[4] & START_STOP_NOFLUSH_MASK)) { + if (sata_hba_start(spx, &rval) != 0) { + mutex_exit(&SATA_CPORT_MUTEX(shi, cport)); + return (rval); + } else { + if (scmd->satacmd_error_reg != 0) { + goto err_out; + } + } + } + sata_build_generic_cmd(scmd, SATAC_IDLE); + scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE; + if (sata_hba_start(spx, &rval) != 0) { + mutex_exit(&SATA_CPORT_MUTEX(shi, cport)); + return (rval); + } else { + if (scmd->satacmd_error_reg != 0) { + goto err_out; + } + } + if ((scsipkt->pkt_cdbp[3] & START_STOP_MODIFIER_MASK)) { + /* + * POWER CONDITION MODIFIER bit set + * to 0x1 or larger it will be handled + * on the same way as bit = 0x1 + */ + if (!(sata_id->ai_cmdset84 & + SATA_IDLE_UNLOAD_SUPPORTED)) { + sdinfo->satadrv_power_level = SATA_POWER_IDLE; + break; + } + sata_build_generic_cmd(scmd, SATAC_IDLE_IM); + scmd->satacmd_features_reg = 0x44; + scmd->satacmd_lba_low_lsb = 0x4c; + scmd->satacmd_lba_mid_lsb = 0x4e; + scmd->satacmd_lba_high_lsb = 0x55; + scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE; + if (sata_hba_start(spx, &rval) != 0) { + mutex_exit(&SATA_CPORT_MUTEX(shi, cport)); + return (rval); + } else { + if (scmd->satacmd_error_reg != 0) { + goto err_out; + } + } + } + sdinfo->satadrv_power_level = SATA_POWER_IDLE; + break; + case 0x3: + sata_build_generic_cmd(scmd, SATAC_FLUSH_CACHE); + scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE; + if (!(scsipkt->pkt_cdbp[4] & START_STOP_NOFLUSH_MASK)) { + if (sata_hba_start(spx, &rval) != 0) { + mutex_exit(&SATA_CPORT_MUTEX(shi, cport)); + return (rval); + } else { + if (scmd->satacmd_error_reg != 0) { + goto err_out; + } + } + } + sata_build_generic_cmd(scmd, SATAC_STANDBY); + scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE; + if (sata_hba_start(spx, &rval) != 0) { + mutex_exit(&SATA_CPORT_MUTEX(shi, cport)); + return (rval); + } else { + if (scmd->satacmd_error_reg != 0) { + goto err_out; + } + } + sdinfo->satadrv_power_level = SATA_POWER_STANDBY; + break; + case 0x7: + sata_build_generic_cmd(scmd, SATAC_CHECK_POWER_MODE); + scmd->satacmd_flags.sata_copy_out_sec_count_lsb = B_TRUE; + scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE; + if (sata_hba_start(spx, &rval) != 0) { + mutex_exit(&SATA_CPORT_MUTEX(shi, cport)); + return (rval); + } else { + if (scmd->satacmd_error_reg != 0) { + goto err_out; + } + } + switch (scmd->satacmd_sec_count_lsb) { + case SATA_PWRMODE_STANDBY: + sata_build_generic_cmd(scmd, SATAC_STANDBY); + scmd->satacmd_sec_count_msb = sata_get_standby_timer( + sdinfo->satadrv_standby_timer); + scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE; + if (sata_hba_start(spx, &rval) != 0) { + mutex_exit(&SATA_CPORT_MUTEX(shi, cport)); + return (rval); + } else { + if (scmd->satacmd_error_reg != 0) { + goto err_out; + } + } + break; + case SATA_PWRMODE_IDLE: + sata_build_generic_cmd(scmd, SATAC_IDLE); + scmd->satacmd_sec_count_msb = sata_get_standby_timer( + sdinfo->satadrv_standby_timer); + scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE; + if (sata_hba_start(spx, &rval) != 0) { + mutex_exit(&SATA_CPORT_MUTEX(shi, cport)); + return (rval); + } else { + if (scmd->satacmd_error_reg != 0) { + goto err_out; + } + } + break; + case SATA_PWRMODE_ACTIVE_SPINDOWN: + case SATA_PWRMODE_ACTIVE_SPINUP: + case SATA_PWRMODE_ACTIVE: + sata_build_generic_cmd(scmd, SATAC_IDLE); + scmd->satacmd_sec_count_msb = sata_get_standby_timer( + sdinfo->satadrv_standby_timer); + scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE; + if (sata_hba_start(spx, &rval) != 0) { + mutex_exit(&SATA_CPORT_MUTEX(shi, cport)); + return (rval); + } else { + if (scmd->satacmd_error_reg != 0) { + goto err_out; + } + } + sata_build_read_verify_cmd(scmd, 1, 5); + scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE; + if (sata_hba_start(spx, &rval) != 0) { + mutex_exit(&SATA_CPORT_MUTEX(shi, cport)); + return (rval); + } else { + if (scmd->satacmd_error_reg != 0) { + goto err_out; + } + } + break; + default: + goto err_out; + } + break; + case 0xb: + if ((sata_get_standby_timer(sdinfo->satadrv_standby_timer) == + 0) || (!(sata_id->ai_cap & SATA_STANDBYTIMER))) { + mutex_exit(&SATA_CPORT_MUTEX(shi, cport)); + return (sata_txlt_check_condition(spx, + KEY_ILLEGAL_REQUEST, + SD_SCSI_ASC_INVALID_FIELD_IN_CDB)); + } + sata_build_generic_cmd(scmd, SATAC_FLUSH_CACHE); + scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE; + if (!(scsipkt->pkt_cdbp[4] & START_STOP_NOFLUSH_MASK)) { + if (sata_hba_start(spx, &rval) != 0) { + mutex_exit(&SATA_CPORT_MUTEX(shi, cport)); + return (rval); + } else { + if (scmd->satacmd_error_reg != 0) { + goto err_out; + } + } + sata_build_generic_cmd(scmd, SATAC_STANDBY_IM); + scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE; + if (sata_hba_start(spx, &rval) != 0) { + mutex_exit(&SATA_CPORT_MUTEX(shi, cport)); + return (rval); + } else { + if (scmd->satacmd_error_reg != 0) { + goto err_out; + } + } + } + bzero(sdinfo->satadrv_standby_timer, sizeof (uchar_t) * 4); + break; + default: +err_out: + mutex_exit(&SATA_CPORT_MUTEX(shi, cport)); + return (sata_txlt_check_condition(spx, KEY_ILLEGAL_REQUEST, + SD_SCSI_ASC_INVALID_FIELD_IN_CDB)); + } + + /* + * since it was synchronous commands, + * a callback function will be called directely. */ mutex_exit(&SATA_CPORT_MUTEX(shi, cport)); - if (synch) { - SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst, - "synchronous execution status %x\n", - spx->txlt_sata_pkt->satapkt_reason); + SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst, + "synchronous execution status %x\n", + spx->txlt_sata_pkt->satapkt_reason); + + if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0) { + sata_set_arq_data(spx->txlt_sata_pkt); + if (taskq_dispatch(SATA_TXLT_TASKQ(spx), + (task_func_t *)scsi_hba_pkt_comp, (void *) scsipkt, + TQ_SLEEP) == 0) { + return (TRAN_BUSY); + } + } + else sata_txlt_nodata_cmd_completion(spx->txlt_sata_pkt); - } + return (TRAN_ACCEPT); } - /* * SATA translate command: Read Capacity. * Emulated command for SATA disks. @@ -3666,7 +4075,7 @@ /* Build mode parameter header */ if (spx->txlt_scsi_pkt->pkt_cdbp[0] == SCMD_MODE_SENSE) { /* 4-byte mode parameter header */ - buf[len++] = 0; /* mode data length */ + buf[len++] = 0; /* mode data length */ buf[len++] = 0; /* medium type */ buf[len++] = 0; /* dev-specific param */ buf[len++] = bdlen; /* Block Descriptor length */ @@ -3822,7 +4231,7 @@ /* fix total mode data length */ if (spx->txlt_scsi_pkt->pkt_cdbp[0] == SCMD_MODE_SENSE) { /* 4-byte mode parameter header */ - buf[0] = len - 1; /* mode data length */ + buf[0] = len - 1; /* mode data length */ } else { buf[0] = (len -2) >> 8; buf[1] = (len -2) & 0xff; @@ -3887,6 +4296,7 @@ * - caching page * - informational exception page * - acoustic management page + * - power condition page * Caching setup is remembered so it could be re-stored in case of * an unexpected device reset. * @@ -4086,6 +4496,30 @@ } break; + case MODEPAGE_POWER_COND: + stat = sata_mode_select_page_1a(spx, + (struct mode_info_power_cond *)&buf[len], + pllen, &pagelen, &rval, &dmod); + /* + * The pagelen value indicates the number of + * parameter bytes already processed. + * The rval is the return value from + * sata_tran_start(). + * The stat indicates the overall status of + * the operation(s). + */ + if (stat != SATA_SUCCESS) + /* + * Page processing did not succeed - + * all error info is already set-up, + * just return + */ + pllen = 0; /* this breaks the loop */ + else { + len += pagelen; + pllen -= pagelen; + } + break; default: *scsipkt->pkt_scbp = STATUS_CHECK; sense = sata_arq_sense(spx); @@ -4246,6 +4680,7 @@ case PAGE_CODE_SELF_TEST_RESULTS: case PAGE_CODE_INFORMATION_EXCEPTIONS: case PAGE_CODE_SMART_READ_DATA: + case PAGE_CODE_START_STOP_CYCLE_COUNTER: break; default: *scsipkt->pkt_scbp = STATUS_CHECK; @@ -4356,6 +4791,30 @@ len = sata_build_lsense_page_30(sdinfo, buf, spx->txlt_sata_hba_inst); goto no_header; + case PAGE_CODE_START_STOP_CYCLE_COUNTER: + sata_id = &sdinfo->satadrv_id; + if (! (sata_id->ai_cmdset82 & SATA_SMART_SUPPORTED)) { + *scsipkt->pkt_scbp = STATUS_CHECK; + sense = sata_arq_sense(spx); + sense->es_key = KEY_ILLEGAL_REQUEST; + sense->es_add_code = + SD_SCSI_ASC_INVALID_FIELD_IN_CDB; + + goto done; + } + if (! (sata_id->ai_features85 & SATA_SMART_ENABLED)) { + *scsipkt->pkt_scbp = STATUS_CHECK; + sense = sata_arq_sense(spx); + sense->es_key = KEY_ABORTED_COMMAND; + sense->es_add_code = + SCSI_ASC_ATA_DEV_FEAT_NOT_ENABLED; + sense->es_qual_code = + SCSI_ASCQ_ATA_DEV_FEAT_NOT_ENABLED; + + goto done; + } + len = sata_build_lsense_page_0e(sdinfo, buf, spx); + goto no_header; default: /* Invalid request */ *scsipkt->pkt_scbp = STATUS_CHECK; @@ -4414,7 +4873,7 @@ * Translate command: Log Select * Not implemented at this time - returns invalid command response. */ -static int +static int sata_txlt_log_select(sata_pkt_txlate_t *spx) { SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst, @@ -5831,12 +6290,26 @@ * This function may be used only if scsi_pkt is non-NULL. */ -static void +static void sata_txlt_nodata_cmd_completion(sata_pkt_t *sata_pkt) { sata_pkt_txlate_t *spx = (sata_pkt_txlate_t *)sata_pkt->satapkt_framework_private; struct scsi_pkt *scsipkt = spx->txlt_scsi_pkt; + + sata_set_arq_data(sata_pkt); + + if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0) + /* scsi callback required */ + scsi_hba_pkt_comp(scsipkt); +} + +static void +sata_set_arq_data(sata_pkt_t *sata_pkt) +{ + sata_pkt_txlate_t *spx = + (sata_pkt_txlate_t *)sata_pkt->satapkt_framework_private; + struct scsi_pkt *scsipkt = spx->txlt_scsi_pkt; struct scsi_extended_sense *sense; scsipkt->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET | @@ -5902,10 +6375,6 @@ } SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst, "Scsi_pkt completion reason %x\n", scsipkt->pkt_reason); - - if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0) - /* scsi callback required */ - scsi_hba_pkt_comp(scsipkt); } @@ -6082,20 +6551,36 @@ /* - * Build Mode sense power condition page - * NOT IMPLEMENTED. + * Build Mode sense power condition page. */ static int sata_build_msense_page_1a(sata_drive_info_t *sdinfo, int pcntrl, uint8_t *buf) { -#ifndef __lock_lint - _NOTE(ARGUNUSED(sdinfo)) - _NOTE(ARGUNUSED(pcntrl)) - _NOTE(ARGUNUSED(buf)) -#endif - return (0); -} - + struct mode_info_power_cond *page = (struct mode_info_power_cond *)buf; + sata_id_t *sata_id = &sdinfo->satadrv_id; + + /* + * Most of the fields are set to 0, being not supported and/or disabled + * power condition page length was 0x0a + */ + bzero(buf, sizeof (struct mode_info_power_cond)); + + if (pcntrl == P_CNTRL_DEFAULT) { + /* default paramters not supported */ + return (0); + } + + page->mode_page.code = MODEPAGE_POWER_COND; + page->mode_page.length = sizeof (struct mode_info_power_cond); + + if (sata_id->ai_cap && SATA_STANDBYTIMER) { + page->standby = 1; + bcopy(sdinfo->satadrv_standby_timer, page->standby_cond_timer, + sizeof (uchar_t) * 4); + } + + return (sizeof (struct mode_info_power_cond)); +} /* * Process mode select caching page 8 (scsi3 format only). @@ -6453,16 +6938,96 @@ return (SATA_SUCCESS); } - - +/* + * Process mode select power condition page 0x1a + * + * This function has to be called with a port mutex held. + * + * Returns SATA_SUCCESS if operation was successful, SATA_FAILURE otherwise. + * + * Cannot be called in the interrupt context. + */ +int +sata_mode_select_page_1a(sata_pkt_txlate_t *spx, struct + mode_info_power_cond *page, int parmlen, int *pagelen, + int *rval, int *dmod) +{ + struct scsi_pkt *scsipkt = spx->txlt_scsi_pkt; + sata_drive_info_t *sdinfo; + sata_cmd_t *scmd = &spx->txlt_sata_pkt->satapkt_cmd; + sata_id_t *sata_id; + struct scsi_extended_sense *sense; + uint8_t ata_count; + int i, len; + + sdinfo = sata_get_device_info(spx->txlt_sata_hba_inst, + &spx->txlt_sata_pkt->satapkt_device); + sata_id = &sdinfo->satadrv_id; + *dmod = 0; + + len = sizeof (struct mode_info_power_cond); + len += sizeof (struct mode_page); + + /* If parmlen is too short or the feature is not supported, drop it */ + if ((len < parmlen) || (page->idle == 1) || + (!(sata_id->ai_cap && SATA_STANDBYTIMER) && page->standby == 1)) { + *scsipkt->pkt_scbp = STATUS_CHECK; + sense = sata_arq_sense(spx); + sense->es_key = KEY_ILLEGAL_REQUEST; + sense->es_add_code = SD_SCSI_ASC_INVALID_FIELD_IN_PARAMS_LIST; + *pagelen = parmlen; + *rval = TRAN_ACCEPT; + return (SATA_FAILURE); + } + + *pagelen = len; + + /* + * Set-up Internal STANDBY command(s) + */ + if (page->standby == 0) + goto out; + + ata_count = sata_get_standby_timer(page->standby_cond_timer); + + scmd->satacmd_addr_type = 0; + scmd->satacmd_sec_count_lsb = ata_count; + scmd->satacmd_lba_low_lsb = 0; + scmd->satacmd_lba_mid_lsb = 0; + scmd->satacmd_lba_high_lsb = 0; + scmd->satacmd_features_reg = 0; + scmd->satacmd_device_reg = 0; + scmd->satacmd_status_reg = 0; + scmd->satacmd_cmd_reg = SATAC_STANDBY; + scmd->satacmd_flags.sata_copy_out_error_reg = B_TRUE; + + /* Transfer command to HBA */ + if (sata_hba_start(spx, rval) != 0) { + return (SATA_FAILURE); + } else { + if ((scmd->satacmd_error_reg != 0) || + (spx->txlt_sata_pkt->satapkt_reason != + SATA_PKT_COMPLETED)) { + sata_xlate_errors(spx); + return (SATA_FAILURE); + } + } + + for (i = 0; i < 4; i++) { + sdinfo->satadrv_standby_timer[i] = page->standby_cond_timer[i]; + } +out: + *dmod = 1; + return (SATA_SUCCESS); +} /* * sata_build_lsense_page0() is used to create the * SCSI LOG SENSE page 0 (supported log pages) * - * Currently supported pages are 0, 0x10, 0x2f and 0x30 + * Currently supported pages are 0, 0x10, 0x2f, 0x30 and 0x0e * (supported log pages, self-test results, informational exceptions - * and Sun vendor specific ATA SMART data). + * Sun vendor specific ATA SMART data, and start stop cycle counter). * * Takes a sata_drive_info t * and the address of a buffer * in which to create the page information. @@ -6491,6 +7056,8 @@ ++num_pages_supported; *page_ptr++ = PAGE_CODE_SMART_READ_DATA; ++num_pages_supported; + *page_ptr++ = PAGE_CODE_START_STOP_CYCLE_COUNTER; + ++num_pages_supported; } lpp->param_len = num_pages_supported; @@ -7022,6 +7589,171 @@ return (sizeof (struct smart_data)); } +/* + * sata_build_lsense_page_0e() is used to create the + * SCSI LOG SENSE page 0e (supported log pages) + * + * Date of Manufacture (0x0001) + * YEAR = "0000" + * WEEK = "00" + * Accounting Date (0x0002) + * 6 ASCII space character(20h) + * Specified cycle count over device lifetime + * VALUE - THRESH - the delta between max and min; + * Accumulated start-stop cycles + * VALUE - WORST - the accumulated cycles; + * + * ID FLAG THRESH VALUE WORST RAW on start/stop counter attribute + * + * Takes a sata_drive_info t * and the address of a buffer + * in which to create the page information as well as a sata_hba_inst_t *. + * + * Returns the number of bytes valid in the buffer. + */ +static int +sata_build_lsense_page_0e(sata_drive_info_t *sdinfo, uint8_t *buf, + sata_pkt_txlate_t *spx) +{ + struct start_stop_cycle_counter_log *log_page; + int i, rval, index; + uint8_t smart_data[512], id, value, worst, thresh; + uint32_t max_count, cycles; + + /* Now do the SMART READ DATA */ + rval = sata_fetch_smart_data(spx->txlt_sata_hba_inst, sdinfo, + (struct smart_data *)smart_data); + if (rval == -1) + return (0); + for (i = 0, id = 0; i < SMART_START_STOP_COUNT_ID * 2; i++) { + index = (i * 12) + 2; + id = smart_data[index]; + if (id != SMART_START_STOP_COUNT_ID) + continue; + else { + thresh = smart_data[index + 2]; + value = smart_data[index + 3]; + worst = smart_data[index + 4]; + break; + } + } + if (id != SMART_START_STOP_COUNT_ID) + return (0); + max_count = value - thresh; + cycles = value - worst; + + log_page = (struct start_stop_cycle_counter_log *)buf; + bzero(log_page, sizeof (struct start_stop_cycle_counter_log)); + log_page->code = 0x0e; + log_page->page_len_low = 0x24; + + log_page->manufactor_date_low = 0x1; + log_page->param_1.fmt_link = 0x1; /* 01b */ + log_page->param_len_1 = 0x06; + for (i = 0; i < 4; i++) { + log_page->year_manu[i] = 0x30; + if (i < 2) + log_page->week_manu[i] = 0x30; + } + + log_page->account_date_low = 0x02; + log_page->param_2.fmt_link = 0x01; /* 01b */ + log_page->param_len_2 = 0x06; + for (i = 0; i < 4; i++) { + log_page->year_account[i] = 0x20; + if (i < 2) + log_page->week_account[i] = 0x20; + } + + log_page->lifetime_code_low = 0x03; + log_page->param_3.fmt_link = 0x03; /* 11b */ + log_page->param_len_3 = 0x04; + /* VALUE - THRESH - the delta between max and min */ + log_page->cycle_code_low = 0x04; + log_page->param_4.fmt_link = 0x03; /* 11b */ + log_page->param_len_4 = 0x04; + /* WORST - THRESH - the distance from 'now' to min */ + + for (i = 0; i < 4; i++) { + log_page->cycle_lifetime[i] = + (max_count >> (8 * (3 - i))) & 0xff; + log_page->cycle_accumulated[i] = + (cycles >> (8 * (3 - i))) & 0xff; + } + + return (sizeof (struct start_stop_cycle_counter_log)); +} + +/* + * This function was used for build a ATA read verify sector command + */ +static void +sata_build_read_verify_cmd(sata_cmd_t *scmd, uint16_t sec, uint64_t lba) +{ + scmd->satacmd_cmd_reg = SATAC_RDVER; + scmd->satacmd_addr_type = ATA_ADDR_LBA28; + + scmd->satacmd_sec_count_lsb = sec & 0xff; + scmd->satacmd_lba_low_lsb = lba & 0xff; + scmd->satacmd_lba_mid_lsb = (lba >> 8) & 0xff; + scmd->satacmd_lba_high_lsb = (lba >> 16) & 0xff; + scmd->satacmd_device_reg = (SATA_ADH_LBA | (lba >> 24) & 0xf); + scmd->satacmd_features_reg = 0; + scmd->satacmd_status_reg = 0; + scmd->satacmd_error_reg = 0; +} + +/* + * This function was used for building an ATA + * command, and only command register need to + * be defined, other register will be zero or na. + */ +static void +sata_build_generic_cmd(sata_cmd_t *scmd, uint8_t cmd) +{ + scmd->satacmd_addr_type = 0; + scmd->satacmd_cmd_reg = cmd; + scmd->satacmd_device_reg = 0; + scmd->satacmd_sec_count_lsb = 0; + scmd->satacmd_lba_low_lsb = 0; + scmd->satacmd_lba_mid_lsb = 0; + scmd->satacmd_lba_high_lsb = 0; + scmd->satacmd_features_reg = 0; + scmd->satacmd_status_reg = 0; + scmd->satacmd_error_reg = 0; +} + +/* + * This function was used for changing the standby + * timer format from SCSI to ATA. + */ +static uint8_t +sata_get_standby_timer(uint8_t *timer) +{ + uint32_t i = 0, count = 0; + uint8_t ata_count; + + for (i = 0; i < 4; i++) { + count = count << 8 | timer[i]; + } + + if (count == 0) + return (0); + + if (count >= 1 && count <= 12000) + ata_count = (count -1) / 50 + 1; + else if (count > 12000 && count <= 12600) + ata_count = 0xfc; + else if (count > 12601 && count <= 12750) + ata_count = 0xff; + else if (count > 12750 && count <= 17999) + ata_count = 0xf1; + else if (count > 18000 && count <= 198000) + ata_count = count / 18000 + 240; + else + ata_count = 0xfd; + return (ata_count); +} + /* ************************** ATAPI-SPECIFIC FUNCTIONS ********************** */ /* @@ -8967,6 +9699,10 @@ /* DMA supported, not no DMA transfer mode is selected !? */ sdinfo->satadrv_settings &= ~SATA_DEV_DMA; + if ((sdinfo->satadrv_id.ai_cmdset83 & 0x20) && + (sdinfo->satadrv_id.ai_features86 & 0x20)) + sdinfo->satadrv_power_level = SATA_POWER_STANDBY; + return (rval); } @@ -13825,7 +14561,7 @@ sata_log(sata_hba_inst_t *sata_hba_inst, uint_t level, char *fmt, ...) { char pathname[128]; - dev_info_t *dip; + dev_info_t *dip = NULL; va_list ap; mutex_enter(&sata_log_mutex); @@ -13854,6 +14590,9 @@ } } + /* sata trace debug */ + sata_trace_debug(dip, sata_log_buf); + mutex_exit(&sata_log_mutex); } @@ -15835,7 +16574,7 @@ */ -static void +static void sata_inject_pkt_fault(sata_pkt_t *spkt, int *rval, int fault) { @@ -15950,3 +16689,232 @@ } #endif + +/* + * SATA Trace Ring Buffer + * ---------------------- + * + * Overview + * + * The SATA trace ring buffer is a ring buffer created and managed by + * the SATA framework module that can be used by any module or driver + * within the SATA framework to store debug messages. + * + * Ring Buffer Interfaces: + * + * sata_vtrace_debug() <-- Adds debug message to ring buffer + * sata_trace_debug() <-- Wraps varargs into sata_vtrace_debug() + * + * Note that the sata_trace_debug() interface was created to give + * consumers the flexibilty of sending debug messages to ring buffer + * as variable arguments. Consumers can send type va_list debug + * messages directly to sata_vtrace_debug(). The sata_trace_debug() + * and sata_vtrace_debug() relationship is similar to that of + * cmn_err(9F) and vcmn_err(9F). + * + * Below is a diagram of the SATA trace ring buffer interfaces and + * sample consumers: + * + * +---------------------------------+ + * | o o SATA Framework Module | + * | o SATA o +------------------+ +------------------+ + * |o Trace o <--|sata_vtrace_debug/|<-----|SATA HBA Driver #1| + * |o R-Buf o |sata_trace_debug |<--+ +------------------+ + * | o o +------------------+ | +------------------+ + * | o o ^ | +--|SATA HBA Driver #2| + * | | | +------------------+ + * | +------------------+ | + * | |SATA Debug Message| | + * | +------------------+ | + * +---------------------------------+ + * + * Supporting Routines: + * + * sata_trace_rbuf_alloc() <-- Initializes ring buffer + * sata_trace_rbuf_free() <-- Destroys ring buffer + * sata_trace_dmsg_alloc() <-- Creates or reuses buffer in ring buffer + * sata_trace_dmsg_free() <-- Destroys content of ring buffer + * + * The default SATA trace ring buffer size is defined by DMSG_RING_SIZE. + * The ring buffer size can be adjusted by setting dmsg_ring_size in + * /etc/system to desired size in unit of bytes. + * + * The individual debug message size in the ring buffer is restricted + * to DMSG_BUF_SIZE. + */ +void +sata_vtrace_debug(dev_info_t *dip, const char *fmt, va_list ap) +{ + sata_trace_dmsg_t *dmsg; + + if (sata_debug_rbuf == NULL) { + return; + } + + /* + * If max size of ring buffer is smaller than size + * required for one debug message then just return + * since we have no room for the debug message. + */ + if (sata_debug_rbuf->maxsize < (sizeof (sata_trace_dmsg_t))) { + return; + } + + mutex_enter(&sata_debug_rbuf->lock); + + /* alloc or reuse on ring buffer */ + dmsg = sata_trace_dmsg_alloc(); + + if (dmsg == NULL) { + /* resource allocation failed */ + mutex_exit(&sata_debug_rbuf->lock); + return; + } + + dmsg->dip = dip; + gethrestime(&dmsg->timestamp); + + (void) vsnprintf(dmsg->buf, sizeof (dmsg->buf), fmt, ap); + + mutex_exit(&sata_debug_rbuf->lock); +} + +void +sata_trace_debug(dev_info_t *dip, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + sata_vtrace_debug(dip, fmt, ap); + va_end(ap); +} + +/* + * This routine is used to manage debug messages + * on ring buffer. + */ +static sata_trace_dmsg_t * +sata_trace_dmsg_alloc(void) +{ + sata_trace_dmsg_t *dmsg_alloc, *dmsg = sata_debug_rbuf->dmsgp; + + if (sata_debug_rbuf->looped == TRUE) { + sata_debug_rbuf->dmsgp = dmsg->next; + return (sata_debug_rbuf->dmsgp); + } + + /* + * If we're looping for the first time, + * connect the ring. + */ + if (((sata_debug_rbuf->size + (sizeof (sata_trace_dmsg_t))) > + sata_debug_rbuf->maxsize) && (sata_debug_rbuf->dmsgh != NULL)) { + dmsg->next = sata_debug_rbuf->dmsgh; + sata_debug_rbuf->dmsgp = sata_debug_rbuf->dmsgh; + sata_debug_rbuf->looped = TRUE; + return (sata_debug_rbuf->dmsgp); + } + + /* If we've gotten this far then memory allocation is needed */ + dmsg_alloc = kmem_zalloc(sizeof (sata_trace_dmsg_t), KM_NOSLEEP); + if (dmsg_alloc == NULL) { + sata_debug_rbuf->allocfailed++; + return (dmsg_alloc); + } else { + sata_debug_rbuf->size += sizeof (sata_trace_dmsg_t); + } + + if (sata_debug_rbuf->dmsgp != NULL) { + dmsg->next = dmsg_alloc; + sata_debug_rbuf->dmsgp = dmsg->next; + return (sata_debug_rbuf->dmsgp); + } else { + /* + * We should only be here if we're initializing + * the ring buffer. + */ + if (sata_debug_rbuf->dmsgh == NULL) { + sata_debug_rbuf->dmsgh = dmsg_alloc; + } else { + /* Something is wrong */ + kmem_free(dmsg_alloc, sizeof (sata_trace_dmsg_t)); + return (NULL); + } + + sata_debug_rbuf->dmsgp = dmsg_alloc; + return (sata_debug_rbuf->dmsgp); + } +} + + +/* + * Free all messages on debug ring buffer. + */ +static void +sata_trace_dmsg_free(void) +{ + sata_trace_dmsg_t *dmsg_next, *dmsg = sata_debug_rbuf->dmsgh; + + while (dmsg != NULL) { + dmsg_next = dmsg->next; + kmem_free(dmsg, sizeof (sata_trace_dmsg_t)); + + /* + * If we've looped around the ring than we're done. + */ + if (dmsg_next == sata_debug_rbuf->dmsgh) { + break; + } else { + dmsg = dmsg_next; + } + } +} + + +/* + * This function can block + */ +static void +sata_trace_rbuf_alloc(void) +{ + sata_debug_rbuf = kmem_zalloc(sizeof (sata_trace_rbuf_t), KM_SLEEP); + + mutex_init(&sata_debug_rbuf->lock, NULL, MUTEX_DRIVER, NULL); + + if (dmsg_ring_size > 0) { + sata_debug_rbuf->maxsize = (size_t)dmsg_ring_size; + } +} + + +static void +sata_trace_rbuf_free(void) +{ + sata_trace_dmsg_free(); + mutex_destroy(&sata_debug_rbuf->lock); + kmem_free(sata_debug_rbuf, sizeof (sata_trace_rbuf_t)); +} + +/* + * If SATA_DEBUG is not defined then this routine is called instead + * of sata_log() via the SATA_LOG_D macro. + */ +static void +sata_trace_log(sata_hba_inst_t *sata_hba_inst, uint_t level, + const char *fmt, ...) +{ +#ifndef __lock_lint + _NOTE(ARGUNUSED(level)) +#endif + + dev_info_t *dip = NULL; + va_list ap; + + if (sata_hba_inst != NULL) { + dip = SATA_DIP(sata_hba_inst); + } + + va_start(ap, fmt); + sata_vtrace_debug(dip, fmt, ap); + va_end(ap); +}
--- a/usr/src/uts/common/io/scsi/adapters/scsi_vhci/scsi_vhci.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/scsi/adapters/scsi_vhci/scsi_vhci.c Mon Jul 20 13:07:46 2009 -0400 @@ -7201,7 +7201,8 @@ } dvlp->svl_fops_name = NULL; - if (dvlp->svl_fops_ctpriv != NULL) { + if (dvlp->svl_fops_ctpriv != NULL && + dvlp->svl_fops != NULL) { dvlp->svl_fops->sfo_device_unprobe(sd, dvlp->svl_fops_ctpriv); }
--- a/usr/src/uts/common/io/scsi/targets/sd.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/scsi/targets/sd.c Mon Jul 20 13:07:46 2009 -0400 @@ -354,6 +354,33 @@ _NOTE(MUTEX_PROTECTS_DATA(sd_scsi_probe_cache_mutex, sd_scsi_probe_cache_head)) +/* + * Power attribute table + */ +static sd_power_attr_ss sd_pwr_ss = { + { "NAME=spindle-motor", "0=off", "1=on", NULL }, + {0, 100}, + {30, 0}, + {20000, 0} +}; + +static sd_power_attr_pc sd_pwr_pc = { + { "NAME=spindle-motor", "0=stopped", "1=standby", "2=idle", + "3=active", NULL }, + {0, 0, 0, 100}, + {90, 90, 20, 0}, + {15000, 15000, 1000, 0} +}; + +/* + * Power level to power condition + */ +static int sd_pl2pc[] = { + SD_TARGET_START_VALID, + SD_TARGET_STANDBY, + SD_TARGET_IDLE, + SD_TARGET_ACTIVE +}; /* * Vendor specific data name property declarations @@ -707,6 +734,7 @@ SD_CONF_BSET_LUN_RESET_ENABLED, &pirus_properties }, { "SUN STK6580_6780", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties }, + { "SUN SUN_6180", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties }, { "STK OPENstorage", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties }, { "STK OpenStorage", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties }, { "STK BladeCtlr", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties }, @@ -863,9 +891,8 @@ #define sd_setup_pm ssd_setup_pm #define sd_create_pm_components ssd_create_pm_components #define sd_ddi_suspend ssd_ddi_suspend -#define sd_ddi_pm_suspend ssd_ddi_pm_suspend #define sd_ddi_resume ssd_ddi_resume -#define sd_ddi_pm_resume ssd_ddi_pm_resume +#define sd_pm_state_change ssd_pm_state_change #define sdpower ssdpower #define sdattach ssdattach #define sddetach ssddetach @@ -1205,9 +1232,8 @@ static void sd_create_pm_components(dev_info_t *devi, struct sd_lun *un); static int sd_ddi_suspend(dev_info_t *devi); -static int sd_ddi_pm_suspend(struct sd_lun *un); static int sd_ddi_resume(dev_info_t *devi); -static int sd_ddi_pm_resume(struct sd_lun *un); +static int sd_pm_state_change(struct sd_lun *un, int level, int flag); static int sdpower(dev_info_t *devi, int component, int level); static int sdattach(dev_info_t *devi, ddi_attach_cmd_t cmd); @@ -1466,8 +1492,8 @@ uint32_t *lbap, int path_flag); static int sd_send_scsi_READ_CAPACITY_16(sd_ssc_t *ssc, uint64_t *capp, uint32_t *lbap, uint32_t *psp, int path_flag); -static int sd_send_scsi_START_STOP_UNIT(sd_ssc_t *ssc, int flag, - int path_flag); +static int sd_send_scsi_START_STOP_UNIT(sd_ssc_t *ssc, int pc_flag, + int flag, int path_flag); static int sd_send_scsi_INQUIRY(sd_ssc_t *ssc, uchar_t *bufaddr, size_t buflen, uchar_t evpd, uchar_t page_code, size_t *residp); static int sd_send_scsi_TEST_UNIT_READY(sd_ssc_t *ssc, int flag); @@ -3176,9 +3202,11 @@ * condition (0x2/0x4/0x3) if the device is "inactive," but * we don't want to fail the attach because it may become * "active" later. - */ - status = sd_send_scsi_START_STOP_UNIT(ssc, SD_TARGET_START, - SD_PATH_DIRECT); + * We don't know if power condition is supported or not at + * this stage, use START STOP bit. + */ + status = sd_send_scsi_START_STOP_UNIT(ssc, SD_START_STOP, + SD_TARGET_START, SD_PATH_DIRECT); if (status != 0) { if (status == EACCES) @@ -4021,6 +4049,20 @@ return; } + if (strcasecmp(name, "power-condition") == 0) { + if (strcasecmp(value, "true") == 0) { + un->un_f_power_condition_disabled = FALSE; + } else if (strcasecmp(value, "false") == 0) { + un->un_f_power_condition_disabled = TRUE; + } else { + goto value_invalid; + } + SD_INFO(SD_LOG_ATTACH_DETACH, un, "sd_set_properties: " + "power condition disabled flag set to %d\n", + un->un_f_power_condition_disabled); + return; + } + if (strcasecmp(name, "timeout-releasereservation") == 0) { if (ddi_strtol(value, &endptr, 0, &val) == 0) { un->un_reserve_release_time = val; @@ -4232,6 +4274,12 @@ suppress_cache_flush = %d" "\n", values->sdt_suppress_cache_flush); break; + case SD_CONF_BSET_PC_DISABLED: + values->sdt_disk_sort_dis = data_list[i]; + SD_INFO(SD_LOG_ATTACH_DETACH, un, + "sd_get_tunables_from_conf: power_condition_dis = " + "%d\n", values->sdt_power_condition_dis); + break; } } } @@ -4713,6 +4761,16 @@ prop_list->sdt_suppress_cache_flush); } + if (flags & SD_CONF_BSET_PC_DISABLED) { + un->un_f_power_condition_disabled = + (prop_list->sdt_power_condition_dis != 0) ? + TRUE : FALSE; + SD_INFO(SD_LOG_ATTACH_DETACH, un, + "sd_set_vers1_properties: power_condition_disabled " + "flag set to %d\n", + prop_list->sdt_power_condition_dis); + } + /* * Validate the throttle values. * If any of the numbers are invalid, set everything to defaults. @@ -5751,6 +5809,9 @@ * This complies with the new power management framework * for certain desktop machines. Create the pm_components * property as a string array property. + * If un_f_pm_supported is TRUE, that means the disk + * attached HBA has set the "pm-capable" property and + * the value of this property is bigger than 0. */ if (un->un_f_pm_supported) { /* @@ -5761,9 +5822,19 @@ * device has a motor. */ un->un_f_start_stop_supported = TRUE; - rval = sd_send_scsi_START_STOP_UNIT(ssc, SD_TARGET_START, - SD_PATH_DIRECT); - + + if (un->un_f_power_condition_supported) { + rval = sd_send_scsi_START_STOP_UNIT(ssc, + SD_POWER_CONDITION, SD_TARGET_ACTIVE, + SD_PATH_DIRECT); + if (rval != 0) { + un->un_f_power_condition_supported = FALSE; + } + } + if (!un->un_f_power_condition_supported) { + rval = sd_send_scsi_START_STOP_UNIT(ssc, + SD_START_STOP, SD_TARGET_START, SD_PATH_DIRECT); + } if (rval != 0) { sd_ssc_assessment(ssc, SD_FMT_IGNORE); un->un_f_start_stop_supported = FALSE; @@ -5773,11 +5844,39 @@ * create pm properties anyways otherwise the parent can't * go to sleep */ + un->un_f_pm_is_enabled = TRUE; (void) sd_create_pm_components(devi, un); - un->un_f_pm_is_enabled = TRUE; - return; - } - + + /* + * If it claims that log sense is supported, check it out. + */ + if (un->un_f_log_sense_supported) { + rval = sd_log_page_supported(ssc, + START_STOP_CYCLE_PAGE); + if (rval == 1) { + /* Page found, use it. */ + un->un_start_stop_cycle_page = + START_STOP_CYCLE_PAGE; + } else { + /* + * Page not found or log sense is not + * supported. + * Notice we do not check the old style + * START_STOP_CYCLE_VU_PAGE because this + * code path does not apply to old disks. + */ + un->un_f_log_sense_supported = FALSE; + un->un_f_pm_log_sense_smart = FALSE; + } + } + + return; + } + + /* + * For the disk whose attached HBA has not set the "pm-capable" + * property, check if it supports the power management. + */ if (!un->un_f_log_sense_supported) { un->un_power_level = SD_SPINDLE_ON; un->un_f_pm_is_enabled = FALSE; @@ -5795,7 +5894,7 @@ /* * If the start-stop cycle counter log page is not supported - * or if the pm-capable property is SD_PM_CAPABLE_FALSE (0) + * or if the pm-capable property is set to be false (0), * then we should not create the pm_components property. */ if (rval == -1) { @@ -5885,44 +5984,53 @@ static void sd_create_pm_components(dev_info_t *devi, struct sd_lun *un) { - char *pm_comp[] = { "NAME=spindle-motor", "0=off", "1=on", NULL }; - - ASSERT(!mutex_owned(SD_MUTEX(un))); - - if (ddi_prop_update_string_array(DDI_DEV_T_NONE, devi, - "pm-components", pm_comp, 3) == DDI_PROP_SUCCESS) { - /* - * When components are initially created they are idle, - * power up any non-removables. - * Note: the return value of pm_raise_power can't be used - * for determining if PM should be enabled for this device. - * Even if you check the return values and remove this - * property created above, the PM framework will not honor the - * change after the first call to pm_raise_power. Hence, - * removal of that property does not help if pm_raise_power - * fails. In the case of removable media, the start/stop - * will fail if the media is not present. - */ - if (un->un_f_attach_spinup && (pm_raise_power(SD_DEVINFO(un), 0, - SD_SPINDLE_ON) == DDI_SUCCESS)) { - mutex_enter(SD_MUTEX(un)); + ASSERT(!mutex_owned(SD_MUTEX(un))); + + if (un->un_f_power_condition_supported) { + if (ddi_prop_update_string_array(DDI_DEV_T_NONE, devi, + "pm-components", sd_pwr_pc.pm_comp, 5) + != DDI_PROP_SUCCESS) { + un->un_power_level = SD_SPINDLE_ACTIVE; + un->un_f_pm_is_enabled = FALSE; + return; + } + } else { + if (ddi_prop_update_string_array(DDI_DEV_T_NONE, devi, + "pm-components", sd_pwr_ss.pm_comp, 3) + != DDI_PROP_SUCCESS) { un->un_power_level = SD_SPINDLE_ON; - mutex_enter(&un->un_pm_mutex); - /* Set to on and not busy. */ - un->un_pm_count = 0; - } else { - mutex_enter(SD_MUTEX(un)); - un->un_power_level = SD_SPINDLE_OFF; - mutex_enter(&un->un_pm_mutex); - /* Set to off. */ - un->un_pm_count = -1; - } - mutex_exit(&un->un_pm_mutex); - mutex_exit(SD_MUTEX(un)); - } else { - un->un_power_level = SD_SPINDLE_ON; - un->un_f_pm_is_enabled = FALSE; - } + un->un_f_pm_is_enabled = FALSE; + return; + } + } + /* + * When components are initially created they are idle, + * power up any non-removables. + * Note: the return value of pm_raise_power can't be used + * for determining if PM should be enabled for this device. + * Even if you check the return values and remove this + * property created above, the PM framework will not honor the + * change after the first call to pm_raise_power. Hence, + * removal of that property does not help if pm_raise_power + * fails. In the case of removable media, the start/stop + * will fail if the media is not present. + */ + if (un->un_f_attach_spinup && (pm_raise_power(SD_DEVINFO(un), 0, + SD_PM_STATE_ACTIVE(un)) == DDI_SUCCESS)) { + mutex_enter(SD_MUTEX(un)); + un->un_power_level = SD_PM_STATE_ACTIVE(un); + mutex_enter(&un->un_pm_mutex); + /* Set to on and not busy. */ + un->un_pm_count = 0; + } else { + mutex_enter(SD_MUTEX(un)); + un->un_power_level = SD_PM_STATE_STOPPED(un); + mutex_enter(&un->un_pm_mutex); + /* Set to off. */ + un->un_pm_count = -1; + } + mutex_exit(&un->un_pm_mutex); + mutex_exit(SD_MUTEX(un)); } @@ -6126,69 +6234,6 @@ /* - * Function: sd_ddi_pm_suspend - * - * Description: Set the drive state to low power. - * Someone else is required to actually change the drive - * power level. - * - * Arguments: un - driver soft state (unit) structure - * - * Return Code: DDI_FAILURE or DDI_SUCCESS - * - * Context: Kernel thread context - */ - -static int -sd_ddi_pm_suspend(struct sd_lun *un) -{ - ASSERT(un != NULL); - SD_TRACE(SD_LOG_POWER, un, "sd_ddi_pm_suspend: entry\n"); - - ASSERT(!mutex_owned(SD_MUTEX(un))); - mutex_enter(SD_MUTEX(un)); - - /* - * Exit if power management is not enabled for this device, or if - * the device is being used by HA. - */ - if ((un->un_f_pm_is_enabled == FALSE) || (un->un_resvd_status & - (SD_RESERVE | SD_WANT_RESERVE | SD_LOST_RESERVE))) { - mutex_exit(SD_MUTEX(un)); - SD_TRACE(SD_LOG_POWER, un, "sd_ddi_pm_suspend: exiting\n"); - return (DDI_SUCCESS); - } - - SD_INFO(SD_LOG_POWER, un, "sd_ddi_pm_suspend: un_ncmds_in_driver=%ld\n", - un->un_ncmds_in_driver); - - /* - * See if the device is not busy, ie.: - * - we have no commands in the driver for this device - * - not waiting for resources - */ - if ((un->un_ncmds_in_driver == 0) && - (un->un_state != SD_STATE_RWAIT)) { - /* - * The device is not busy, so it is OK to go to low power state. - * Indicate low power, but rely on someone else to actually - * change it. - */ - mutex_enter(&un->un_pm_mutex); - un->un_pm_count = -1; - mutex_exit(&un->un_pm_mutex); - un->un_power_level = SD_SPINDLE_OFF; - } - - mutex_exit(SD_MUTEX(un)); - - SD_TRACE(SD_LOG_POWER, un, "sd_ddi_pm_suspend: exit\n"); - - return (DDI_SUCCESS); -} - - -/* * Function: sd_ddi_resume * * Description: Performs system power-up operations.. @@ -6244,7 +6289,8 @@ */ if (un->un_f_attach_spinup) { mutex_exit(SD_MUTEX(un)); - (void) pm_raise_power(SD_DEVINFO(un), 0, SD_SPINDLE_ON); + (void) pm_raise_power(SD_DEVINFO(un), 0, + SD_PM_STATE_ACTIVE(un)); mutex_enter(SD_MUTEX(un)); } @@ -6294,42 +6340,76 @@ /* - * Function: sd_ddi_pm_resume - * - * Description: Set the drive state to powered on. - * Someone else is required to actually change the drive - * power level. + * Function: sd_pm_state_change + * + * Description: Change the driver power state. + * Someone else is required to actually change the driver + * power level. * * Arguments: un - driver soft state (unit) structure + * level - the power level that is changed to + * flag - to decide how to change the power state * * Return Code: DDI_SUCCESS * * Context: Kernel thread context */ - -static int -sd_ddi_pm_resume(struct sd_lun *un) -{ - ASSERT(un != NULL); - - ASSERT(!mutex_owned(SD_MUTEX(un))); - mutex_enter(SD_MUTEX(un)); - un->un_power_level = SD_SPINDLE_ON; - - ASSERT(!mutex_owned(&un->un_pm_mutex)); - mutex_enter(&un->un_pm_mutex); - if (SD_DEVICE_IS_IN_LOW_POWER(un)) { - un->un_pm_count++; - ASSERT(un->un_pm_count == 0); - /* - * Note: no longer do the cv_broadcast on un_suspend_cv. The - * un_suspend_cv is for a system resume, not a power management - * device resume. (4297749) - * cv_broadcast(&un->un_suspend_cv); - */ - } - mutex_exit(&un->un_pm_mutex); - mutex_exit(SD_MUTEX(un)); +static int +sd_pm_state_change(struct sd_lun *un, int level, int flag) +{ + ASSERT(un != NULL); + SD_TRACE(SD_LOG_POWER, un, "sd_pm_state_change: entry\n"); + + ASSERT(!mutex_owned(SD_MUTEX(un))); + mutex_enter(SD_MUTEX(un)); + + if (flag == SD_PM_STATE_ROLLBACK || SD_PM_IS_IO_CAPABLE(un, level)) { + un->un_power_level = level; + ASSERT(!mutex_owned(&un->un_pm_mutex)); + mutex_enter(&un->un_pm_mutex); + if (SD_DEVICE_IS_IN_LOW_POWER(un)) { + un->un_pm_count++; + ASSERT(un->un_pm_count == 0); + } + mutex_exit(&un->un_pm_mutex); + } else { + /* + * Exit if power management is not enabled for this device, + * or if the device is being used by HA. + */ + if ((un->un_f_pm_is_enabled == FALSE) || (un->un_resvd_status & + (SD_RESERVE | SD_WANT_RESERVE | SD_LOST_RESERVE))) { + mutex_exit(SD_MUTEX(un)); + SD_TRACE(SD_LOG_POWER, un, + "sd_pm_state_change: exiting\n"); + return (DDI_FAILURE); + } + + SD_INFO(SD_LOG_POWER, un, "sd_pm_state_change: " + "un_ncmds_in_driver=%ld\n", un->un_ncmds_in_driver); + + /* + * See if the device is not busy, ie.: + * - we have no commands in the driver for this device + * - not waiting for resources + */ + if ((un->un_ncmds_in_driver == 0) && + (un->un_state != SD_STATE_RWAIT)) { + /* + * The device is not busy, so it is OK to go to low + * power state. Indicate low power, but rely on someone + * else to actually change it. + */ + mutex_enter(&un->un_pm_mutex); + un->un_pm_count = -1; + mutex_exit(&un->un_pm_mutex); + un->un_power_level = level; + } + } + + mutex_exit(SD_MUTEX(un)); + + SD_TRACE(SD_LOG_POWER, un, "sd_pm_state_change: exit\n"); return (DDI_SUCCESS); } @@ -6451,12 +6531,12 @@ uchar_t state_before_pm; int got_semaphore_here; sd_ssc_t *ssc; + int last_power_level; instance = ddi_get_instance(devi); if (((un = ddi_get_soft_state(sd_state, instance)) == NULL) || - (SD_SPINDLE_OFF > level) || (level > SD_SPINDLE_ON) || - component != 0) { + !SD_PM_IS_LEVEL_VALID(un, level) || component != 0) { return (DDI_FAILURE); } @@ -6487,10 +6567,11 @@ * If un_ncmds_in_driver is non-zero it indicates commands are * already being processed in the driver, or if the semaphore was * not gotten here it indicates an open or close is being processed. - * At the same time somebody is requesting to go low power which - * can't happen, therefore we need to return failure. - */ - if ((level == SD_SPINDLE_OFF) && + * At the same time somebody is requesting to go to a lower power + * that can't perform I/O, which can't happen, therefore we need to + * return failure. + */ + if ((!SD_PM_IS_IO_CAPABLE(un, level)) && ((un->un_ncmds_in_driver != 0) || (got_semaphore_here == 0))) { mutex_exit(SD_MUTEX(un)); @@ -6536,11 +6617,12 @@ mutex_exit(SD_MUTEX(un)); /* - * If "pm-capable" property is set to TRUE by HBA drivers, - * bypass the following checking, otherwise, check the log - * sense information for this device - */ - if ((level == SD_SPINDLE_OFF) && un->un_f_log_sense_supported) { + * If log sense command is not supported, bypass the + * following checking, otherwise, check the log sense + * information for this device. + */ + if (SD_PM_STOP_MOTOR_NEEDED(un, level) && + un->un_f_log_sense_supported) { /* * Get the log sense information to understand whether the * the powercycle counts have gone beyond the threshhold. @@ -6601,17 +6683,24 @@ (log_page_data[0x1c] << 24) | (log_page_data[0x1d] << 16) | (log_page_data[0x1E] << 8) | log_page_data[0x1F]; - sd_pm_tran_data.un.scsi_cycles.lifemax = maxcycles; - ncycles = (log_page_data[0x24] << 24) | (log_page_data[0x25] << 16) | (log_page_data[0x26] << 8) | log_page_data[0x27]; - sd_pm_tran_data.un.scsi_cycles.ncycles = ncycles; - - for (i = 0; i < DC_SCSI_MFR_LEN; i++) { - sd_pm_tran_data.un.scsi_cycles.svc_date[i] = - log_page_data[8+i]; + if (un->un_f_pm_log_sense_smart) { + sd_pm_tran_data.un.smart_count.allowed = maxcycles; + sd_pm_tran_data.un.smart_count.consumed = ncycles; + sd_pm_tran_data.un.smart_count.flag = 0; + sd_pm_tran_data.format = DC_SMART_FORMAT; + } else { + sd_pm_tran_data.un.scsi_cycles.lifemax = maxcycles; + sd_pm_tran_data.un.scsi_cycles.ncycles = ncycles; + for (i = 0; i < DC_SCSI_MFR_LEN; i++) { + sd_pm_tran_data.un.scsi_cycles.svc_date[i] = + log_page_data[8+i]; + } + sd_pm_tran_data.un.scsi_cycles.flag = 0; + sd_pm_tran_data.format = DC_SCSI_FORMAT; } kmem_free(log_page_data, log_page_size); @@ -6620,10 +6709,6 @@ * Call pm_trans_check routine to get the Ok from * the global policy */ - - sd_pm_tran_data.format = DC_SCSI_FORMAT; - sd_pm_tran_data.un.scsi_cycles.flag = 0; - rval = pm_trans_check(&sd_pm_tran_data, &intvlp); #ifdef SDDEBUG if (sd_force_pm_supported) { @@ -6704,13 +6789,14 @@ } } - if (level == SD_SPINDLE_OFF) { + if (!SD_PM_IS_IO_CAPABLE(un, level)) { /* * Save the last state... if the STOP FAILS we need it * for restoring */ mutex_enter(SD_MUTEX(un)); save_state = un->un_last_state; + last_power_level = un->un_power_level; /* * There must not be any cmds. getting processed * in the driver when we get here. Power to the @@ -6720,10 +6806,11 @@ mutex_exit(SD_MUTEX(un)); /* - * For now suspend the device completely before spindle is + * For now PM suspend the device completely before spindle is * turned off */ - if ((rval = sd_ddi_pm_suspend(un)) == DDI_FAILURE) { + if ((rval = sd_pm_state_change(un, level, SD_PM_STATE_CHANGE)) + == DDI_FAILURE) { if (got_semaphore_here != 0) { sema_v(&un->un_semoclose); } @@ -6734,6 +6821,7 @@ */ mutex_enter(SD_MUTEX(un)); un->un_state = state_before_pm; + un->un_power_level = last_power_level; cv_broadcast(&un->un_suspend_cv); mutex_exit(SD_MUTEX(un)); SD_TRACE(SD_LOG_IO_PM, un, @@ -6756,19 +6844,28 @@ * attention. Don't do retries. Bypass the PM layer, otherwise * a deadlock on un_pm_busy_cv will occur. */ - if (level == SD_SPINDLE_ON) { + if (SD_PM_IS_IO_CAPABLE(un, level)) { sval = sd_send_scsi_TEST_UNIT_READY(ssc, SD_DONT_RETRY_TUR | SD_BYPASS_PM); if (sval != 0) sd_ssc_assessment(ssc, SD_FMT_IGNORE); } - SD_TRACE(SD_LOG_IO_PM, un, "sdpower: sending \'%s\' unit\n", - ((level == SD_SPINDLE_ON) ? "START" : "STOP")); - - sval = sd_send_scsi_START_STOP_UNIT(ssc, - ((level == SD_SPINDLE_ON) ? SD_TARGET_START : SD_TARGET_STOP), - SD_PATH_DIRECT); + if (un->un_f_power_condition_supported) { + char *pm_condition_name[] = {"STOPPED", "STANDBY", + "IDLE", "ACTIVE"}; + SD_TRACE(SD_LOG_IO_PM, un, + "sdpower: sending \'%s\' power condition", + pm_condition_name[level]); + sval = sd_send_scsi_START_STOP_UNIT(ssc, SD_POWER_CONDITION, + sd_pl2pc[level], SD_PATH_DIRECT); + } else { + SD_TRACE(SD_LOG_IO_PM, un, "sdpower: sending \'%s\' unit\n", + ((level == SD_SPINDLE_ON) ? "START" : "STOP")); + sval = sd_send_scsi_START_STOP_UNIT(ssc, SD_START_STOP, + ((level == SD_SPINDLE_ON) ? SD_TARGET_START : + SD_TARGET_STOP), SD_PATH_DIRECT); + } if (sval != 0) { if (sval == EIO) sd_ssc_assessment(ssc, SD_FMT_STATUS_CHECK); @@ -6790,8 +6887,7 @@ * In all other cases we setup for the new state * and return success. */ - switch (level) { - case SD_SPINDLE_OFF: + if (!SD_PM_IS_IO_CAPABLE(un, level)) { if ((medium_present == TRUE) && (sval != 0)) { /* The stop command from above failed */ rval = DDI_FAILURE; @@ -6801,17 +6897,14 @@ * sd_pm_resume() and set the state back to * it's previous value. */ - (void) sd_ddi_pm_resume(un); + (void) sd_pm_state_change(un, last_power_level, + SD_PM_STATE_ROLLBACK); mutex_enter(SD_MUTEX(un)); un->un_last_state = save_state; mutex_exit(SD_MUTEX(un)); - break; - } - /* - * The stop command from above succeeded. - */ - if (un->un_f_monitor_media_state) { - /* + } else if (un->un_f_monitor_media_state) { + /* + * The stop command from above succeeded. * Terminate watch thread in case of removable media * devices going into low power state. This is as per * the requirements of pm framework, otherwise commands @@ -6831,10 +6924,9 @@ mutex_exit(SD_MUTEX(un)); } } - break; - - default: /* The level requested is spindle on... */ - /* + } else { + /* + * The level requested is I/O capable. * Legacy behavior: return success on a failed spinup * if there is no media in the drive. * Do this by looking at medium_present here. @@ -6842,37 +6934,39 @@ if ((sval != 0) && medium_present) { /* The start command from above failed */ rval = DDI_FAILURE; - break; - } - /* - * The start command from above succeeded - * Resume the devices now that we have - * started the disks - */ - (void) sd_ddi_pm_resume(un); - - /* - * Resume the watch thread since it was suspended - * when the device went into low power mode. - */ - if (un->un_f_monitor_media_state) { - mutex_enter(SD_MUTEX(un)); - if (un->un_f_watcht_stopped == TRUE) { - opaque_t temp_token; - - un->un_f_watcht_stopped = FALSE; + } else { + /* + * The start command from above succeeded + * PM resume the devices now that we have + * started the disks + */ + (void) sd_pm_state_change(un, level, + SD_PM_STATE_CHANGE); + + /* + * Resume the watch thread since it was suspended + * when the device went into low power mode. + */ + if (un->un_f_monitor_media_state) { + mutex_enter(SD_MUTEX(un)); + if (un->un_f_watcht_stopped == TRUE) { + opaque_t temp_token; + + un->un_f_watcht_stopped = FALSE; + mutex_exit(SD_MUTEX(un)); + temp_token = scsi_watch_request_submit( + SD_SCSI_DEVP(un), + sd_check_media_time, + SENSE_LENGTH, sd_media_watch_cb, + (caddr_t)dev); + mutex_enter(SD_MUTEX(un)); + un->un_swr_token = temp_token; + } mutex_exit(SD_MUTEX(un)); - temp_token = scsi_watch_request_submit( - SD_SCSI_DEVP(un), - sd_check_media_time, - SENSE_LENGTH, sd_media_watch_cb, - (caddr_t)dev); - mutex_enter(SD_MUTEX(un)); - un->un_swr_token = temp_token; - } - mutex_exit(SD_MUTEX(un)); - } - } + } + } + } + if (got_semaphore_here != 0) { sema_v(&un->un_semoclose); } @@ -8593,8 +8687,8 @@ } else { mutex_exit(&un->un_pm_mutex); if ((un->un_f_pm_is_enabled == TRUE) && - (pm_lower_power(SD_DEVINFO(un), 0, SD_SPINDLE_OFF) != - DDI_SUCCESS)) { + (pm_lower_power(SD_DEVINFO(un), 0, SD_PM_STATE_STOPPED(un)) + != DDI_SUCCESS)) { SD_ERROR(SD_LOG_ATTACH_DETACH, un, "sd_dr_detach: Lower power request failed, ignoring.\n"); /* @@ -9718,12 +9812,11 @@ /* * pm_raise_power will cause sdpower to be called * which brings the device power level to the - * desired state, ON in this case. If successful, - * un_pm_count and un_power_level will be updated - * appropriately. + * desired state, If successful, un_pm_count and + * un_power_level will be updated appropriately. */ return_status = pm_raise_power(SD_DEVINFO(un), 0, - SD_SPINDLE_ON); + SD_PM_STATE_ACTIVE(un)); mutex_enter(&un->un_pm_mutex); @@ -11724,6 +11817,7 @@ * Return Code: 0 - successful completion of the given command * EIO - scsi_uscsi_handle_command() failed * ENXIO - soft state not found for specified dev + * ECANCELED - command cancelled due to low power * EINVAL * EFAULT - copyin/copyout error * return code of scsi_uscsi_handle_command(): @@ -11779,6 +11873,23 @@ */ ssc->ssc_flags |= SSC_FLAGS_NEED_ASSESSMENT; + /* + * if USCSI_PMFAILFAST is set and un is in low power, fail the + * command immediately. + */ + mutex_enter(SD_MUTEX(un)); + mutex_enter(&un->un_pm_mutex); + if ((uscmd->uscsi_flags & USCSI_PMFAILFAST) && + SD_DEVICE_IS_IN_LOW_POWER(un)) { + SD_TRACE(SD_LOG_IO, un, "sd_ssc_send:" + "un:0x%p is in low power\n", un); + mutex_exit(&un->un_pm_mutex); + mutex_exit(SD_MUTEX(un)); + return (ECANCELED); + } + mutex_exit(&un->un_pm_mutex); + mutex_exit(SD_MUTEX(un)); + #ifdef SDDEBUG switch (dataspace) { case UIO_USERSPACE: @@ -20059,6 +20170,8 @@ * * Arguments: ssc - ssc contatins pointer to driver soft state (unit) * structure for this target. + * pc_flag - SD_POWER_CONDITION + * SD_START_STOP * flag - SD_TARGET_START * SD_TARGET_STOP * SD_TARGET_EJECT @@ -20078,7 +20191,8 @@ */ static int -sd_send_scsi_START_STOP_UNIT(sd_ssc_t *ssc, int flag, int path_flag) +sd_send_scsi_START_STOP_UNIT(sd_ssc_t *ssc, int pc_flag, int flag, + int path_flag) { struct scsi_extended_sense sense_buf; union scsi_cdb cdb; @@ -20095,7 +20209,7 @@ "sd_send_scsi_START_STOP_UNIT: entry: un:0x%p\n", un); if (un->un_f_check_start_stop && - ((flag == SD_TARGET_START) || (flag == SD_TARGET_STOP)) && + ((pc_flag == SD_START_STOP) && (flag != SD_TARGET_EJECT)) && (un->un_f_start_stop_supported != TRUE)) { return (0); } @@ -20119,7 +20233,8 @@ bzero(&sense_buf, sizeof (struct scsi_extended_sense)); cdb.scc_cmd = SCMD_START_STOP; - cdb.cdb_opaque[4] = (uchar_t)flag; + cdb.cdb_opaque[4] = (pc_flag == SD_POWER_CONDITION) ? + (uchar_t)(flag << 4) : (uchar_t)flag; ucmd_buf.uscsi_cdb = (char *)&cdb; ucmd_buf.uscsi_cdblen = CDB_GROUP0; @@ -20214,6 +20329,7 @@ { struct sd_lun *un = arg; sd_ssc_t *ssc; + int power_level; int rval; ASSERT(un != NULL); @@ -20232,16 +20348,30 @@ } mutex_exit(SD_MUTEX(un)); + ssc = sd_ssc_init(un); /* * When a START STOP command is issued from here, it is part of a * failure recovery operation and must be issued before any other * commands, including any pending retries. Thus it must be sent * using SD_PATH_DIRECT_PRIORITY. It doesn't matter if the spin up * succeeds or not, we will start I/O after the attempt. - */ - ssc = sd_ssc_init(un); - rval = sd_send_scsi_START_STOP_UNIT(ssc, SD_TARGET_START, - SD_PATH_DIRECT_PRIORITY); + * If power condition is supported and the current power level + * is capable of performing I/O, we should set the power condition + * to that level. Otherwise, set the power condition to ACTIVE. + */ + if (un->un_f_power_condition_supported) { + mutex_enter(SD_MUTEX(un)); + ASSERT(SD_PM_IS_LEVEL_VALID(un, un->un_power_level)); + power_level = sd_pwr_pc.ran_perf[un->un_power_level] + > 0 ? un->un_power_level : SD_SPINDLE_ACTIVE; + mutex_exit(SD_MUTEX(un)); + rval = sd_send_scsi_START_STOP_UNIT(ssc, SD_POWER_CONDITION, + sd_pl2pc[power_level], SD_PATH_DIRECT_PRIORITY); + } else { + rval = sd_send_scsi_START_STOP_UNIT(ssc, SD_START_STOP, + SD_TARGET_START, SD_PATH_DIRECT_PRIORITY); + } + if (rval != 0) sd_ssc_assessment(ssc, SD_FMT_IGNORE); sd_ssc_fini(ssc); @@ -22285,8 +22415,8 @@ if (!ISCD(un)) { err = ENOTTY; } else { - err = sd_send_scsi_START_STOP_UNIT(ssc, SD_TARGET_STOP, - SD_PATH_STANDARD); + err = sd_send_scsi_START_STOP_UNIT(ssc, SD_START_STOP, + SD_TARGET_STOP, SD_PATH_STANDARD); goto done_with_assess; } break; @@ -22296,8 +22426,8 @@ if (!ISCD(un)) { err = ENOTTY; } else { - err = sd_send_scsi_START_STOP_UNIT(ssc, SD_TARGET_START, - SD_PATH_STANDARD); + err = sd_send_scsi_START_STOP_UNIT(ssc, SD_START_STOP, + SD_TARGET_START, SD_PATH_STANDARD); goto done_with_assess; } break; @@ -22307,8 +22437,8 @@ if (!ISCD(un)) { err = ENOTTY; } else { - err = sd_send_scsi_START_STOP_UNIT(ssc, SD_TARGET_CLOSE, - SD_PATH_STANDARD); + err = sd_send_scsi_START_STOP_UNIT(ssc, SD_START_STOP, + SD_TARGET_CLOSE, SD_PATH_STANDARD); goto done_with_assess; } break; @@ -25345,7 +25475,8 @@ /* * use pm framework to power on HBA 1st */ - (void) pm_raise_power(SD_DEVINFO(un), 0, SD_SPINDLE_ON); + (void) pm_raise_power(SD_DEVINFO(un), 0, + SD_PM_STATE_ACTIVE(un)); /* * Dump no long uses sdpower to power on a device, it's @@ -25378,7 +25509,8 @@ return (EIO); } scsi_destroy_pkt(start_pktp); - (void) sd_ddi_pm_resume(un); + (void) sd_pm_state_change(un, SD_PM_STATE_ACTIVE(un), + SD_PM_STATE_CHANGE); } else { mutex_exit(&un->un_pm_mutex); } @@ -28358,8 +28490,8 @@ } ssc = sd_ssc_init(un); - rval = sd_send_scsi_START_STOP_UNIT(ssc, SD_TARGET_EJECT, - SD_PATH_STANDARD); + rval = sd_send_scsi_START_STOP_UNIT(ssc, SD_START_STOP, + SD_TARGET_EJECT, SD_PATH_STANDARD); sd_ssc_fini(ssc); if (rval == 0) { @@ -30306,7 +30438,7 @@ static void sd_set_unit_attributes(struct sd_lun *un, dev_info_t *devi) { - int pm_capable_prop; + int pm_cap; ASSERT(un->un_sd); ASSERT(un->un_sd->sd_inq); @@ -30426,33 +30558,47 @@ * power manage the device without checking the start/stop * cycle count log sense page. * - * If "pm-capable" exists and is SD_PM_CAPABLE_FALSE (0) + * If "pm-capable" exists and is set to be false (0), * then we should not power manage the device. * - * If "pm-capable" doesn't exist then pm_capable_prop will + * If "pm-capable" doesn't exist then pm_cap will * be set to SD_PM_CAPABLE_UNDEFINED (-1). In this case, * sd will check the start/stop cycle count log sense page * and power manage the device if the cycle count limit has * not been exceeded. */ - pm_capable_prop = ddi_prop_get_int(DDI_DEV_T_ANY, devi, + pm_cap = ddi_prop_get_int(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, "pm-capable", SD_PM_CAPABLE_UNDEFINED); - if (pm_capable_prop == SD_PM_CAPABLE_UNDEFINED) { + if (SD_PM_CAPABLE_IS_UNDEFINED(pm_cap)) { un->un_f_log_sense_supported = TRUE; + if (!un->un_f_power_condition_disabled && + SD_INQUIRY(un)->inq_ansi == 6) { + un->un_f_power_condition_supported = TRUE; + } } else { /* * pm-capable property exists. * - * Convert "TRUE" values for pm_capable_prop to - * SD_PM_CAPABLE_TRUE (1) to make it easier to check - * later. "TRUE" values are any values except - * SD_PM_CAPABLE_FALSE (0) and - * SD_PM_CAPABLE_UNDEFINED (-1) - */ - if (pm_capable_prop == SD_PM_CAPABLE_FALSE) { + * Convert "TRUE" values for pm_cap to + * SD_PM_CAPABLE_IS_TRUE to make it easier to check + * later. "TRUE" values are any values defined in + * inquiry.h. + */ + if (SD_PM_CAPABLE_IS_FALSE(pm_cap)) { un->un_f_log_sense_supported = FALSE; } else { + /* SD_PM_CAPABLE_IS_TRUE case */ un->un_f_pm_supported = TRUE; + if (!un->un_f_power_condition_disabled && + SD_PM_CAPABLE_IS_SPC_4(pm_cap)) { + un->un_f_power_condition_supported = + TRUE; + } + if (SD_PM_CAP_LOG_SUPPORTED(pm_cap)) { + un->un_f_log_sense_supported = TRUE; + un->un_f_pm_log_sense_smart = + SD_PM_CAP_SMART_LOG(pm_cap); + } } SD_INFO(SD_LOG_ATTACH_DETACH, un,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/io/uath/THIRDPARTYLICENSE Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 2006 Sam Leffler, Errno Consulting + * Copyright (c) 2008-2009 Weongyo Jeong <weongyo@freebsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +/* + * This driver is distantly derived from a driver of the same name + * by Damien Bergamini. The original copyright is included below: + * + * Copyright (c) 2006 + * Damien Bergamini <damien.bergamini@free.fr> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/io/uath/THIRDPARTYLICENSE.descrip Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,1 @@ +ATHEROS AR5523 USB WIFI DRIVER
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/io/uath/uath.c Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,3370 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Copyright (c) 2006 Sam Leffler, Errno Consulting + * Copyright (c) 2008-2009 Weongyo Jeong <weongyo@freebsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +/* + * This driver is distantly derived from a driver of the same name + * by Damien Bergamini. The original copyright is included below: + * + * Copyright (c) 2006 + * Damien Bergamini <damien.bergamini@free.fr> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +#include <sys/types.h> +#include <sys/cmn_err.h> +#include <sys/strsubr.h> +#include <sys/strsun.h> +#include <sys/modctl.h> +#include <sys/devops.h> +#include <sys/mac_provider.h> +#include <sys/mac_wifi.h> +#include <sys/net80211.h> + +#define USBDRV_MAJOR_VER 2 +#define USBDRV_MINOR_VER 0 +#include <sys/usb/usba.h> +#include <sys/usb/usba/usba_types.h> + +#include "uath_reg.h" +#include "uath_var.h" + +static void *uath_soft_state_p = NULL; + +/* + * Bit flags in the ral_dbg_flags + */ +#define UATH_DBG_MSG 0x000001 +#define UATH_DBG_ERR 0x000002 +#define UATH_DBG_USB 0x000004 +#define UATH_DBG_TX 0x000008 +#define UATH_DBG_RX 0x000010 +#define UATH_DBG_FW 0x000020 +#define UATH_DBG_TX_CMD 0x000040 +#define UATH_DBG_RX_CMD 0x000080 +#define UATH_DBG_ALL 0x000fff + +uint32_t uath_dbg_flags = 0; + +#ifdef DEBUG +#define UATH_DEBUG \ + uath_debug +#else +#define UATH_DEBUG +#endif + +/* + * Various supported device vendors/products. + * UB51: AR5005UG 802.11b/g, UB52: AR5005UX 802.11b/g + */ +#define UATH_FLAG_PRE_FIRMWARE (1 << 0) +#define UATH_FLAG_ABG (1 << 1) +#define UATH_FLAG_ERR (1 << 2) +#define UATH_DEV(v, p, f) \ + { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, (f) }, \ + { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p##_NF }, \ + (f) | UATH_FLAG_PRE_FIRMWARE } +#define UATH_DEV_UG(v, p) UATH_DEV(v, p, 0) +#define UATH_DEV_UX(v, p) UATH_DEV(v, p, UATH_FLAG_ABG) + +struct uath_devno { + uint16_t vendor_id; + uint16_t product_id; +}; + +static const struct uath_type { + struct uath_devno dev; + uint8_t flags; +} uath_devs[] = { + UATH_DEV_UG(ACCTON, SMCWUSBTG2), + UATH_DEV_UG(ATHEROS, AR5523), + UATH_DEV_UG(ATHEROS2, AR5523_1), + UATH_DEV_UG(ATHEROS2, AR5523_2), + UATH_DEV_UX(ATHEROS2, AR5523_3), + UATH_DEV_UG(CONCEPTRONIC, AR5523_1), + UATH_DEV_UX(CONCEPTRONIC, AR5523_2), + UATH_DEV_UX(DLINK, DWLAG122), + UATH_DEV_UX(DLINK, DWLAG132), + UATH_DEV_UG(DLINK, DWLG132), + UATH_DEV_UG(GIGASET, AR5523), + UATH_DEV_UG(GIGASET, SMCWUSBTG), + UATH_DEV_UG(GLOBALSUN, AR5523_1), + UATH_DEV_UX(GLOBALSUN, AR5523_2), + UATH_DEV_UG(IODATA, USBWNG54US), + UATH_DEV_UG(MELCO, WLIU2KAMG54), + UATH_DEV_UX(NETGEAR, WG111U), + UATH_DEV_UG(NETGEAR3, WG111T), + UATH_DEV_UG(NETGEAR3, WPN111), + UATH_DEV_UG(PHILIPS, SNU6500), + UATH_DEV_UX(UMEDIA, AR5523_2), + UATH_DEV_UG(UMEDIA, TEW444UBEU), + UATH_DEV_UG(WISTRONNEWEB, AR5523_1), + UATH_DEV_UX(WISTRONNEWEB, AR5523_2), + UATH_DEV_UG(ZCOM, AR5523) +}; + +static char uath_fwmod[] = "uathfw"; +static char uath_binmod[] = "uathbin"; + +/* + * Supported rates for 802.11b/g modes (in 500Kbps unit). + */ +static const struct ieee80211_rateset uath_rateset_11b = + { 4, { 2, 4, 11, 22 } }; + +static const struct ieee80211_rateset uath_rateset_11g = + { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } }; + +/* + * device operations + */ +static int uath_attach(dev_info_t *, ddi_attach_cmd_t); +static int uath_detach(dev_info_t *, ddi_detach_cmd_t); + +/* + * Module Loading Data & Entry Points + */ +DDI_DEFINE_STREAM_OPS(uath_dev_ops, nulldev, nulldev, uath_attach, + uath_detach, nodev, NULL, D_MP, NULL, ddi_quiesce_not_needed); + +static struct modldrv uath_modldrv = { + &mod_driverops, /* Type of module. This one is a driver */ + "Atheros AR5523 USB Driver v1.1", /* short description */ + &uath_dev_ops /* driver specific ops */ +}; + +static struct modlinkage modlinkage = { + MODREV_1, + (void *)&uath_modldrv, + NULL +}; + +static int uath_m_stat(void *, uint_t, uint64_t *); +static int uath_m_start(void *); +static void uath_m_stop(void *); +static int uath_m_promisc(void *, boolean_t); +static int uath_m_multicst(void *, boolean_t, const uint8_t *); +static int uath_m_unicst(void *, const uint8_t *); +static mblk_t *uath_m_tx(void *, mblk_t *); +static void uath_m_ioctl(void *, queue_t *, mblk_t *); +static int uath_m_setprop(void *, const char *, mac_prop_id_t, + uint_t, const void *); +static int uath_m_getprop(void *, const char *, mac_prop_id_t, + uint_t, uint_t, void *, uint_t *); + +static mac_callbacks_t uath_m_callbacks = { + MC_IOCTL | MC_SETPROP | MC_GETPROP, + uath_m_stat, + uath_m_start, + uath_m_stop, + uath_m_promisc, + uath_m_multicst, + uath_m_unicst, + uath_m_tx, + uath_m_ioctl, + NULL, + NULL, + NULL, + uath_m_setprop, + uath_m_getprop +}; + +static usb_alt_if_data_t * + uath_lookup_alt_if(usb_client_dev_data_t *, + uint_t, uint_t, uint_t); +static usb_ep_data_t * + uath_lookup_ep_data(dev_info_t *, + usb_client_dev_data_t *, uint_t, uint_t, uint8_t, uint8_t); +static const char * + uath_codename(int code); + +static uint_t uath_lookup(uint16_t, uint16_t); +static void uath_list_all_eps(usb_alt_if_data_t *); +static int uath_open_pipes(struct uath_softc *); +static void uath_close_pipes(struct uath_softc *); +static int uath_fw_send(struct uath_softc *, + usb_pipe_handle_t, const void *, size_t); +static int uath_fw_ack(struct uath_softc *, int); +static int uath_loadsym(ddi_modhandle_t, char *, char **, size_t *); +static int uath_loadfirmware(struct uath_softc *); +static int uath_alloc_cmd_list(struct uath_softc *, + struct uath_cmd *, int, int); +static int uath_init_cmd_list(struct uath_softc *); +static void uath_free_cmd_list(struct uath_cmd *, int); +static int uath_host_available(struct uath_softc *); +static void uath_get_capability(struct uath_softc *, uint32_t, uint32_t *); +static int uath_get_devcap(struct uath_softc *); +static int uath_get_devstatus(struct uath_softc *, uint8_t *); +static int uath_get_status(struct uath_softc *, uint32_t, void *, int); + +static void uath_cmd_lock_init(struct uath_cmd_lock *); +static void uath_cmd_lock_destroy(struct uath_cmd_lock *); +static int uath_cmd_lock_wait(struct uath_cmd_lock *, clock_t); +static void uath_cmd_lock_signal(struct uath_cmd_lock *); + +static int uath_cmd_read(struct uath_softc *, uint32_t, const void *, + int, void *, int, int); +static int uath_cmd_write(struct uath_softc *, uint32_t, const void *, + int, int); +static int uath_cmdsend(struct uath_softc *, uint32_t, + const void *, int, void *, int, int); +static int uath_rx_cmd_xfer(struct uath_softc *); +static int uath_tx_cmd_xfer(struct uath_softc *, + usb_pipe_handle_t, const void *, uint_t); +static void uath_cmd_txeof(usb_pipe_handle_t, struct usb_bulk_req *); +static void uath_cmd_rxeof(usb_pipe_handle_t, usb_bulk_req_t *); +static void uath_cmdeof(struct uath_softc *, struct uath_cmd *); + +static void uath_init_data_queue(struct uath_softc *); +static int uath_rx_data_xfer(struct uath_softc *sc); +static int uath_tx_data_xfer(struct uath_softc *, mblk_t *); +static void uath_data_txeof(usb_pipe_handle_t, usb_bulk_req_t *); +static void uath_data_rxeof(usb_pipe_handle_t, usb_bulk_req_t *); + +static int uath_create_connection(struct uath_softc *, uint32_t); +static int uath_set_rates(struct uath_softc *, + const struct ieee80211_rateset *); +static int uath_write_associd(struct uath_softc *); +static int uath_set_ledsteady(struct uath_softc *, int, int); +static int uath_set_ledblink(struct uath_softc *, int, int, int, int); +static void uath_update_rxstat(struct uath_softc *, uint32_t); +static int uath_send(ieee80211com_t *, mblk_t *, uint8_t); +static int uath_reconnect(dev_info_t *); +static int uath_disconnect(dev_info_t *); +static int uath_newstate(struct ieee80211com *, enum ieee80211_state, int); + +static int uath_dataflush(struct uath_softc *); +static int uath_cmdflush(struct uath_softc *); +static int uath_flush(struct uath_softc *); +static int uath_set_ledstate(struct uath_softc *, int); +static int uath_set_chan(struct uath_softc *, struct ieee80211_channel *); +static int uath_reset_tx_queues(struct uath_softc *); +static int uath_wme_init(struct uath_softc *); +static int uath_config_multi(struct uath_softc *, + uint32_t, const void *, int); +static void uath_config(struct uath_softc *, uint32_t, uint32_t); +static int uath_switch_channel(struct uath_softc *, + struct ieee80211_channel *); +static int uath_set_rxfilter(struct uath_softc *, uint32_t, uint32_t); +static int uath_init_locked(void *); +static void uath_stop_locked(void *); +static int uath_init(struct uath_softc *); +static void uath_stop(struct uath_softc *); +static void uath_resume(struct uath_softc *); + +static void +uath_debug(uint32_t dbg_flags, const int8_t *fmt, ...) +{ + va_list args; + + if (dbg_flags & uath_dbg_flags) { + va_start(args, fmt); + vcmn_err(CE_CONT, fmt, args); + va_end(args); + } +} + +static uint_t +uath_lookup(uint16_t vendor_id, uint16_t product_id) +{ + int i, size; + + size = sizeof (uath_devs) / sizeof (struct uath_type); + + for (i = 0; i < size; i++) { + if ((vendor_id == uath_devs[i].dev.vendor_id) && + (product_id == uath_devs[i].dev.product_id)) + return (uath_devs[i].flags); + } + return (UATH_FLAG_ERR); +} + +/* + * Return a specific alt_if from the device descriptor tree. + */ +static usb_alt_if_data_t * +uath_lookup_alt_if(usb_client_dev_data_t *dev_data, uint_t config, + uint_t interface, uint_t alt) +{ + usb_cfg_data_t *cfg_data; + usb_if_data_t *if_data; + usb_alt_if_data_t *if_alt_data; + + /* + * Assume everything is in the tree for now, + * (USB_PARSE_LVL_ALL) + * so we can directly index the array. + */ + + /* Descend to configuration, configs are 1-based */ + if (config < 1 || config > dev_data->dev_n_cfg) + return (NULL); + cfg_data = &dev_data->dev_cfg[config - 1]; + + /* Descend to interface */ + if (interface > cfg_data->cfg_n_if - 1) + return (NULL); + if_data = &cfg_data->cfg_if[interface]; + + /* Descend to alt */ + if (alt > if_data->if_n_alt - 1) + return (NULL); + if_alt_data = &if_data->if_alt[alt]; + + return (if_alt_data); +} + +/* + * Print all endpoints of an alt_if. + */ +static void +uath_list_all_eps(usb_alt_if_data_t *ifalt) +{ + usb_ep_data_t *ep_data; + usb_ep_descr_t *ep_descr; + int i; + + for (i = 0; i < ifalt->altif_n_ep; i++) { + ep_data = &ifalt->altif_ep[i]; + ep_descr = &ep_data->ep_descr; + UATH_DEBUG(UATH_DBG_USB, + "uath: uath_list_all_endpoint: " + "ep addresa[%x] is %x", + i, ep_descr->bEndpointAddress); + } +} + +static usb_ep_data_t * +uath_lookup_ep_data(dev_info_t *dip, + usb_client_dev_data_t *dev_datap, + uint_t interface, + uint_t alternate, + uint8_t address, + uint8_t type) +{ + usb_alt_if_data_t *altif_data; + int i; + + if ((dip == NULL) || (dev_datap == NULL)) + return (NULL); + + altif_data = &dev_datap->dev_curr_cfg-> + cfg_if[interface].if_alt[alternate]; + + for (i = 0; i < altif_data->altif_n_ep; i++) { + usb_ep_descr_t *ept = &altif_data->altif_ep[i].ep_descr; + uint8_t ept_type = ept->bmAttributes & USB_EP_ATTR_MASK; + uint8_t ept_address = ept->bEndpointAddress; + + if (ept->bLength == 0) + continue; + if ((ept_type == type) && + ((type == USB_EP_ATTR_CONTROL) || (address == ept_address))) + return (&altif_data->altif_ep[i]); + } + return (NULL); +} + +/* + * Open communication pipes. + * The following pipes are used by the AR5523: + * ep0: 0x81 IN Rx cmd + * ep1: 0x01 OUT Tx cmd + * ep2: 0x82 IN Rx data + * ep3: 0x02 OUT Tx data + */ +static int +uath_open_pipes(struct uath_softc *sc) +{ + usb_ep_data_t *ep_node; + usb_ep_descr_t *ep_descr; + usb_pipe_policy_t policy; + int err; + +#ifdef DEBUG + usb_alt_if_data_t *altif_data; + + altif_data = uath_lookup_alt_if(sc->sc_udev, UATH_CONFIG_NO, + UATH_IFACE_INDEX, UATH_ALT_IF_INDEX); + if (altif_data == NULL) { + UATH_DEBUG(UATH_DBG_ERR, "alt_if not found"); + return (USB_FAILURE); + } + + uath_list_all_eps(altif_data); +#endif + + /* + * XXX pipes numbers are hardcoded because we don't have any way + * to distinguish the data pipes from the firmware command pipes + * (both are bulk pipes) using the endpoints descriptors. + */ + ep_node = uath_lookup_ep_data(sc->sc_dev, sc->sc_udev, + 0, 0, 0x81, USB_EP_ATTR_BULK); + ep_descr = &ep_node->ep_descr; + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_open_pipes(): " + "find pipe %x\n", ep_descr->bEndpointAddress); + + bzero(&policy, sizeof (usb_pipe_policy_t)); + policy.pp_max_async_reqs = UATH_CMD_LIST_COUNT; + + err = usb_pipe_open(sc->sc_dev, &ep_node->ep_descr, + &policy, USB_FLAGS_SLEEP, &sc->rx_cmd_pipe); + if (err != USB_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_open_pipes(): " + "failed to open rx data pipe, err = %x\n", + err); + goto fail; + } + + + ep_node = uath_lookup_ep_data(sc->sc_dev, sc->sc_udev, + 0, 0, 0x01, USB_EP_ATTR_BULK); + ep_descr = &ep_node->ep_descr; + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_open_pipes(): " + "find pipe %x\n", + ep_descr->bEndpointAddress); + + bzero(&policy, sizeof (usb_pipe_policy_t)); + policy.pp_max_async_reqs = UATH_CMD_LIST_COUNT; + + err = usb_pipe_open(sc->sc_dev, &ep_node->ep_descr, + &policy, USB_FLAGS_SLEEP, &sc->tx_cmd_pipe); + if (err != USB_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_open_pipes(): " + "failed to open tx command pipe, err = %x\n", + err); + goto fail; + } + + ep_node = uath_lookup_ep_data(sc->sc_dev, sc->sc_udev, + 0, 0, 0x82, USB_EP_ATTR_BULK); + ep_descr = &ep_node->ep_descr; + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_open_pipes(): " + "find pipe %x\n", + ep_descr->bEndpointAddress); + + bzero(&policy, sizeof (usb_pipe_policy_t)); + policy.pp_max_async_reqs = UATH_RX_DATA_LIST_COUNT; + + err = usb_pipe_open(sc->sc_dev, &ep_node->ep_descr, + &policy, USB_FLAGS_SLEEP, &sc->rx_data_pipe); + if (err != USB_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_open_pipes(): " + "failed to open tx pipe, err = %x\n", + err); + goto fail; + } + + ep_node = uath_lookup_ep_data(sc->sc_dev, sc->sc_udev, + 0, 0, 0x02, USB_EP_ATTR_BULK); + ep_descr = &ep_node->ep_descr; + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_open_pipes(): " + "find pipe %x\n", + ep_descr->bEndpointAddress); + + bzero(&policy, sizeof (usb_pipe_policy_t)); + policy.pp_max_async_reqs = UATH_TX_DATA_LIST_COUNT; + + err = usb_pipe_open(sc->sc_dev, &ep_node->ep_descr, + &policy, USB_FLAGS_SLEEP, &sc->tx_data_pipe); + if (err != USB_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_open_pipes(): " + "failed to open rx command pipe, err = %x\n", + err); + goto fail; + } + + return (UATH_SUCCESS); +fail: + uath_close_pipes(sc); + return (err); +} + +static void +uath_close_pipes(struct uath_softc *sc) +{ + usb_flags_t flags = USB_FLAGS_SLEEP; + + if (sc->rx_cmd_pipe != NULL) { + usb_pipe_reset(sc->sc_dev, sc->rx_cmd_pipe, flags, NULL, 0); + usb_pipe_close(sc->sc_dev, sc->rx_cmd_pipe, flags, NULL, 0); + sc->rx_cmd_pipe = NULL; + } + + if (sc->tx_cmd_pipe != NULL) { + usb_pipe_reset(sc->sc_dev, sc->tx_cmd_pipe, flags, NULL, 0); + usb_pipe_close(sc->sc_dev, sc->tx_cmd_pipe, flags, NULL, 0); + sc->tx_cmd_pipe = NULL; + } + + if (sc->rx_data_pipe != NULL) { + usb_pipe_reset(sc->sc_dev, sc->rx_data_pipe, flags, NULL, 0); + usb_pipe_close(sc->sc_dev, sc->rx_data_pipe, flags, NULL, 0); + sc->rx_data_pipe = NULL; + } + + if (sc->tx_data_pipe != NULL) { + usb_pipe_reset(sc->sc_dev, sc->tx_data_pipe, flags, NULL, 0); + usb_pipe_close(sc->sc_dev, sc->tx_data_pipe, flags, NULL, 0); + sc->tx_data_pipe = NULL; + } + +} + +static const char * +uath_codename(int code) +{ +#define N(a) (sizeof (a)/sizeof (a[0])) + static const char *names[] = { + "0x00", + "HOST_AVAILABLE", + "BIND", + "TARGET_RESET", + "TARGET_GET_CAPABILITY", + "TARGET_SET_CONFIG", + "TARGET_GET_STATUS", + "TARGET_GET_STATS", + "TARGET_START", + "TARGET_STOP", + "TARGET_ENABLE", + "TARGET_DISABLE", + "CREATE_CONNECTION", + "UPDATE_CONNECT_ATTR", + "DELETE_CONNECT", + "SEND", + "FLUSH", + "STATS_UPDATE", + "BMISS", + "DEVICE_AVAIL", + "SEND_COMPLETE", + "DATA_AVAIL", + "SET_PWR_MODE", + "BMISS_ACK", + "SET_LED_STEADY", + "SET_LED_BLINK", + "SETUP_BEACON_DESC", + "BEACON_INIT", + "RESET_KEY_CACHE", + "RESET_KEY_CACHE_ENTRY", + "SET_KEY_CACHE_ENTRY", + "SET_DECOMP_MASK", + "SET_REGULATORY_DOMAIN", + "SET_LED_STATE", + "WRITE_ASSOCID", + "SET_STA_BEACON_TIMERS", + "GET_TSF", + "RESET_TSF", + "SET_ADHOC_MODE", + "SET_BASIC_RATE", + "MIB_CONTROL", + "GET_CHANNEL_DATA", + "GET_CUR_RSSI", + "SET_ANTENNA_SWITCH", + "0x2c", "0x2d", "0x2e", + "USE_SHORT_SLOT_TIME", + "SET_POWER_MODE", + "SETUP_PSPOLL_DESC", + "SET_RX_MULTICAST_FILTER", + "RX_FILTER", + "PER_CALIBRATION", + "RESET", + "DISABLE", + "PHY_DISABLE", + "SET_TX_POWER_LIMIT", + "SET_TX_QUEUE_PARAMS", + "SETUP_TX_QUEUE", + "RELEASE_TX_QUEUE", + }; + static char buf[8]; + + if (code < N(names)) + return (names[code]); + if (code == WDCMSG_SET_DEFAULT_KEY) + return ("SET_DEFAULT_KEY"); + + (void) snprintf(buf, sizeof (buf), "0x%02x", code); + return (buf); +#undef N +} + +static int +uath_fw_send(struct uath_softc *sc, usb_pipe_handle_t pipe, + const void *data, size_t len) +{ + usb_bulk_req_t *send_req; + mblk_t *mblk; + int res; + + send_req = usb_alloc_bulk_req(sc->sc_dev, len, USB_FLAGS_SLEEP); + + send_req->bulk_len = (int)len; + send_req->bulk_attributes = USB_ATTRS_AUTOCLEARING; + send_req->bulk_timeout = UATH_CMD_TIMEOUT; + + mblk = send_req->bulk_data; + bcopy(data, mblk->b_wptr, len); + mblk->b_wptr += len; + + res = usb_pipe_bulk_xfer(pipe, send_req, USB_FLAGS_SLEEP); + if (res != USB_SUCCESS) { + UATH_DEBUG(UATH_DBG_FW, "uath: uath_fw_send(): " + "Error %x writing data to bulk/out pipe", res); + return (UATH_FAILURE); + } + + usb_free_bulk_req(send_req); + return (UATH_SUCCESS); +} + +static int +uath_fw_ack(struct uath_softc *sc, int len) +{ + struct uath_fwblock *rxblock; + usb_bulk_req_t *req; + mblk_t *mp; + int err; + + req = usb_alloc_bulk_req(sc->sc_dev, len, USB_FLAGS_SLEEP); + if (req == NULL) { + UATH_DEBUG(UATH_DBG_FW, + "uath: uath_fw_ack(): " + "uath_rx_transfer(): failed to allocate req"); + return (UATH_FAILURE); + } + + req->bulk_len = len; + req->bulk_client_private = (usb_opaque_t)sc; + req->bulk_timeout = 0; + req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK + | USB_ATTRS_AUTOCLEARING; + + err = usb_pipe_bulk_xfer(sc->rx_cmd_pipe, req, USB_FLAGS_SLEEP); + if (err != USB_SUCCESS) { + UATH_DEBUG(UATH_DBG_FW, "uath: uath_fw_ack(): " + "failed to do rx xfer, %d", err); + usb_free_bulk_req(req); + return (UATH_FAILURE); + } + + mp = req->bulk_data; + req->bulk_data = NULL; + + rxblock = (struct uath_fwblock *)mp->b_rptr; + UATH_DEBUG(UATH_DBG_FW, "uath: uath_fw_ack() " + "rxblock flags=0x%x total=%d\n", + BE_32(rxblock->flags), BE_32(rxblock->rxtotal)); + + freemsg(mp); + usb_free_bulk_req(req); + + return (UATH_SUCCESS); +} + +/* + * find uath firmware module's "_start" "_end" symbols + * and get its size. + */ +static int +uath_loadsym(ddi_modhandle_t modp, char *sym, char **start, size_t *len) +{ + char start_sym[64]; + char end_sym[64]; + char *p, *end; + int rv; + size_t n; + + (void) snprintf(start_sym, sizeof (start_sym), "%s_start", sym); + (void) snprintf(end_sym, sizeof (end_sym), "%s_end", sym); + + p = (char *)ddi_modsym(modp, start_sym, &rv); + if (p == NULL || rv != 0) { + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_loadsym(): " + "mod %s: symbol %s not found\n", uath_fwmod, start_sym); + return (UATH_FAILURE); + } + + end = (char *)ddi_modsym(modp, end_sym, &rv); + if (end == NULL || rv != 0) { + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_loadsym(): " + "mod %s: symbol %s not found\n", uath_fwmod, end_sym); + return (UATH_FAILURE); + } + + n = _PTRDIFF(end, p); + *start = p; + *len = n; + + return (UATH_SUCCESS); +} + +/* + * Load the MIPS R4000 microcode into the device. Once the image is loaded, + * the device will detach itself from the bus and reattach later with a new + * product Id (a la ezusb). XXX this could also be implemented in userland + * through /dev/ugen. + */ +static int +uath_loadfirmware(struct uath_softc *sc) +{ + struct uath_fwblock txblock; + ddi_modhandle_t modp; + char *fw_index, *fw_image = NULL; + size_t fw_size, len; + int err = DDI_SUCCESS, rv = 0; + + modp = ddi_modopen(uath_fwmod, KRTLD_MODE_FIRST, &rv); + if (modp == NULL) { + cmn_err(CE_WARN, "uath: uath_loadfirmware(): " + "module %s not found\n", uath_fwmod); + goto label; + } + + err = uath_loadsym(modp, uath_binmod, &fw_index, &fw_size); + if (err != UATH_SUCCESS) { + cmn_err(CE_WARN, "uath: uath_loadfirmware(): " + "could not get firmware\n"); + goto label; + } + + fw_image = (char *)kmem_alloc(fw_size, KM_SLEEP); + if (fw_image == NULL) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_loadfirmware(): " + "failed to alloc firmware memory\n"); + err = UATH_FAILURE; + goto label; + } + + (void) memcpy(fw_image, fw_index, fw_size); + fw_index = fw_image; + len = fw_size; + UATH_DEBUG(UATH_DBG_MSG, "loading firmware size = %lu\n", fw_size); + + /* bzero(txblock, sizeof (struct uath_fwblock)); */ + txblock.flags = BE_32(UATH_WRITE_BLOCK); + txblock.total = BE_32(fw_size); + + while (len > 0) { + size_t mlen = min(len, UATH_MAX_FWBLOCK_SIZE); + + txblock.remain = BE_32(len - mlen); + txblock.len = BE_32(mlen); + + UATH_DEBUG(UATH_DBG_FW, "uath: uath_loadfirmware(): " + "sending firmware block: %d bytes sending\n", mlen); + UATH_DEBUG(UATH_DBG_FW, "uath: uath_loadfirmware(): " + "sending firmware block: %d bytes remaining\n", + len - mlen); + + /* send firmware block meta-data */ + err = uath_fw_send(sc, sc->tx_cmd_pipe, &txblock, + sizeof (struct uath_fwblock)); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_FW, "uath: uath_loadfirmware(): " + "send block meta-data error"); + goto label; + } + + /* send firmware block data */ + err = uath_fw_send(sc, sc->tx_data_pipe, fw_index, mlen); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_FW, "uath: uath_loadfirmware() " + "send block data err"); + goto label; + } + + /* wait for ack from firmware */ + err = uath_fw_ack(sc, sizeof (struct uath_fwblock)); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_FW, "uath: uath_loadfirmware() " + "rx block ack err"); + goto label; + } + + fw_index += mlen; + len -= mlen; + } + +label: + if (fw_image != NULL) + kmem_free(fw_image, fw_size); + fw_image = fw_index = NULL; + if (modp != NULL) + (void) ddi_modclose(modp); + return (err); +} + +static int +uath_alloc_cmd_list(struct uath_softc *sc, struct uath_cmd cmds[], + int ncmd, int maxsz) +{ + int i, err; + + for (i = 0; i < ncmd; i++) { + struct uath_cmd *cmd = &cmds[i]; + + cmd->sc = sc; /* backpointer for callbacks */ + cmd->msgid = i; + cmd->buf = kmem_zalloc(maxsz, KM_NOSLEEP); + if (cmd->buf == NULL) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_alloc_cmd_list(): " + "could not allocate xfer buffer\n"); + err = DDI_ENOMEM; + goto fail; + } + } + return (UATH_SUCCESS); + +fail: + uath_free_cmd_list(cmds, ncmd); + return (err); +} + +static int +uath_init_cmd_list(struct uath_softc *sc) +{ + int i; + + sc->sc_cmdid = sc->rx_cmd_queued = sc->tx_cmd_queued = 0; + for (i = 0; i < UATH_CMD_LIST_COUNT; i++) { + if (uath_rx_cmd_xfer(sc) != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_init_cmd_list(): " + "failed to init cmd list %x\n", i); + return (UATH_FAILURE); + } + } + return (UATH_SUCCESS); +} + +static void +uath_free_cmd_list(struct uath_cmd cmds[], int ncmd) +{ + int i; + + for (i = 0; i < ncmd; i++) + if (cmds[i].buf != NULL) { + kmem_free(cmds[i].buf, UATH_MAX_CMDSZ); + cmds[i].buf = NULL; + } +} + +static int +uath_host_available(struct uath_softc *sc) +{ + struct uath_cmd_host_available setup; + + /* inform target the host is available */ + setup.sw_ver_major = BE_32(ATH_SW_VER_MAJOR); + setup.sw_ver_minor = BE_32(ATH_SW_VER_MINOR); + setup.sw_ver_patch = BE_32(ATH_SW_VER_PATCH); + setup.sw_ver_build = BE_32(ATH_SW_VER_BUILD); + return (uath_cmd_read(sc, WDCMSG_HOST_AVAILABLE, + &setup, sizeof (setup), NULL, 0, 0)); +} + +static void +uath_get_capability(struct uath_softc *sc, uint32_t cap, uint32_t *val) +{ + int err; + + cap = BE_32(cap); + err = uath_cmd_read(sc, WDCMSG_TARGET_GET_CAPABILITY, &cap, + sizeof (cap), val, sizeof (uint32_t), UATH_CMD_FLAG_MAGIC); + if (err == UATH_SUCCESS) + *val = BE_32(*val); + else + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_get_capability(): " + "could not read capability %u\n", BE_32(cap)); +} + +static int +uath_get_devcap(struct uath_softc *sc) +{ + struct uath_devcap *cap = &sc->sc_devcap; + + /* collect device capabilities */ + uath_get_capability(sc, CAP_TARGET_VERSION, + &cap->targetVersion); + uath_get_capability(sc, CAP_TARGET_REVISION, + &cap->targetRevision); + uath_get_capability(sc, CAP_MAC_VERSION, + &cap->macVersion); + uath_get_capability(sc, CAP_MAC_REVISION, + &cap->macRevision); + uath_get_capability(sc, CAP_PHY_REVISION, + &cap->phyRevision); + uath_get_capability(sc, CAP_ANALOG_5GHz_REVISION, + &cap->analog5GhzRevision); + uath_get_capability(sc, CAP_ANALOG_2GHz_REVISION, + &cap->analog2GhzRevision); + uath_get_capability(sc, CAP_REG_DOMAIN, + &cap->regDomain); + uath_get_capability(sc, CAP_REG_CAP_BITS, + &cap->regCapBits); + + /* NB: not supported in rev 1.5 */ + /* uath_get_capability(sc, CAP_COUNTRY_CODE, cap->countryCode); */ + + uath_get_capability(sc, CAP_WIRELESS_MODES, + &cap->wirelessModes); + uath_get_capability(sc, CAP_CHAN_SPREAD_SUPPORT, + &cap->chanSpreadSupport); + uath_get_capability(sc, CAP_COMPRESS_SUPPORT, + &cap->compressSupport); + uath_get_capability(sc, CAP_BURST_SUPPORT, + &cap->burstSupport); + uath_get_capability(sc, CAP_FAST_FRAMES_SUPPORT, + &cap->fastFramesSupport); + uath_get_capability(sc, CAP_CHAP_TUNING_SUPPORT, + &cap->chapTuningSupport); + uath_get_capability(sc, CAP_TURBOG_SUPPORT, + &cap->turboGSupport); + uath_get_capability(sc, CAP_TURBO_PRIME_SUPPORT, + &cap->turboPrimeSupport); + uath_get_capability(sc, CAP_DEVICE_TYPE, + &cap->deviceType); + uath_get_capability(sc, CAP_WME_SUPPORT, + &cap->wmeSupport); + uath_get_capability(sc, CAP_TOTAL_QUEUES, + &cap->numTxQueues); + uath_get_capability(sc, CAP_CONNECTION_ID_MAX, + &cap->connectionIdMax); + + uath_get_capability(sc, CAP_LOW_5GHZ_CHAN, + &cap->low5GhzChan); + uath_get_capability(sc, CAP_HIGH_5GHZ_CHAN, + &cap->high5GhzChan); + uath_get_capability(sc, CAP_LOW_2GHZ_CHAN, + &cap->low2GhzChan); + uath_get_capability(sc, CAP_HIGH_2GHZ_CHAN, + &cap->high2GhzChan); + uath_get_capability(sc, CAP_TWICE_ANTENNAGAIN_5G, + &cap->twiceAntennaGain5G); + uath_get_capability(sc, CAP_TWICE_ANTENNAGAIN_2G, + &cap->twiceAntennaGain2G); + + uath_get_capability(sc, CAP_CIPHER_AES_CCM, + &cap->supportCipherAES_CCM); + uath_get_capability(sc, CAP_CIPHER_TKIP, + &cap->supportCipherTKIP); + uath_get_capability(sc, CAP_MIC_TKIP, + &cap->supportMicTKIP); + + cap->supportCipherWEP = 1; /* NB: always available */ + return (UATH_SUCCESS); +} + +static int +uath_get_status(struct uath_softc *sc, uint32_t which, void *odata, int olen) +{ + int err; + + which = BE_32(which); + err = uath_cmd_read(sc, WDCMSG_TARGET_GET_STATUS, + &which, sizeof (which), odata, olen, UATH_CMD_FLAG_MAGIC); + if (err != UATH_SUCCESS) + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_get_status(): " + "could not read EEPROM offset 0x%02x\n", BE_32(which)); + return (err); +} + +static int +uath_get_devstatus(struct uath_softc *sc, uint8_t macaddr[IEEE80211_ADDR_LEN]) +{ + int err; + + /* retrieve MAC address */ + err = uath_get_status(sc, ST_MAC_ADDR, macaddr, IEEE80211_ADDR_LEN); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_get_devstatus(): " + "could not read MAC address\n"); + return (err); + } + + err = uath_get_status(sc, ST_SERIAL_NUMBER, + &sc->sc_serial[0], sizeof (sc->sc_serial)); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_get_devstatus(): " + "could not read device serial number\n"); + return (err); + } + + return (UATH_SUCCESS); +} + +/* + * uath_cmd_lock: a special signal structure that is used for notification + * that a callback function has been called. + */ + +/* Initializes the uath_cmd_lock structure. */ +static void +uath_cmd_lock_init(struct uath_cmd_lock *lock) +{ + ASSERT(lock != NULL); + mutex_init(&lock->mutex, NULL, MUTEX_DRIVER, NULL); + cv_init(&lock->cv, NULL, CV_DRIVER, NULL); + lock->done = B_FALSE; +} + +/* Deinitalizes the uath_cb_lock structure. */ +void +uath_cmd_lock_destroy(struct uath_cmd_lock *lock) +{ + ASSERT(lock != NULL); + mutex_destroy(&lock->mutex); + cv_destroy(&lock->cv); +} + +/* + * Wait on lock until someone calls the "signal" function or the timeout + * expires. Note: timeout is in microseconds. + */ +static int +uath_cmd_lock_wait(struct uath_cmd_lock *lock, clock_t timeout) +{ + int res, cv_res; + clock_t etime; + + ASSERT(lock != NULL); + mutex_enter(&lock->mutex); + + if (timeout < 0) { + /* no timeout - wait as long as needed */ + while (lock->done == B_FALSE) + cv_wait(&lock->cv, &lock->mutex); + } else { + /* wait with timeout (given in usec) */ + etime = ddi_get_lbolt() + drv_usectohz(timeout); + while (lock->done == B_FALSE) { + cv_res = cv_timedwait_sig(&lock->cv, + &lock->mutex, etime); + if (cv_res <= 0) break; + } + } + + res = (lock->done == B_TRUE) ? UATH_SUCCESS : UATH_FAILURE; + mutex_exit(&lock->mutex); + + return (res); +} + +/* Signal that the job (eg. callback) is done and unblock anyone who waits. */ +static void +uath_cmd_lock_signal(struct uath_cmd_lock *lock) +{ + ASSERT(lock != NULL); + + mutex_enter(&lock->mutex); + lock->done = B_TRUE; + cv_broadcast(&lock->cv); + mutex_exit(&lock->mutex); +} + +static int +uath_cmd_read(struct uath_softc *sc, uint32_t code, const void *idata, + int ilen, void *odata, int olen, int flags) +{ + flags |= UATH_CMD_FLAG_READ; + return (uath_cmdsend(sc, code, idata, ilen, odata, olen, flags)); +} + +static int +uath_cmd_write(struct uath_softc *sc, uint32_t code, const void *data, + int len, int flags) +{ + flags &= ~UATH_CMD_FLAG_READ; + return (uath_cmdsend(sc, code, data, len, NULL, 0, flags)); +} + +/* + * Low-level function to send read or write commands to the firmware. + */ +static int +uath_cmdsend(struct uath_softc *sc, uint32_t code, const void *idata, int ilen, + void *odata, int olen, int flags) +{ + struct uath_cmd_hdr *hdr; + struct uath_cmd *cmd; + int err; + + /* grab a xfer */ + cmd = &sc->sc_cmd[sc->sc_cmdid]; + + cmd->flags = flags; + /* always bulk-out a multiple of 4 bytes */ + cmd->buflen = (sizeof (struct uath_cmd_hdr) + ilen + 3) & ~3; + + hdr = (struct uath_cmd_hdr *)cmd->buf; + bzero(hdr, sizeof (struct uath_cmd_hdr)); + hdr->len = BE_32(cmd->buflen); + hdr->code = BE_32(code); + hdr->msgid = cmd->msgid; /* don't care about endianness */ + hdr->magic = BE_32((cmd->flags & UATH_CMD_FLAG_MAGIC) ? 1 << 24 : 0); + bcopy(idata, (uint8_t *)(hdr + 1), ilen); + + UATH_DEBUG(UATH_DBG_TX_CMD, "uath: uath_cmdsend(): " + "queue %x send %s [flags 0x%x] olen %d\n", + cmd->msgid, uath_codename(code), cmd->flags, olen); + + cmd->odata = odata; + if (odata == NULL) + UATH_DEBUG(UATH_DBG_TX_CMD, "uath: uath_cmdsend(): " + "warning - odata is NULL\n"); + else if (olen < UATH_MAX_CMDSZ - sizeof (*hdr) + sizeof (uint32_t)) + UATH_DEBUG(UATH_DBG_TX_CMD, "uath: uath_cmdsend(): " + "warning - olen %x is short\n, olen"); + cmd->olen = olen; + + err = uath_tx_cmd_xfer(sc, sc->tx_cmd_pipe, cmd->buf, cmd->buflen); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_cmdsend(): " + "Error writing command\n"); + return (UATH_FAILURE); + } + + sc->sc_cmdid = (sc->sc_cmdid + 1) % UATH_CMD_LIST_COUNT; + + if (cmd->flags & UATH_CMD_FLAG_READ) { + /* wait at most two seconds for command reply */ + uath_cmd_lock_init(&sc->rlock); + err = uath_cmd_lock_wait(&sc->rlock, 2000000); + cmd->odata = NULL; /* in case reply comes too late */ + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_cmdsend(): " + "timeout waiting for reply, " + "to cmd 0x%x (%u), queue %x\n", + code, code, cmd->msgid); + err = UATH_FAILURE; + } else if (cmd->olen != olen) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_cmdsend(): " + "unexpected reply data count " + "to cmd 0x%x (%x), got %u, expected %u\n", + code, cmd->msgid, cmd->olen, olen); + err = UATH_FAILURE; + } + uath_cmd_lock_destroy(&sc->rlock); + return (err); + } + + return (UATH_SUCCESS); +} + +/* ARGSUSED */ +static void +uath_cmd_txeof(usb_pipe_handle_t pipe, struct usb_bulk_req *req) +{ + struct uath_softc *sc = (struct uath_softc *)req->bulk_client_private; + + UATH_DEBUG(UATH_DBG_TX_CMD, "uath: uath_cmd_txeof(): " + "cr:%s(%d), flags:0x%x, tx queued %d\n", + usb_str_cr(req->bulk_completion_reason), + req->bulk_completion_reason, + req->bulk_cb_flags, + sc->tx_cmd_queued); + + if (req->bulk_completion_reason != USB_CR_OK) + sc->sc_tx_err++; + + mutex_enter(&sc->sc_txlock_cmd); + sc->tx_cmd_queued--; + mutex_exit(&sc->sc_txlock_cmd); + usb_free_bulk_req(req); +} + +static int +uath_tx_cmd_xfer(struct uath_softc *sc, + usb_pipe_handle_t pipe, const void *data, uint_t len) +{ + usb_bulk_req_t *send_req; + mblk_t *mblk; + int res; + + send_req = usb_alloc_bulk_req(sc->sc_dev, len, USB_FLAGS_SLEEP); + + send_req->bulk_client_private = (usb_opaque_t)sc; + send_req->bulk_len = (int)len; + send_req->bulk_attributes = USB_ATTRS_AUTOCLEARING; + send_req->bulk_timeout = UATH_CMD_TIMEOUT; + send_req->bulk_cb = uath_cmd_txeof; + send_req->bulk_exc_cb = uath_cmd_txeof; + send_req->bulk_completion_reason = 0; + send_req->bulk_cb_flags = 0; + + mblk = send_req->bulk_data; + bcopy(data, mblk->b_rptr, len); + mblk->b_wptr += len; + + res = usb_pipe_bulk_xfer(pipe, send_req, USB_FLAGS_NOSLEEP); + if (res != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_tx_cmd_xfer(): " + "Error %x writing cmd to bulk/out pipe", res); + return (UATH_FAILURE); + } + + mutex_enter(&sc->sc_txlock_cmd); + sc->tx_cmd_queued++; + mutex_exit(&sc->sc_txlock_cmd); + return (UATH_SUCCESS); +} + +static void +uath_cmdeof(struct uath_softc *sc, struct uath_cmd *cmd) +{ + struct uath_cmd_hdr *hdr; + int dlen; + + hdr = (struct uath_cmd_hdr *)cmd->buf; + + hdr->code = BE_32(hdr->code); + hdr->len = BE_32(hdr->len); + hdr->magic = BE_32(hdr->magic); /* target status on return */ + + /* NB: msgid is passed thru w/o byte swapping */ + UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_cmdeof(): " + "%s: [ix %x] len=%x status %x\n", + uath_codename(hdr->code), + hdr->msgid, + hdr->len, + hdr->magic); + + switch (hdr->code & 0xff) { + /* reply to a read command */ + default: + dlen = hdr->len - sizeof (*hdr); + UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_cmdeof(): " + "code %x data len %u\n", + hdr->code & 0xff, dlen); + + /* + * The first response from the target after the + * HOST_AVAILABLE has an invalid msgid so we must + * treat it specially. + */ + if ((hdr->msgid < UATH_CMD_LIST_COUNT) && (hdr->code != 0x13)) { + uint32_t *rp = (uint32_t *)(hdr + 1); + uint_t olen; + + if (!(sizeof (*hdr) <= hdr->len && + hdr->len < UATH_MAX_CMDSZ)) { + UATH_DEBUG(UATH_DBG_RX_CMD, + "uath: uath_cmdeof(): " + "invalid WDC msg length %u; " + "msg ignored\n", + hdr->len); + return; + } + + /* + * Calculate return/receive payload size; the + * first word, if present, always gives the + * number of bytes--unless it's 0 in which + * case a single 32-bit word should be present. + */ + if (dlen >= sizeof (uint32_t)) { + olen = BE_32(rp[0]); + dlen -= sizeof (uint32_t); + if (olen == 0) { + /* convention is 0 =>'s one word */ + olen = sizeof (uint32_t); + /* XXX KASSERT(olen == dlen ) */ + } + } else + olen = 0; + + if (cmd->odata != NULL) { + /* NB: cmd->olen validated in uath_cmd */ + if (olen > cmd->olen) { + /* XXX complain? */ + UATH_DEBUG(UATH_DBG_RX_CMD, + "uath: uath_cmdeof(): " + "cmd 0x%x olen %u cmd olen %u\n", + hdr->code, olen, cmd->olen); + olen = cmd->olen; + } + if (olen > dlen) { + /* XXX complain, shouldn't happen */ + UATH_DEBUG(UATH_DBG_RX_CMD, + "uath: uath_cmdeof(): " + "cmd 0x%x olen %u dlen %u\n", + hdr->code, olen, dlen); + olen = dlen; + } + /* XXX have submitter do this */ + /* copy answer into caller's supplied buffer */ + bcopy(&rp[1], cmd->odata, olen); + cmd->olen = olen; + } + } + + /* Just signal that something happened */ + uath_cmd_lock_signal(&sc->rlock); + break; + + case WDCMSG_TARGET_START: + UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_cmdeof(): " + "receive TARGET STAERT\n"); + + if (hdr->msgid >= UATH_CMD_LIST_COUNT) { + /* XXX */ + return; + } + dlen = hdr->len - sizeof (*hdr); + if (dlen != sizeof (uint32_t)) { + /* XXX something wrong */ + return; + } + /* XXX have submitter do this */ + /* copy answer into caller's supplied buffer */ + bcopy(hdr + 1, cmd->odata, sizeof (uint32_t)); + cmd->olen = sizeof (uint32_t); + + /* wake up caller */ + uath_cmd_lock_signal(&sc->rlock); + break; + + case WDCMSG_SEND_COMPLETE: + /* this notification is sent when UATH_TX_NOTIFY is set */ + UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_cmdeof(): " + "receive Tx notification\n"); + break; + + case WDCMSG_TARGET_GET_STATS: + UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_cmdeof(): " + "received device statistics\n"); + break; + } +} + +/* ARGSUSED */ +static void +uath_cmd_rxeof(usb_pipe_handle_t pipe, usb_bulk_req_t *req) +{ + struct uath_softc *sc = (struct uath_softc *)req->bulk_client_private; + struct uath_cmd_hdr *hdr; + struct uath_cmd *cmd; + mblk_t *m, *mp; + int len; + + UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_cmd_rxeof(): " + "cr:%s(%d), flags:0x%x, rx queued %d\n", + usb_str_cr(req->bulk_completion_reason), + req->bulk_completion_reason, + req->bulk_cb_flags, + sc->rx_cmd_queued); + + m = req->bulk_data; + req->bulk_data = NULL; + + if (req->bulk_completion_reason != USB_CR_OK) { + UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_cmd_rxeof(): " + "USB CR is not OK\n"); + goto fail; + } + + if (m->b_cont != NULL) { + /* Fragmented message, concatenate */ + mp = msgpullup(m, -1); + freemsg(m); + m = mp; + mp = NULL; + } + + len = msgdsize(m); + if (len < sizeof (struct uath_cmd_hdr)) { + UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_rx_cmdeof(): " + "short xfer error\n"); + goto fail; + } + + hdr = (struct uath_cmd_hdr *)m->b_rptr; + if (BE_32(hdr->code) == 0x13) + cmd = &sc->sc_cmd[0]; + else + cmd = &sc->sc_cmd[hdr->msgid]; + + bcopy(m->b_rptr, cmd->buf, len); + uath_cmdeof(sc, cmd); + (void) uath_rx_cmd_xfer(sc); +fail: + mutex_enter(&sc->sc_rxlock_cmd); + sc->rx_cmd_queued--; + mutex_exit(&sc->sc_rxlock_cmd); + if (m) freemsg(m); + usb_free_bulk_req(req); +} + +static int +uath_rx_cmd_xfer(struct uath_softc *sc) +{ + usb_bulk_req_t *req; + int err; + + req = usb_alloc_bulk_req(sc->sc_dev, UATH_MAX_CMDSZ, USB_FLAGS_SLEEP); + if (req == NULL) { + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_rx_cmd_xfer(): " + "failed to allocate req"); + return (UATH_FAILURE); + } + + req->bulk_len = UATH_MAX_CMDSZ; + req->bulk_client_private = (usb_opaque_t)sc; + req->bulk_cb = uath_cmd_rxeof; + req->bulk_exc_cb = uath_cmd_rxeof; + req->bulk_timeout = 0; + req->bulk_completion_reason = 0; + req->bulk_cb_flags = 0; + req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK + | USB_ATTRS_AUTOCLEARING; + + err = usb_pipe_bulk_xfer(sc->rx_cmd_pipe, req, USB_FLAGS_NOSLEEP); + if (err != USB_SUCCESS) { + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_rx_cmd_xfer(): " + "failed to do rx xfer, %d", err); + usb_free_bulk_req(req); + return (UATH_FAILURE); + } + + mutex_enter(&sc->sc_rxlock_cmd); + sc->rx_cmd_queued++; + mutex_exit(&sc->sc_rxlock_cmd); + return (UATH_SUCCESS); +} + +static void +uath_init_data_queue(struct uath_softc *sc) +{ + sc->tx_data_queued = sc->rx_data_queued = 0; +} + +/* ARGSUSED */ +static void +uath_data_txeof(usb_pipe_handle_t pipe, usb_bulk_req_t *req) +{ + struct uath_softc *sc = (struct uath_softc *)req->bulk_client_private; + struct ieee80211com *ic = &sc->sc_ic; + + UATH_DEBUG(UATH_DBG_TX, "uath: uath_data_txeof(): " + "uath_txeof(): cr:%s(%d), flags:0x%x, tx_data_queued %d\n", + usb_str_cr(req->bulk_completion_reason), + req->bulk_completion_reason, + req->bulk_cb_flags, + sc->tx_data_queued); + + if (req->bulk_completion_reason != USB_CR_OK) + sc->sc_tx_err++; + + mutex_enter(&sc->sc_txlock_data); + sc->tx_data_queued--; + + if (sc->sc_need_sched) { + sc->sc_need_sched = 0; + mac_tx_update(ic->ic_mach); + } + + mutex_exit(&sc->sc_txlock_data); + usb_free_bulk_req(req); +} + +static int +uath_tx_data_xfer(struct uath_softc *sc, mblk_t *mp) +{ + usb_bulk_req_t *req; + int err; + + req = usb_alloc_bulk_req(sc->sc_dev, 0, USB_FLAGS_SLEEP); + if (req == NULL) { + UATH_DEBUG(UATH_DBG_TX, "uath: uath_tx_data_xfer(): " + "uath_tx_data_xfer(): failed to allocate req"); + freemsg(mp); + return (UATH_FAILURE); + } + + req->bulk_len = msgdsize(mp); + req->bulk_data = mp; + req->bulk_client_private = (usb_opaque_t)sc; + req->bulk_timeout = UATH_DATA_TIMEOUT; + req->bulk_attributes = USB_ATTRS_AUTOCLEARING; + req->bulk_cb = uath_data_txeof; + req->bulk_exc_cb = uath_data_txeof; + req->bulk_completion_reason = 0; + req->bulk_cb_flags = 0; + + if ((err = usb_pipe_bulk_xfer(sc->tx_data_pipe, req, 0)) != + USB_SUCCESS) { + + UATH_DEBUG(UATH_DBG_TX, "uath: uath_tx_data_xfer(): " + "failed to do tx xfer, %d", err); + usb_free_bulk_req(req); + return (UATH_FAILURE); + } + + sc->tx_data_queued++; + return (UATH_SUCCESS); +} + +/* ARGSUSED */ +static void +uath_data_rxeof(usb_pipe_handle_t pipe, usb_bulk_req_t *req) +{ + struct uath_softc *sc = (struct uath_softc *)req->bulk_client_private; + struct ieee80211com *ic = &sc->sc_ic; + struct uath_chunk *chunk; + struct uath_rx_desc *desc; + struct ieee80211_frame *wh; + struct ieee80211_node *ni; + + mblk_t *m, *mp; + uint8_t *rxbuf; + int actlen, pktlen; + + mutex_enter(&sc->sc_rxlock_data); + + UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): " + "cr:%s(%d), flags:0x%x, rx_data_queued %d\n", + usb_str_cr(req->bulk_completion_reason), + req->bulk_completion_reason, + req->bulk_cb_flags, + sc->rx_data_queued); + + mp = req->bulk_data; + req->bulk_data = NULL; + + if (req->bulk_completion_reason != USB_CR_OK) { + UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): " + "USB CR is not OK\n"); + sc->sc_rx_err++; + goto fail; + } + + rxbuf = (uint8_t *)mp->b_rptr; + actlen = (uintptr_t)mp->b_wptr - (uintptr_t)mp->b_rptr; + if (actlen < UATH_MIN_RXBUFSZ) { + UATH_DEBUG(UATH_DBG_RX, "uath_data_rxeof(): " + "wrong recv size %d\n", actlen); + sc->sc_rx_err++; + goto fail; + } + + chunk = (struct uath_chunk *)rxbuf; + if (chunk->seqnum == 0 && chunk->flags == 0 && chunk->length == 0) { + UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): " + "strange response\n"); + UATH_RESET_INTRX(sc); + sc->sc_rx_err++; + goto fail; + } + + if (chunk->seqnum != sc->sc_intrx_nextnum) { + UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): " + "invalid seqnum %d, expected %d\n", + chunk->seqnum, sc->sc_intrx_nextnum); + UATH_STAT_INC(sc, st_badchunkseqnum); + UATH_RESET_INTRX(sc); + sc->sc_rx_err++; + goto fail; + } + + /* check multi-chunk frames */ + if ((chunk->seqnum == 0 && !(chunk->flags & UATH_CFLAGS_FINAL)) || + (chunk->seqnum != 0 && (chunk->flags & UATH_CFLAGS_FINAL)) || + chunk->flags & UATH_CFLAGS_RXMSG) { + UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): " + "receive multi-chunk frames " + "chunk seqnum %x, flags %x, length %u\n", + chunk->seqnum, chunk->flags, BE_16(chunk->length)); + UATH_STAT_INC(sc, st_multichunk); + } + + + /* if the frame is not final continue the transfer */ + if (!(chunk->flags & UATH_CFLAGS_FINAL)) + sc->sc_intrx_nextnum++; + + /* + * if the frame is not set UATH_CFLAGS_RXMSG, then rx descriptor is + * located at the end, 32-bit aligned + */ + desc = (chunk->flags & UATH_CFLAGS_RXMSG) ? + (struct uath_rx_desc *)(chunk + 1) : + (struct uath_rx_desc *)(((uint8_t *)chunk) + + sizeof (struct uath_chunk) + BE_16(chunk->length) - + sizeof (struct uath_rx_desc)); + + UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): " + "frame len %u code %u status %u rate %u antenna %u " + "rssi %d channel %u phyerror %u connix %u " + "decrypterror %u keycachemiss %u\n", + BE_32(desc->framelen), BE_32(desc->code), BE_32(desc->status), + BE_32(desc->rate), BE_32(desc->antenna), BE_32(desc->rssi), + BE_32(desc->channel), BE_32(desc->phyerror), BE_32(desc->connix), + BE_32(desc->decrypterror), BE_32(desc->keycachemiss)); + + if (BE_32(desc->len) > IEEE80211_MAX_LEN) { + UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): " + "bad descriptor (len=%d)\n", BE_32(desc->len)); + UATH_STAT_INC(sc, st_toobigrxpkt); + goto fail; + } + + uath_update_rxstat(sc, BE_32(desc->status)); + + pktlen = BE_32(desc->framelen) - UATH_RX_DUMMYSIZE; + + if ((m = allocb(pktlen, BPRI_MED)) == NULL) { + UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): " + "allocate mblk failed.\n"); + sc->sc_rx_nobuf++; + goto fail; + } + bcopy((rxbuf + sizeof (struct uath_chunk)), m->b_rptr, pktlen); + + m->b_wptr = m->b_rptr + pktlen; + wh = (struct ieee80211_frame *)m->b_rptr; + ni = ieee80211_find_rxnode(ic, wh); + + /* send the frame to the 802.11 layer */ + (void) ieee80211_input(ic, m, ni, (int)BE_32(desc->rssi), 0); + + /* node is no longer needed */ + ieee80211_free_node(ni); +fail: + sc->rx_data_queued--; + if (mp) freemsg(mp); + usb_free_bulk_req(req); + mutex_exit(&sc->sc_rxlock_data); + if (UATH_IS_RUNNING(sc) && !UATH_IS_SUSPEND(sc)) { + (void) uath_rx_data_xfer(sc); + } +} + +static int +uath_rx_data_xfer(struct uath_softc *sc) +{ + usb_bulk_req_t *req; + int err; + + req = usb_alloc_bulk_req(sc->sc_dev, + IEEE80211_MAX_LEN, USB_FLAGS_SLEEP); + if (req == NULL) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_rx_data_xfer(): " + "failed to allocate req"); + return (UATH_SUCCESS); + } + + req->bulk_len = IEEE80211_MAX_LEN; + req->bulk_cb = uath_data_rxeof; + req->bulk_exc_cb = uath_data_rxeof; + req->bulk_client_private = (usb_opaque_t)sc; + req->bulk_timeout = 0; + req->bulk_completion_reason = 0; + req->bulk_cb_flags = 0; + req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK + | USB_ATTRS_AUTOCLEARING; + + err = usb_pipe_bulk_xfer(sc->rx_data_pipe, req, 0); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_rx_data_xfer(): " + "failed to do rx xfer, %d", err); + usb_free_bulk_req(req); + return (UATH_FAILURE); + } + + mutex_enter(&sc->sc_rxlock_data); + sc->rx_data_queued++; + mutex_exit(&sc->sc_rxlock_data); + return (UATH_SUCCESS); +} + +static void +uath_update_rxstat(struct uath_softc *sc, uint32_t status) +{ + + switch (status) { + case UATH_STATUS_STOP_IN_PROGRESS: + UATH_STAT_INC(sc, st_stopinprogress); + break; + case UATH_STATUS_CRC_ERR: + UATH_STAT_INC(sc, st_crcerr); + break; + case UATH_STATUS_PHY_ERR: + UATH_STAT_INC(sc, st_phyerr); + break; + case UATH_STATUS_DECRYPT_CRC_ERR: + UATH_STAT_INC(sc, st_decrypt_crcerr); + break; + case UATH_STATUS_DECRYPT_MIC_ERR: + UATH_STAT_INC(sc, st_decrypt_micerr); + break; + case UATH_STATUS_DECOMP_ERR: + UATH_STAT_INC(sc, st_decomperr); + break; + case UATH_STATUS_KEY_ERR: + UATH_STAT_INC(sc, st_keyerr); + break; + case UATH_STATUS_ERR: + UATH_STAT_INC(sc, st_err); + break; + default: + break; + } +} + +static void +uath_next_scan(void *arg) +{ + struct uath_softc *sc = arg; + struct ieee80211com *ic = &sc->sc_ic; + + if (ic->ic_state == IEEE80211_S_SCAN) + ieee80211_next_scan(ic); + + sc->sc_scan_id = 0; +} + +static int +uath_create_connection(struct uath_softc *sc, uint32_t connid) +{ + const struct ieee80211_rateset *rs; + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_node *ni = ic->ic_bss; + struct uath_cmd_create_connection create; + int err; + + bzero(&create, sizeof (create)); + create.connid = BE_32(connid); + create.bssid = BE_32(0); + /* XXX packed or not? */ + create.size = BE_32(sizeof (struct uath_cmd_rateset)); + + rs = &ni->in_rates; + create.connattr.rateset.length = rs->ir_nrates; + bcopy(rs->ir_rates, &create.connattr.rateset.set[0], + rs->ir_nrates); + + /* XXX turbo */ + if (UATH_IS_CHAN_A(ni->in_chan)) + create.connattr.wlanmode = BE_32(WLAN_MODE_11a); + else if (UATH_IS_CHAN_ANYG(ni->in_chan)) + create.connattr.wlanmode = BE_32(WLAN_MODE_11g); + else + create.connattr.wlanmode = BE_32(WLAN_MODE_11b); + + err = uath_cmd_write(sc, WDCMSG_CREATE_CONNECTION, &create, + sizeof (create), 0); + return (err); +} + +static int +uath_set_rates(struct uath_softc *sc, const struct ieee80211_rateset *rs) +{ + struct uath_cmd_rates rates; + int err; + + bzero(&rates, sizeof (rates)); + rates.connid = BE_32(UATH_ID_BSS); /* XXX */ + rates.size = BE_32(sizeof (struct uath_cmd_rateset)); + /* XXX bounds check rs->rs_nrates */ + rates.rateset.length = rs->ir_nrates; + bcopy(rs->ir_rates, &rates.rateset.set[0], rs->ir_nrates); + + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_set_rates(): " + "setting supported rates nrates=%d\n", rs->ir_nrates); + err = uath_cmd_write(sc, WDCMSG_SET_BASIC_RATE, + &rates, sizeof (rates), 0); + return (err); +} + +static int +uath_write_associd(struct uath_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_node *ni = ic->ic_bss; + struct uath_cmd_set_associd associd; + int err; + + bzero(&associd, sizeof (associd)); + associd.defaultrateix = BE_32(1); /* XXX */ + associd.associd = BE_32(ni->in_associd); + associd.timoffset = BE_32(0x3b); /* XXX */ + IEEE80211_ADDR_COPY(associd.bssid, ni->in_bssid); + err = uath_cmd_write(sc, WDCMSG_WRITE_ASSOCID, &associd, + sizeof (associd), 0); + return (err); +} + +static int +uath_set_ledsteady(struct uath_softc *sc, int lednum, int ledmode) +{ + struct uath_cmd_ledsteady led; + int err; + + led.lednum = BE_32(lednum); + led.ledmode = BE_32(ledmode); + + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_set_ledsteady(): " + "set %s led %s (steady)\n", + (lednum == UATH_LED_LINK) ? "link" : "activity", + ledmode ? "on" : "off"); + err = uath_cmd_write(sc, WDCMSG_SET_LED_STEADY, &led, sizeof (led), 0); + return (err); +} + +static int +uath_set_ledblink(struct uath_softc *sc, int lednum, int ledmode, + int blinkrate, int slowmode) +{ + struct uath_cmd_ledblink led; + int err; + + led.lednum = BE_32(lednum); + led.ledmode = BE_32(ledmode); + led.blinkrate = BE_32(blinkrate); + led.slowmode = BE_32(slowmode); + + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_set_ledblink(): " + "set %s led %s (blink)\n", + (lednum == UATH_LED_LINK) ? "link" : "activity", + ledmode ? "on" : "off"); + + err = uath_cmd_write(sc, WDCMSG_SET_LED_BLINK, + &led, sizeof (led), 0); + return (err); +} + + +static int +uath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) +{ + struct uath_softc *sc = (struct uath_softc *)ic; + struct ieee80211_node *ni = ic->ic_bss; + enum ieee80211_state ostate; + int err; + + ostate = ic->ic_state; + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_newstate(): " + "%d -> %d\n", ostate, nstate); + + if (sc->sc_scan_id != 0) { + (void) untimeout(sc->sc_scan_id); + sc->sc_scan_id = 0; + } + + UATH_LOCK(sc); + + if (UATH_IS_DISCONNECT(sc) && (nstate != IEEE80211_S_INIT)) { + UATH_UNLOCK(sc); + return (DDI_SUCCESS); + } + + if (UATH_IS_SUSPEND(sc) && (nstate != IEEE80211_S_INIT)) { + UATH_UNLOCK(sc); + return (DDI_SUCCESS); + } + + switch (nstate) { + case IEEE80211_S_INIT: + if (ostate == IEEE80211_S_RUN) { + /* turn link and activity LEDs off */ + (void) uath_set_ledstate(sc, 0); + } + break; + case IEEE80211_S_SCAN: + if (uath_switch_channel(sc, ic->ic_curchan) != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_newstate(): " + "could not switch channel\n"); + break; + } + sc->sc_scan_id = timeout(uath_next_scan, (void *)sc, + drv_usectohz(250000)); + break; + case IEEE80211_S_AUTH: + /* XXX good place? set RTS threshold */ + uath_config(sc, CFG_USER_RTS_THRESHOLD, ic->ic_rtsthreshold); + + if (uath_switch_channel(sc, ni->in_chan) != 0) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_newstate(): " + "could not switch channel\n"); + break; + } + if (uath_create_connection(sc, UATH_ID_BSS) != 0) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_newstate(): " + "could not create connection\n"); + break; + } + break; + case IEEE80211_S_ASSOC: + if (uath_set_rates(sc, &ni->in_rates) != 0) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_newstate(): " + "could not set negotiated rate set\n"); + break; + } + break; + case IEEE80211_S_RUN: + /* XXX monitor mode doesn't be supported */ + if (ic->ic_opmode == IEEE80211_M_MONITOR) { + (void) uath_set_ledstate(sc, 1); + break; + } + + /* + * Tx rate is controlled by firmware, report the maximum + * negotiated rate in ifconfig output. + */ + ni->in_txrate = ni->in_rates.ir_nrates - 1; + + if (uath_write_associd(sc) != 0) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_newstate(): " + "could not write association id\n"); + break; + } + /* turn link LED on */ + (void) uath_set_ledsteady(sc, UATH_LED_LINK, UATH_LED_ON); + /* make activity LED blink */ + (void) uath_set_ledblink(sc, UATH_LED_ACTIVITY, + UATH_LED_ON, 1, 2); + /* set state to associated */ + (void) uath_set_ledstate(sc, 1); + break; + } + + UATH_UNLOCK(sc); + + err = sc->sc_newstate(ic, nstate, arg); + return (err); +} + +static int +uath_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type) +{ + struct uath_softc *sc = (struct uath_softc *)ic; + struct uath_chunk *chunk; + struct uath_tx_desc *desc; + struct ieee80211_frame *wh; + struct ieee80211_node *ni = NULL; + struct ieee80211_key *k; + + mblk_t *m, *m0; + int err, off, mblen; + int pktlen, framelen, msglen; + + err = UATH_SUCCESS; + + mutex_enter(&sc->sc_txlock_data); + + if (UATH_IS_SUSPEND(sc)) { + err = 0; + goto fail; + } + + if (sc->tx_data_queued > UATH_TX_DATA_LIST_COUNT) { + UATH_DEBUG(UATH_DBG_TX, "uath: uath_send(): " + "no TX buffer available!\n"); + if ((type & IEEE80211_FC0_TYPE_MASK) == + IEEE80211_FC0_TYPE_DATA) { + sc->sc_need_sched = 1; + } + sc->sc_tx_nobuf++; + err = ENOMEM; + goto fail; + } + + m = allocb(UATH_MAX_TXBUFSZ, BPRI_MED); + if (m == NULL) { + UATH_DEBUG(UATH_DBG_TX, "uath: uath_send(): " + "can't alloc mblk.\n"); + err = DDI_FAILURE; + goto fail; + } + + /* skip TX descriptor */ + m->b_rptr += sizeof (struct uath_chunk) + sizeof (struct uath_tx_desc); + m->b_wptr += sizeof (struct uath_chunk) + sizeof (struct uath_tx_desc); + + for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) { + mblen = (uintptr_t)m0->b_wptr - (uintptr_t)m0->b_rptr; + (void) memcpy(m->b_rptr + off, m0->b_rptr, mblen); + off += mblen; + } + m->b_wptr += off; + + wh = (struct ieee80211_frame *)m->b_rptr; + + ni = ieee80211_find_txnode(ic, wh->i_addr1); + if (ni == NULL) { + err = DDI_FAILURE; + freemsg(m); + goto fail; + } + + if ((type & IEEE80211_FC0_TYPE_MASK) == + IEEE80211_FC0_TYPE_DATA) { + (void) ieee80211_encap(ic, m, ni); + } + + if (wh->i_fc[1] & IEEE80211_FC1_WEP) { + k = ieee80211_crypto_encap(ic, m); + if (k == NULL) { + freemsg(m); + err = DDI_FAILURE; + goto fail; + } + /* packet header may have moved, reset our local pointer */ + wh = (struct ieee80211_frame *)m->b_rptr; + } + + pktlen = (uintptr_t)m->b_wptr - (uintptr_t)m->b_rptr; + framelen = pktlen + IEEE80211_CRC_LEN; + msglen = framelen + sizeof (struct uath_tx_desc); + + m->b_rptr -= sizeof (struct uath_chunk) + sizeof (struct uath_tx_desc); + + chunk = (struct uath_chunk *)m->b_rptr; + desc = (struct uath_tx_desc *)(chunk + 1); + + /* one chunk only for now */ + chunk->seqnum = 0; + chunk->flags = UATH_CFLAGS_FINAL; + chunk->length = BE_16(msglen); + + /* fill Tx descriptor */ + desc->msglen = BE_32(msglen); + /* NB: to get UATH_TX_NOTIFY reply, `msgid' must be larger than 0 */ + desc->msgid = sc->sc_msgid; /* don't care about endianness */ + desc->type = BE_32(WDCMSG_SEND); + switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { + case IEEE80211_FC0_TYPE_CTL: + case IEEE80211_FC0_TYPE_MGT: + /* NB: force all management frames to highest queue */ + if (ni->in_flags & UATH_NODE_QOS) { + /* NB: force all management frames to highest queue */ + desc->txqid = BE_32(WME_AC_VO | UATH_TXQID_MINRATE); + } else + desc->txqid = BE_32(WME_AC_BE | UATH_TXQID_MINRATE); + break; + case IEEE80211_FC0_TYPE_DATA: + /* XXX multicast frames should honor mcastrate */ + desc->txqid = BE_32(WME_AC_BE); + break; + default: + UATH_DEBUG(UATH_DBG_TX, "uath: uath_send(): " + "bogus frame type 0x%x (%s)\n", + wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK); + err = EIO; + goto fail; + } + + if (ic->ic_state == IEEE80211_S_AUTH || + ic->ic_state == IEEE80211_S_ASSOC || + ic->ic_state == IEEE80211_S_RUN) + desc->connid = BE_32(UATH_ID_BSS); + else + desc->connid = BE_32(UATH_ID_INVALID); + desc->flags = BE_32(0 /* no UATH_TX_NOTIFY */); + desc->buflen = BE_32(pktlen); + + (void) uath_tx_data_xfer(sc, m); + + sc->sc_msgid = (sc->sc_msgid + 1) % UATH_TX_DATA_LIST_COUNT; + + ic->ic_stats.is_tx_frags++; + ic->ic_stats.is_tx_bytes += pktlen; + +fail: + if (ni != NULL) + ieee80211_free_node(ni); + if ((mp) && + ((type & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA || + err == 0)) { + freemsg(mp); + } + mutex_exit(&sc->sc_txlock_data); + return (err); +} + +static int +uath_reconnect(dev_info_t *devinfo) +{ + struct uath_softc *sc; + struct ieee80211com *ic; + int err; + uint16_t vendor_id, product_id; + + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_reconnect(): " + "uath online\n"); + + sc = ddi_get_soft_state(uath_soft_state_p, ddi_get_instance(devinfo)); + ASSERT(sc != NULL); + ic = (struct ieee80211com *)&sc->sc_ic; + + if (!UATH_IS_RECONNECT(sc)) { + err = uath_open_pipes(sc); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): " + "could not open pipes\n"); + return (DDI_FAILURE); + } + + err = uath_loadfirmware(sc); + if (err != DDI_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): " + "could not download firmware\n"); + return (DDI_FAILURE); + } + + uath_close_pipes(sc); + usb_client_detach(sc->sc_dev, sc->sc_udev); + + /* reset device */ + err = usb_reset_device(sc->sc_dev, USB_RESET_LVL_DEFAULT); + if (err != USB_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): " + "could not reset device %x\n", err); + } + + err = usb_client_attach(devinfo, USBDRV_VERSION, 0); + if (err != USB_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): " + "usb_client_attach failed\n"); + } + + err = usb_get_dev_data(devinfo, &sc->sc_udev, + USB_PARSE_LVL_ALL, 0); + if (err != USB_SUCCESS) { + sc->sc_udev = NULL; + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): " + "usb_get_dev_data failed\n"); + } + + vendor_id = sc->sc_udev->dev_descr->idVendor; + product_id = sc->sc_udev->dev_descr->idProduct; + sc->dev_flags = uath_lookup(vendor_id, product_id); + if (sc->dev_flags == UATH_FLAG_ERR) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): " + "HW does not match\n"); + } + + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_reconnect(): " + "vendorId = %x,deviceID = %x, flags = %x\n", + vendor_id, product_id, sc->dev_flags); + + UATH_LOCK(sc); + sc->sc_flags |= UATH_FLAG_RECONNECT; + UATH_UNLOCK(sc); + + } else { + err = uath_open_pipes(sc); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): " + "could not open pipes\n"); + return (DDI_FAILURE); + } + + /* + * Allocate xfers for firmware commands. + */ + err = uath_alloc_cmd_list(sc, sc->sc_cmd, UATH_CMD_LIST_COUNT, + UATH_MAX_CMDSZ); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): " + "could not allocate Tx command list\n"); + return (DDI_FAILURE); + } + + err = uath_init_cmd_list(sc); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): " + "could not init RX command list\n"); + return (DDI_FAILURE); + } + + /* + * We're now ready to send+receive firmware commands. + */ + err = uath_host_available(sc); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): " + "could not initialize adapter\n"); + return (DDI_FAILURE); + } + + err = uath_get_devcap(sc); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): " + "could not get device capabilities\n"); + return (DDI_FAILURE); + } + + err = uath_get_devstatus(sc, ic->ic_macaddr); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): " + "could not get dev status\n"); + return (DDI_FAILURE); + } + + err = usb_check_same_device(sc->sc_dev, NULL, USB_LOG_L2, -1, + USB_CHK_BASIC, NULL); + if (err != USB_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): " + "different device connected %x\n", err); + return (DDI_FAILURE); + } + + err = uath_init(sc); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): " + "device re-connect failed\n"); + return (DDI_FAILURE); + } + + UATH_LOCK(sc); + sc->sc_flags &= ~UATH_FLAG_RECONNECT; + sc->sc_flags &= ~UATH_FLAG_DISCONNECT; + sc->sc_flags |= UATH_FLAG_RUNNING; + UATH_UNLOCK(sc); + } + + return (DDI_SUCCESS); +} + +static int +uath_disconnect(dev_info_t *devinfo) +{ + struct uath_softc *sc; + struct ieee80211com *ic; + + /* + * We can't call uath_stop() here, since the hardware is removed, + * we can't access the register anymore. + */ + sc = ddi_get_soft_state(uath_soft_state_p, ddi_get_instance(devinfo)); + ASSERT(sc != NULL); + + if (sc->sc_flags & UATH_FLAG_RECONNECT) { + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_disconnect(): " + "stage 0 in re-connect\n"); + uath_close_pipes(sc); + return (DDI_SUCCESS); + } + + UATH_LOCK(sc); + sc->sc_flags |= UATH_FLAG_DISCONNECT; + UATH_UNLOCK(sc); + + ic = (struct ieee80211com *)&sc->sc_ic; + ieee80211_new_state(ic, IEEE80211_S_INIT, -1); + + UATH_LOCK(sc); + sc->sc_flags &= ~UATH_FLAG_RUNNING; /* STOP */ + UATH_UNLOCK(sc); + + /* abort and free xfers */ + uath_free_cmd_list(sc->sc_cmd, UATH_CMD_LIST_COUNT); + + /* close Tx/Rx pipes */ + uath_close_pipes(sc); + + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_disconnect(): " + "offline success\n"); + + return (DDI_SUCCESS); +} + +static int +uath_dataflush(struct uath_softc *sc) +{ + struct uath_chunk *chunk; + struct uath_tx_desc *desc; + uint8_t *buf; + int err; + + buf = kmem_alloc(UATH_MAX_TXBUFSZ, KM_NOSLEEP); + if (buf == NULL) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_dataflush(): " + "no bufs\n"); + return (ENOBUFS); + } + + chunk = (struct uath_chunk *)buf; + desc = (struct uath_tx_desc *)(chunk + 1); + + /* one chunk only */ + chunk->seqnum = 0; + chunk->flags = UATH_CFLAGS_FINAL; + chunk->length = BE_16(sizeof (struct uath_tx_desc)); + + bzero(desc, sizeof (struct uath_tx_desc)); + desc->msglen = BE_32(sizeof (struct uath_tx_desc)); + desc->msgid = sc->sc_msgid; /* don't care about endianness */ + desc->type = BE_32(WDCMSG_FLUSH); + desc->txqid = BE_32(0); + desc->connid = BE_32(0); + desc->flags = BE_32(0); + + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_dataflush(): " + "send flush ix %d\n", desc->msgid); + + err = uath_fw_send(sc, sc->tx_data_pipe, buf, + sizeof (struct uath_chunk) + sizeof (struct uath_tx_desc)); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_dataflush(): " + "data flush error"); + return (UATH_FAILURE); + } + + kmem_free(buf, UATH_MAX_TXBUFSZ); + sc->sc_msgid = (sc->sc_msgid + 1) % UATH_TX_DATA_LIST_COUNT; + + return (UATH_SUCCESS); +} + +static int +uath_cmdflush(struct uath_softc *sc) +{ + return (uath_cmd_write(sc, WDCMSG_FLUSH, NULL, 0, 0)); +} + +static int +uath_flush(struct uath_softc *sc) +{ + int err; + + err = uath_dataflush(sc); + if (err != UATH_SUCCESS) + goto failed; + + err = uath_cmdflush(sc); + if (err != UATH_SUCCESS) + goto failed; + + return (UATH_SUCCESS); +failed: + return (err); +} + +static int +uath_set_ledstate(struct uath_softc *sc, int connected) +{ + int err; + + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_set_ledstate(): " + "set led state %sconnected\n", connected ? "" : "!"); + + connected = BE_32(connected); + err = uath_cmd_write(sc, WDCMSG_SET_LED_STATE, + &connected, sizeof (connected), 0); + return (err); +} + +static int +uath_config_multi(struct uath_softc *sc, uint32_t reg, const void *data, + int len) +{ + struct uath_write_mac write; + int err; + + write.reg = BE_32(reg); + write.len = BE_32(len); + bcopy(data, write.data, len); + + /* properly handle the case where len is zero (reset) */ + err = uath_cmd_write(sc, WDCMSG_TARGET_SET_CONFIG, &write, + (len == 0) ? sizeof (uint32_t) : 2 * sizeof (uint32_t) + len, 0); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_config_multi(): " + "could not write %d bytes to register 0x%02x\n", len, reg); + } + return (err); +} + +static void +uath_config(struct uath_softc *sc, uint32_t reg, uint32_t val) +{ + struct uath_write_mac write; + int err; + + write.reg = BE_32(reg); + write.len = BE_32(0); /* 0 = single write */ + *(uint32_t *)write.data = BE_32(val); + + err = uath_cmd_write(sc, WDCMSG_TARGET_SET_CONFIG, &write, + 3 * sizeof (uint32_t), 0); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_config(): " + "could not write register 0x%02x\n", + reg); + } +} + +static int +uath_switch_channel(struct uath_softc *sc, struct ieee80211_channel *c) +{ + int err; + + /* set radio frequency */ + err = uath_set_chan(sc, c); + if (err) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_switch_channel(): " + "could not set channel\n"); + goto failed; + } + + /* reset Tx rings */ + err = uath_reset_tx_queues(sc); + if (err) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_switch_channel(): " + "could not reset Tx queues\n"); + goto failed; + } + + /* set Tx rings WME properties */ + err = uath_wme_init(sc); + if (err) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_switch_channel(): " + "could not init Tx queues\n"); + goto failed; + } + + err = uath_set_ledstate(sc, 0); + if (err) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_switch_channel(): " + "could not set led state\n"); + goto failed; + } + + err = uath_flush(sc); + if (err) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_switch_channel(): " + "could not flush pipes\n"); + goto failed; + } + +failed: + return (err); +} + +static int +uath_set_rxfilter(struct uath_softc *sc, uint32_t bits, uint32_t op) +{ + struct uath_cmd_rx_filter rxfilter; + + rxfilter.bits = BE_32(bits); + rxfilter.op = BE_32(op); + + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_set_rxfilter(): " + "setting Rx filter=0x%x flags=0x%x\n", bits, op); + + return ((uath_cmd_write(sc, WDCMSG_RX_FILTER, &rxfilter, + sizeof (rxfilter), 0))); +} + +static int +uath_set_chan(struct uath_softc *sc, struct ieee80211_channel *c) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct uath_cmd_reset reset; + + bzero(&reset, sizeof (reset)); + if (IEEE80211_IS_CHAN_2GHZ(c)) + reset.flags |= BE_32(UATH_CHAN_2GHZ); + if (IEEE80211_IS_CHAN_5GHZ(c)) + reset.flags |= BE_32(UATH_CHAN_5GHZ); + /* NB: 11g =>'s 11b so don't specify both OFDM and CCK */ + if (UATH_IS_CHAN_OFDM(c)) + reset.flags |= BE_32(UATH_CHAN_OFDM); + else if (UATH_IS_CHAN_CCK(c)) + reset.flags |= BE_32(UATH_CHAN_CCK); + /* turbo can be used in either 2GHz or 5GHz */ + if (c->ich_flags & IEEE80211_CHAN_TURBO) + reset.flags |= BE_32(UATH_CHAN_TURBO); + + reset.freq = BE_32(c->ich_freq); + reset.maxrdpower = BE_32(50); /* XXX */ + reset.channelchange = BE_32(1); + reset.keeprccontent = BE_32(0); + + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_set_chan(): " + "set channel %d, flags 0x%x freq %u\n", + ieee80211_chan2ieee(ic, c), + BE_32(reset.flags), BE_32(reset.freq)); + + return (uath_cmd_write(sc, WDCMSG_RESET, &reset, sizeof (reset), 0)); +} + +static int +uath_reset_tx_queues(struct uath_softc *sc) +{ + int ac, err; + + for (ac = 0; ac < 4; ac++) { + const uint32_t qid = BE_32(ac); + err = uath_cmd_write(sc, WDCMSG_RELEASE_TX_QUEUE, &qid, + sizeof (qid), 0); + if (err != UATH_SUCCESS) + break; + } + return (err); +} + +static int +uath_wme_init(struct uath_softc *sc) +{ + /* XXX get from net80211 */ + static const struct uath_wme_settings uath_wme_11g[4] = { + { 7, 4, 10, 0, 0 }, /* Background */ + { 3, 4, 10, 0, 0 }, /* Best-Effort */ + { 3, 3, 4, 26, 0 }, /* Video */ + { 2, 2, 3, 47, 0 } /* Voice */ + }; + + struct uath_cmd_txq_setup qinfo; + int ac, err; + + for (ac = 0; ac < 4; ac++) { + qinfo.qid = BE_32(ac); + qinfo.len = BE_32(sizeof (qinfo.attr)); + qinfo.attr.priority = BE_32(ac); /* XXX */ + qinfo.attr.aifs = BE_32(uath_wme_11g[ac].aifsn); + qinfo.attr.logcwmin = BE_32(uath_wme_11g[ac].logcwmin); + qinfo.attr.logcwmax = BE_32(uath_wme_11g[ac].logcwmax); + qinfo.attr.mode = BE_32(uath_wme_11g[ac].acm); + qinfo.attr.qflags = BE_32(1); + qinfo.attr.bursttime = + BE_32(UATH_TXOP_TO_US(uath_wme_11g[ac].txop)); + + err = uath_cmd_write(sc, WDCMSG_SETUP_TX_QUEUE, &qinfo, + sizeof (qinfo), 0); + if (err != UATH_SUCCESS) + break; + } + return (err); +} + +static void +uath_stop_locked(void *arg) +{ + struct uath_softc *sc = (struct uath_softc *)arg; + + /* flush data & control requests into the target */ + (void) uath_flush(sc); + + /* set a LED status to the disconnected. */ + (void) uath_set_ledstate(sc, 0); + + /* stop the target */ + (void) uath_cmd_write(sc, WDCMSG_TARGET_STOP, NULL, 0, 0); + + /* abort any pending transfers */ + usb_pipe_reset(sc->sc_dev, sc->rx_data_pipe, USB_FLAGS_SLEEP, NULL, 0); + usb_pipe_reset(sc->sc_dev, sc->tx_data_pipe, USB_FLAGS_SLEEP, NULL, 0); + usb_pipe_reset(sc->sc_dev, sc->tx_cmd_pipe, USB_FLAGS_SLEEP, NULL, 0); +} + +static int +uath_init_locked(void *arg) +{ + struct uath_softc *sc = arg; + struct ieee80211com *ic = &sc->sc_ic; + uint32_t val; + int i, err; + + if (UATH_IS_RUNNING(sc)) + uath_stop_locked(sc); + + uath_init_data_queue(sc); + + /* reset variables */ + sc->sc_intrx_nextnum = sc->sc_msgid = 0; + + val = BE_32(0); + (void) uath_cmd_write(sc, WDCMSG_BIND, &val, sizeof (val), 0); + + /* set MAC address */ + (void) uath_config_multi(sc, CFG_MAC_ADDR, + ic->ic_macaddr, IEEE80211_ADDR_LEN); + + /* XXX honor net80211 state */ + uath_config(sc, CFG_RATE_CONTROL_ENABLE, 0x00000001); + uath_config(sc, CFG_DIVERSITY_CTL, 0x00000001); + uath_config(sc, CFG_ABOLT, 0x0000003f); + uath_config(sc, CFG_WME_ENABLED, 0x00000001); + + uath_config(sc, CFG_SERVICE_TYPE, 1); + uath_config(sc, CFG_TP_SCALE, 0x00000000); + uath_config(sc, CFG_TPC_HALF_DBM5, 0x0000003c); + uath_config(sc, CFG_TPC_HALF_DBM2, 0x0000003c); + uath_config(sc, CFG_OVERRD_TX_POWER, 0x00000000); + uath_config(sc, CFG_GMODE_PROTECTION, 0x00000000); + uath_config(sc, CFG_GMODE_PROTECT_RATE_INDEX, 0x00000003); + uath_config(sc, CFG_PROTECTION_TYPE, 0x00000000); + uath_config(sc, CFG_MODE_CTS, 0x00000002); + + err = uath_cmd_read(sc, WDCMSG_TARGET_START, NULL, 0, + &val, sizeof (val), UATH_CMD_FLAG_MAGIC); + if (err) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_init_locked(): " + "could not start target\n"); + goto fail; + } + + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_init_locked(): " + "%s returns handle: 0x%x\n", + uath_codename(WDCMSG_TARGET_START), BE_32(val)); + + /* set default channel */ + err = uath_switch_channel(sc, ic->ic_curchan); + if (err) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_init_locked(): " + "could not switch channel, error %d\n", err); + goto fail; + } + + val = BE_32(TARGET_DEVICE_AWAKE); + (void) uath_cmd_write(sc, WDCMSG_SET_PWR_MODE, &val, sizeof (val), 0); + /* XXX? check */ + (void) uath_cmd_write(sc, WDCMSG_RESET_KEY_CACHE, NULL, 0, 0); + + for (i = 0; i < UATH_RX_DATA_LIST_COUNT; i++) { + err = uath_rx_data_xfer(sc); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_init_locked(): " + "could not alloc rx xfer %x\n", i); + goto fail; + } + } + + /* enable Rx */ + (void) uath_set_rxfilter(sc, 0x0, UATH_FILTER_OP_INIT); + (void) uath_set_rxfilter(sc, + UATH_FILTER_RX_UCAST | UATH_FILTER_RX_MCAST | + UATH_FILTER_RX_BCAST | UATH_FILTER_RX_BEACON, + UATH_FILTER_OP_SET); + + return (UATH_SUCCESS); + +fail: + uath_stop_locked(sc); + return (err); +} + +static int +uath_init(struct uath_softc *sc) +{ + int err; + + UATH_LOCK(sc); + err = uath_init_locked(sc); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_init(): " + "failed to initialize uath hardware\n"); + UATH_UNLOCK(sc); + return (DDI_FAILURE); + } + UATH_UNLOCK(sc); + return (DDI_SUCCESS); +} + +static void +uath_stop(struct uath_softc *sc) +{ + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_stop(): " + "uath stop now\n"); + + UATH_LOCK(sc); + uath_stop_locked(sc); + UATH_UNLOCK(sc); +} + +static void +uath_resume(struct uath_softc *sc) +{ + int err; + + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_resume(): " + "uath resume now\n"); + + /* check device changes after suspend */ + if (usb_check_same_device(sc->sc_dev, NULL, USB_LOG_L2, -1, + USB_CHK_BASIC | USB_CHK_CFG, NULL) != USB_SUCCESS) { + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_resume: " + "no or different device connected\n"); + return; + } + + /* + * initialize hardware + */ + err = uath_init_cmd_list(sc); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_resume(): " + "could not init RX command list\n"); + return; + } + + err = uath_init(sc); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_resume(): " + "hardware init failed\n"); + uath_stop(sc); + return; + } + + ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1); + UATH_LOCK(sc); + sc->sc_flags &= ~UATH_FLAG_SUSPEND; + sc->sc_flags |= UATH_FLAG_RUNNING; + UATH_UNLOCK(sc); +} + +static int +uath_m_start(void *arg) +{ + struct uath_softc *sc = (struct uath_softc *)arg; + struct ieee80211com *ic = &sc->sc_ic; + int err; + + /* + * initialize hardware + */ + err = uath_init(sc); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_m_start(): " + "device configuration failed\n"); + uath_stop(sc); + return (err); + } + + ieee80211_new_state(ic, IEEE80211_S_INIT, -1); + + UATH_LOCK(sc); + sc->sc_flags |= UATH_FLAG_RUNNING; + UATH_UNLOCK(sc); + return (DDI_SUCCESS); +} + +static void +uath_m_stop(void *arg) +{ + struct uath_softc *sc = (struct uath_softc *)arg; + struct ieee80211com *ic = &sc->sc_ic; + + ieee80211_new_state(ic, IEEE80211_S_INIT, -1); + + if (!UATH_IS_DISCONNECT(sc)) + uath_stop(sc); + + UATH_LOCK(sc); + sc->sc_flags &= ~UATH_FLAG_RUNNING; + UATH_UNLOCK(sc); +} + +static void +uath_m_ioctl(void* arg, queue_t *wq, mblk_t *mp) +{ + struct uath_softc *sc = (struct uath_softc *)arg; + struct ieee80211com *ic = &sc->sc_ic; + int err; + + err = ieee80211_ioctl(ic, wq, mp); + UATH_LOCK(sc); + if (err == ENETRESET) { + if (ic->ic_des_esslen) { + if (UATH_IS_RUNNING(sc)) { + UATH_UNLOCK(sc); + (void) uath_init(sc); + (void) ieee80211_new_state(ic, + IEEE80211_S_SCAN, -1); + UATH_LOCK(sc); + } + } + } + UATH_UNLOCK(sc); +} + +/*ARGSUSED*/ +static int +uath_m_unicst(void *arg, const uint8_t *macaddr) +{ + return (0); +} + +/*ARGSUSED*/ +static int +uath_m_multicst(void *arg, boolean_t add, const uint8_t *mca) +{ + return (0); +} + +/*ARGSUSED*/ +static int +uath_m_promisc(void *arg, boolean_t on) +{ + return (0); +} + +/* + * callback functions for /get/set properties + */ +static int +uath_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, + uint_t wldp_length, const void *wldp_buf) +{ + struct uath_softc *sc = (struct uath_softc *)arg; + struct ieee80211com *ic = &sc->sc_ic; + int err; + + err = ieee80211_setprop(ic, pr_name, wldp_pr_num, + wldp_length, wldp_buf); + UATH_LOCK(sc); + if (err == ENETRESET) { + if (ic->ic_des_esslen && UATH_IS_RUNNING(sc)) { + UATH_UNLOCK(sc); + (void) uath_init(sc); + (void) ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); + UATH_LOCK(sc); + } + err = 0; + } + UATH_UNLOCK(sc); + return (err); +} + +static int +uath_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, + uint_t pr_flags, uint_t wldp_length, void *wldp_buf, uint_t *perm) +{ + struct uath_softc *sc = (struct uath_softc *)arg; + int err; + + err = ieee80211_getprop(&sc->sc_ic, pr_name, wldp_pr_num, + pr_flags, wldp_length, wldp_buf, perm); + return (err); +} + +static int +uath_m_stat(void *arg, uint_t stat, uint64_t *val) +{ + struct uath_softc *sc = (struct uath_softc *)arg; + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_node *ni = NULL; + struct ieee80211_rateset *rs = NULL; + + UATH_LOCK(sc); + switch (stat) { + case MAC_STAT_IFSPEED: + ni = ic->ic_bss; + rs = &ni->in_rates; + *val = ((ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) ? + (rs->ir_rates[ni->in_txrate] & IEEE80211_RATE_VAL) + : ic->ic_fixed_rate) * 5000000ull; + break; + case MAC_STAT_NOXMTBUF: + *val = sc->sc_tx_nobuf; + break; + case MAC_STAT_NORCVBUF: + *val = sc->sc_rx_nobuf; + break; + case MAC_STAT_IERRORS: + *val = sc->sc_rx_err; + break; + case MAC_STAT_RBYTES: + *val = ic->ic_stats.is_rx_bytes; + break; + case MAC_STAT_IPACKETS: + *val = ic->ic_stats.is_rx_frags; + break; + case MAC_STAT_OBYTES: + *val = ic->ic_stats.is_tx_bytes; + break; + case MAC_STAT_OPACKETS: + *val = ic->ic_stats.is_tx_frags; + break; + case MAC_STAT_OERRORS: + case WIFI_STAT_TX_FAILED: + *val = sc->sc_tx_err; + break; + case WIFI_STAT_TX_RETRANS: + *val = sc->sc_tx_retries; + break; + case WIFI_STAT_FCS_ERRORS: + case WIFI_STAT_WEP_ERRORS: + case WIFI_STAT_TX_FRAGS: + case WIFI_STAT_MCAST_TX: + case WIFI_STAT_RTS_SUCCESS: + case WIFI_STAT_RTS_FAILURE: + case WIFI_STAT_ACK_FAILURE: + case WIFI_STAT_RX_FRAGS: + case WIFI_STAT_MCAST_RX: + case WIFI_STAT_RX_DUPS: + UATH_UNLOCK(sc); + return (ieee80211_stat(ic, stat, val)); + default: + UATH_UNLOCK(sc); + return (ENOTSUP); + } + UATH_UNLOCK(sc); + + return (0); +} + +static mblk_t * +uath_m_tx(void *arg, mblk_t *mp) +{ + struct uath_softc *sc = (struct uath_softc *)arg; + struct ieee80211com *ic = &sc->sc_ic; + mblk_t *next; + + /* + * No data frames go out unless we're associated; this + * should not happen as the 802.11 layer does not enable + * the xmit queue until we enter the RUN state. + */ + if ((ic->ic_state != IEEE80211_S_RUN) || + UATH_IS_SUSPEND(sc)) { + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_m_tx(): " + "discard, state %u\n", ic->ic_state); + freemsgchain(mp); + return (NULL); + } + + while (mp != NULL) { + next = mp->b_next; + mp->b_next = NULL; + if (uath_send(ic, mp, IEEE80211_FC0_TYPE_DATA) != DDI_SUCCESS) { + mp->b_next = next; + break; + } + mp = next; + } + return (mp); +} + +static int +uath_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) +{ + struct uath_softc *sc; + struct ieee80211com *ic; + + int i, err, instance; + char strbuf[32]; + uint16_t vendor_id, product_id; + + wifi_data_t wd = { 0 }; + mac_register_t *macp; + + switch (cmd) { + case DDI_ATTACH: + break; + case DDI_RESUME: + sc = ddi_get_soft_state(uath_soft_state_p, + ddi_get_instance(devinfo)); + ASSERT(sc != NULL); + uath_resume(sc); + return (DDI_SUCCESS); + default: + return (DDI_FAILURE); + } + + instance = ddi_get_instance(devinfo); + err = ddi_soft_state_zalloc(uath_soft_state_p, instance); + if (err != DDI_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): " + "ddi_soft_state_zalloc failed\n"); + return (DDI_FAILURE); + } + + sc = ddi_get_soft_state(uath_soft_state_p, instance); + ic = (ieee80211com_t *)&sc->sc_ic; + sc->sc_dev = devinfo; + + err = usb_client_attach(devinfo, USBDRV_VERSION, 0); + if (err != USB_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): " + "usb_client_attach failed\n"); + goto fail1; + } + + err = usb_get_dev_data(devinfo, &sc->sc_udev, USB_PARSE_LVL_ALL, 0); + if (err != USB_SUCCESS) { + sc->sc_udev = NULL; + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): " + "usb_get_dev_data failed\n"); + goto fail2; + } + + vendor_id = sc->sc_udev->dev_descr->idVendor; + product_id = sc->sc_udev->dev_descr->idProduct; + sc->dev_flags = uath_lookup(vendor_id, product_id); + if (sc->dev_flags == UATH_FLAG_ERR) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): " + "HW does not match\n"); + goto fail2; + } + + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_attach(): " + "vendorId = %x,deviceID = %x, flags = %x\n", + vendor_id, product_id, sc->dev_flags); + + /* + * We must open the pipes early because they're used to upload the + * firmware (pre-firmware devices) or to send firmware commands. + */ + err = uath_open_pipes(sc); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): " + "could not open pipes\n"); + goto fail3; + } + + if (sc->dev_flags & UATH_FLAG_PRE_FIRMWARE) { + err = uath_loadfirmware(sc); + if (err != DDI_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): " + "could not read firmware %s, err %d\n", + "uath-ar5523", err); + goto fail3; + } + + uath_close_pipes(sc); + usb_client_detach(sc->sc_dev, sc->sc_udev); + + err = usb_reset_device(devinfo, USB_RESET_LVL_REATTACH); + if (err != USB_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): " + "could not re-attach, err %d\n", err); + goto fail1; + } + return (DDI_SUCCESS); + } + + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_attach(): " + "firmware download and re-attach successfully\n"); + + /* + * Only post-firmware devices here. + */ + mutex_init(&sc->sc_genlock, NULL, MUTEX_DRIVER, NULL); + mutex_init(&sc->sc_rxlock_cmd, NULL, MUTEX_DRIVER, NULL); + mutex_init(&sc->sc_txlock_cmd, NULL, MUTEX_DRIVER, NULL); + mutex_init(&sc->sc_rxlock_data, NULL, MUTEX_DRIVER, NULL); + mutex_init(&sc->sc_txlock_data, NULL, MUTEX_DRIVER, NULL); + + /* + * Allocate xfers for firmware commands. + */ + err = uath_alloc_cmd_list(sc, sc->sc_cmd, UATH_CMD_LIST_COUNT, + UATH_MAX_CMDSZ); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): " + "could not allocate Tx command list\n"); + goto fail4; + } + + err = uath_init_cmd_list(sc); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): " + "could not init RX command list\n"); + goto fail5; + } + + /* + * We're now ready to send+receive firmware commands. + */ + err = uath_host_available(sc); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): " + "could not initialize adapter\n"); + goto fail5; + } + + err = uath_get_devcap(sc); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): " + "could not get device capabilities\n"); + goto fail5; + } + + err = uath_get_devstatus(sc, ic->ic_macaddr); + if (err != UATH_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): " + "could not get dev status\n"); + goto fail5; + } + + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_attach(): " + "MAC address is: %x:%x:%x:%x:%x:%x\n", + ic->ic_macaddr[0], ic->ic_macaddr[1], ic->ic_macaddr[2], + ic->ic_macaddr[3], ic->ic_macaddr[4], ic->ic_macaddr[5]); + + ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ + ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ + ic->ic_state = IEEE80211_S_INIT; + + ic->ic_maxrssi = 40; + + ic->ic_xmit = uath_send; + + /* set device capabilities */ + ic->ic_caps = + IEEE80211_C_TXPMGT | /* tx power management */ + IEEE80211_C_SHPREAMBLE | /* short preamble supported */ + IEEE80211_C_SHSLOT; /* short slot time supported */ + + ic->ic_caps |= IEEE80211_C_WPA; /* Support WPA/WPA2 */ + + /* set supported .11b and .11g rates */ + ic->ic_sup_rates[IEEE80211_MODE_11B] = uath_rateset_11b; + ic->ic_sup_rates[IEEE80211_MODE_11G] = uath_rateset_11g; + + /* set supported .11b and .11g channels (1 through 11) */ + for (i = 1; i <= 11; i++) { + ic->ic_sup_channels[i].ich_freq = + ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ); + ic->ic_sup_channels[i].ich_flags = + IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | + IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; + } + + ieee80211_attach(ic); + + /* register WPA door */ + ieee80211_register_door(ic, ddi_driver_name(devinfo), + ddi_get_instance(devinfo)); + + /* override state transition machine */ + sc->sc_newstate = ic->ic_newstate; + ic->ic_newstate = uath_newstate; + ieee80211_media_init(ic); + ic->ic_def_txkey = 0; + + sc->sc_flags = 0; + + /* + * Provide initial settings for the WiFi plugin; whenever this + * information changes, we need to call mac_plugindata_update() + */ + wd.wd_opmode = ic->ic_opmode; + wd.wd_secalloc = WIFI_SEC_NONE; + IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid); + + if ((macp = mac_alloc(MAC_VERSION)) == NULL) { + UATH_DEBUG(UATH_DBG_ERR, "uath_attach(): " + "MAC version mismatch\n"); + goto fail5; + } + + macp->m_type_ident = MAC_PLUGIN_IDENT_WIFI; + macp->m_driver = sc; + macp->m_dip = devinfo; + macp->m_src_addr = ic->ic_macaddr; + macp->m_callbacks = &uath_m_callbacks; + macp->m_min_sdu = 0; + macp->m_max_sdu = IEEE80211_MTU; + macp->m_pdata = &wd; + macp->m_pdata_size = sizeof (wd); + + err = mac_register(macp, &ic->ic_mach); + mac_free(macp); + if (err != 0) { + UATH_DEBUG(UATH_DBG_ERR, "uath_attach(): " + "mac_register() error %x\n", err); + goto fail5; + }; + + err = usb_register_hotplug_cbs(devinfo, + uath_disconnect, uath_reconnect); + if (err != USB_SUCCESS) { + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): " + "failed to register events\n"); + goto fail6; + } + + /* + * Create minor node of type DDI_NT_NET_WIFI + */ + (void) snprintf(strbuf, sizeof (strbuf), "%s%d", + "uath", instance); + err = ddi_create_minor_node(devinfo, strbuf, S_IFCHR, + instance + 1, DDI_NT_NET_WIFI, 0); + if (err != DDI_SUCCESS) + UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): " + "ddi_create_minor_node() failed\n"); + + /* + * Notify link is down now + */ + mac_link_update(ic->ic_mach, LINK_STATE_DOWN); + + UATH_DEBUG(UATH_DBG_MSG, "uath: uath_attach(): " + "attach success\n"); + return (DDI_SUCCESS); + +fail6: + (void) mac_unregister(ic->ic_mach); +fail5: + uath_free_cmd_list(sc->sc_cmd, UATH_CMD_LIST_COUNT); +fail4: + mutex_destroy(&sc->sc_genlock); + mutex_destroy(&sc->sc_rxlock_cmd); + mutex_destroy(&sc->sc_rxlock_data); + mutex_destroy(&sc->sc_txlock_cmd); + mutex_destroy(&sc->sc_txlock_data); +fail3: + uath_close_pipes(sc); +fail2: + usb_client_detach(sc->sc_dev, sc->sc_udev); +fail1: + ddi_soft_state_free(uath_soft_state_p, ddi_get_instance(devinfo)); + return (DDI_FAILURE); +} + +static int +uath_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) +{ + struct uath_softc *sc; + + sc = ddi_get_soft_state(uath_soft_state_p, ddi_get_instance(devinfo)); + ASSERT(sc != NULL); + + switch (cmd) { + case DDI_DETACH: + break; + case DDI_SUSPEND: + if (UATH_IS_RUNNING(sc)) { + ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1); + uath_stop(sc); + } + UATH_LOCK(sc); + sc->sc_flags &= ~UATH_FLAG_RUNNING; + sc->sc_flags |= UATH_FLAG_SUSPEND; + UATH_UNLOCK(sc); + return (DDI_SUCCESS); + default: + return (DDI_FAILURE); + } + + if (sc->dev_flags & UATH_FLAG_PRE_FIRMWARE) { + ddi_soft_state_free(uath_soft_state_p, + ddi_get_instance(devinfo)); + return (DDI_SUCCESS); + } + + if (!UATH_IS_DISCONNECT(sc) && UATH_IS_RUNNING(sc)) + uath_stop(sc); + + uath_free_cmd_list(sc->sc_cmd, UATH_CMD_LIST_COUNT); + + if (mac_disable(sc->sc_ic.ic_mach) != 0) + return (DDI_FAILURE); + + /* + * Unregister from the MAC layer subsystem + */ + if (mac_unregister(sc->sc_ic.ic_mach) != 0) + return (DDI_FAILURE); + + /* + * detach ieee80211 layer + */ + ieee80211_detach(&sc->sc_ic); + + /* close Tx/Rx pipes */ + uath_close_pipes(sc); + usb_unregister_hotplug_cbs(devinfo); + + mutex_destroy(&sc->sc_genlock); + mutex_destroy(&sc->sc_rxlock_cmd); + mutex_destroy(&sc->sc_rxlock_data); + mutex_destroy(&sc->sc_txlock_cmd); + mutex_destroy(&sc->sc_txlock_data); + + /* pipes will be close in uath_stop() */ + usb_client_detach(devinfo, sc->sc_udev); + sc->sc_udev = NULL; + + ddi_remove_minor_node(devinfo, NULL); + ddi_soft_state_free(uath_soft_state_p, ddi_get_instance(devinfo)); + + return (DDI_SUCCESS); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + +int +_init(void) +{ + int status; + + status = ddi_soft_state_init(&uath_soft_state_p, + sizeof (struct uath_softc), 1); + if (status != 0) + return (status); + + mac_init_ops(&uath_dev_ops, "uath"); + status = mod_install(&modlinkage); + if (status != 0) { + mac_fini_ops(&uath_dev_ops); + ddi_soft_state_fini(&uath_soft_state_p); + } + return (status); +} + +int +_fini(void) +{ + int status; + + status = mod_remove(&modlinkage); + if (status == 0) { + mac_fini_ops(&uath_dev_ops); + ddi_soft_state_fini(&uath_soft_state_p); + } + return (status); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/io/uath/uath_fw/LICENSE Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,36 @@ +/*- + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the following conditions are met: + * 1. The materials contained herein are unmodified and are used + * unmodified. + * 2. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following NO + * ''WARRANTY'' disclaimer below (''Disclaimer''), without + * modification. + * 3. Redistributions in binary form must reproduce at minimum a + * disclaimer similar to the Disclaimer below and any redistribution + * must be conditioned upon including a substantially similar + * Disclaimer requirement for further binary redistribution. + * 4. Neither the names of the above-listed copyright holders nor the + * names of any contributors may be used to endorse or promote + * product derived from this software without specific prior written + * permission. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE + * FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. + */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/io/uath/uath_fw/LICENSE.descrip Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,1 @@ +ATHEROS AR5523 USB FIRMWARE
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/io/uath/uath_fw/uathfw_mod.c Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,67 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * misc module wrapper for a firmware module for uath driver + * User must use elfwrap(1) to convert raw firmware data file to + * ELF object file. Then use ld(1) to link the ELF object file and + * this module to produce a kernel loadable module. + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/modctl.h> + + +extern struct mod_ops mod_miscops; +static struct modlmisc modlmisc = { + &mod_miscops, + "uath firmware wrapper module 1.1" +}; +static struct modlinkage modlinkage = { + MODREV_1, + &modlmisc, + 0 +}; + +int +_init(void) +{ + return (mod_install(&modlinkage)); +} + +int +_fini(void) +{ + return (mod_remove(&modlinkage)); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/io/uath/uath_reg.h Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,567 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Copyright (c) 2006 + * Damien Bergamini <damien.bergamini@free.fr> + * Copyright (c) 2006 Sam Leffler, Errno Consulting + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +#ifndef _UATH_REG_H +#define _UATH_REG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Location in the endpoint descriptor tree used by the device */ +#define UATH_CONFIG_NO 1 +#define UATH_IFACE_INDEX 0 +#define UATH_ALT_IF_INDEX 0 + +/* all fields are big endian */ +#pragma pack(1) +struct uath_fwblock { + uint32_t flags; +#define UATH_WRITE_BLOCK (1 << 4) + uint32_t len; +#define UATH_MAX_FWBLOCK_SIZE 2048 + uint32_t total; + uint32_t remain; + uint32_t rxtotal; + uint32_t pad[123]; +}; +#pragma pack() + +#define UATH_MAX_CMDSZ 512 + +/* + * Messages are passed in Target Endianness. All fixed-size + * fields of a WDS Control Message are treated as 32-bit + * values and Control Msgs are guaranteed to be 32-bit aligned. + * + * The format of a WDS Control Message is as follows: + * Message Length 32 bits + * Message Opcode 32 bits + * Message ID 32 bits + * parameter 1 + * parameter 2 + * ... + * + * A variable-length parameter, or a parmeter that is larger than + * 32 bits is passed as <length, data> pair, where length is a + * 32-bit quantity and data is padded to 32 bits. + */ +#pragma pack(1) +struct uath_cmd_hdr { + uint32_t len; /* msg length including header */ + uint32_t code; /* operation code */ +/* NB: these are defined for rev 1.5 firmware; rev 1.6 is different */ +/* messages from Host -> Target */ +#define WDCMSG_HOST_AVAILABLE 0x01 +#define WDCMSG_BIND 0x02 +#define WDCMSG_TARGET_RESET 0x03 +#define WDCMSG_TARGET_GET_CAPABILITY 0x04 +#define WDCMSG_TARGET_SET_CONFIG 0x05 +#define WDCMSG_TARGET_GET_STATUS 0x06 +#define WDCMSG_TARGET_GET_STATS 0x07 +#define WDCMSG_TARGET_START 0x08 +#define WDCMSG_TARGET_STOP 0x09 +#define WDCMSG_TARGET_ENABLE 0x0a +#define WDCMSG_TARGET_DISABLE 0x0b +#define WDCMSG_CREATE_CONNECTION 0x0c +#define WDCMSG_UPDATE_CONNECT_ATTR 0x0d +#define WDCMSG_DELETE_CONNECT 0x0e +#define WDCMSG_SEND 0x0f +#define WDCMSG_FLUSH 0x10 +/* messages from Target -> Host */ +#define WDCMSG_STATS_UPDATE 0x11 +#define WDCMSG_BMISS 0x12 +#define WDCMSG_DEVICE_AVAIL 0x13 +#define WDCMSG_SEND_COMPLETE 0x14 +#define WDCMSG_DATA_AVAIL 0x15 +#define WDCMSG_SET_PWR_MODE 0x16 +#define WDCMSG_BMISS_ACK 0x17 +#define WDCMSG_SET_LED_STEADY 0x18 +#define WDCMSG_SET_LED_BLINK 0x19 +/* more messages */ +#define WDCMSG_SETUP_BEACON_DESC 0x1a +#define WDCMSG_BEACON_INIT 0x1b +#define WDCMSG_RESET_KEY_CACHE 0x1c +#define WDCMSG_RESET_KEY_CACHE_ENTRY 0x1d +#define WDCMSG_SET_KEY_CACHE_ENTRY 0x1e +#define WDCMSG_SET_DECOMP_MASK 0x1f +#define WDCMSG_SET_REGULATORY_DOMAIN 0x20 +#define WDCMSG_SET_LED_STATE 0x21 +#define WDCMSG_WRITE_ASSOCID 0x22 +#define WDCMSG_SET_STA_BEACON_TIMERS 0x23 +#define WDCMSG_GET_TSF 0x24 +#define WDCMSG_RESET_TSF 0x25 +#define WDCMSG_SET_ADHOC_MODE 0x26 +#define WDCMSG_SET_BASIC_RATE 0x27 +#define WDCMSG_MIB_CONTROL 0x28 +#define WDCMSG_GET_CHANNEL_DATA 0x29 +#define WDCMSG_GET_CUR_RSSI 0x2a +#define WDCMSG_SET_ANTENNA_SWITCH 0x2b +#define WDCMSG_USE_SHORT_SLOT_TIME 0x2f +#define WDCMSG_SET_POWER_MODE 0x30 +#define WDCMSG_SETUP_PSPOLL_DESC 0x31 +#define WDCMSG_SET_RX_MULTICAST_FILTER 0x32 +#define WDCMSG_RX_FILTER 0x33 +#define WDCMSG_PER_CALIBRATION 0x34 +#define WDCMSG_RESET 0x35 +#define WDCMSG_DISABLE 0x36 +#define WDCMSG_PHY_DISABLE 0x37 +#define WDCMSG_SET_TX_POWER_LIMIT 0x38 +#define WDCMSG_SET_TX_QUEUE_PARAMS 0x39 +#define WDCMSG_SETUP_TX_QUEUE 0x3a +#define WDCMSG_RELEASE_TX_QUEUE 0x3b +#define WDCMSG_SET_DEFAULT_KEY 0x43 + uint32_t msgid; /* msg id (supplied by host) */ + uint32_t magic; /* response desired/target status */ + uint32_t debug[4]; /* debug data area */ + /* msg data follows */ +}; +#pragma pack() + +#define UATH_RX_DUMMYSIZE 4 + +#pragma pack(1) +struct uath_chunk { + uint8_t seqnum; /* sequence number for ordering */ + uint8_t flags; +#define UATH_CFLAGS_FINAL 0x01 /* final chunk of a msg */ +#define UATH_CFLAGS_RXMSG 0x02 /* chunk contains rx completion */ +#define UATH_CFLAGS_DEBUG 0x04 /* for debugging */ + uint16_t length; /* chunk size in bytes */ + /* chunk data follows */ +}; +#pragma pack() + +/* + * Message format for a WDCMSG_DATA_AVAIL message from Target to Host. + */ +#pragma pack(1) +struct uath_rx_desc { + uint32_t len; /* msg length including header */ + uint32_t code; /* WDCMSG_DATA_AVAIL */ + uint32_t gennum; /* generation number */ + uint32_t status; /* start of RECEIVE_INFO */ +#define UATH_STATUS_OK 0 +#define UATH_STATUS_STOP_IN_PROGRESS 1 +#define UATH_STATUS_CRC_ERR 2 +#define UATH_STATUS_PHY_ERR 3 +#define UATH_STATUS_DECRYPT_CRC_ERR 4 +#define UATH_STATUS_DECRYPT_MIC_ERR 5 +#define UATH_STATUS_DECOMP_ERR 6 +#define UATH_STATUS_KEY_ERR 7 +#define UATH_STATUS_ERR 8 + uint32_t tstamp_low; /* low-order 32-bits of rx timestamp */ + uint32_t tstamp_high; /* high-order 32-bits of rx timestamp */ + uint32_t framelen; /* frame length */ + uint32_t rate; /* rx rate code */ + uint32_t antenna; + int32_t rssi; + uint32_t channel; + uint32_t phyerror; + uint32_t connix; /* key table ix for bss traffic */ + uint32_t decrypterror; + uint32_t keycachemiss; + uint32_t pad; /* XXX? */ +}; +#pragma pack() + +#pragma pack(1) +struct uath_tx_desc { + uint32_t msglen; + uint32_t msgid; /* msg id (supplied by host) */ + uint32_t type; /* opcode: WDMSG_SEND or WDCMSG_FLUSH */ + uint32_t txqid; /* tx queue id and flags */ +#define UATH_TXQID_MASK 0x0f +#define UATH_TXQID_MINRATE 0x10 /* use min tx rate */ +#define UATH_TXQID_FF 0x20 /* content is fast frame */ + uint32_t connid; /* tx connection id */ +#define UATH_ID_INVALID 0xffffffff /* for sending prior to connection */ + uint32_t flags; /* non-zero if response desired */ +#define UATH_TX_NOTIFY (1 << 24) /* f/w will send a UATH_NOTIF_TX */ + uint32_t buflen; /* payload length */ +}; +#pragma pack() + +#pragma pack(1) +struct uath_cmd_host_available { + uint32_t sw_ver_major; + uint32_t sw_ver_minor; + uint32_t sw_ver_patch; + uint32_t sw_ver_build; +}; +#pragma pack() + +#define ATH_SW_VER_MAJOR 1 +#define ATH_SW_VER_MINOR 5 +#define ATH_SW_VER_PATCH 0 +#define ATH_SW_VER_BUILD 9999 + + +/* structure for command UATH_CMD_WRITE_MAC */ +#pragma pack(1) +struct uath_write_mac { + uint32_t reg; + uint32_t len; + uint8_t data[32]; +}; +#pragma pack() + +#pragma pack(1) +struct uath_cmd_ledsteady { /* WDCMSG_SET_LED_STEADY */ + uint32_t lednum; +#define UATH_LED_LINK 0 +#define UATH_LED_ACTIVITY 1 + uint32_t ledmode; +#define UATH_LED_OFF 0 +#define UATH_LED_ON 1 +}; +#pragma pack() + +#pragma pack(1) +struct uath_cmd_ledblink { /* WDCMSG_SET_LED_BLINK */ + uint32_t lednum; + uint32_t ledmode; + uint32_t blinkrate; + uint32_t slowmode; +}; +#pragma pack() + +/* structure for command WDCMSG_RESET */ +#pragma pack(1) +struct uath_cmd_reset { + uint32_t flags; /* channel flags */ +#define UATH_CHAN_TURBO 0x0100 +#define UATH_CHAN_CCK 0x0200 +#define UATH_CHAN_OFDM 0x0400 +#define UATH_CHAN_2GHZ 0x1000 +#define UATH_CHAN_5GHZ 0x2000 + uint32_t freq; /* channel frequency */ + uint32_t maxrdpower; + uint32_t cfgctl; + uint32_t twiceantennareduction; + uint32_t channelchange; + uint32_t keeprccontent; +}; +#pragma pack() + +#pragma pack(1) +struct uath_cmd_rateset { + uint8_t length; +#define UATH_MAX_NRATES 32 + uint8_t set[UATH_MAX_NRATES]; +}; +#pragma pack() + +#pragma pack(1) +/* structure for command WDCMSG_SET_BASIC_RATE */ +struct uath_cmd_rates { + uint32_t connid; + uint32_t keeprccontent; + uint32_t size; + struct uath_cmd_rateset rateset; +}; +#pragma pack() + +enum { + WLAN_MODE_NONE = 0, + WLAN_MODE_11b, + WLAN_MODE_11a, + WLAN_MODE_11g, + WLAN_MODE_11a_TURBO, + WLAN_MODE_11g_TURBO, + WLAN_MODE_11a_TURBO_PRIME, + WLAN_MODE_11g_TURBO_PRIME, + WLAN_MODE_11a_XR, + WLAN_MODE_11g_XR, +}; + +#pragma pack(1) +struct uath_cmd_connection_attr { + uint32_t longpreambleonly; + struct uath_cmd_rateset rateset; + uint32_t wlanmode; +}; +#pragma pack() + +#pragma pack(1) +/* structure for command WDCMSG_CREATE_CONNECTION */ +struct uath_cmd_create_connection { + uint32_t connid; + uint32_t bssid; + uint32_t size; + struct uath_cmd_connection_attr connattr; +}; +#pragma pack() + +#pragma pack(1) +struct uath_cmd_txq_attr { + uint32_t priority; + uint32_t aifs; + uint32_t logcwmin; + uint32_t logcwmax; + uint32_t bursttime; + uint32_t mode; + uint32_t qflags; +}; +#pragma pack() + +#pragma pack(1) +struct uath_cmd_txq_setup { /* WDCMSG_SETUP_TX_QUEUE */ + uint32_t qid; + uint32_t len; + struct uath_cmd_txq_attr attr; +}; +#pragma pack() + +#pragma pack(1) +struct uath_cmd_rx_filter { /* WDCMSG_RX_FILTER */ + uint32_t bits; +#define UATH_FILTER_RX_UCAST 0x00000001 +#define UATH_FILTER_RX_MCAST 0x00000002 +#define UATH_FILTER_RX_BCAST 0x00000004 +#define UATH_FILTER_RX_CONTROL 0x00000008 +#define UATH_FILTER_RX_BEACON 0x00000010 /* beacon frames */ +#define UATH_FILTER_RX_PROM 0x00000020 /* promiscuous mode */ +#define UATH_FILTER_RX_PHY_ERR 0x00000040 /* phy errors */ +#define UATH_FILTER_RX_PHY_RADAR 0x00000080 /* radar phy errors */ +#define UATH_FILTER_RX_XR_POOL 0x00000400 /* XR group polls */ +#define UATH_FILTER_RX_PROBE_REQ 0x00000800 + uint32_t op; +#define UATH_FILTER_OP_INIT 0x0 +#define UATH_FILTER_OP_SET 0x1 +#define UATH_FILTER_OP_CLEAR 0x2 +#define UATH_FILTER_OP_TEMP 0x3 +#define UATH_FILTER_OP_RESTORE 0x4 +}; +#pragma pack() + +#pragma pack(1) +struct uath_cmd_set_associd { /* WDCMSG_WRITE_ASSOCID */ + uint32_t defaultrateix; + uint32_t associd; + uint32_t timoffset; + uint32_t turboprime; + uint32_t bssid[2]; +}; +#pragma pack() + +enum { + CFG_NONE, /* Sentinal to indicate "no config" */ + CFG_REG_DOMAIN, /* Regulatory Domain */ + CFG_RATE_CONTROL_ENABLE, + CFG_DEF_XMIT_DATA_RATE, /* NB: if rate control is not enabled */ + CFG_HW_TX_RETRIES, + CFG_SW_TX_RETRIES, + CFG_SLOW_CLOCK_ENABLE, + CFG_COMP_PROC, + CFG_USER_RTS_THRESHOLD, + CFG_XR2NORM_RATE_THRESHOLD, + CFG_XRMODE_SWITCH_COUNT, + CFG_PROTECTION_TYPE, + CFG_BURST_SEQ_THRESHOLD, + CFG_ABOLT, + CFG_IQ_LOG_COUNT_MAX, + CFG_MODE_CTS, + CFG_WME_ENABLED, + CFG_GPRS_CBR_PERIOD, + CFG_SERVICE_TYPE, + /* MAC Address to use. Overrides EEPROM */ + CFG_MAC_ADDR, + CFG_DEBUG_EAR, + CFG_INIT_REGS, + /* An ID for use in error & debug messages */ + CFG_DEBUG_ID, + CFG_COMP_WIN_SZ, + CFG_DIVERSITY_CTL, + CFG_TP_SCALE, + CFG_TPC_HALF_DBM5, + CFG_TPC_HALF_DBM2, + CFG_OVERRD_TX_POWER, + CFG_USE_32KHZ_CLOCK, + CFG_GMODE_PROTECTION, + CFG_GMODE_PROTECT_RATE_INDEX, + CFG_GMODE_NON_ERP_PREAMBLE, + CFG_WDC_TRANSPORT_CHUNK_SIZE, +}; + +enum { + /* Sentinal to indicate "no capability" */ + CAP_NONE, + CAP_ALL, /* ALL capabilities */ + CAP_TARGET_VERSION, + CAP_TARGET_REVISION, + CAP_MAC_VERSION, + CAP_MAC_REVISION, + CAP_PHY_REVISION, + CAP_ANALOG_5GHz_REVISION, + CAP_ANALOG_2GHz_REVISION, + /* Target supports WDC message debug features */ + CAP_DEBUG_WDCMSG_SUPPORT, + + CAP_REG_DOMAIN, + CAP_COUNTRY_CODE, + CAP_REG_CAP_BITS, + + CAP_WIRELESS_MODES, + CAP_CHAN_SPREAD_SUPPORT, + CAP_SLEEP_AFTER_BEACON_BROKEN, + CAP_COMPRESS_SUPPORT, + CAP_BURST_SUPPORT, + CAP_FAST_FRAMES_SUPPORT, + CAP_CHAP_TUNING_SUPPORT, + CAP_TURBOG_SUPPORT, + CAP_TURBO_PRIME_SUPPORT, + CAP_DEVICE_TYPE, + CAP_XR_SUPPORT, + CAP_WME_SUPPORT, + CAP_TOTAL_QUEUES, + CAP_CONNECTION_ID_MAX, /* Should absorb CAP_KEY_CACHE_SIZE */ + + CAP_LOW_5GHZ_CHAN, + CAP_HIGH_5GHZ_CHAN, + CAP_LOW_2GHZ_CHAN, + CAP_HIGH_2GHZ_CHAN, + + CAP_MIC_AES_CCM, + CAP_MIC_CKIP, + CAP_MIC_TKIP, + CAP_MIC_TKIP_WME, + CAP_CIPHER_AES_CCM, + CAP_CIPHER_CKIP, + CAP_CIPHER_TKIP, + + CAP_TWICE_ANTENNAGAIN_5G, + CAP_TWICE_ANTENNAGAIN_2G, +}; + +enum { + ST_NONE, /* Sentinal to indicate "no status" */ + ST_ALL, + ST_SERVICE_TYPE, + ST_WLAN_MODE, + ST_FREQ, + ST_BAND, + ST_LAST_RSSI, + ST_PS_FRAMES_DROPPED, + ST_CACHED_DEF_ANT, + ST_COUNT_OTHER_RX_ANT, + ST_USE_FAST_DIVERSITY, + ST_MAC_ADDR, + ST_RX_GENERATION_NUM, + ST_TX_QUEUE_DEPTH, + ST_SERIAL_NUMBER, + ST_WDC_TRANSPORT_CHUNK_SIZE, +}; + +enum { + TARGET_DEVICE_AWAKE, + TARGET_DEVICE_SLEEP, + TARGET_DEVICE_PWRDN, + TARGET_DEVICE_PWRSAVE, + TARGET_DEVICE_SUSPEND, + TARGET_DEVICE_RESUME, +}; + +#define UATH_MAX_TXBUFSZ \ + (sizeof (struct uath_chunk) + sizeof (struct uath_tx_desc) + \ + IEEE80211_MAX_LEN) + +/* + * it's not easy to measure how the chunk is passed into the host if the target + * passed the multi-chunks so just we check a minimal size we can imagine. + */ +#define UATH_MIN_RXBUFSZ (sizeof (struct uath_chunk)) + +#define USB_VENDOR_ACCTON 0x083a /* Accton Technology */ +#define USB_VENDOR_ATHEROS 0x168c /* Atheros Communications */ +#define USB_VENDOR_ATHEROS2 0x0cf3 /* Atheros Communications */ +#define USB_VENDOR_CONCEPTRONIC 0x0d8e /* Conceptronic */ +#define USB_VENDOR_DLINK 0x2001 /* D-Link */ +#define USB_VENDOR_GIGASET 0x1690 /* Gigaset */ +#define USB_VENDOR_GLOBALSUN 0x16ab /* Global Sun Technology */ +#define USB_VENDOR_IODATA 0x04bb /* I/O Data */ +#define USB_VENDOR_MELCO 0x0411 /* Melco */ +#define USB_VENDOR_NETGEAR 0x0846 /* BayNETGEAR */ +#define USB_VENDOR_NETGEAR3 0x1385 /* Netgear */ +#define USB_VENDOR_PHILIPS 0x0471 /* Philips */ +#define USB_VENDOR_UMEDIA 0x157e /* U-MEDIA Communications */ +#define USB_VENDOR_WISTRONNEWEB 0x1435 /* Wistron NeWeb */ +#define USB_VENDOR_ZCOM 0x0cde /* Z-Com */ + +#define USB_PRODUCT_ACCTON_SMCWUSBTG2 0x4506 /* SMCWUSBT-G2 */ +#define USB_PRODUCT_ACCTON_SMCWUSBTG2_NF 0x4507 /* SMCWUSBT-G2 */ +#define USB_PRODUCT_ATHEROS_AR5523 0x0001 /* AR5523 */ +#define USB_PRODUCT_ATHEROS_AR5523_NF 0x0002 /* AR5523 */ +#define USB_PRODUCT_ATHEROS2_AR5523_1 0x0003 /* AR5523 */ +#define USB_PRODUCT_ATHEROS2_AR5523_1_NF 0x0002 /* AR5523 */ +#define USB_PRODUCT_ATHEROS2_AR5523_2 0x0005 /* AR5523 */ +#define USB_PRODUCT_ATHEROS2_AR5523_2_NF 0x0004 /* AR5523 */ +#define USB_PRODUCT_ATHEROS2_AR5523_3 0x0007 /* AR5523 */ +#define USB_PRODUCT_ATHEROS2_AR5523_3_NF 0x0006 /* AR5523 */ +#define USB_PRODUCT_CONCEPTRONIC_AR5523_1 0x7801 /* AR5523 */ +#define USB_PRODUCT_CONCEPTRONIC_AR5523_1_NF 0x7802 /* AR5523 */ +#define USB_PRODUCT_CONCEPTRONIC_AR5523_2 0x7811 /* AR5523 */ +#define USB_PRODUCT_CONCEPTRONIC_AR5523_2_NF 0x7812 /* AR5523 */ +#define USB_PRODUCT_DLINK_DWLAG122 0x3a04 /* DWL-AG122 */ +#define USB_PRODUCT_DLINK_DWLAG122_NF 0x3a05 /* DWL-AG122 */ +#define USB_PRODUCT_DLINK_DWLAG132 0x3a00 /* DWL-AG132 */ +#define USB_PRODUCT_DLINK_DWLAG132_NF 0x3a01 /* DWL-AG132 */ +#define USB_PRODUCT_DLINK_DWLG132 0x3a02 /* DWL-G132 */ +#define USB_PRODUCT_DLINK_DWLG132_NF 0x3a03 /* DWL-G132 */ +#define USB_PRODUCT_GIGASET_AR5523 0x0712 /* AR5523 */ +#define USB_PRODUCT_GIGASET_AR5523_NF 0x0713 /* AR5523 */ +#define USB_PRODUCT_GIGASET_SMCWUSBTG 0x0710 /* SMCWUSBT-G */ +#define USB_PRODUCT_GIGASET_SMCWUSBTG_NF 0x0711 /* SMCWUSBT-G */ +#define USB_PRODUCT_GLOBALSUN_AR5523_1 0x7801 /* AR5523 */ +#define USB_PRODUCT_GLOBALSUN_AR5523_1_NF 0x7802 /* AR5523 */ +#define USB_PRODUCT_GLOBALSUN_AR5523_2 0x7811 /* AR5523 */ +#define USB_PRODUCT_GLOBALSUN_AR5523_2_NF 0x7812 /* AR5523 */ +#define USB_PRODUCT_IODATA_USBWNG54US 0x0928 /* USB WN-G54/US */ +#define USB_PRODUCT_IODATA_USBWNG54US_NF 0x0929 /* USB WN-G54/US */ +#define USB_PRODUCT_MELCO_WLIU2KAMG54 0x0091 /* WLI-U2-KAMG54 */ +#define USB_PRODUCT_MELCO_WLIU2KAMG54_NF 0x0092 /* WLI-U2-KAMG54 */ +#define USB_PRODUCT_NETGEAR_WG111U 0x4300 /* WG111U */ +#define USB_PRODUCT_NETGEAR_WG111U_NF 0x4301 /* WG111U */ +#define USB_PRODUCT_NETGEAR3_WG111T 0x4252 /* WG111T */ +#define USB_PRODUCT_NETGEAR3_WG111T_NF 0x4251 /* WG111T */ +#define USB_PRODUCT_NETGEAR3_WPN111 0x5f00 /* WPN111 */ +#define USB_PRODUCT_NETGEAR3_WPN111_NF 0x5f01 /* WPN111 */ +#define USB_PRODUCT_PHILIPS_SNU6500 0x1232 /* SNU6500 */ +#define USB_PRODUCT_PHILIPS_SNU6500_NF 0x1233 /* SNU6500 */ +#define USB_PRODUCT_UMEDIA_AR5523_2 0x3205 /* AR5523 */ +#define USB_PRODUCT_UMEDIA_AR5523_2_NF 0x3206 /* AR5523 */ +#define USB_PRODUCT_UMEDIA_TEW444UBEU 0x3006 /* TEW-444UB EU */ +#define USB_PRODUCT_UMEDIA_TEW444UBEU_NF 0x3007 /* TEW-444UB EU */ +#define USB_PRODUCT_WISTRONNEWEB_AR5523_1 0x0826 /* AR5523 */ +#define USB_PRODUCT_WISTRONNEWEB_AR5523_1_NF 0x0827 /* AR5523 */ +#define USB_PRODUCT_WISTRONNEWEB_AR5523_2 0x082a /* AR5523 */ +#define USB_PRODUCT_WISTRONNEWEB_AR5523_2_NF 0x0829 /* AR5523 */ +#define USB_PRODUCT_ZCOM_AR5523 0x0012 /* AR5523 */ +#define USB_PRODUCT_ZCOM_AR5523_NF 0x0013 /* AR5523 */ + +#ifdef __cplusplus +} +#endif + +#endif /* _UATH_REG_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/io/uath/uath_var.h Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,264 @@ +/* + * + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Copyright (c) 2006 + * Damien Bergamini <damien.bergamini@free.fr> + * Copyright (c) 2006 Sam Leffler, Errno Consulting + * Copyright (c) 2008-2009 Weongyo Jeong <weongyo@freebsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +#ifndef _UATH_VAR_H +#define _UATH_VAR_H + +#include <sys/queue.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define UATH_ID_BSS 2 /* Connection ID */ + +#define UATH_RX_DATA_LIST_COUNT 1 /* 128 */ +#define UATH_TX_DATA_LIST_COUNT 8 /* 16 */ +#define UATH_CMD_LIST_COUNT 8 /* 60 */ + +#define UATH_DATA_TIMEOUT 10000 +#define UATH_CMD_TIMEOUT 1000 + +/* + * Useful combinations of channel characteristics from net80211. + */ +#define UATH_CHAN_A \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM) +#define UATH_CHAN_B \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK) +#define UATH_CHAN_PUREG \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM) +#define UATH_CHAN_G \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN) + +#define UATH_IS_CHAN_A(_c) \ + (((_c)->ich_flags & UATH_CHAN_A) == UATH_CHAN_A) +#define UATH_IS_CHAN_B(_c) \ + (((_c)->ich_flags & UATH_CHAN_B) == UATH_CHAN_B) +#define UATH_IS_CHAN_PUREG(_c) \ + (((_c)->ich_flags & UATH_CHAN_PUREG) == UATH_CHAN_PUREG) +#define UATH_IS_CHAN_G(_c) \ + (((_c)->ich_flags & UATH_CHAN_G) == UATH_CHAN_G) +#define UATH_IS_CHAN_ANYG(_c) \ + (UATH_IS_CHAN_PUREG(_c) || UATH_IS_CHAN_G(_c)) + +#define UATH_IS_CHAN_OFDM(_c) \ + ((_c)->ich_flags & IEEE80211_CHAN_OFDM) +#define UATH_IS_CHAN_CCK(_c) \ + ((_c)->ich_flags & IEEE80211_CHAN_CCK) + +#define UATH_NODE_QOS 0x0002 /* QoS enabled */ + + +/* flags for sending firmware commands */ +#define UATH_CMD_FLAG_ASYNC (1 << 0) +#define UATH_CMD_FLAG_READ (1 << 1) +#define UATH_CMD_FLAG_MAGIC (1 << 2) + +struct uath_cmd { + struct uath_softc *sc; + uint32_t flags; + uint32_t msgid; + uint8_t *buf; + uint16_t buflen; + void *odata; /* NB: tx only */ + int olen; /* space in odata */ + STAILQ_ENTRY(uath_cmd) next; +}; +typedef STAILQ_HEAD(, uath_cmd) uath_cmdhead; + +struct uath_data { + struct uath_softc *sc; + uint8_t *buf; + uint16_t buflen; + struct ieee80211_node *ni; /* NB: tx only */ + STAILQ_ENTRY(uath_data) next; +}; +typedef STAILQ_HEAD(, uath_data) uath_datahead; + +struct uath_cmd_lock { + boolean_t done; + kmutex_t mutex; + kcondvar_t cv; +}; + +struct uath_wme_settings { + uint8_t aifsn; + uint8_t logcwmin; + uint8_t logcwmax; + uint16_t txop; +#define UATH_TXOP_TO_US(txop) ((txop) << 5) + uint8_t acm; +}; + +struct uath_devcap { + uint32_t targetVersion; + uint32_t targetRevision; + uint32_t macVersion; + uint32_t macRevision; + uint32_t phyRevision; + uint32_t analog5GhzRevision; + uint32_t analog2GhzRevision; + uint32_t regDomain; + uint32_t regCapBits; + uint32_t countryCode; + uint32_t keyCacheSize; + uint32_t numTxQueues; + uint32_t connectionIdMax; + uint32_t wirelessModes; +#define UATH_WIRELESS_MODE_11A 0x01 +#define UATH_WIRELESS_MODE_TURBO 0x02 +#define UATH_WIRELESS_MODE_11B 0x04 +#define UATH_WIRELESS_MODE_11G 0x08 +#define UATH_WIRELESS_MODE_108G 0x10 + uint32_t chanSpreadSupport; + uint32_t compressSupport; + uint32_t burstSupport; + uint32_t fastFramesSupport; + uint32_t chapTuningSupport; + uint32_t turboGSupport; + uint32_t turboPrimeSupport; + uint32_t deviceType; + uint32_t wmeSupport; + uint32_t low2GhzChan; + uint32_t high2GhzChan; + uint32_t low5GhzChan; + uint32_t high5GhzChan; + uint32_t supportCipherWEP; + uint32_t supportCipherAES_CCM; + uint32_t supportCipherTKIP; + uint32_t supportCipherMicAES_CCM; + uint32_t supportMicTKIP; + uint32_t twiceAntennaGain5G; + uint32_t twiceAntennaGain2G; +}; + +struct uath_stat { + uint32_t st_badchunkseqnum; + uint32_t st_invalidlen; + uint32_t st_multichunk; + uint32_t st_toobigrxpkt; + uint32_t st_stopinprogress; + uint32_t st_crcerr; + uint32_t st_phyerr; + uint32_t st_decrypt_crcerr; + uint32_t st_decrypt_micerr; + uint32_t st_decomperr; + uint32_t st_keyerr; + uint32_t st_err; + /* not use CMD/RX/TX queues, so ignore some structure */ +}; +#define UATH_STAT_INC(sc, var) (sc)->sc_stat.var++ +#define UATH_STAT_DEC(sc, var) (sc)->sc_stat.var-- + +struct uath_softc { + struct ieee80211com sc_ic; + dev_info_t *sc_dev; + + usb_client_dev_data_t *sc_udev; /* usb dev */ + int dev_flags; + uint32_t sc_flags; + + usb_pipe_handle_t rx_cmd_pipe; + usb_pipe_handle_t rx_data_pipe; + usb_pipe_handle_t tx_cmd_pipe; + usb_pipe_handle_t tx_data_pipe; + + kmutex_t sc_genlock; + kmutex_t sc_rxlock_cmd; + kmutex_t sc_rxlock_data; + kmutex_t sc_txlock_cmd; + kmutex_t sc_txlock_data; + + struct uath_cmd sc_cmd[UATH_CMD_LIST_COUNT]; + struct uath_data sc_rx[UATH_RX_DATA_LIST_COUNT]; + struct uath_data sc_tx[UATH_TX_DATA_LIST_COUNT]; + + int tx_cmd_queued; + int rx_cmd_queued; + int tx_data_queued; + int rx_data_queued; + + int sc_cmdid; + + struct uath_stat sc_stat; + + struct uath_cmd_lock rlock; + struct uath_cmd_lock wlock; + + struct uath_devcap sc_devcap; + uint8_t sc_serial[16]; + + uint32_t sc_msgid; + uint32_t sc_seqnum; + + uint8_t sc_intrx_nextnum; + uint32_t sc_intrx_len; +#define UATH_MAX_INTRX_SIZE 3616 + + timeout_id_t sc_scan_id; + timeout_id_t sc_stat_id; + + uint32_t sc_need_sched; + + /* kstats */ + uint32_t sc_tx_nobuf; + uint32_t sc_rx_nobuf; + uint32_t sc_tx_err; + uint32_t sc_rx_err; + uint32_t sc_tx_retries; + + int (*sc_newstate)(struct ieee80211com *, + enum ieee80211_state, int); +}; + +#define UATH_SUCCESS 0 +#define UATH_FAILURE -1 + +#define UATH_FLAG_RUNNING (1 << 0) +#define UATH_FLAG_SUSPEND (1 << 1) +#define UATH_FLAG_RECONNECT (1 << 2) +#define UATH_FLAG_DISCONNECT (1 << 3) + +#define UATH_LOCK(sc) mutex_enter(&(sc)->sc_genlock) +#define UATH_UNLOCK(sc) mutex_exit(&(sc)->sc_genlock) +#define UATH_IS_RUNNING(_sc) ((_sc)->sc_flags & UATH_FLAG_RUNNING) +#define UATH_IS_SUSPEND(_sc) ((_sc)->sc_flags & UATH_FLAG_SUSPEND) +#define UATH_IS_DISCONNECT(_sc) ((_sc)->sc_flags & UATH_FLAG_DISCONNECT) +#define UATH_IS_RECONNECT(_sc) ((_sc)->sc_flags & UATH_FLAG_RECONNECT) + +#define UATH_RESET_INTRX(sc) do { \ + (sc)->sc_intrx_nextnum = 0; \ + (sc)->sc_intrx_len = 0; \ + _NOTE(CONSTCOND) \ +} while (0) + + +#ifdef __cplusplus +} +#endif + +#endif /* _UATH_VAR_H */
--- a/usr/src/uts/common/io/vuidmice/vuidps2.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/io/vuidmice/vuidps2.c Mon Jul 20 13:07:46 2009 -0400 @@ -59,18 +59,18 @@ #define PS2_DELTA_Y 3 /* Got delta X */ #define PS2_WHEEL_DELTA_Z 4 #define PS2_WHEEL5_DELTA_Z 5 -#define PS2_WAIT_RESET_ACK 6 -#define PS2_WAIT_RESET_AA 7 -#define PS2_WAIT_RESET_00 8 +#define PS2_WAIT_RESET_COMPLETE 6 +#define PS2_WAIT_FOR_AA 7 +#define PS2_WAIT_FOR_00 8 #define PS2_WAIT_SETRES0_ACK1 9 #define PS2_WAIT_SETRES0_ACK2 10 /* -+ must be consecutive */ #define PS2_WAIT_SCALE1_1_ACK 11 /* | */ #define PS2_WAIT_SCALE1_2_ACK 12 /* | */ #define PS2_WAIT_SCALE1_3_ACK 13 /* -+ */ -#define PS2_WAIT_STATREQ_ACK 14 -#define PS2_WAIT_STATUS_1 15 -#define PS2_WAIT_STATUS_BUTTONS 16 -#define PS2_WAIT_STATUS_REV 17 +#define PS2_WAIT_STATREQ_ACK 14 /* -+ */ +#define PS2_WAIT_STATUS_1 15 /* | */ +#define PS2_WAIT_STATUS_BUTTONS 16 /* | must stay in this order */ +#define PS2_WAIT_STATUS_REV 17 /* -+ */ #define PS2_WAIT_STATUS_3 18 #define PS2_WAIT_WHEEL_SMPL1_CMD_ACK 19 /* Set the sample rate to 200 */ #define PS2_WAIT_WHEEL_SMPL1_RATE_ACK 20 @@ -94,9 +94,6 @@ #define PS2_WAIT_STREAM_ACK 38 #define PS2_WAIT_ON_ACK 39 -#define MSE_AA 0xaa -#define MSE_00 0x00 - #define MOUSE_MODE_PLAIN 0 /* Normal PS/2 mouse - 3 byte msgs */ #define MOUSE_MODE_WHEEL 1 /* Wheel mouse - 4 byte msgs */ #define MOUSE_MODE_WHEEL5 2 /* Wheel + 5 btn mouse - 4 byte msgs */ @@ -115,7 +112,6 @@ #define PS2_MAX_INIT_COUNT 5 - static void vuidmice_send_wheel_event(queue_t *const, uchar_t, uchar_t, uchar_t, int); extern void VUID_PUTNEXT(queue_t *const, uchar_t, uchar_t, uchar_t, int); @@ -126,7 +122,6 @@ * We apply timeout to nearly each command-response * during initialization: * - * Set timeout for RESET * Set timeout for SET RESOLUTION * Set timeout for SET SCALE * Set timeout for SET SAMPLE RATE @@ -141,7 +136,8 @@ static void vuid_set_timeout(queue_t *const qp, clock_t time) { - ASSERT(STATEP->init_tid == 0); + if (STATEP->init_tid != 0) + (void) quntimeout(qp, STATEP->init_tid); STATEP->init_tid = qtimeout(qp, VUID_INIT_TIMEOUT, qp, drv_usectohz(time)); } @@ -149,7 +145,6 @@ static void vuid_cancel_timeout(queue_t *const qp) { - ASSERT(STATEP->init_tid != 0); (void) quntimeout(qp, STATEP->init_tid); STATEP->init_tid = 0; } @@ -214,6 +209,30 @@ } } +static void +vuidmice_start_wdc_or_setres(queue_t *qp) +{ + /* Set timeout for set res or sample rate */ + vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_GROUP); + + /* + * Start the wheel-mouse detection code. First, we look + * for standard wheel mice. If we set the sample rate + * to 200, 100, and then 80 and finally request the + * device ID, a wheel mouse will return an ID of 0x03. + * After that, we'll try for the wheel+5 variety. The + * incantation in this case is 200, 200, and 80. We'll + * get 0x04 back in that case. + */ + if (STATEP->inited & PS2_FLAG_NO_EXTN) { + STATEP->state = PS2_WAIT_SETRES3_ACK1; + put1(WR(qp), MSESETRES); + } else { + STATEP->state = PS2_WAIT_WHEEL_SMPL1_CMD_ACK; + put1(WR(qp), MSECHGMOD); + } +} + int VUID_OPEN(queue_t *const qp) { @@ -222,10 +241,7 @@ STATEP->inited = 0; STATEP->nbuttons = 3; - STATEP->state = PS2_WAIT_RESET_ACK; - - /* Set timeout for reset */ - vuid_set_timeout(qp, PS2_INIT_TMOUT_RESET); + STATEP->state = PS2_WAIT_RESET_COMPLETE; put1(WR(qp), MSERESET); @@ -277,24 +293,49 @@ STATEP->inited |= PS2_FLAG_NO_EXTN; } - if (++STATEP->init_count >= PS2_MAX_INIT_COUNT) { - STATEP->inited |= PS2_FLAG_INIT_TIMEOUT; + + /* + * If the Logitech button detection sequence timed out at some point + * in the sequence, ignore it and skip to the next step in + * initialization. Do NOT count this as a timeout, so do NOT + * increment init_count. + */ + if (STATEP->state >= PS2_WAIT_STATREQ_ACK && + STATEP->state <= PS2_WAIT_STATUS_REV) { + + /* See the comment under the PS2_WAIT_STATUS_BUTTONS case */ +#if defined(VUID3PS2) + STATEP->nbuttons = 3; +#else + STATEP->nbuttons = 2; +#endif + vuidmice_start_wdc_or_setres(qp); return; } - - STATEP->state = PS2_WAIT_RESET_ACK; + /* + * If the initialization process has timed out too many times, even if + * a subset of the process was successful, stop trying and put the + * mouse in the only state from which it can recover -- waiting for an + * 0xAA 0x00 response (i.e. like one we get on resume from mouse8042 + * or from a replug). + */ + if (++STATEP->init_count >= PS2_MAX_INIT_COUNT) { + STATEP->inited |= PS2_FLAG_INIT_TIMEOUT; + STATEP->state = PS2_WAIT_FOR_AA; + } else { - vuid_set_timeout(qp, PS2_INIT_TMOUT_RESET); + STATEP->state = PS2_WAIT_RESET_COMPLETE; - /* try again */ - put1(WR(qp), MSERESET); + /* Try to reset the mouse again */ + put1(WR(qp), MSERESET); + } } void VUID_QUEUE(queue_t *const qp, mblk_t *mp) { - int code; + int code, length; clock_t now; clock_t elapsed; clock_t mouse_timeout; @@ -305,6 +346,7 @@ STATEP->last_event_lbolt = now; while (mp->b_rptr < mp->b_wptr) { + length = MBLKL(mp); code = *mp->b_rptr++; switch (STATEP->state) { @@ -391,10 +433,39 @@ break; + case PS2_WAIT_FOR_AA: + /* + * On Dell latitude D800, the initial MSE_ACK is + * received after the initialization sequence + * times out, so restart it here. + */ + if (code == MSE_ACK) { + STATEP->inited &= ~PS2_FLAG_INIT_TIMEOUT; + STATEP->init_count = 0; + STATEP->state = PS2_WAIT_RESET_COMPLETE; + put1(WR(qp), MSERESET); + break; + } + + if (code != MSE_AA) + break; + + STATEP->state = PS2_WAIT_FOR_00; + break; + + case PS2_WAIT_FOR_00: + if (code != MSE_00) + break; + + STATEP->inited &= ~PS2_FLAG_INIT_TIMEOUT; + STATEP->init_count = 0; + STATEP->state = PS2_WAIT_RESET_COMPLETE; + put1(WR(qp), MSERESET); + break; + case PS2_MAYBE_REATTACH: if (code == MSE_00) { - STATEP->state = PS2_WAIT_RESET_ACK; - vuid_set_timeout(qp, PS2_INIT_TMOUT_RESET); + STATEP->state = PS2_WAIT_RESET_COMPLETE; put1(WR(qp), MSERESET); break; } @@ -542,48 +613,45 @@ STATEP->deltax = STATEP->deltay = 0; break; - case PS2_WAIT_RESET_ACK: - if (code != MSE_ACK) { + case PS2_WAIT_RESET_COMPLETE: + + /* + * If length is 1, code holds the data from the message. + * for lengths > 1, we look at *(mp->b_rptr + offset) + * for the rest of the data. + */ + if (length == 1) { + /* + * Technically, a length of 1 from the mouse + * driver should only contain a MSEERROR or + * MSERESEND value, but we don't test + * that here because we'd be issuing a reset + * anyway. For mice that are not connected, + * we will receive a MSERESEND quickly. + */ + if (++STATEP->init_count >= + PS2_MAX_INIT_COUNT) { + STATEP->inited |= PS2_FLAG_INIT_TIMEOUT; + STATEP->state = PS2_WAIT_FOR_AA; + } else { + put1(WR(qp), MSERESET); + } + break; + + } else if (length != 3) { break; } - /* - * On Dell latitude D800, we find that the MSE_ACK is - * coming up even after timeout in VUID_OPEN during - * early boot. So here (PS2_WAIT_RESET_ACK) we check - * if timeout happened before, if true, we reset the - * timeout to restart the initialization. - */ - if (STATEP->inited & PS2_FLAG_INIT_TIMEOUT) { - STATEP->inited &= ~PS2_FLAG_INIT_TIMEOUT; - STATEP->init_count = 0; - vuid_set_timeout(qp, PS2_INIT_TMOUT_RESET); - break; - } + mp->b_rptr += 2; /* Skip past the 0xAA 0x00 */ - STATEP->state = PS2_WAIT_RESET_AA; - break; - - case PS2_WAIT_RESET_AA: - if (code != MSE_AA) { - break; - } - STATEP->state = PS2_WAIT_RESET_00; - break; - - case PS2_WAIT_RESET_00: - if (code != MSE_00) { - break; - } - - /* Reset has been ok */ - vuid_cancel_timeout(qp); + /* Reset completed successfully */ STATEP->state = PS2_WAIT_SETRES0_ACK1; /* Set timeout for set res */ vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_GROUP); + /* Begin Logitech autodetect sequence */ put1(WR(qp), MSESETRES); break; @@ -673,30 +741,12 @@ case PS2_WAIT_STATUS_3: - /* Status request has been ok */ + /* Status request completed successfully */ vuid_cancel_timeout(qp); - /* Set timeout for set res or sample rate */ - vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_GROUP); + vuidmice_start_wdc_or_setres(qp); + break; - /* - * Start the wheel-mouse detection code. First, we look - * for standard wheel mice. If we set the sample rate - * to 200, 100, and then 80 and finally request the - * device ID, a wheel mouse will return an ID of 0x03. - * After that, we'll try for the wheel+5 variety. The - * incantation in this case is 200, 200, and 80. We'll - * get 0x04 back in that case. - */ - if (STATEP->inited & PS2_FLAG_NO_EXTN) { - STATEP->state = PS2_WAIT_SETRES3_ACK1; - put1(WR(qp), MSESETRES); - } else { - STATEP->state = PS2_WAIT_WHEEL_SMPL1_CMD_ACK; - put1(WR(qp), MSECHGMOD); - } - - break; case PS2_WAIT_WHEEL_SMPL1_CMD_ACK: if (code != MSE_ACK) { break; @@ -741,7 +791,7 @@ break; } - /* Set sample rate has been ok */ + /* Set sample rate completed successfully */ vuid_cancel_timeout(qp); STATEP->state = PS2_WAIT_WHEEL_DEV_CMD; @@ -761,7 +811,7 @@ case PS2_WAIT_WHEEL_DEV_ACK: - /* Get dev has been ok */ + /* Get dev completed successfully */ vuid_cancel_timeout(qp); if (code != 0x03) { @@ -837,7 +887,7 @@ break; } - /* Set sample rate has been ok */ + /* Set sample rate completed successfully */ vuid_cancel_timeout(qp); STATEP->state = PS2_WAIT_WHEEL5_DEV_CMD; @@ -869,7 +919,7 @@ MOUSE_MODE_WHEEL; } - /* Wheel5 get dev has been ok */ + /* Wheel5 get dev completed successfully */ vuid_cancel_timeout(qp); /* FALLTHROUGH */ @@ -897,7 +947,7 @@ break; } - /* Set res has been ok */ + /* Set res completed successfully */ vuid_cancel_timeout(qp); STATEP->state = PS2_WAIT_STREAM_ACK; @@ -922,9 +972,17 @@ break; } - /* Enable has been ok */ + /* Enable completed successfully */ + + /* + * The entire initialization sequence + * is complete. Now, we can clear the + * init_count retry counter. + */ + STATEP->init_count = 0; vuid_cancel_timeout(qp); + STATEP->state = PS2_START; break; }
--- a/usr/src/uts/common/nfs/nfs4.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/nfs/nfs4.h Mon Jul 20 13:07:46 2009 -0400 @@ -546,6 +546,7 @@ * finfo - reference to the open file for this state * share_access - how did the openowner OPEN the file (access) * share_deny - how did the openowner OPEN the file (deny) + * opened - has VOP_OPEN been done * closed - has this file been closed? * lostatelist - root of list of lo_state associated with this state/file * node - node for state struct list of states @@ -557,6 +558,7 @@ struct rfs4_file *rs_finfo; uint32_t rs_share_access; uint32_t rs_share_deny; + unsigned rs_opened:1; unsigned rs_closed:1; list_t rs_lostatelist; list_node_t rs_node;
--- a/usr/src/uts/common/os/devcfg.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/os/devcfg.c Mon Jul 20 13:07:46 2009 -0400 @@ -52,6 +52,7 @@ #include <sys/reboot.h> #include <sys/sysmacros.h> #include <sys/systm.h> +#include <sys/fs/sdev_impl.h> #include <sys/sunldi.h> #include <sys/sunldi_impl.h>
--- a/usr/src/uts/common/os/main.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/os/main.c Mon Jul 20 13:07:46 2009 -0400 @@ -485,7 +485,6 @@ * and swap have been set up. */ consconfig(); - release_bootstrap(); /* * attach drivers with ddi-forceattach prop @@ -544,6 +543,12 @@ start_other_cpus(0); /* + * Release bootstrap here since PROM interfaces are + * used to start other CPUs above. + */ + release_bootstrap(); + + /* * Finish lgrp initialization after all CPUS are brought online. */ lgrp_main_mp_init();
--- a/usr/src/uts/common/os/mem_config.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/os/mem_config.c Mon Jul 20 13:07:46 2009 -0400 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -72,20 +72,42 @@ static int delspan_reserve(pfn_t, pgcnt_t); static void delspan_unreserve(pfn_t, pgcnt_t); -static kmutex_t memseg_lists_lock; -static struct memseg *memseg_va_avail; +kmutex_t memseg_lists_lock; +struct memseg *memseg_va_avail; +struct memseg *memseg_alloc(void); static struct memseg *memseg_delete_junk; static struct memseg *memseg_edit_junk; void memseg_remap_init(void); -static void memseg_remap_to_dummy(caddr_t, pgcnt_t); +static void memseg_remap_to_dummy(struct memseg *); static void kphysm_addmem_error_undospan(pfn_t, pgcnt_t); static struct memseg *memseg_reuse(pgcnt_t); static struct kmem_cache *memseg_cache; /* - * Add a chunk of memory to the system. page_t's for this memory - * are allocated in the first few pages of the chunk. + * Interfaces to manage externally allocated + * page_t memory (metadata) for a memseg. + */ +#pragma weak memseg_alloc_meta +#pragma weak memseg_free_meta +#pragma weak memseg_get_metapfn +#pragma weak memseg_remap_meta + +extern int ppvm_enable; +extern page_t *ppvm_base; +extern int memseg_alloc_meta(pfn_t, pgcnt_t, void **, pgcnt_t *); +extern void memseg_free_meta(void *, pgcnt_t); +extern pfn_t memseg_get_metapfn(void *, pgcnt_t); +extern void memseg_remap_meta(struct memseg *); +static int memseg_is_dynamic(struct memseg *); +static int memseg_includes_meta(struct memseg *); +static pfn_t memseg_get_start(struct memseg *); +static void memseg_cpu_vm_flush(void); + +int meta_alloc_enable; + +/* + * Add a chunk of memory to the system. * base: starting PAGESIZE page of new memory. * npgs: length in PAGESIZE pages. * @@ -94,24 +116,35 @@ * dynamically most likely means more hash misses, since the tables will * be smaller than they otherwise would be. */ +#ifdef DEBUG +static int memseg_debug; +#define MEMSEG_DEBUG(args...) if (memseg_debug) printf(args) +#else +#define MEMSEG_DEBUG(...) +#endif + int kphysm_add_memory_dynamic(pfn_t base, pgcnt_t npgs) { - page_t *pp; - page_t *opp, *oepp; + page_t *pp; + page_t *opp, *oepp, *segpp; struct memseg *seg; uint64_t avmem; pfn_t pfn; pfn_t pt_base = base; pgcnt_t tpgs = npgs; - pgcnt_t metapgs; + pgcnt_t metapgs = 0; int exhausted; pfn_t pnum; int mnode; caddr_t vaddr; int reuse; int mlret; + int rv; + int flags; + int meta_alloc = 0; void *mapva; + void *metabase = (void *)base; pgcnt_t nkpmpgs = 0; offset_t kpm_pages_off; @@ -145,8 +178,7 @@ if (mlret == MEML_SPANOP_EALLOC) { delspan_unreserve(pt_base, tpgs); return (KPHYSM_ERESOURCE); - } else - if (mlret == MEML_SPANOP_ESPAN) { + } else if (mlret == MEML_SPANOP_ESPAN) { delspan_unreserve(pt_base, tpgs); return (KPHYSM_ESPAN); } else { @@ -155,6 +187,20 @@ } } + if (meta_alloc_enable) { + /* + * Allocate the page_t's from existing memory; + * if that fails, allocate from the incoming memory. + */ + rv = memseg_alloc_meta(base, npgs, &metabase, &metapgs); + if (rv == KPHYSM_OK) { + ASSERT(metapgs); + ASSERT(btopr(npgs * sizeof (page_t)) <= metapgs); + meta_alloc = 1; + goto mapalloc; + } + } + /* * We store the page_t's for this new memory in the first * few pages of the chunk. Here, we go and get'em ... @@ -220,13 +266,13 @@ */ if (exhausted) { kphysm_addmem_error_undospan(pt_base, tpgs); - /* * There is no specific error code for 'too small'. */ return (KPHYSM_ERESOURCE); } +mapalloc: /* * We may re-use a previously allocated VA space for the page_ts * eventually, but we need to initialize and lock the pages first. @@ -242,6 +288,8 @@ cmn_err(CE_WARN, "kphysm_add_memory_dynamic:" " Can't allocate VA for page_ts"); + if (meta_alloc) + memseg_free_meta(metabase, metapgs); kphysm_addmem_error_undospan(pt_base, tpgs); return (KPHYSM_ERESOURCE); @@ -258,6 +306,8 @@ pfn = pt_base; vaddr = (caddr_t)pp; for (pnum = 0; pnum < metapgs; pnum++) { + if (meta_alloc) + pfn = memseg_get_metapfn(metabase, (pgcnt_t)pnum); hat_devload(kas.a_hat, vaddr, ptob(1), pfn, PROT_READ | PROT_WRITE, HAT_LOAD | HAT_LOAD_LOCK | HAT_LOAD_NOCONSIST); @@ -276,7 +326,8 @@ HAT_UNLOAD_UNMAP|HAT_UNLOAD_UNLOCK); vmem_free(heap_arena, mapva, ptob(metapgs)); - + if (meta_alloc) + memseg_free_meta(metabase, metapgs); kphysm_addmem_error_undospan(pt_base, tpgs); return (KPHYSM_EFAULT); @@ -289,31 +340,26 @@ * this may change with COD or in larger SSM systems with * nested latency groups, so we must not assume that the * node does not yet exist. - * - * Also, using pt_base (page table base address) - * and tpgs (total number of pages) to mimic the case when a - * memory board is already installed in a system at boot - * time. This will ensure the entire address range is - * specified in order to have proper deletion. */ pnum = pt_base + tpgs - 1; - mem_node_add_slice(pt_base, pnum); + mem_node_add_range(pt_base, pnum); /* * Allocate or resize page counters as necessary to accommodate * the increase in memory pages. */ mnode = PFN_2_MEM_NODE(pnum); - if (page_ctrs_adjust(mnode) != 0) { - - mem_node_pre_del_slice(pt_base, pnum); - mem_node_post_del_slice(pt_base, pnum, 0); + PAGE_CTRS_ADJUST(base, npgs, rv); + if (rv) { + + mem_node_del_range(pt_base, pnum); hat_unload(kas.a_hat, (caddr_t)pp, ptob(metapgs), HAT_UNLOAD_UNMAP|HAT_UNLOAD_UNLOCK); vmem_free(heap_arena, mapva, ptob(metapgs)); - + if (meta_alloc) + memseg_free_meta(metabase, metapgs); kphysm_addmem_error_undospan(pt_base, tpgs); return (KPHYSM_ERESOURCE); @@ -333,9 +379,23 @@ memlist_write_unlock(); /* See if we can find a memseg to re-use. */ - seg = memseg_reuse(metapgs); - - reuse = (seg != NULL); + if (meta_alloc) { + seg = memseg_reuse(0); + reuse = 1; /* force unmapping of temp mapva */ + flags = MEMSEG_DYNAMIC | MEMSEG_META_ALLOC; + /* + * There is a 1:1 fixed relationship between a pfn + * and a page_t VA. The pfn is used as an index into + * the ppvm_base page_t table in order to calculate + * the page_t base address for a given pfn range. + */ + segpp = ppvm_base + base; + } else { + seg = memseg_reuse(metapgs); + reuse = (seg != NULL); + flags = MEMSEG_DYNAMIC | MEMSEG_META_INCL; + segpp = pp; + } /* * Initialize the memseg structure representing this memory @@ -343,15 +403,31 @@ * initialization and add the memory to the system. * In order to prevent lock deadlocks, the add_physmem() * code is repeated here, but split into several stages. + * + * If a memseg is reused, invalidate memseg pointers in + * all cpu vm caches. We need to do this this since the check + * pp >= seg->pages && pp < seg->epages + * used in various places is not atomic and so the first compare + * can happen before reuse and the second compare after reuse. + * The invalidation ensures that a memseg is not deferenced while + * it's page/pfn pointers are changing. */ if (seg == NULL) { - seg = kmem_cache_alloc(memseg_cache, KM_SLEEP); - bzero(seg, sizeof (struct memseg)); - seg->msegflags = MEMSEG_DYNAMIC; - seg->pages = pp; + seg = memseg_alloc(); + ASSERT(seg != NULL); + seg->msegflags = flags; + MEMSEG_DEBUG("memseg_get: alloc seg=0x%p, pages=0x%p", + (void *)seg, (void *)(seg->pages)); + seg->pages = segpp; } else { - /*EMPTY*/ - ASSERT(seg->msegflags & MEMSEG_DYNAMIC); + ASSERT(seg->msegflags == flags); + ASSERT(seg->pages_base == seg->pages_end); + MEMSEG_DEBUG("memseg_get: reuse seg=0x%p, pages=0x%p", + (void *)seg, (void *)(seg->pages)); + if (meta_alloc) { + memseg_cpu_vm_flush(); + seg->pages = segpp; + } } seg->epages = seg->pages + npgs; @@ -382,6 +458,9 @@ pfn = pt_base; vaddr = (caddr_t)seg->pages; for (pnum = 0; pnum < metapgs; pnum++) { + if (meta_alloc) + pfn = memseg_get_metapfn(metabase, + (pgcnt_t)pnum); hat_devload(kas.a_hat, vaddr, ptob(1), pfn, PROT_READ | PROT_WRITE, HAT_LOAD_REMAP | HAT_LOAD | HAT_LOAD_NOCONSIST); @@ -509,14 +588,16 @@ } /* - * Only return an available memseg of exactly the right size. + * Only return an available memseg of exactly the right size + * if size is required. * When the meta data area has it's own virtual address space * we will need to manage this more carefully and do best fit * allocations, possibly splitting an available area. */ -static struct memseg * +struct memseg * memseg_reuse(pgcnt_t metapgs) { + int type; struct memseg **segpp, *seg; mutex_enter(&memseg_lists_lock); @@ -525,12 +606,24 @@ for (; (seg = *segpp) != NULL; segpp = &seg->lnext) { caddr_t end; + /* + * Make sure we are reusing the right segment type. + */ + type = metapgs ? MEMSEG_META_INCL : MEMSEG_META_ALLOC; + + if ((seg->msegflags & (MEMSEG_META_INCL | MEMSEG_META_ALLOC)) + != type) + continue; + if (kpm_enable) end = hat_kpm_mseg_reuse(seg); else end = (caddr_t)seg->epages; - if (btopr(end - (caddr_t)seg->pages) == metapgs) { + /* + * Check for the right size if it is provided. + */ + if (!metapgs || btopr(end - (caddr_t)seg->pages) == metapgs) { *segpp = seg->lnext; seg->lnext = NULL; break; @@ -968,25 +1061,11 @@ /* * Return whether memseg was created by kphysm_add_memory_dynamic(). - * If this is the case and startp non zero, return also the start pfn - * of the meta data via startp. */ static int -memseg_is_dynamic(struct memseg *seg, pfn_t *startp) +memseg_is_dynamic(struct memseg *seg) { - pfn_t pt_start; - - if ((seg->msegflags & MEMSEG_DYNAMIC) == 0) - return (0); - - /* Meta data is required to be at the beginning */ - ASSERT(hat_getpfnum(kas.a_hat, (caddr_t)seg->epages) < seg->pages_base); - - pt_start = hat_getpfnum(kas.a_hat, (caddr_t)seg->pages); - if (startp != NULL) - *startp = pt_start; - - return (1); + return (seg->msegflags & MEMSEG_DYNAMIC); } int @@ -1090,13 +1169,12 @@ /* Span and memseg don't overlap. */ continue; } + mseg_start = memseg_get_start(seg); /* Check that segment is suitable for delete. */ - if (memseg_is_dynamic(seg, &mseg_start)) { + if (memseg_includes_meta(seg)) { /* - * Can only delete whole added segments - * for the moment. - * Check that this is completely within the - * span. + * Check that this segment is completely + * within the span. */ if (mseg_start < mdsp->mds_base || seg->pages_end > p_end) { @@ -1106,10 +1184,6 @@ pages_checked += seg->pages_end - mseg_start; } else { /* - * Set mseg_start for accounting below. - */ - mseg_start = seg->pages_base; - /* * If this segment is larger than the span, * try to split it. After the split, it * is necessary to restart. @@ -1231,9 +1305,7 @@ } } if (seg != NULL) { - if (!memseg_is_dynamic(seg, &mseg_start)) { - mseg_start = seg->pages_base; - } + mseg_start = memseg_get_start(seg); /* * Now have the full extent of the memseg so * do the range check. @@ -1722,11 +1794,6 @@ (mhp->mh_cancel == 0); mdsp = mdsp->mds_next) { pfn_t pfn, p_end; - if (first_scan) { - mem_node_pre_del_slice(mdsp->mds_base, - mdsp->mds_base + mdsp->mds_npgs - 1); - } - p_end = mdsp->mds_base + mdsp->mds_npgs; for (pfn = mdsp->mds_base; (pfn < p_end) && (mhp->mh_cancel == 0); pfn++) { @@ -2309,13 +2376,13 @@ kphysm_del_cleanup(mhp); /* - * mem_node_post_del_slice needs to be after kphysm_del_cleanup so + * mem_node_del_range needs to be after kphysm_del_cleanup so * that the mem_node_config[] will remain intact for the cleanup. */ for (mdsp = mhp->mh_transit.trl_spans; mdsp != NULL; mdsp = mdsp->mds_next) { - mem_node_post_del_slice(mdsp->mds_base, - mdsp->mds_base + mdsp->mds_npgs - 1, 0); + mem_node_del_range(mdsp->mds_base, + mdsp->mds_base + mdsp->mds_npgs - 1); } comp_code = KPHYSM_OK; @@ -2477,29 +2544,68 @@ mutex_exit(&pp_dummy_lock); } -static void -memseg_remap_to_dummy(caddr_t pp, pgcnt_t metapgs) +/* + * Remap a page-aglined range of page_t's to dummy pages. + */ +void +remap_to_dummy(caddr_t va, pgcnt_t metapgs) { - ASSERT(pp_dummy != NULL); + int phase; + + ASSERT(IS_P2ALIGNED((uint64_t)va, PAGESIZE)); + + /* + * We may start remapping at a non-zero page offset + * within the dummy pages since the low/high ends + * of the outgoing pp's could be shared by other + * memsegs (see memseg_remap_meta). + */ + phase = btop((uint64_t)va) % pp_dummy_npages; + ASSERT(PAGESIZE % sizeof (page_t) || phase == 0); while (metapgs != 0) { pgcnt_t n; - int i; + int i, j; n = pp_dummy_npages; if (n > metapgs) n = metapgs; for (i = 0; i < n; i++) { - hat_devload(kas.a_hat, pp, ptob(1), pp_dummy_pfn[i], + j = (i + phase) % pp_dummy_npages; + hat_devload(kas.a_hat, va, ptob(1), pp_dummy_pfn[j], PROT_READ, HAT_LOAD | HAT_LOAD_NOCONSIST | HAT_LOAD_REMAP); - pp += ptob(1); + va += ptob(1); } metapgs -= n; } } +static void +memseg_remap_to_dummy(struct memseg *seg) +{ + caddr_t pp; + pgcnt_t metapgs; + + ASSERT(memseg_is_dynamic(seg)); + ASSERT(pp_dummy != NULL); + + + if (!memseg_includes_meta(seg)) { + memseg_remap_meta(seg); + return; + } + + pp = (caddr_t)seg->pages; + metapgs = seg->pages_base - memseg_get_start(seg); + ASSERT(metapgs != 0); + + seg->pages_end = seg->pages_base; + + remap_to_dummy(pp, metapgs); +} + /* * Transition all the deleted pages to the deleted state so that * page_lock will not wait. The page_lock_delete call will @@ -2588,9 +2694,6 @@ pfn_t mseg_start; pfn_t mseg_base, mseg_end; pgcnt_t mseg_npgs; - page_t *pp; - pgcnt_t metapgs; - int dynamic; int mlret; seglist = seg->lnext; @@ -2609,17 +2712,11 @@ mseg_base = seg->pages_base; mseg_end = seg->pages_end; mseg_npgs = MSEG_NPAGES(seg); - dynamic = memseg_is_dynamic(seg, &mseg_start); - - seg->pages_end = seg->pages_base; - - if (dynamic) { - pp = seg->pages; - metapgs = mseg_base - mseg_start; - ASSERT(metapgs != 0); - + mseg_start = memseg_get_start(seg); + + if (memseg_is_dynamic(seg)) { /* Remap the meta data to our special dummy area. */ - memseg_remap_to_dummy((caddr_t)pp, metapgs); + memseg_remap_to_dummy(seg); mutex_enter(&memseg_lists_lock); seg->lnext = memseg_va_avail; @@ -2627,16 +2724,13 @@ mutex_exit(&memseg_lists_lock); } else { /* - * Set for clean-up below. - */ - mseg_start = seg->pages_base; - /* * For memory whose page_ts were allocated * at boot, we need to find a new use for * the page_t memory. * For the moment, just leak it. * (It is held in the memseg_delete_junk list.) */ + seg->pages_end = seg->pages_base; mutex_enter(&memseg_lists_lock); seg->lnext = memseg_delete_junk; @@ -3019,7 +3113,7 @@ memsegs_unlock(1); return (0); } - if (memseg_is_dynamic(seg, (pfn_t *)NULL)) { + if (memseg_includes_meta(seg)) { memsegs_unlock(1); return (0); } @@ -3053,18 +3147,13 @@ seg_low = NULL; seg_high = NULL; - if (size_low != 0) { - seg_low = kmem_cache_alloc(memseg_cache, KM_SLEEP); - bzero(seg_low, sizeof (struct memseg)); - } - - seg_mid = kmem_cache_alloc(memseg_cache, KM_SLEEP); - bzero(seg_mid, sizeof (struct memseg)); - - if (size_high != 0) { - seg_high = kmem_cache_alloc(memseg_cache, KM_SLEEP); - bzero(seg_high, sizeof (struct memseg)); - } + if (size_low != 0) + seg_low = memseg_alloc(); + + seg_mid = memseg_alloc(); + + if (size_high != 0) + seg_high = memseg_alloc(); /* * All allocation done now. @@ -3075,6 +3164,7 @@ seg_low->pages_base = seg->pages_base; seg_low->pages_end = seg_low->pages_base + size_low; seg_low->next = seg_mid; + seg_low->msegflags = seg->msegflags; } if (size_high != 0) { seg_high->pages = seg->epages - size_high; @@ -3082,6 +3172,7 @@ seg_high->pages_base = seg->pages_end - size_high; seg_high->pages_end = seg_high->pages_base + size_high; seg_high->next = seg->next; + seg_high->msegflags = seg->msegflags; } seg_mid->pages = seg->pages + size_low; @@ -3089,6 +3180,7 @@ seg_mid->epages = seg->epages - size_high; seg_mid->pages_end = seg->pages_end - size_high; seg_mid->next = (seg_high != NULL) ? seg_high : seg->next; + seg_mid->msegflags = seg->msegflags; /* * Update hat_kpm specific info of all involved memsegs and @@ -3147,3 +3239,64 @@ memseg_cache = kmem_cache_create("memseg_cache", sizeof (struct memseg), 0, NULL, NULL, NULL, NULL, static_arena, KMC_NOHASH); } + +struct memseg * +memseg_alloc() +{ + struct memseg *seg; + + seg = kmem_cache_alloc(memseg_cache, KM_SLEEP); + bzero(seg, sizeof (struct memseg)); + + return (seg); +} + +/* + * Return whether the page_t memory for this memseg + * is included in the memseg itself. + */ +static int +memseg_includes_meta(struct memseg *seg) +{ + return (seg->msegflags & MEMSEG_META_INCL); +} + +pfn_t +memseg_get_start(struct memseg *seg) +{ + pfn_t pt_start; + + if (memseg_includes_meta(seg)) { + pt_start = hat_getpfnum(kas.a_hat, (caddr_t)seg->pages); + + /* Meta data is required to be at the beginning */ + ASSERT(pt_start < seg->pages_base); + } else + pt_start = seg->pages_base; + + return (pt_start); +} + +/* + * Invalidate memseg pointers in cpu private vm data caches. + */ +static void +memseg_cpu_vm_flush() +{ + cpu_t *cp; + vm_cpu_data_t *vc; + + mutex_enter(&cpu_lock); + pause_cpus(NULL); + + cp = cpu_list; + do { + vc = cp->cpu_vm_data; + vc->vc_pnum_memseg = NULL; + vc->vc_pnext_memseg = NULL; + + } while ((cp = cp->cpu_next) != cpu_list); + + start_cpus(); + mutex_exit(&cpu_lock); +}
--- a/usr/src/uts/common/os/modconf.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/os/modconf.c Mon Jul 20 13:07:46 2009 -0400 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -56,7 +56,6 @@ #include <sys/brand.h> #include <sys/cpc_pcbe.h> #include <sys/kstat.h> -#include <sys/fs/sdev_node.h> #include <sys/socketvar.h> #include <sys/kiconv.h> @@ -229,17 +228,6 @@ }; /* - * /dev fs modules - */ -static int mod_infodev(struct modldev *, struct modlinkage *, int *); -static int mod_installdev(struct modldev *, struct modlinkage *); -static int mod_removedev(struct modldev *, struct modlinkage *); - -struct mod_ops mod_devfsops = { - mod_installdev, mod_removedev, mod_infodev -}; - -/* * PCBE (Performance Counter BackEnd) modules. */ static int mod_installpcbe(struct modlpcbe *, struct modlinkage *); @@ -545,42 +533,6 @@ } /* - * manage /dev fs modules - */ -/*ARGSUSED*/ -static int -mod_infodev(struct modldev *modl, struct modlinkage *modlp, int *p0) -{ - if (mod_getctl(modlp) == NULL) { - *p0 = -1; - return (0); /* module is not yet installed */ - } - - *p0 = 0; - return (0); -} - -static int -mod_installdev(struct modldev *modl, struct modlinkage *modlp) -{ - struct modctl *mcp; - - if ((mcp = mod_getctl(modlp)) == NULL) - return (EINVAL); - return (sdev_module_register(mcp->mod_modname, modl->dev_ops)); -} - -/* - * /dev modules are not unloadable. - */ -/*ARGSUSED*/ -static int -mod_removedev(struct modldev *modl, struct modlinkage *modlp) -{ - return (EBUSY); -} - -/* * Install a new driver */ static int
--- a/usr/src/uts/common/os/modctl.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/os/modctl.c Mon Jul 20 13:07:46 2009 -0400 @@ -76,7 +76,7 @@ #include <ipp/ipp_impl.h> #include <sys/fs/dv_node.h> #include <sys/strsubr.h> -#include <sys/fs/sdev_node.h> +#include <sys/fs/sdev_impl.h> static int mod_circdep(struct modctl *); static int modinfo(modid_t, struct modinfo *); @@ -2247,11 +2247,7 @@ switch (subcmd) { case MODDEVNAME_LOOKUPDOOR: - case MODDEVNAME_DEVFSADMNODE: - error = devname_filename_register(subcmd, (char *)a1); - break; - case MODDEVNAME_NSMAPS: - error = devname_nsmaps_register((char *)a1, (size_t)a2); + error = devname_filename_register((char *)a1); break; case MODDEVNAME_PROFILE: error = devname_profile_update((char *)a1, (size_t)a2);
--- a/usr/src/uts/common/os/sunpm.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/os/sunpm.c Mon Jul 20 13:07:46 2009 -0400 @@ -6604,6 +6604,7 @@ char *ptr; int lower_bound_cycles, upper_bound_cycles, cycles_allowed; int cycles_diff, cycles_over; + struct pm_smart_count *smart_p; if (datap == NULL) { PMD(PMD_TCHECK, ("%s: NULL data pointer!\n", pmf)) @@ -6785,6 +6786,18 @@ PMD(PMD_TCHECK, ("%s: no cycle is allowed in %ld secs\n", pmf, *intervalp)) return (0); + } else if (datap->format == DC_SMART_FORMAT) { + /* + * power cycles of SATA disks are reported from SMART + * attributes. + */ + smart_p = &datap->un.smart_count; + if (smart_p->consumed >= smart_p->allowed) { + *intervalp = (LONG_MAX / hz); + PMD(PMD_TCHECK, ("%s: exceeded lifemax cycles.\n", pmf)) + return (0); + } else + return (1); } PMD(PMD_TCHECK, ("%s: unknown format!\n", pmf))
--- a/usr/src/uts/common/rpc/xdr.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/rpc/xdr.c Mon Jul 20 13:07:46 2009 -0400 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -307,6 +307,29 @@ } /* + * XDR an unsigned char + */ +bool_t +xdr_u_char(XDR *xdrs, uchar_t *cp) +{ + int i; + + switch (xdrs->x_op) { + case XDR_ENCODE: + i = (*cp); + return (XDR_PUTINT32(xdrs, &i)); + case XDR_DECODE: + if (!XDR_GETINT32(xdrs, &i)) + return (FALSE); + *cp = (uchar_t)i; + return (TRUE); + case XDR_FREE: + return (TRUE); + } + return (FALSE); +} + +/* * XDR booleans * * PSARC 2003/523 Contract Private Interface @@ -608,6 +631,32 @@ } /* + * xdr_vector(): + * + * XDR a fixed length array. Unlike variable-length arrays, the storage + * of fixed length arrays is static and unfreeable. + * > basep: base of the array + * > size: size of the array + * > elemsize: size of each element + * > xdr_elem: routine to XDR each element + */ +bool_t +xdr_vector(XDR *xdrs, char *basep, const uint_t nelem, + const uint_t elemsize, const xdrproc_t xdr_elem) +{ + uint_t i; + char *elptr; + + elptr = basep; + for (i = 0; i < nelem; i++) { + if (!(*xdr_elem)(xdrs, elptr, LASTUNSIGNED)) + return (FALSE); + elptr += elemsize; + } + return (TRUE); +} + +/* * Wrapper for xdr_string that can be called directly from * routines like clnt_call */
--- a/usr/src/uts/common/rpc/xdr.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/rpc/xdr.h Mon Jul 20 13:07:46 2009 -0400 @@ -18,7 +18,7 @@ * * CDDL HEADER END * - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ @@ -420,6 +420,8 @@ extern bool_t xdr_string(XDR *, char **, const uint_t); extern bool_t xdr_union(XDR *, enum_t *, char *, const struct xdr_discrim *, const xdrproc_t); +extern bool_t xdr_vector(XDR *, char *, const uint_t, const uint_t, + const xdrproc_t); extern unsigned int xdr_sizeof(xdrproc_t, void *); extern bool_t xdr_hyper(XDR *, longlong_t *); @@ -428,6 +430,7 @@ extern bool_t xdr_u_longlong_t(XDR *, u_longlong_t *); extern bool_t xdr_char(XDR *, char *); +extern bool_t xdr_u_char(XDR *, uchar_t *); extern bool_t xdr_wrapstring(XDR *, char **); extern bool_t xdr_reference(XDR *, caddr_t *, uint_t, const xdrproc_t); extern bool_t xdr_pointer(XDR *, char **, uint_t, const xdrproc_t); @@ -446,9 +449,6 @@ #endif #ifndef _KERNEL -extern bool_t xdr_u_char(XDR *, uchar_t *); -extern bool_t xdr_vector(XDR *, char *, const uint_t, const uint_t, const -xdrproc_t); extern bool_t xdr_float(XDR *, float *); extern bool_t xdr_double(XDR *, double *); extern bool_t xdr_quadruple(XDR *, long double *); @@ -468,12 +468,14 @@ extern bool_t xdr_opaque(); extern bool_t xdr_string(); extern bool_t xdr_union(); +extern bool_t xdr_vector(); extern bool_t xdr_hyper(); extern bool_t xdr_longlong_t(); extern bool_t xdr_u_hyper(); extern bool_t xdr_u_longlong_t(); extern bool_t xdr_char(); +extern bool_t xdr_u_char(); extern bool_t xdr_reference(); extern bool_t xdr_pointer(); extern void xdr_free(); @@ -492,8 +494,6 @@ #endif #ifndef _KERNEL -extern bool_t xdr_u_char(); -extern bool_t xdr_vector(); extern bool_t xdr_float(); extern bool_t xdr_double(); extern bool_t xdr_quadruple();
--- a/usr/src/uts/common/rpcsvc/idmap_prot.x Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/rpcsvc/idmap_prot.x Mon Jul 20 13:07:46 2009 -0400 @@ -19,13 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - /* opaque type to support non-ASCII strings */ typedef string idmap_utf8str<>; +typedef idmap_utf8str idmap_utf8str_list<>; /* Return status */ typedef int idmap_retcode; @@ -270,6 +270,76 @@ }; #endif +/* + * Represents an error from the directory lookup service. + * + * code is an ASCII string that is a key for the error. It is not + * localized. + * + * fmt is a format string with %n markers for where to include + * params[n-1]. It should be, but NEEDSWORK is not localized to + * the caller's locale. + * + * params is a list of parameters for the error - e.g. the name that + * encountered a failure, the server that reported the failure, et cetera. + * The values are to be used both as marked in fmt and for machine + * interpretation of the error. + */ +struct directory_error_rpc { + idmap_utf8str code; + idmap_utf8str fmt; + idmap_utf8str params<>; +}; + +/* + * One value of a multivalued attribute. + */ +typedef opaque directory_value_rpc<>; + +/* + * The value of an attribute, if found. Note that this is a list + * of directory_value_rpc objects, to support multivalued attributes. + */ +union directory_values_rpc switch (bool found) { + case TRUE: + directory_value_rpc values<>; + case FALSE: + void; +}; + +/* + * The status of the lookup for any particular identifier. + */ +enum directory_lookup_status_rpc { + DIRECTORY_NOT_FOUND = 0, + DIRECTORY_FOUND = 1, + DIRECTORY_ERROR = 2 +}; + +/* + * This is the data returned for a particular identifier, either a + * list of attribute values or an error. + */ +union directory_entry_rpc switch (directory_lookup_status_rpc status) { + case DIRECTORY_NOT_FOUND: + void; + case DIRECTORY_FOUND: + directory_values_rpc attrs<>; + case DIRECTORY_ERROR: + directory_error_rpc err; +}; + +/* + * This is the result from a request, either a list of the entries for + * the identifiers specified, or an error. + */ +union directory_results_rpc switch (bool failed) { + case TRUE: + directory_error_rpc err; + case FALSE: + directory_entry_rpc entries<>; +}; + program IDMAP_PROG { version IDMAP_V1 { void @@ -302,6 +372,27 @@ idmap_prop_res IDMAP_GET_PROP(idmap_prop_type) = 6; #endif + /* + * Retrieve directory information about a list of users + * or groups by name or SID. + * + * ids is a list of user names, group names, or SIDs. + * + * types is a list of types of the ids in the id list. + * If the type list is shorter than the id list, the last + * type listed applies to all of the ids from that point. + * The defined types are: + * 'n' - name (could be user or group) + * 'u' - user + * 'g' - group + * 's' - SID + * + * attrs is a list of attribute names to retrieve. + */ + directory_results_rpc DIRECTORY_GET_COMMON( + idmap_utf8str_list ids, + idmap_utf8str types, + idmap_utf8str_list attrs) = 7; } = 1; } = 100172;
--- a/usr/src/uts/common/smbsrv/ndl/srvsvc.ndl Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/smbsrv/ndl/srvsvc.ndl Mon Jul 20 13:07:46 2009 -0400 @@ -403,6 +403,7 @@ SWITCH(switch_value) union mslm_NetConnectInfoResUnion ru; }; +typedef struct mslm_NetConnectInfo srvsvc_NetConnectInfo_t; OPERATION(SRVSVC_OPNUM_NetConnectEnum) struct mslm_NetConnectEnum { @@ -993,22 +994,19 @@ * * servername * [in] Pointer to a string that specifies the DNS or NetBIOS name - * of the remote server on which the function is to execute. If this - * parameter is NULL, the local computer is used. - * Windows NT 4.0 and earlier: This string must begin with \\. + * of the server. Servers should not validate this parameter. + * This parameter may be NULL and on Windows NT 4.0 and earlier it + * should begin with \\. * * UncClientName - * [in] Pointer to a string that specifies the computer name of the - * client to disconnect. If UncClientName is NULL, then all the sessions - * of the user identified by the username parameter will be deleted on - * the server specified by servername. For more information, see - * NetSessionEnum. + * [in] Pointer to a string that specifies the name of the client + * to disconnect. If UncClientName is NULL, all sessions associated + * with the specified user will be disconnected. * * username * [in] Pointer to a string that specifies the name of the user whose - * session is to be terminated. If this parameter is NULL, all users' - * sessions from the client specified by the UncClientName parameter - * are to be terminated. + * session is to be terminated. If username is NULL, all sessions + * from the specified client will be disconnected. * * Remarks * Windows 95/98/Me: You must specify the session key in the sReserved @@ -1041,8 +1039,11 @@ */ /* for svX_platform */ -#define SV_PLATFORM_ID_OS2 400 -#define SV_PLATFORM_ID_NT 500 +#define SV_PLATFORM_ID_DOS 300 +#define SV_PLATFORM_ID_OS2 400 +#define SV_PLATFORM_ID_NT 500 +#define SV_PLATFORM_ID_OSF 600 +#define SV_PLATFORM_ID_VMS 700 /* Bit-mapped values for svX_type fields */ #define SV_TYPE_WORKSTATION 0x00000001
--- a/usr/src/uts/common/smbsrv/smb_ioctl.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/smbsrv/smb_ioctl.h Mon Jul 20 13:07:46 2009 -0400 @@ -47,8 +47,10 @@ #define SMB_IOC_GMTOFF _IOW(SMB_IOC_BASE, 7, int) #define SMB_IOC_SHARE _IOW(SMB_IOC_BASE, 8, int) #define SMB_IOC_UNSHARE _IOW(SMB_IOC_BASE, 9, int) -#define SMB_IOC_USER_NUMBER _IOW(SMB_IOC_BASE, 10, int) -#define SMB_IOC_USER_LIST _IOW(SMB_IOC_BASE, 11, int) +#define SMB_IOC_NUMOPEN _IOW(SMB_IOC_BASE, 10, int) +#define SMB_IOC_SVCENUM _IOW(SMB_IOC_BASE, 11, int) +#define SMB_IOC_FILE_CLOSE _IOW(SMB_IOC_BASE, 12, int) +#define SMB_IOC_SESSION_CLOSE _IOW(SMB_IOC_BASE, 13, int) typedef struct smb_ioc_header { uint32_t version; @@ -80,18 +82,55 @@ int udoor; } smb_ioc_start_t; -typedef struct smb_ioc_usernum { +typedef struct smb_ioc_opennum { smb_ioc_header_t hdr; - uint32_t num; -} smb_ioc_usernum_t; + uint32_t open_users; + uint32_t open_trees; + uint32_t open_files; + uint32_t qualtype; + char qualifier[MAXNAMELEN]; +} smb_ioc_opennum_t; + +/* + * For enumeration, user and session are synonymous, as are + * connection and tree. + */ +#define SMB_SVCENUM_TYPE_USER 0x55534552 /* 'USER' */ +#define SMB_SVCENUM_TYPE_TREE 0x54524545 /* 'TREE' */ +#define SMB_SVCENUM_TYPE_FILE 0x46494C45 /* 'FILE' */ +#define SMB_SVCENUM_TYPE_SHARE 0x53484152 /* 'SHAR' */ -typedef struct smb_ioc_ulist { +typedef struct smb_svcenum { + uint32_t se_type; /* object type to enumerate */ + uint32_t se_level; /* level of detail being requested */ + uint32_t se_prefmaxlen; /* client max size buffer preference */ + uint32_t se_resume; /* client resume handle */ + uint32_t se_bavail; /* remaining buffer space in bytes */ + uint32_t se_bused; /* consumed buffer space in bytes */ + uint32_t se_ntotal; /* total number of objects */ + uint32_t se_nlimit; /* max number of objects to return */ + uint32_t se_nitems; /* number of objects in buf */ + uint32_t se_nskip; /* number of objects to skip */ + uint32_t se_status; /* enumeration status */ + uint32_t se_buflen; /* length of the buffer in bytes */ + uint8_t se_buf[1]; /* buffer to hold enumeration data */ +} smb_svcenum_t; + +typedef struct smb_ioc_svcenum { smb_ioc_header_t hdr; - uint32_t cookie; - uint32_t num; - uint32_t data_len; - uint8_t data[1]; -} smb_ioc_ulist_t; + smb_svcenum_t svcenum; +} smb_ioc_svcenum_t; + +typedef struct smb_ioc_session { + smb_ioc_header_t hdr; + char client[MAXNAMELEN]; + char username[MAXNAMELEN]; +} smb_ioc_session_t; + +typedef struct smb_ioc_fileid { + smb_ioc_header_t hdr; + uint32_t uniqid; +} smb_ioc_fileid_t; typedef struct smb_ioc_cfg { smb_ioc_header_t hdr; @@ -117,8 +156,10 @@ smb_ioc_cfg_t ioc_cfg; smb_ioc_start_t ioc_start; smb_ioc_listen_t ioc_listen; - smb_ioc_usernum_t ioc_unum; - smb_ioc_ulist_t ioc_ulist; + smb_ioc_opennum_t ioc_opennum; + smb_ioc_svcenum_t ioc_svcenum; + smb_ioc_session_t ioc_session; + smb_ioc_fileid_t ioc_fileid; smb_ioc_share_t ioc_share; } smb_ioc_t;
--- a/usr/src/uts/common/smbsrv/smb_kproto.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/smbsrv/smb_kproto.h Mon Jul 20 13:07:46 2009 -0400 @@ -198,6 +198,7 @@ ((op)->create_disposition != FILE_SUPERSEDE) && \ ((op)->create_disposition != FILE_OVERWRITE)) \ +uint32_t smb_lock_get_lock_count(smb_node_t *); uint32_t smb_unlock_range(smb_request_t *, smb_node_t *, uint64_t, uint64_t); uint32_t smb_lock_range(smb_request_t *, uint64_t, uint64_t, uint32_t, @@ -313,8 +314,6 @@ void smb_opipe_door_fini(void); int smb_opipe_door_open(int); void smb_opipe_door_close(void); -void smb_user_context_init(smb_user_t *, smb_opipe_context_t *); -void smb_user_context_fini(smb_opipe_context_t *); /* * SMB server functions (file smb_server.c) @@ -329,13 +328,14 @@ int smb_server_tcp_listen(smb_ioc_listen_t *); int smb_server_nbt_receive(void); int smb_server_tcp_receive(void); -uint32_t smb_server_get_user_count(void); uint32_t smb_server_get_session_count(void); int smb_server_share_export(smb_ioc_share_t *); int smb_server_share_unexport(smb_ioc_share_t *); int smb_server_set_gmtoff(smb_ioc_gmt_t *); -int smb_server_user_number(smb_ioc_usernum_t *); -int smb_server_user_list(smb_ioc_ulist_t *); +int smb_server_numopen(smb_ioc_opennum_t *); +int smb_server_enum(smb_ioc_svcenum_t *); +int smb_server_session_close(smb_ioc_session_t *); +int smb_server_file_close(smb_ioc_fileid_t *); void smb_server_reconnection_check(smb_server_t *, smb_session_t *); void smb_server_get_cfg(smb_server_t *, smb_kmod_cfg_t *); @@ -474,6 +474,8 @@ void smb_session_list_terminate(smb_session_list_t *, smb_session_t *); void smb_session_list_signal(smb_session_list_t *); smb_user_t *smb_session_dup_user(smb_session_t *, char *, char *); +void smb_session_getclient(smb_session_t *, char *, size_t); +boolean_t smb_session_isclient(smb_session_t *, const char *); void smb_session_correct_keep_alive_values(smb_session_list_t *, uint32_t); void smb_session_oplock_break(smb_session_t *, smb_ofile_t *); int smb_session_send(smb_session_t *, uint8_t type, mbuf_chain_t *); @@ -489,16 +491,20 @@ * ofile functions (file smb_ofile.c) */ smb_ofile_t *smb_ofile_lookup_by_fid(smb_tree_t *, uint16_t); +smb_ofile_t *smb_ofile_lookup_by_uniqid(smb_tree_t *, uint32_t); +boolean_t smb_ofile_disallow_fclose(smb_ofile_t *); smb_ofile_t *smb_ofile_open(smb_tree_t *, smb_node_t *, uint16_t, open_param_t *, uint16_t, uint32_t, smb_error_t *); void smb_ofile_close(smb_ofile_t *, uint32_t); uint32_t smb_ofile_access(smb_ofile_t *, cred_t *, uint32_t); int smb_ofile_seek(smb_ofile_t *, ushort_t, int32_t, uint32_t *); +boolean_t smb_ofile_hold(smb_ofile_t *); void smb_ofile_release(smb_ofile_t *); void smb_ofile_close_all(smb_tree_t *); void smb_ofile_close_all_by_pid(smb_tree_t *, uint16_t); void smb_ofile_set_flags(smb_ofile_t *, uint32_t); boolean_t smb_ofile_is_open(smb_ofile_t *); +int smb_ofile_enum(smb_ofile_t *, smb_svcenum_t *); uint32_t smb_ofile_open_check(smb_ofile_t *, cred_t *, uint32_t, uint32_t); uint32_t smb_ofile_rename_check(smb_ofile_t *); uint32_t smb_ofile_delete_check(smb_ofile_t *); @@ -554,12 +560,19 @@ smb_tree_t *smb_user_lookup_share(smb_user_t *, const char *, smb_tree_t *); smb_tree_t *smb_user_lookup_volume(smb_user_t *, const char *, smb_tree_t *); boolean_t smb_user_is_admin(smb_user_t *); +boolean_t smb_user_namecmp(smb_user_t *, const char *); +int smb_user_enum(smb_user_t *, smb_svcenum_t *); void smb_user_close_pid(smb_user_t *, uint16_t); void smb_user_disconnect_trees(smb_user_t *user); void smb_user_disconnect_share(smb_user_t *, const char *); +int smb_user_fclose(smb_user_t *, uint32_t); +boolean_t smb_user_hold(smb_user_t *); void smb_user_release(smb_user_t *); cred_t *smb_user_getcred(smb_user_t *); cred_t *smb_user_getprivcred(smb_user_t *); +void smb_user_netinfo_init(smb_user_t *, smb_netuserinfo_t *); +void smb_user_netinfo_fini(smb_netuserinfo_t *); +int smb_user_netinfo_encode(smb_user_t *, uint8_t *, size_t, uint32_t *); /* * SMB tree functions (file smb_tree.c) @@ -568,6 +581,8 @@ void smb_tree_disconnect(smb_tree_t *, boolean_t); void smb_tree_close_pid(smb_tree_t *, uint16_t); boolean_t smb_tree_has_feature(smb_tree_t *, uint_t); +int smb_tree_enum(smb_tree_t *, smb_svcenum_t *); +int smb_tree_fclose(smb_tree_t *, uint32_t); boolean_t smb_tree_hold(smb_tree_t *); void smb_tree_release(smb_tree_t *); smb_odir_t *smb_tree_lookup_odir(smb_tree_t *, uint16_t);
--- a/usr/src/uts/common/smbsrv/smb_ktypes.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/smbsrv/smb_ktypes.h Mon Jul 20 13:07:46 2009 -0400 @@ -507,10 +507,9 @@ volatile int flags; /* FILE_NOTIFY_CHANGE_* */ volatile int waiting_event; /* # of clients requesting FCN */ smb_times_t n_timestamps; /* cached timestamps */ - unsigned int what; smb_oplock_t n_oplock; - struct smb_node *dir_snode; /* Directory of node */ - struct smb_node *unnamed_stream_node; /* set in stream nodes */ + struct smb_node *n_dnode; /* directory node */ + struct smb_node *n_unode; /* unnamed stream node */ /* Credentials for delayed delete */ cred_t *delete_on_close_cred; uint32_t n_delete_on_close_flags; @@ -873,6 +872,8 @@ acl_type_t t_acltype; uint32_t t_access; uint32_t t_shr_flags; + time_t t_connect_time; + volatile uint32_t t_open_files; } smb_tree_t; #define SMB_TREE_VFS(tree) ((tree)->t_snode->vp->v_vfsp) @@ -942,7 +943,7 @@ char *p_name; uint32_t p_busy; smb_opipe_hdr_t p_hdr; - smb_opipe_context_t p_context; + smb_netuserinfo_t p_user; uint8_t *p_doorbuf; uint8_t *p_data; } smb_opipe_t; @@ -1656,7 +1657,7 @@ char name[MAXNAMELEN]; } smb_trans2_setinfo_t; -#define SMB_IS_STREAM(node) ((node)->unnamed_stream_node) +#define SMB_IS_STREAM(node) ((node)->n_unode) typedef struct smb_tsd { void (*proc)();
--- a/usr/src/uts/common/smbsrv/smb_xdr.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/smbsrv/smb_xdr.h Mon Jul 20 13:07:46 2009 -0400 @@ -33,6 +33,7 @@ #include <rpc/xdr.h> #include <sys/param.h> #include <smbsrv/smbinfo.h> +#include <smbsrv/smb_ioctl.h> typedef struct smb_dr_kshare { int32_t k_op; @@ -46,10 +47,6 @@ #define xdr_int16_t xdr_short #define xdr_uint16_t xdr_u_short -extern bool_t xdr_u_char(XDR *xdrs, uchar_t *cp); -extern bool_t xdr_vector(XDR *xdrs, char *basep, uint_t nelem, - uint_t elemsize, xdrproc_t xdr_elem); - smb_dr_kshare_t *smb_share_mkabsolute(uint8_t *buf, uint32_t len); #else uint8_t *smb_kshare_mkselfrel(smb_dr_kshare_t *kshare, uint32_t *len); @@ -91,25 +88,68 @@ uint32_t oh_status; } smb_opipe_hdr_t; -typedef struct smb_opipe_context { - uint64_t oc_session_id; - uint16_t oc_uid; - uint16_t oc_domain_len; - char *oc_domain; - uint16_t oc_account_len; - char *oc_account; - uint16_t oc_workstation_len; - char *oc_workstation; - smb_inaddr_t oc_ipaddr; - int32_t oc_native_os; - int64_t oc_logon_time; - uint32_t oc_flags; -} smb_opipe_context_t; +typedef struct smb_netuserinfo { + uint64_t ui_session_id; + uint16_t ui_uid; + uint16_t ui_domain_len; + char *ui_domain; + uint16_t ui_account_len; + char *ui_account; + uint16_t ui_workstation_len; + char *ui_workstation; + smb_inaddr_t ui_ipaddr; + int32_t ui_native_os; + int64_t ui_logon_time; + uint32_t ui_numopens; + uint32_t ui_flags; +} smb_netuserinfo_t; + +typedef struct smb_opennum { + uint32_t open_users; + uint32_t open_trees; + uint32_t open_files; + uint32_t qualtype; + char qualifier[MAXNAMELEN]; +} smb_opennum_t; -typedef struct smb_ulist { - uint32_t ul_cnt; - smb_opipe_context_t *ul_users; -} smb_ulist_t; +typedef struct smb_netconnectinfo { + uint32_t ci_id; + uint32_t ci_type; + uint32_t ci_numopens; + uint32_t ci_numusers; + uint32_t ci_time; + uint32_t ci_namelen; + uint32_t ci_sharelen; + char *ci_username; + char *ci_share; +} smb_netconnectinfo_t; + +typedef struct smb_netfileinfo { + uint16_t fi_fid; + uint32_t fi_uniqid; + uint32_t fi_permissions; + uint32_t fi_numlocks; + uint32_t fi_pathlen; + uint32_t fi_namelen; + char *fi_path; + char *fi_username; +} smb_netfileinfo_t; + +typedef struct smb_netsvcitem { + list_node_t nsi_lnd; + union { + smb_netuserinfo_t nsi_user; + smb_netconnectinfo_t nsi_tree; + smb_netfileinfo_t nsi_ofile; + } nsi_un; +} smb_netsvcitem_t; + +typedef struct smb_netsvc { + list_t ns_list; + smb_netsvcitem_t *ns_items; + smb_ioc_svcenum_t *ns_ioc; + uint32_t ns_ioclen; +} smb_netsvc_t; /* xdr routines for common door arguments/results */ extern bool_t xdr_smb_dr_string_t(XDR *, smb_dr_string_t *); @@ -120,11 +160,18 @@ int smb_opipe_hdr_encode(smb_opipe_hdr_t *, uint8_t *, uint32_t); int smb_opipe_hdr_decode(smb_opipe_hdr_t *, uint8_t *, uint32_t); bool_t smb_opipe_hdr_xdr(XDR *xdrs, smb_opipe_hdr_t *objp); -int smb_opipe_context_encode(smb_opipe_context_t *, uint8_t *, uint32_t, +int smb_netuserinfo_encode(smb_netuserinfo_t *, uint8_t *, uint32_t, uint_t *); +int smb_netuserinfo_decode(smb_netuserinfo_t *, uint8_t *, uint32_t, uint_t *); +bool_t smb_netuserinfo_xdr(XDR *, smb_netuserinfo_t *); +int smb_netconnectinfo_encode(smb_netconnectinfo_t *, uint8_t *, uint32_t, uint_t *); -int smb_opipe_context_decode(smb_opipe_context_t *, uint8_t *, uint32_t, +int smb_netconnectinfo_decode(smb_netconnectinfo_t *, uint8_t *, uint32_t, uint_t *); -bool_t smb_opipe_context_xdr(XDR *, smb_opipe_context_t *); +bool_t smb_netconnectinfo_xdr(XDR *, smb_netconnectinfo_t *); +int smb_netfileinfo_encode(smb_netfileinfo_t *, uint8_t *, uint32_t, uint_t *); +int smb_netfileinfo_decode(smb_netfileinfo_t *, uint8_t *, uint32_t, uint_t *); +bool_t smb_netfileinfo_xdr(XDR *, smb_netfileinfo_t *); + /* * VSS Door Structures */
--- a/usr/src/uts/common/sys/Makefile Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/Makefile Mon Jul 20 13:07:46 2009 -0400 @@ -807,7 +807,6 @@ decomp.h \ dv_node.h \ sdev_impl.h \ - sdev_node.h \ fifonode.h \ hsfs_isospec.h \ hsfs_node.h \
--- a/usr/src/uts/common/sys/fct.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/fct.h Mon Jul 20 13:07:46 2009 -0400 @@ -158,6 +158,9 @@ #define FCHBA_DRIVER_NAME_LEN 256 #define FCHBA_SYMB_NAME_LEN 255 +#define FC_TGT_PORT_INFO_CMD (((uint32_t)'I') << 24) +#define FC_TGT_PORT_RLS FC_TGT_PORT_INFO_CMD + 0x1 + typedef struct fct_port_attrs { char manufacturer[FCHBA_MANUFACTURER_LEN]; char serial_number[FCHBA_SERIAL_NUMBER_LEN]; @@ -174,6 +177,15 @@ uint32_t max_frame_size; } fct_port_attrs_t; +typedef struct fct_port_link_status { + uint32_t LinkFailureCount; + uint32_t LossOfSyncCount; + uint32_t LossOfSignalsCount; + uint32_t PrimitiveSeqProtocolErrorCount; + uint32_t InvalidTransmissionWordCount; + uint32_t InvalidCRCCount; +} fct_port_link_status_t; + typedef struct fct_dbuf_store { void *fds_fct_private; void *fds_fca_private; @@ -232,6 +244,9 @@ struct fct_flogi_xchg *fx); void (*port_populate_hba_details)( struct fct_local_port *port, struct fct_port_attrs *port_attrs); + fct_status_t (*port_info)(uint32_t cmd, + struct fct_local_port *port, void *arg, uint8_t *buf, + uint32_t *bufsizep); } fct_local_port_t; /* @@ -277,6 +292,15 @@ uint8_t port_rpwwn[8]; } fct_link_info_t; +typedef struct fct_port_stat { + kstat_named_t link_failure_cnt; + kstat_named_t loss_of_sync_cnt; + kstat_named_t loss_of_signals_cnt; + kstat_named_t prim_seq_protocol_err_cnt; + kstat_named_t invalid_tx_word_cnt; + kstat_named_t invalid_crc_cnt; +} fct_port_stat_t; + /* * port topology */
--- a/usr/src/uts/common/sys/fct_defines.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/fct_defines.h Mon Jul 20 13:07:46 2009 -0400 @@ -71,6 +71,7 @@ #define ELS_OP_FLOGI 0x04 #define ELS_OP_LOGO 0x05 #define ELS_OP_ABTX 0x06 +#define ELS_OP_RLS 0x0f #define ELS_OP_ECHO 0x10 #define ELS_OP_REC 0x13 #define ELS_OP_SRR 0x14
--- a/usr/src/uts/common/sys/fctio.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/fctio.h Mon Jul 20 13:07:46 2009 -0400 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _FCTIO_H @@ -38,6 +38,7 @@ #define FCTIO_GET_DISCOVERED_PORT_ATTRIBUTES (FCTIO_SUB_CMD + 0x04) #define FCTIO_GET_PORT_ATTRIBUTES (FCTIO_SUB_CMD + 0x05) #define FCTIO_GET_ADAPTER_PORT_STATS (FCTIO_SUB_CMD + 0x06) +#define FCTIO_GET_LINK_STATUS (FCTIO_SUB_CMD + 0x07) /* * fcio_xfer definitions
--- a/usr/src/uts/common/sys/fm/io/ddi.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/fm/io/ddi.h Mon Jul 20 13:07:46 2009 -0400 @@ -19,15 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SYS_FM_IO_DDI_H #define _SYS_FM_IO_DDI_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -45,6 +43,8 @@ #define DDI_FM_DEVICE_BADINT_LIMIT "badint_limit" #define DDI_FM_DEVICE_INTERN_CORR "intern_corr" #define DDI_FM_DEVICE_INTERN_UNCORR "intern_uncorr" +#define DDI_FM_DEVICE_FW_CORRUPT "fw_corrupt" +#define DDI_FM_DEVICE_FW_MISMATCH "fw_mismatch" /* service impact ereport definitions */ #define DDI_FM_SERVICE_IMPACT "service"
--- a/usr/src/uts/common/sys/fs/dv_node.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/fs/dv_node.h Mon Jul 20 13:07:46 2009 -0400 @@ -40,7 +40,7 @@ #include <sys/sunddi.h> #include <sys/devops.h> #include <sys/ddi_impldefs.h> -#include <sys/fs/sdev_node.h> +#include <sys/fs/sdev_impl.h> #include <sys/devpolicy.h> #include <sys/avl.h> #include <sys/vfs_opreg.h>
--- a/usr/src/uts/common/sys/fs/sdev_impl.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/fs/sdev_impl.h Mon Jul 20 13:07:46 2009 -0400 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -69,17 +69,6 @@ * supported devfsadm_cmd */ #define DEVFSADMD_RUN_ALL 1 -#define DEVFSADMD_NS_LOOKUP 2 -#define DEVFSADMD_NS_READDIR 3 - -/* - * supported protocols - */ -typedef enum devname_spec { - DEVNAME_NS_NONE = 0, - DEVNAME_NS_PATH, /* physical /devices path */ - DEVNAME_NS_DEV /* /dev path */ -} devname_spec_t; /* * devfsadm_error codes @@ -87,35 +76,16 @@ #define DEVFSADM_RUN_INVALID 1 #define DEVFSADM_RUN_EPERM 2 #define DEVFSADM_RUN_NOTSUP 3 -#define DEVFSADM_NS_FAILED 4 - -typedef struct sdev_ns_handle { - char ns_name[MAXPATHLEN]; /* device to be looked up */ - char ns_map[MAXPATHLEN]; -} sdev_ns_handle_t; - -typedef struct sdev_lkp_handle { - devname_spec_t devfsadm_spec; /* returned path property */ - char devfsadm_link[MAXPATHLEN]; /* symlink destination */ -} sdev_lkp_handle_t; - -typedef struct sdev_rdr_handle { - uint32_t ns_mapcount; /* number of entries in the map */ - uint32_t maplist_size; -} sdev_rdr_handle_t; /* * devfsadm/devname door data structures */ typedef struct sdev_door_arg { uint8_t devfsadm_cmd; /* what to do for devfsadm[d] */ - sdev_ns_handle_t ns_hdl; } sdev_door_arg_t; typedef struct sdev_door_res { int32_t devfsadm_error; - sdev_lkp_handle_t ns_lkp_hdl; - sdev_rdr_handle_t ns_rdr_hdl; } sdev_door_res_t; #ifdef _KERNEL @@ -134,7 +104,6 @@ */ struct devname_handle { struct sdev_node *dh_data; /* the sdev_node */ - devname_spec_t dh_spec; void *dh_args; }; typedef struct devname_handle devname_handle_t; @@ -145,7 +114,6 @@ */ typedef struct sdev_global_data { struct devname_handle sdev_ghandle; - struct devname_nsmap *sdev_gmapinfo; /* VDIR name service info */ ulong_t sdev_dir_ggen; /* name space generation # */ } sdev_global_data_t; @@ -200,7 +168,6 @@ #define sdev_gdata sdev_instance_data.sdev_globaldata #define sdev_handle sdev_gdata.sdev_ghandle -#define sdev_mapinfo sdev_gdata.sdev_gmapinfo #define sdev_gdir_gen sdev_gdata.sdev_dir_ggen #define sdev_ldir_gen sdev_ldata.sdev_dir_lgen @@ -353,7 +320,7 @@ /* * devname_inactive_func() */ -extern void devname_inactive_func(struct vnode *, struct cred *, +extern void devname_inactive_func(struct vnode *, struct cred *cred, void (*)(struct vnode *)); /* @@ -418,7 +385,7 @@ } extern int sdev_wait4lookup(struct sdev_node *, int); -extern int devname_filename_register(int, char *); +extern int devname_filename_register(char *); extern int devname_nsmaps_register(char *, size_t); extern void sdev_devfsadm_lockinit(void); extern void sdev_devfsadm_lockdestroy(void); @@ -432,13 +399,6 @@ extern struct vnodeops *devvt_getvnodeops(void); /* - * Directory Based Device Naming (DBNR) defines - */ - -#define ETC_DEV_DIR "/etc/dev" -#define DEVNAME_NSCONFIG "sdev_nsconfig_mod" - -/* * directory name rule */ struct devname_nsmap { @@ -447,7 +407,6 @@ char *dir_name; /* /dev subdir name, e.g. /dev/disk */ char *dir_module; /* devname module impl the operations */ char *dir_map; /* dev naming rules, e.g. /etc/dev/disks */ - struct devname_ops *dir_ops; /* directory specific vnode ops */ char *dir_newmodule; /* to be reloaded */ char *dir_newmap; /* to be reloaded */ int dir_invalid; /* map entry obsolete */ @@ -466,15 +425,6 @@ } devname_lkp_arg_t; /* - * name-value-property restured - */ -typedef struct devname_lkp_result { - devname_spec_t devname_spec; /* link to /devices or /dev */ - char *devname_link; /* the source path */ - int reserved; -} devname_lkp_result_t; - -/* * directory name-value populating results */ typedef struct devname_rdr_result { @@ -559,25 +509,6 @@ * name service globals and prototypes */ -extern struct devname_ops *devname_ns_ops; -extern int devname_nsmaps_loaded; -extern kmutex_t devname_nsmaps_lock; - -extern void sdev_invalidate_nsmaps(void); -extern void sdev_validate_nsmaps(void); -extern int sdev_module_register(char *, struct devname_ops *); -extern struct devname_nsmap *sdev_get_nsmap_by_dir(char *, int); -extern struct devname_nsmap *sdev_get_nsmap_by_module(char *); -extern void sdev_dispatch_to_nsrdr_thread(struct sdev_node *, char *, - devname_rdr_result_t *); -extern void sdev_insert_nsmap(char *, char *, char *); -extern int devname_nsmap_lookup(devname_lkp_arg_t *, devname_lkp_result_t **); -extern struct devname_nsmap *sdev_get_map(struct sdev_node *, int); -extern int sdev_nsmaps_loaded(void); -extern void sdev_replace_nsmap(struct devname_nsmap *, char *, char *); -extern int sdev_nsmaps_reloaded(void); -extern int devname_get_dir_nsmap(devname_handle_t *, struct devname_nsmap **); - /* * vnodeops and vfsops helpers */ @@ -632,13 +563,6 @@ extern void *sdev_get_vtor(struct sdev_node *dv); /* - * devinfo helpers - */ -extern int sdev_modctl_readdir(const char *, char ***, int *, int *, int); -extern void sdev_modctl_readdir_free(char **, int, int); -extern int sdev_modctl_devexists(const char *); - -/* * ncache handlers */ @@ -651,6 +575,13 @@ extern void sdev_modctl_dump_files(void); /* + * devinfo helpers + */ +extern int sdev_modctl_readdir(const char *, char ***, int *, int *, int); +extern void sdev_modctl_readdir_free(char **, int, int); +extern int sdev_modctl_devexists(const char *); + +/* * globals */ extern kmutex_t sdev_lock;
--- a/usr/src/uts/common/sys/fs/sdev_node.h Tue Jul 14 11:18:27 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _SYS_SDEV_NODE_H -#define _SYS_SDEV_NODE_H - -#pragma ident "%Z%%M% %I% %E% SMI" - - -#include <sys/fs/sdev_impl.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef _KERNEL - -#define DEVNOPS_REV 1 - -/* - * directory vnode ops implemented in a loadable module - */ -struct devname_ops { - int devnops_rev; /* module build version */ - int (*devnops_lookup)(char *, devname_handle_t *, struct cred *); - int (*devnops_remove)(devname_handle_t *); - int (*devnops_rename)(devname_handle_t *, char *); - int (*devnops_getattr)(devname_handle_t *, struct vattr *, - struct cred *); - int (*devnops_readdir)(devname_handle_t *, struct cred *); - void (*devnops_inactive)(devname_handle_t *, struct cred *); -}; - -/* - * supported protocols - */ -#define DEVNAME_NS_PATH 1 -#define DEVNAME_NS_DEV 2 - -/* - * default devname_ops for a /dev directory - * that has a device name binding rule map - */ -extern void devname_set_nodetype(devname_handle_t *, void *, int); -extern void devname_get_vnode(devname_handle_t *, vnode_t **); -extern int devname_get_path(devname_handle_t *, char **); -extern int devname_get_name(devname_handle_t *, char **); -extern int devname_get_dir_handle(devname_handle_t *, devname_handle_t **); -extern void devname_get_dir_vnode(devname_handle_t *, vnode_t **); -extern int devname_get_dir_path(devname_handle_t *, char **); -extern int devname_get_dir_name(devname_handle_t *, char **); - -#endif /* _KERNEL */ - -#ifdef __cplusplus -} -#endif - -#endif /* _SYS_SDEV_NODE_H */
--- a/usr/src/uts/common/sys/fs/zfs.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/fs/zfs.h Mon Jul 20 13:07:46 2009 -0400 @@ -18,6 +18,7 @@ * * CDDL HEADER END */ + /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. @@ -280,14 +281,15 @@ #define SPA_VERSION_14 14ULL #define SPA_VERSION_15 15ULL #define SPA_VERSION_16 16ULL +#define SPA_VERSION_17 17ULL /* * When bumping up SPA_VERSION, make sure GRUB ZFS understands the on-disk * format change. Go to usr/src/grub/grub-0.97/stage2/{zfs-include/, fsys_zfs*}, * and do the appropriate changes. Also bump the version number in * usr/src/grub/capability. */ -#define SPA_VERSION SPA_VERSION_16 -#define SPA_VERSION_STRING "16" +#define SPA_VERSION SPA_VERSION_17 +#define SPA_VERSION_STRING "17" /* * Symbolic names for the changes that caused a SPA_VERSION switch. @@ -303,7 +305,7 @@ #define SPA_VERSION_INITIAL SPA_VERSION_1 #define SPA_VERSION_DITTO_BLOCKS SPA_VERSION_2 #define SPA_VERSION_SPARES SPA_VERSION_3 -#define SPA_VERSION_RAID6 SPA_VERSION_3 +#define SPA_VERSION_RAIDZ2 SPA_VERSION_3 #define SPA_VERSION_BPLIST_ACCOUNT SPA_VERSION_3 #define SPA_VERSION_RAIDZ_DEFLATE SPA_VERSION_3 #define SPA_VERSION_DNODE_BYTES SPA_VERSION_3 @@ -325,6 +327,7 @@ #define SPA_VERSION_PASSTHROUGH_X SPA_VERSION_14 #define SPA_VERSION_USERSPACE SPA_VERSION_15 #define SPA_VERSION_STMF_PROP SPA_VERSION_16 +#define SPA_VERSION_RAIDZ3 SPA_VERSION_17 /* * ZPL version - rev'd whenever an incompatible on-disk format change
--- a/usr/src/uts/common/sys/i8042.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/i8042.h Mon Jul 20 13:07:46 2009 -0400 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -56,21 +56,18 @@ #define I8042_INT_INPUT_AVAIL 0x00 #define I8042_INT_INPUT_DATA 0x01 #define I8042_INT_OUTPUT_DATA 0x03 -#define I8042_INT_CMD_PLUS_PARAM 0x05 /* See comment below */ +#define I8042_LOCK 0x05 /* See comment below */ #define I8042_POLL_INPUT_AVAIL 0x10 #define I8042_POLL_INPUT_DATA 0x11 #define I8042_POLL_OUTPUT_DATA 0x13 -#define I8042_POLL_CMD_PLUS_PARAM 0x15 /* See comment below */ +#define I8042_UNLOCK 0x15 /* See comment below */ /* - * The I8042_INT_CMD_PLUS_PARAM and I8042_POLL_CMD_PLUS_PARAM virtual - * registers are meant to be used with i8042_rep_put8() [via - * ddi_rep_put8 in child drivers], which is designed to allow commands - * that have responses (or that have responses plus an option byte) to - * execute atomically with respect to commands from other children - * (some 8042 implementations get confused when other child devices - * intersperse their own commands while a command to a different - * 8042-connected device is in flight). + * The I8042_LOCK and I8042_UNLOCK virtual + * registers are meant to be used by child drivers that require exclusive + * access to the 8042 registers for an atomic transaction (e.g. keyboard + * enable, mouse reset) that consists of multiple single-byte commands + * and (possibly) their arguments. */ /* Softint priority used */
--- a/usr/src/uts/common/sys/ib/adapters/hermon/hermon.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/ib/adapters/hermon/hermon.h Mon Jul 20 13:07:46 2009 -0400 @@ -722,6 +722,7 @@ ddi_acc_handle_t hs_fm_uarhdl; /* fm-protected UAR hdl */ ddi_device_acc_attr_t hs_fm_accattr; /* fm-protected acc attr */ ddi_periodic_t hs_fm_poll_thread; /* fma poll thread */ + int32_t hs_fm_degraded_reason; /* degradation cause */ #ifdef FMA_TEST mod_hash_t *hs_fm_test_hash; /* testset */ mod_hash_t *hs_fm_id_hash; /* testid */
--- a/usr/src/uts/common/sys/ib/adapters/hermon/hermon_fm.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/ib/adapters/hermon/hermon_fm.h Mon Jul 20 13:07:46 2009 -0400 @@ -202,6 +202,11 @@ #define HCA_PIO_PERSISTENT (2) /* persistent error */ #define HCA_PIO_RETRY_CNT (3) +/* HCA firmware faults */ +#define HCA_FW_MISC 0x1 /* firmware misc faults */ +#define HCA_FW_CORRUPT 0x2 /* firmware corruption */ +#define HCA_FW_MISMATCH 0x3 /* firmware version mismatch */ + /* * Hermon FM macros */
--- a/usr/src/uts/common/sys/ib/ibnex/ibnex_devctl.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/ib/ibnex/ibnex_devctl.h Mon Jul 20 13:07:46 2009 -0400 @@ -184,8 +184,17 @@ * * Caller sets hca_guid field of this structure. * + * Caller allocates memory for hca device path. Sets hca_device_path to point + * to the allocated memory and hca_device_path_alloc_sz to the number of bytes + * allocated. + * * Upon successful return from the IOCTL, hca_info will contain HCA attributes - * for the specified GUID. + * for the specified GUID. hca_info.hca_device_path_len will contain the actual + * string length of the hca device path plus the terminating null character. + * hca_info.hca_device_path will point to null terminated hca device path + * string if the caller allocated memory for the hca device path is large + * enough to hold the hca device path and the terminating null character. + * Otherwise hca_info.hca_device_path will be set to NULL. * * * IBNEX_CTL_QUERY_HCA_PORT @@ -281,6 +290,14 @@ char hca_driver_name[MAX_HCA_DRVNAME_LEN]; int hca_driver_instance; + /* + * hca device path and the length. + * hca_device_path_len is string length of the actual hca device path + * plus the terminating null character. + */ + char *hca_device_path; + uint_t hca_device_path_len; + ibt_hca_flags_t hca_flags; /* HCA capabilities etc */ ibt_hca_flags2_t hca_flags2; /* HCA capabilities etc */ @@ -359,14 +376,130 @@ int32_t hca_pad; } ibnex_ctl_hca_info_t; +typedef struct ibnex_ctl_hca_info_32_s { + ib_guid_t hca_node_guid; /* Node GUID */ + ib_guid_t hca_si_guid; /* Optional System Image GUID */ + uint_t hca_nports; /* Number of physical ports */ + + /* HCA driver name and instance number */ + char hca_driver_name[MAX_HCA_DRVNAME_LEN]; + int hca_driver_instance; + + /* + * hca device path and the length. + * hca_device_path_len is string length of the actual hca device path + * plus the terminating null character. + */ + caddr32_t hca_device_path; + uint_t hca_device_path_len; + + ibt_hca_flags_t hca_flags; /* HCA capabilities etc */ + ibt_hca_flags2_t hca_flags2; /* HCA capabilities etc */ + + uint32_t hca_vendor_id; /* Vendor ID */ + uint16_t hca_device_id; /* Device ID */ + uint32_t hca_version_id; /* Version ID */ + + uint_t hca_max_chans; /* Max channels supported */ + uint_t hca_max_chan_sz; /* Max outstanding WRs on any */ + /* channel */ + + uint_t hca_max_sgl; /* Max SGL entries per WR */ + + uint_t hca_max_cq; /* Max num of CQs supported */ + uint_t hca_max_cq_sz; /* Max capacity of each CQ */ + + ibt_page_sizes_t hca_page_sz; /* Bit mask of page sizes */ + + uint_t hca_max_memr; /* Max num of HCA mem regions */ + ib_memlen_t hca_max_memr_len; /* Largest block, in bytes of */ + /* mem that can be registered */ + uint_t hca_max_mem_win; /* Max Memory windows in HCA */ + + uint_t hca_max_rsc; /* Max Responder Resources of */ + /* this HCA for RDMAR/Atomics */ + /* with this HCA as target. */ + uint8_t hca_max_rdma_in_chan; /* Max RDMAR/Atomics in per */ + /* chan this HCA as target. */ + uint8_t hca_max_rdma_out_chan; /* Max RDMA Reads/Atomics out */ + /* per channel by this HCA */ + uint_t hca_max_ipv6_chan; /* Max IPV6 channels in HCA */ + uint_t hca_max_ether_chan; /* Max Ether channels in HCA */ + + uint_t hca_max_mcg_chans; /* Max number of channels */ + /* that can join multicast */ + /* groups */ + uint_t hca_max_mcg; /* Max multicast groups */ + uint_t hca_max_chan_per_mcg; /* Max number of channels per */ + /* Multicast group in HCA */ + uint16_t hca_max_partitions; /* Max partitions in HCA */ + + ib_time_t hca_local_ack_delay; + + uint_t hca_max_port_sgid_tbl_sz; + uint16_t hca_max_port_pkey_tbl_sz; + uint_t hca_max_pd; /* Max# of Protection Domains */ + + uint_t hca_max_ud_dest; + uint_t hca_max_srqs; /* Max SRQs supported */ + uint_t hca_max_srqs_sz; /* Max outstanding WRs on any */ + /* SRQ */ + uint_t hca_max_srq_sgl; /* Max SGL entries per SRQ WR */ + uint_t hca_max_cq_handlers; + ibt_lkey_t hca_reserved_lkey; /* Reserved L_Key value */ + uint_t hca_max_fmrs; /* Max FMR Supported */ + + uint_t hca_max_lso_size; + uint_t hca_max_lso_hdr_size; + uint_t hca_max_inline_size; + + uint_t hca_max_cq_mod_count; /* CQ notify moderation */ + uint_t hca_max_cq_mod_usec; + + uint32_t hca_fw_major_version; /* firmware version */ + uint16_t hca_fw_minor_version; + uint16_t hca_fw_micro_version; + + /* detailed WQE size info */ + uint_t hca_ud_send_inline_sz; /* inline size in bytes */ + uint_t hca_conn_send_inline_sz; + uint_t hca_conn_rdmaw_inline_overhead; + uint_t hca_recv_sgl_sz; /* detailed SGL sizes */ + uint_t hca_ud_send_sgl_sz; + uint_t hca_conn_send_sgl_sz; + uint_t hca_conn_rdma_sgl_overhead; + int32_t hca_pad; +} ibnex_ctl_hca_info_32_t; + /* * Data structure for IBNEX_CTL_QUERY_HCA */ typedef struct ibnex_ctl_query_hca_s { - ib_guid_t hca_guid; /* in: HCA GUID */ + ib_guid_t hca_guid; /* in: HCA GUID */ + + /* + * in: user allocated memory pointer for hca device path and number of + * bytes allocated for the hca device path. + */ + char *hca_device_path; + uint_t hca_device_path_alloc_sz; + ibnex_ctl_hca_info_t hca_info; /* out: HCA information */ } ibnex_ctl_query_hca_t; +typedef struct ibnex_ctl_query_hca_32_s { + ib_guid_t hca_guid; /* in: HCA GUID */ + + /* + * in: user allocated memory pointer for hca device path and number of + * bytes allocated for the hca device path. + */ + caddr32_t hca_device_path; + uint_t hca_device_path_alloc_sz; + + ibnex_ctl_hca_info_32_t hca_info; /* out: HCA information */ +} ibnex_ctl_query_hca_32_t; + /* * HCA port information structure */
--- a/usr/src/uts/common/sys/ib/ibtl/impl/ibtl_ibnex.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/ib/ibtl/impl/ibtl_ibnex.h Mon Jul 20 13:07:46 2009 -0400 @@ -238,6 +238,8 @@ * driver_name - caller allocated buffer which will contain * HCA driver name upon success * driver_instance - HCA driver instance + * hca_device_path - caller allocated buffer of size MAXPATHLEN which + * will contain hca device path upon success. * Returns: * IBT_SUCCESS/IBT_FAILURE * Description: @@ -245,7 +247,8 @@ * specified HCA. */ ibt_status_t -ibtl_ibnex_query_hca_byguid(ib_guid_t, ibt_hca_attr_t *, char *, size_t, int *); +ibtl_ibnex_query_hca_byguid(ib_guid_t, ibt_hca_attr_t *, char *, size_t, int *, + char *); #ifdef __cplusplus }
--- a/usr/src/uts/common/sys/ib/mgt/ibdm/ibdm_ibnex.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/ib/mgt/ibdm/ibdm_ibnex.h Mon Jul 20 13:07:46 2009 -0400 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -52,7 +52,9 @@ typedef enum ibdm_events_e { IBDM_EVENT_HCA_ADDED, IBDM_EVENT_HCA_REMOVED, - IBDM_EVENT_IOC_PROP_UPDATE + IBDM_EVENT_IOC_PROP_UPDATE, + IBDM_EVENT_PORT_UP, + IBDM_EVENT_PORT_PKEY_CHANGE } ibdm_events_t; /*
--- a/usr/src/uts/common/sys/lvm/meta_basic.x Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/lvm/meta_basic.x Mon Jul 20 13:07:46 2009 -0400 @@ -20,7 +20,7 @@ % */ % %/* -% * Copyright 2008 Sun Microsystems, Inc. All rights reserved. +% * Copyright 2009 Sun Microsystems, Inc. All rights reserved. % * Use is subject to license terms. % */ % @@ -177,42 +177,6 @@ % return (FALSE); % return (TRUE); %} -% -#ifdef _KERNEL -% -%#define LASTUNSIGNED ((u_int)0-1) -% -%/* -% * xdr_vector(): -% * -% * XDR a fixed length array. Unlike variable-length arrays, -% * the storage of fixed length arrays is static and unfreeable. -% * > basep: base of the array -% * > size: size of the array -% * > elemsize: size of each element -% * > xdr_elem: routine to XDR each element -% */ -%bool_t -%xdr_vector(xdrs, basep, nelem, elemsize, xdr_elem) -% XDR *xdrs; -% char *basep; -% u_int nelem; -% u_int elemsize; -% xdrproc_t xdr_elem; -%{ -% u_int i; -% char *elptr; -% -% elptr = basep; -% for (i = 0; i < nelem; i++) { -% if (! (*xdr_elem)(xdrs, elptr, LASTUNSIGNED)) { -% return (FALSE); -% } -% elptr += elemsize; -% } -% return (TRUE); -%} -#endif /* _KERNEL */ #endif /* RPC_XDR */ #ifdef RPC_HDR @@ -351,11 +315,6 @@ %extern bool_t xdr_minor_t(XDR *xdrs, minor_t *objp); %extern bool_t xdr_timeval(XDR *xdrs, struct timeval *objp); %extern bool_t xdr_clnt_stat(XDR *xdrs, enum clnt_stat *objp); -#ifdef _KERNEL -%extern bool_t xdr_vector(XDR *xdrs, char *basep, -% u_int nelem, u_int elemsize, -% xdrproc_t xdr_elem); -#endif /* _KERNEL */ %#else /* K&R C */ #ifndef _KERNEL %extern bool_t xdr_uint_t(); @@ -374,9 +333,5 @@ %extern bool_t xdr_minor_t(); %extern bool_t xdr_timeval(); %extern bool_t xdr_clnt_stat(); -% -#ifdef _KERNEL -%extern bool_t xdr_vector(); -#endif /* _KERNEL */ %#endif /* K&R C */ #endif /* RPC_HDR */
--- a/usr/src/uts/common/sys/modctl.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/modctl.h Mon Jul 20 13:07:46 2009 -0400 @@ -78,7 +78,6 @@ extern struct mod_ops mod_dacfops; extern struct mod_ops mod_ippops; extern struct mod_ops mod_pcbeops; -extern struct mod_ops mod_devfsops; extern struct mod_ops mod_kiconvops; #endif /* _KERNEL */ @@ -183,13 +182,6 @@ struct brand *brand_branddef; }; -/* for devname fs */ -struct modldev { - struct mod_ops *dev_modops; - char *dev_linkinfo; - struct devname_ops *dev_ops; -}; - /* For socket Modules. */ struct modlsockmod { struct mod_ops *sockmod_modops; @@ -293,8 +285,6 @@ * devname subcmds for MODDEVNAME */ #define MODDEVNAME_LOOKUPDOOR 0 -#define MODDEVNAME_DEVFSADMNODE 1 -#define MODDEVNAME_NSMAPS 2 #define MODDEVNAME_PROFILE 3 #define MODDEVNAME_RECONFIG 4 #define MODDEVNAME_SYSAVAIL 5
--- a/usr/src/uts/common/sys/mouse.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/mouse.h Mon Jul 20 13:07:46 2009 -0400 @@ -2,9 +2,8 @@ * 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. + * Common Development and Distribution License (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. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1999 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ /* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */ @@ -31,77 +30,16 @@ #ifndef _SYS_MOUSE_H #define _SYS_MOUSE_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif -#define BUTCHNGMASK 0x38 -#define MOVEMENT 0x40 - -#define BUTSTATMASK 7 -#define BUT3STAT 1 -#define BUT2STAT 2 -#define BUT1STAT 4 -#define BUT3CHNG 8 -#define BUT2CHNG 0x10 -#define BUT1CHNG 0x20 - -struct mse_event { - uchar_t type; /* event type (see below) */ - uchar_t code; /* when type is XQ_MOTION or XQ_BUTTON, => */ - /* bit 0 clear if right button pushed; */ - /* bit 1 clear if middle button pushed; */ - /* bit 2 clear if left button pushed; */ - char x; /* delta x movement (mouse motion only) */ - char y; /* delta y movement (mouse motion only) */ -}; - -#define MSE_BUTTON 0 -#define MSE_MOTION 1 - -struct mouseinfo { - unsigned char status; - char xmotion, ymotion; -}; - -/* Ioctl Command definitions */ - -#define MOUSEIOC ('M'<<8) -#define MOUSEIOCREAD (MOUSEIOC|60) -#define MOUSEISOPEN (MOUSEIOC|66) -#define MOUSE320 (MOUSEIOC|67) -#define MSEBUTTONS (MOUSEIOC|68) -#define TS_CALIB (MOUSEIOC|70) /* Touch screen: set the calibration */ -#define TS_RECALIB (MOUSEIOC|71) /* Touch screen: disable calibration */ -#define TS_CURPOS (MOUSEIOC|72) /* Touch screen: set cursor position */ -#define MOUSEIOCDELAY (MOUSEIOC|80) -#define MOUSEIOCNDELAY (MOUSEIOC|81) -#define MOUSEIOCCONFIG (MOUSEIOC|100) -#define MOUSEIOCMON (MOUSEIOC|101) - -#define VPC_MOUSE_READ MOUSEIOCREAD - -#define UPPERLIM 127 -#define LOWERLIM -128 -#define ONEBYTE(x) ((x) > UPPERLIM ? UPPERLIM : \ - (x) < LOWERLIM ? LOWERLIM : (x)) - -/* 320 mouse command/query structure */ - -struct cmd_320 { - int cmd; - int arg1; - int arg2; - int arg3; -}; - /* * AT&T 320 (PS/2 style) Mouse Commands */ #define MSERESET 0xff /* reset mouse */ #define MSERESEND 0xfe /* resend last data stream */ +#define MSEERROR 0xfc /* error */ #define MSESETDEF 0xf6 /* set default status */ #define MSEOFF 0xf5 /* disable mouse */ #define MSEON 0xf4 /* enable mouse */ @@ -117,53 +55,12 @@ #define MSESCALE2 0xe7 /* set 2:1 scaling */ #define MSESCALE1 0xe6 /* set 1:1 scaling */ -/* - * 320 mouse 8042 controller commands and flags - */ -#define MSE_ROP 0xD0 /* read output port command */ -#define MSE_RIP 0xC0 /* read input port command */ -#define MSE_WOP 0xD3 /* write to loopback command */ -#define MSE_WAD 0xD4 /* write to device command */ -#define MSE_RCB 0x20 /* read command byte command */ -#define MSE_WCB 0x60 /* write command byte command */ -#define MSE_INBF 0x03 /* input/output buffer full flag */ -#define MSE_OUTBF 0x21 /* output buffer full flag */ -#define MSE_ENAB 0xA8 /* enable 8042 interface */ -#define MSE_DISAB 0xA7 /* disable 8042 interface */ #define MSE_ACK 0xFA /* Acknowledgement byte from 8042 */ -typedef struct mouseinfo MOUSEINFO; - -/* - * Begin Carrol touch screen-specific definitions. - */ - -/* - * Calibration data structure. Used with TS_CALIB ioctl to register the upper - * left opto-coordinate that corresponds to the upper left corner of the active - * video area, and the lower right opto-coordinate that corresponds to the - * lower right corner of the active video area. - */ +/* Post-reset return values */ +#define MSE_AA 0xaa +#define MSE_00 0x00 -struct ts_calib { - int c_ulx, /* upper left X opto-coordinate of active video area */ - c_uly, /* upper left Y opto-coordinate of active video area */ - c_lrx, /* lower right X opto-coordinate of active video area */ - c_lry; /* lower right Y opto-coordinate of active video area */ -}; - -/* - * Position cursor at the given "pixel" coordinate. - */ - -struct ts_curpos { - int p_xpos, /* X cursor coordinate */ - p_ypos; /* Y cursor coordinate */ -}; - -/* - * End Carrol touch screen-specific definitions. - */ #ifdef __cplusplus }
--- a/usr/src/uts/common/sys/pset.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/pset.h Mon Jul 20 13:07:46 2009 -0400 @@ -19,15 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SYS_PSET_H #define _SYS_PSET_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -60,6 +58,7 @@ extern int pset_assign(psetid_t, processorid_t, psetid_t *); extern int pset_info(psetid_t, int *, uint_t *, processorid_t *); extern int pset_bind(psetid_t, idtype_t, id_t, psetid_t *); +extern int pset_bind_lwp(psetid_t, id_t, pid_t, psetid_t *); extern int pset_getloadavg(psetid_t, double [], int); extern int pset_list(psetid_t *, uint_t *); extern int pset_setattr(psetid_t, uint_t); @@ -72,6 +71,7 @@ extern int pset_assign(); extern int pset_info(); extern int pset_bind(); +extern int pset_bind_lwp(); extern int pset_getloadavg(); extern int pset_list(); extern int pset_setattr(); @@ -93,6 +93,7 @@ #define PSET_SETATTR 7 #define PSET_GETATTR 8 #define PSET_ASSIGN_FORCED 9 +#define PSET_BIND_LWP 10 /* attribute bits */ #define PSET_NOESCAPE 0x0001
--- a/usr/src/uts/common/sys/sata/adapters/ahci/ahcivar.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/sata/adapters/ahci/ahcivar.h Mon Jul 20 13:07:46 2009 -0400 @@ -352,6 +352,8 @@ #define AHCI_DEBUG 1 +#endif + #define AHCIDBG_INIT 0x0001 #define AHCIDBG_ENTRY 0x0002 #define AHCIDBG_PRDT 0x0004 @@ -373,44 +375,28 @@ extern uint32_t ahci_debug_flags; -#define AHCIDBG0(flag, ahci_ctlp, format) \ - if (ahci_debug_flags & (flag)) { \ - ahci_log(ahci_ctlp, CE_WARN, format); \ - } +#if DEBUG -#define AHCIDBG1(flag, ahci_ctlp, format, arg1) \ +#define AHCIDBG(flag, ahci_ctlp, fmt, args ...) \ if (ahci_debug_flags & (flag)) { \ - ahci_log(ahci_ctlp, CE_WARN, format, arg1); \ - } - -#define AHCIDBG2(flag, ahci_ctlp, format, arg1, arg2) \ - if (ahci_debug_flags & (flag)) { \ - ahci_log(ahci_ctlp, CE_WARN, format, arg1, arg2); \ + ahci_log(ahci_ctlp, CE_WARN, fmt, ## args); \ + if (ahci_ctlp == NULL) \ + sata_trace_debug(NULL, fmt, ## args); \ + else \ + sata_trace_debug(ahci_ctlp->ahcictl_dip,\ + fmt, ## args); \ } -#define AHCIDBG3(flag, ahci_ctlp, format, arg1, arg2, arg3) \ - if (ahci_debug_flags & (flag)) { \ - ahci_log(ahci_ctlp, CE_WARN, format, arg1, arg2, arg3); \ - } - -#define AHCIDBG4(flag, ahci_ctlp, format, arg1, arg2, arg3, arg4) \ - if (ahci_debug_flags & (flag)) { \ - ahci_log(ahci_ctlp, CE_WARN, format, arg1, arg2, arg3, arg4); \ - } - -#define AHCIDBG5(flag, ahci_ctlp, format, arg1, arg2, arg3, arg4, arg5) \ - if (ahci_debug_flags & (flag)) { \ - ahci_log(ahci_ctlp, CE_WARN, format, arg1, arg2, \ - arg3, arg4, arg5); \ - } #else -#define AHCIDBG0(flag, dip, frmt) -#define AHCIDBG1(flag, dip, frmt, arg1) -#define AHCIDBG2(flag, dip, frmt, arg1, arg2) -#define AHCIDBG3(flag, dip, frmt, arg1, arg2, arg3) -#define AHCIDBG4(flag, dip, frmt, arg1, arg2, arg3, arg4) -#define AHCIDBG5(flag, dip, frmt, arg1, arg2, arg3, arg4, arg5) +#define AHCIDBG(flag, ahci_ctlp, fmt, args ...) \ + if (ahci_debug_flags & (flag)) { \ + if (ahci_ctlp == NULL) \ + sata_trace_debug(NULL, fmt, ## args); \ + else \ + sata_trace_debug(ahci_ctlp->ahcictl_dip,\ + fmt, ## args); \ + } #endif /* DEBUG */
--- a/usr/src/uts/common/sys/sata/impl/sata.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/sata/impl/sata.h Mon Jul 20 13:07:46 2009 -0400 @@ -227,6 +227,13 @@ uint64_t satadrv_max_queue_depth; /* maximum queue depth */ sata_id_t satadrv_id; /* Device Identify Data */ struct sata_drive_stats satadrv_stats; /* drive statistics */ + + /* + * saved standby timer + * [0] - [3] = high - low + */ + uint8_t satadrv_standby_timer[4]; + uint8_t satadrv_power_level; /* saved power level */ }; typedef struct sata_drive_info sata_drive_info_t; @@ -313,6 +320,22 @@ typedef struct sata_pmport_info sata_pmport_info_t; /* + * sata drive's power level + * default value is active + */ +#define SATA_POWER_ACTIVE 0x00 +#define SATA_POWER_IDLE 0x01 +#define SATA_POWER_STANDBY 0x02 +#define SATA_POWER_STOPPED 0x03 + +/* + * pm-capable value definition according to PSARC 2009/310 + */ +#define SATA_CAP_POWER_CONDITON PM_CAPABLE_SPC4 +#define SATA_CAP_SMART_PAGE PM_CAPABLE_SMART_LOG +#define SATA_CAP_LOG_SENSE PM_CAPABLE_LOG_SUPPORTED + +/* * Port SSTATUS register (sata_port_scr sport_sstatus field). * Link bits are valid only in port active state. */ @@ -470,9 +493,12 @@ #define SD_SCSI_ASC_INVALID_COMMAND_CODE 0x20 #define SD_SCSI_ASC_LBA_OUT_OF_RANGE 0x21 #define SD_SCSI_ASC_INVALID_FIELD_IN_CDB 0x24 -#define SD_SCSI_ASC_INVALID_FIELD_IN_PARAMS_LIST 0x26 +#define SD_SCSI_ASC_INVALID_FIELD_IN_PARAMS_LIST 0x26 #define SD_SCSI_ASC_RESET 0x29 #define SD_SCSI_ASC_SAVING_PARAMS_NOT_SUPPORTED 0x39 +#define SD_SCSI_ASC_CMD_SEQUENCE_ERR 0x2c +#define SD_SCSI_ASC_LOW_POWER_CONDITION_ON 0x5e +#define SD_SCSI_ASC_LU_NOT_RESPONSE 0x05 /* SCSI defs missing from scsi headers */ @@ -485,6 +511,28 @@ #define MODEPAGE_RW_ERRRECOV 0x01 /* read/write recovery */ /* + * medium access command + */ +#define SATA_IS_MEDIUM_ACCESS_CMD(cmd) \ + (((cmd) == SCMD_READ) || ((cmd) == SCMD_WRITE) || \ + ((cmd) == SCMD_READ_G1) || ((cmd) == SCMD_WRITE_G1) || \ + ((cmd) == SCMD_READ_G4) || ((cmd) == SCMD_WRITE_G4) || \ + ((cmd) == SCMD_READ_G5) || ((cmd) == SCMD_WRITE_G5) || \ + ((cmd) == SCMD_VERIFY) || ((cmd) == SCMD_VERIFY_G4) || \ + ((cmd) == SCMD_VERIFY_G5) || ((cmd) == 0x7f) /* VERIFY(32) */|| \ + ((cmd) == SCMD_SYNCHRONIZE_CACHE) || ((cmd) == SCMD_SPACE_G4) || \ + ((cmd) == SCMD_READ_POSITION) || \ + ((cmd) == 0x90) /* PRE-FETCH(16) */ || \ + ((cmd) == SCMD_READ_DEFECT_LIST) || \ + ((cmd) == 0xb7) /* READ DEFECT DATA */ || \ + ((cmd) == SCMD_READ_LONG) || ((cmd) == SCMD_SVC_ACTION_IN_G4) || \ + ((cmd) == SCMD_WRITE_LONG) || ((cmd) == SCMD_SVC_ACTION_OUT_G4) || \ + ((cmd) == 0x41) || ((cmd) == 0x93) || /* WRITE SAME */ \ + ((cmd) == 0x52) || ((cmd) == 0x50) || /* XDREAD & XDWRITE */ \ + ((cmd) == 0x53) || ((cmd) == 0x51) || /* XDWRITEREAD & XPWRITE */ \ + ((cmd) == 0x7f)) + +/* * Macros for accessing various structure fields */
--- a/usr/src/uts/common/sys/sata/sata_defs.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/sata/sata_defs.h Mon Jul 20 13:07:46 2009 -0400 @@ -45,6 +45,7 @@ #define SATAC_DOOR_LOCK 0xde /* door lock */ #define SATAC_DOOR_UNLOCK 0xdf /* door unlock */ #define SATAC_IDLE 0xe3 /* idle */ +#define SATAC_STANDBY 0xe2 /* standby */ /* * ATA/ATAPI disk commands (subset) @@ -94,9 +95,11 @@ */ #define SATAC_CHECK_POWER_MODE 0xe5 /* check power mode */ -#define SATA_PWRMODE_STANDBY 0 /* standby mode */ -#define SATA_PWRMODE_IDLE 0x80 /* idle mode */ -#define SATA_PWRMODE_ACTIVE 0xFF /* active or idle mode, rev7 spec */ +#define SATA_PWRMODE_STANDBY 0 /* standby mode */ +#define SATA_PWRMODE_IDLE 0x80 /* idle mode */ +#define SATA_PWRMODE_ACTIVE_SPINDOWN 0x40 /* PM0 and spinning down */ +#define SATA_PWRMODE_ACTIVE_SPINUP 0x41 /* PM0 and spinning up */ +#define SATA_PWRMODE_ACTIVE 0xFF /* active or idle mode */ /* @@ -152,8 +155,8 @@ * Following is the ATA Device Identify data layout */ typedef struct sata_id { -/* WORD */ -/* OFFSET COMMENT */ +/* WORD */ +/* OFFSET COMMENT */ ushort_t ai_config; /* 0 general configuration bits */ ushort_t ai_fixcyls; /* 1 # of cylinders (obsolete) */ ushort_t ai_resv0; /* 2 # reserved */ @@ -245,7 +248,7 @@ #define SATA_ATA_TYPE_MASK 0x8001 /* ATA Device type mask */ #define SATA_ATA_TYPE 0x0000 /* ATA device */ -#define SATA_REM_MEDIA 0x0080 /* Removable media */ +#define SATA_REM_MEDIA 0x0080 /* Removable media */ #define SATA_INCOMPLETE_DATA 0x0004 /* Incomplete Identify Device data */ #define SATA_CFA_TYPE 0x848a /* CFA feature set device */ @@ -297,6 +300,8 @@ /* Identify Device: command set supported/enabled bits - words 84 & 87 */ #define SATA_SMART_SELF_TEST_SUPPORTED 0x0002 /* SMART self-test supported */ +/* IDLE IMMEDIATE with UNLOAD FEATURE supported */ +#define SATA_IDLE_UNLOAD_SUPPORTED 0x2000 /* Identify (Packet) Device word 63, ATA/ATAPI-6 & 7 */ #define SATA_MDMA_SEL_MASK 0x0700 /* Multiword DMA selected */ @@ -329,11 +334,11 @@ /* Identify Packet Device: general config bits - word 0 */ #define SATA_ATAPI_TYPE_MASK 0xc000 -#define SATA_ATAPI_TYPE 0x8000 /* ATAPI device */ -#define SATA_ATAPI_ID_PKT_SZ 0x0003 /* Packet size mask */ +#define SATA_ATAPI_TYPE 0x8000 /* ATAPI device */ +#define SATA_ATAPI_ID_PKT_SZ 0x0003 /* Packet size mask */ #define SATA_ATAPI_ID_PKT_12B 0x0000 /* Packet size 12 bytes */ #define SATA_ATAPI_ID_PKT_16B 0x0001 /* Packet size 16 bytes */ -#define SATA_ATAPI_ID_DRQ_TYPE 0x0060 /* DRQ asserted in 3ms after pkt */ +#define SATA_ATAPI_ID_DRQ_TYPE 0x0060 /* DRQ asserted in 3ms after pkt */ #define SATA_ATAPI_ID_DRQ_INTR 0x0020 /* Obsolete in ATA/ATAPI 7 */ #define SATA_ATAPI_ID_DEV_TYPE 0x0f00 /* device type/command set mask */ @@ -413,9 +418,9 @@ * Status bits from AT_STATUS register */ #define SATA_STATUS_BSY 0x80 /* controller busy */ -#define SATA_STATUS_DRDY 0x40 /* drive ready */ +#define SATA_STATUS_DRDY 0x40 /* drive ready */ #define SATA_STATUS_DF 0x20 /* device fault */ -#define SATA_STATUS_DSC 0x10 /* seek operation complete */ +#define SATA_STATUS_DSC 0x10 /* seek operation complete */ #define SATA_STATUS_DRQ 0x08 /* data request */ #define SATA_STATUS_CORR 0x04 /* obsolete */ #define SATA_STATUS_IDX 0x02 /* obsolete */ @@ -508,6 +513,9 @@ uint8_t ncq_checksum; }; +/* SMART attribute of Start/Stop Count */ +#define SMART_START_STOP_COUNT_ID 0x4 + /* * SMART data structures */ @@ -574,6 +582,24 @@ }; /* + * The definition of CONTROL byte field in SCSI command + * according to SAM 5 + */ +#define CTL_BYTE_VENDOR_MASK 0xc0 +#define CTL_BYTE_NACA_MASK 0x04 + +/* + * The definition of mask in START STOP UNIT command + */ +#define START_STOP_IMMED_MASK 0x01 +#define START_STOP_POWER_COND_MASK 0xF0 +#define START_STOP_START_MASK 0x01 +#define START_STOP_LOEJ_MASK 0x02 +#define START_STOP_NOFLUSH_MASK 0x04 +#define START_STOP_MODIFIER_MASK 0x0f +#define START_STOP_POWER_COND_SHIFT 4 + +/* * SMART specific data * These eventually need to go to a generic scsi hearder file * for now they will reside here @@ -583,6 +609,7 @@ #define PAGE_CODE_SELF_TEST_RESULTS 0x10 #define PAGE_CODE_INFORMATION_EXCEPTIONS 0x2f #define PAGE_CODE_SMART_READ_DATA 0x30 +#define PAGE_CODE_START_STOP_CYCLE_COUNTER 0x0e struct log_parameter {
--- a/usr/src/uts/common/sys/sata/sata_hba.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/sata/sata_hba.h Mon Jul 20 13:07:46 2009 -0400 @@ -20,7 +20,7 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -714,6 +714,40 @@ void sata_free_error_retrieval_pkt(sata_pkt_t *); void sata_free_dma_resources(sata_pkt_t *); +/* + * SATA trace ring buffer constants + */ +#define DMSG_RING_SIZE 0x100000 /* 1MB */ +#define DMSG_BUF_SIZE 256 + +/* + * SATA trace ring buffer content + */ +typedef struct sata_trace_dmsg { + dev_info_t *dip; + timespec_t timestamp; + char buf[DMSG_BUF_SIZE]; + struct sata_trace_dmsg *next; +} sata_trace_dmsg_t; + +/* + * SATA trace ring buffer header + */ +typedef struct sata_trace_rbuf { + kmutex_t lock; /* lock to avoid clutter */ + int looped; /* completed ring */ + int allocfailed; /* dmsg mem alloc failed */ + size_t size; /* current size */ + size_t maxsize; /* max size */ + sata_trace_dmsg_t *dmsgh; /* messages head */ + sata_trace_dmsg_t *dmsgp; /* ptr to last message */ +} sata_trace_rbuf_t; + +/* + * SATA trace ring buffer interfaces + */ +void sata_trace_debug(dev_info_t *, const char *fmt, ...); +void sata_vtrace_debug(dev_info_t *, const char *fmt, va_list); #ifdef __cplusplus }
--- a/usr/src/uts/common/sys/scsi/generic/inquiry.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/scsi/generic/inquiry.h Mon Jul 20 13:07:46 2009 -0400 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -425,6 +425,24 @@ /* ---- data follows ---- */ }; +/* + * "pm-capable" integer property bit mask definitions + */ +#define PM_CAPABLE_PM_MASK 0x0000ffff /* use lower 16 bits to */ + /* indicate PM mode */ +#define PM_CAPABLE_CCS RDF_CCS +#define PM_CAPABLE_SCSI2 RDF_SCSI2 +#define PM_CAPABLE_SPC RDF_SCSI_SPC +#define PM_CAPABLE_SPC2 RDF_SCSI_SPC2 +#define PM_CAPABLE_SPC3 RDF_SCSI_SPC3 +#define PM_CAPABLE_SPC4 RDF_SCSI_SPC4 +#define PM_CAPABLE_LOG_MASK 0xffff0000 /* use upper 16 bit to */ + /* indicate log specifics */ +#define PM_CAPABLE_LOG_SUPPORTED 0x10000 /* Log page 0xE might be */ + /* supported */ +#define PM_CAPABLE_SMART_LOG 0x20000 /* Log page 0xE reports SMART */ + /* attributes instead of the */ + /* default SCSI Log pages */ #ifdef __cplusplus } #endif
--- a/usr/src/uts/common/sys/scsi/generic/mode.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/scsi/generic/mode.h Mon Jul 20 13:07:46 2009 -0400 @@ -19,15 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SYS_SCSI_GENERIC_MODE_H #define _SYS_SCSI_GENERIC_MODE_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -391,6 +389,89 @@ #define MRIE_NO_SENSE 0x5 #define MRIE_ONLY_ON_REQUEST 0x6 +struct mode_info_power_cond { + struct mode_page mode_page; /* common mode page header */ + uchar_t reserved; +#if defined(_BIT_FIELDS_LTOH) + uchar_t standby :1, /* standby bit */ + idle :1, /* idle bit */ + :6; /* reserved */ +#elif defined(_BIT_FIELDS_HTOL) + uchar_t :6, /* reserved */ + idle :1, /* idle bit */ + standby :1; /* standby bit */ +#else +#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined +#endif + uchar_t idle_cond_timer_high; + uchar_t idle_cond_timer_low; + uchar_t standby_cond_timer[4]; +}; + +struct parameter_control { +#if defined(_BIT_FIELDS_LTOH) + uchar_t fmt_link:2, /* format and link bit */ + tmc :2, /* tmc bit */ + etc :1, /* etc bit */ + tsd :1, /* tsd bit */ + reserv :1, /* obsolete */ + du :1; /* du bit */ +#elif defined(_BIT_FIELDS_HTOL) + uchar_t du :1, /* du bit */ + reserv :1, /* obsolete */ + tsd :1, /* tsd bit */ + etc :1, /* etc bit */ + tmc :2, /* tmc bit */ + fmt_link:2; /* format and link bit */ +#else +#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined +#endif +}; + +struct start_stop_cycle_counter_log { +#if defined(_BIT_FIELDS_LTOH) + uchar_t code :6, /* page code bit */ + spf :1, /* spf bit */ + ds :1; /* ds bit */ +#elif defined(_BIT_FIELDS_HTOL) + uchar_t ds :1, /* ds bit */ + spf :1, /* spf bit */ + code :6; /* page code bit */ +#else +#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined +#endif + uchar_t sub_page_code; + uchar_t page_len_high; + uchar_t page_len_low; + + uchar_t manufactor_date_high; + uchar_t manufactor_date_low; + struct parameter_control param_1; + uchar_t param_len_1; + uchar_t year_manu[4]; + uchar_t week_manu[2]; + + uchar_t account_date_high; + uchar_t account_date_low; + struct parameter_control param_2; + uchar_t param_len_2; + uchar_t year_account[4]; + uchar_t week_account[2]; + + uchar_t lifetime_code_high; + uchar_t lifetime_code_low; + struct parameter_control param_3; + uchar_t param_len_3; + uchar_t cycle_lifetime[4]; + + uchar_t cycle_code_high; + uchar_t cycle_code_low; + struct parameter_control param_4; + uchar_t param_len_4; + uchar_t cycle_accumulated[4]; +}; + + #ifdef __cplusplus } #endif
--- a/usr/src/uts/common/sys/scsi/impl/uscsi.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/scsi/impl/uscsi.h Mon Jul 20 13:07:46 2009 -0400 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -152,8 +152,14 @@ #define USCSI_NOPARITY 0x00000010 /* run command without parity */ #define USCSI_NODISCON 0x00000020 /* run command without disconnects */ +/* + * suitable for FMA module for PM purpose + */ +#define USCSI_PMFAILFAST 0x00100000 /* fail command if device is */ + /* in low power */ -#define USCSI_RESERVED 0xfff00000 /* Reserved Bits, must be zero */ + +#define USCSI_RESERVED 0xffe00000 /* Reserved Bits, must be zero */ struct uscsi_rqs { int rqs_flags; /* see below */
--- a/usr/src/uts/common/sys/scsi/targets/sddef.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/scsi/targets/sddef.h Mon Jul 20 13:07:46 2009 -0400 @@ -125,7 +125,7 @@ * Macro to retrieve the DDI instance number from the given buf struct. * The instance number is encoded in the minor device number. */ -#define SD_GET_INSTANCE_FROM_BUF(bp) \ +#define SD_GET_INSTANCE_FROM_BUF(bp) \ (getminor((bp)->b_edev) >> SDUNIT_SHIFT) @@ -447,7 +447,13 @@ /* sent in sdclose */ un_f_devid_transport_defined :1, /* devid defined by transport */ un_f_rmw_type :2, /* RMW type */ - un_f_reserved :10; + un_f_power_condition_disabled :1, /* power condition disabled */ + /* through sd configuration */ + un_f_power_condition_supported :1, /* support power condition */ + /* field by hardware */ + un_f_pm_log_sense_smart :1, /* log sense support SMART */ + /* feature attribute */ + un_f_reserved :7; /* Ptr to table of strings for ASC/ASCQ error message printing */ struct scsi_asq_key_strings *un_additional_codes; @@ -1783,11 +1789,28 @@ #define SD_CONF_NOT_USED 32 /* - * Return values from "pm-capable" property + * "pm-capable" property values and macros */ #define SD_PM_CAPABLE_UNDEFINED -1 -#define SD_PM_CAPABLE_FALSE 0 -#define SD_PM_CAPABLE_TRUE 1 + +#define SD_PM_CAPABLE_IS_UNDEFINED(pm_cap) \ + (pm_cap == SD_PM_CAPABLE_UNDEFINED) + +#define SD_PM_CAPABLE_IS_FALSE(pm_cap) \ + ((pm_cap & PM_CAPABLE_PM_MASK) == 0) + +#define SD_PM_CAPABLE_IS_TRUE(pm_cap) \ + (!SD_PM_CAPABLE_IS_UNDEFINED(pm_cap) && \ + ((pm_cap & PM_CAPABLE_PM_MASK) > 0)) + +#define SD_PM_CAPABLE_IS_SPC_4(pm_cap) \ + ((pm_cap & PM_CAPABLE_PM_MASK) == PM_CAPABLE_SPC4) + +#define SD_PM_CAP_LOG_SUPPORTED(pm_cap) \ + ((pm_cap & PM_CAPABLE_LOG_SUPPORTED) ? TRUE : FALSE) + +#define SD_PM_CAP_SMART_LOG(pm_cap) \ + ((pm_cap & PM_CAPABLE_SMART_LOG) ? TRUE : FALSE) /* * Property data values used in static configuration table @@ -2022,6 +2045,13 @@ #define SD_CONF_BSET_CACHE_IS_NV (1 << SD_CONF_SET_CACHE_IS_NV) /* + * Bit in flags telling driver that the power condition flag from [s]sd.conf + * [s]sd-config-list and driver table. + */ +#define SD_CONF_SET_PC_DISABLED 19 +#define SD_CONF_BSET_PC_DISABLED (1 << SD_CONF_SET_PC_DISABLED) + +/* * This is the number of items currently settable in the sd.conf * sd-config-list. The mask value is defined for parameter checking. The * item count and mask should be updated when new properties are added. @@ -2040,6 +2070,7 @@ int sdt_disk_sort_dis; int sdt_lun_reset_enable; int sdt_suppress_cache_flush; + int sdt_power_condition_dis; } sd_tunables; /* Type definition for static configuration table entries */ @@ -2050,13 +2081,21 @@ } sd_disk_config_t; /* - * byte 4 options for 1bh command + * first 2 bits of byte 4 options for 1bh command */ #define SD_TARGET_STOP 0x00 #define SD_TARGET_START 0x01 #define SD_TARGET_EJECT 0x02 #define SD_TARGET_CLOSE 0x03 +/* + * power condition of byte 4 for 1bh command + */ +#define SD_TARGET_START_VALID 0x00 +#define SD_TARGET_ACTIVE 0x01 +#define SD_TARGET_IDLE 0x02 +#define SD_TARGET_STANDBY 0x03 + #define SD_MODE_SENSE_PAGE3_CODE 0x03 #define SD_MODE_SENSE_PAGE4_CODE 0x04 @@ -2143,7 +2182,47 @@ #define SD_SPINDLE_UNINIT (-1) #define SD_SPINDLE_OFF 0 #define SD_SPINDLE_ON 1 -#define SD_PM_NOT_SUPPORTED 2 +#define SD_SPINDLE_STOPPED 0 +#define SD_SPINDLE_STANDBY 1 +#define SD_SPINDLE_IDLE 2 +#define SD_SPINDLE_ACTIVE 3 +#define SD_PM_NOT_SUPPORTED 4 + +/* + * Power method flag + */ +#define SD_START_STOP 0 +#define SD_POWER_CONDITION 1 + + +/* + * Number of power level for start stop or power condition + */ +#define SD_PM_NUM_LEVEL_SSU_SS 2 +#define SD_PM_NUM_LEVEL_SSU_PC 4 + +/* + * SD internal power state change flag + */ +#define SD_PM_STATE_CHANGE 0 +#define SD_PM_STATE_ROLLBACK 1 + +/* + * Power attribute table + */ +typedef struct disk_power_attr_ss { + char *pm_comp[SD_PM_NUM_LEVEL_SSU_SS + 2]; /* pm component */ + int ran_perf[SD_PM_NUM_LEVEL_SSU_SS]; /* random performance */ + int pwr_saving[SD_PM_NUM_LEVEL_SSU_SS]; /* power saving */ + int latency[SD_PM_NUM_LEVEL_SSU_SS]; /* latency */ +}sd_power_attr_ss; + +typedef struct disk_power_attr_pc { + char *pm_comp[SD_PM_NUM_LEVEL_SSU_PC + 2]; /* pm component */ + int ran_perf[SD_PM_NUM_LEVEL_SSU_PC]; /* random performance */ + int pwr_saving[SD_PM_NUM_LEVEL_SSU_PC]; /* power saving */ + int latency[SD_PM_NUM_LEVEL_SSU_PC]; /* latency */ +}sd_power_attr_pc; /* @@ -2166,6 +2245,30 @@ #define SD_OK_TO_SUSPEND_SCSI_WATCHER(un) (un->un_swr_token != NULL) #define SD_DEVICE_IS_IN_LOW_POWER(un) ((un->un_f_pm_is_enabled) && \ (un->un_pm_count < 0)) +#define SD_PM_STATE_ACTIVE(un) \ + (un->un_f_power_condition_supported ? \ + SD_SPINDLE_ACTIVE : SD_SPINDLE_ON) +#define SD_PM_STATE_STOPPED(un) \ + (un->un_f_power_condition_supported ? \ + SD_SPINDLE_STOPPED : SD_SPINDLE_OFF) +#define SD_PM_IS_LEVEL_VALID(un, level) \ + ((un->un_f_power_condition_supported && \ + level >= SD_SPINDLE_STOPPED && \ + level <= SD_SPINDLE_ACTIVE) || \ + (!un->un_f_power_condition_supported && \ + level >= SD_SPINDLE_OFF && \ + level <= SD_SPINDLE_ON)) +#define SD_PM_IS_IO_CAPABLE(un, level) \ + ((un->un_f_power_condition_supported && \ + sd_pwr_pc.ran_perf[level] > 0) || \ + (!un->un_f_power_condition_supported && \ + sd_pwr_ss.ran_perf[level] > 0)) +#define SD_PM_STOP_MOTOR_NEEDED(un, level) \ + ((un->un_f_power_condition_supported && \ + level <= SD_SPINDLE_STANDBY) || \ + (!un->un_f_power_condition_supported && \ + level == SD_SPINDLE_OFF)) + /* * Could move this define to some thing like log sense.h in SCSA headers * But for now let it live here.
--- a/usr/src/uts/common/sys/socket_proto.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/socket_proto.h Mon Jul 20 13:07:46 2009 -0400 @@ -60,6 +60,7 @@ uint_t sopp_rcvtimer; /* delayed recv notification (time) */ uint32_t sopp_rcvthresh; /* delayed recv notification (bytes) */ socklen_t sopp_maxaddrlen; /* maximum size of protocol address */ + boolean_t sopp_loopback; /* loopback connection */ }; /* flags to determine which socket options are set */ @@ -75,6 +76,7 @@ #define SOCKOPT_RCVTHRESH 0x0200 #define SOCKOPT_MAXADDRLEN 0x0400 /* set max address length */ #define SOCKOPT_MINPSZ 0x0800 /* set minpsz for protocols */ +#define SOCKOPT_LOOPBACK 0x1000 /* set loopback */ #define IS_SO_OOB_INLINE(so) ((so)->so_proto_props.sopp_oobinline)
--- a/usr/src/uts/common/sys/stmf_sbd_ioctl.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/stmf_sbd_ioctl.h Mon Jul 20 13:07:46 2009 -0400 @@ -83,6 +83,7 @@ slu_rev_valid:1, slu_serial_valid:1, slu_alias_valid:1, + slu_mgmt_url_valid:1, slu_guid_valid:1, slu_company_id_valid:1, slu_writeback_cache_disable_valid:1, @@ -98,8 +99,7 @@ uint16_t slu_blksize; uint32_t slu_company_id; uint16_t slu_alias_off; - uint8_t slu_rsvd2; - uint8_t slu_rsvd; + uint16_t slu_mgmt_url_off; uint32_t slu_rsvd1; char slu_rev[4]; char slu_vid[8]; @@ -120,6 +120,7 @@ uint32_t mlu_lu_size_valid:1, mlu_serial_valid:1, mlu_alias_valid:1, + mlu_mgmt_url_valid:1, mlu_writeback_cache_disable_valid:1, mlu_writeback_cache_disable:1, mlu_write_protected_valid:1, @@ -128,9 +129,12 @@ mlu_by_fname:1; uint64_t mlu_lu_size; uint16_t mlu_alias_off; + uint16_t mlu_mgmt_url_off; uint16_t mlu_serial_off; uint16_t mlu_serial_size; uint16_t mlu_fname_off; + uint16_t mlu_rsvd1; + uint32_t mlu_rsvd2; uint8_t mlu_input_guid[16]; char mlu_buf[8]; /* can be more than 8 */ } sbd_modify_lu_t; @@ -151,6 +155,7 @@ slp_data_fname_valid:1, slp_zfs_meta:1, slp_alias_valid:1, + slp_mgmt_url_valid:1, slp_lu_vid:1, slp_lu_pid:1, slp_lu_rev:1, @@ -165,6 +170,7 @@ uint16_t slp_serial_off; uint16_t slp_blksize; uint16_t slp_alias_off; + uint16_t slp_mgmt_url_off; uint32_t slp_buf_size_needed; /* Upon return */ uint16_t slp_serial_size; uint16_t slp_rsvd;
--- a/usr/src/uts/common/sys/sunpm.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/sys/sunpm.h Mon Jul 20 13:07:46 2009 -0400 @@ -19,15 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SYS_SUNPM_H #define _SYS_SUNPM_H -#pragma ident "%Z%%M% %I% %E% SMI" - /* * Sun Specific Power Management definitions */ @@ -51,9 +49,10 @@ #ifdef _KERNEL /* - * Power cycle transition check is supported for these devices. + * Power cycle transition check is supported for SCSI and SATA devices. */ #define DC_SCSI_FORMAT 0x1 /* SCSI */ +#define DC_SMART_FORMAT 0x2 /* SMART */ #define DC_SCSI_MFR_LEN 6 /* YYYYWW */ @@ -64,10 +63,17 @@ int flag; /* reserved for future */ }; +struct pm_smart_count { + int allowed; /* normalized max cycles allowed */ + int consumed; /* normalized consumed cycles */ + int flag; /* type of cycles */ +}; + struct pm_trans_data { int format; /* data format */ union { struct pm_scsi_cycles scsi_cycles; + struct pm_smart_count smart_count; } un; };
--- a/usr/src/uts/common/syscall/pset.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/syscall/pset.c Mon Jul 20 13:07:46 2009 -0400 @@ -470,6 +470,66 @@ return (error); } +/* + * Bind the lwp:id of process:pid to processor set: pset + */ +static int +pset_bind_lwp(psetid_t pset, id_t id, pid_t pid, psetid_t *opset) +{ + kthread_t *tp; + proc_t *pp; + psetid_t oldpset; + void *projbuf, *zonebuf; + int error = 0; + + pool_lock(); + mutex_enter(&cpu_lock); + projbuf = fss_allocbuf(FSS_NPROJ_BUF, FSS_ALLOC_PROJ); + zonebuf = fss_allocbuf(FSS_NPROJ_BUF, FSS_ALLOC_ZONE); + + mutex_enter(&pidlock); + if ((pid == P_MYID && id == P_MYID) || + (pid == curproc->p_pid && id == P_MYID)) { + pp = curproc; + tp = curthread; + mutex_enter(&pp->p_lock); + } else { + if (pid == P_MYID) { + pp = curproc; + } else if ((pp = prfind(pid)) == NULL) { + error = ESRCH; + goto err; + } + if (pp != curproc && id == P_MYID) { + error = EINVAL; + goto err; + } + mutex_enter(&pp->p_lock); + if ((tp = idtot(pp, id)) == NULL) { + mutex_exit(&pp->p_lock); + error = ESRCH; + goto err; + } + } + + error = pset_bind_thread(tp, pset, &oldpset, projbuf, zonebuf); + mutex_exit(&pp->p_lock); +err: + mutex_exit(&pidlock); + + fss_freebuf(projbuf, FSS_ALLOC_PROJ); + fss_freebuf(zonebuf, FSS_ALLOC_ZONE); + mutex_exit(&cpu_lock); + pool_unlock(); + if (opset != NULL) { + if (copyout(&oldpset, opset, sizeof (psetid_t)) != 0) + return (set_errno(EFAULT)); + } + if (error != 0) + return (set_errno(error)); + return (0); +} + static int pset_bind(psetid_t pset, idtype_t idtype, id_t id, psetid_t *opset) { @@ -797,6 +857,9 @@ case PSET_BIND: return (pset_bind((psetid_t)arg1, (idtype_t)arg2, (id_t)arg3, (psetid_t *)arg4)); + case PSET_BIND_LWP: + return (pset_bind_lwp((psetid_t)arg1, (id_t)arg2, + (pid_t)arg3, (psetid_t *)arg4)); case PSET_GETLOADAVG: return (pset_getloadavg((psetid_t)arg1, (int *)arg2, (int)arg3));
--- a/usr/src/uts/common/vm/page.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/vm/page.h Mon Jul 20 13:07:46 2009 -0400 @@ -1126,6 +1126,8 @@ /* msegflags */ #define MEMSEG_DYNAMIC 0x1 /* DR: memory was added dynamically */ +#define MEMSEG_META_INCL 0x2 /* DR: memseg includes it's metadata */ +#define MEMSEG_META_ALLOC 0x4 /* DR: memseg allocated it's metadata */ /* memseg support macros */ #define MSEG_NPAGES(SEG) ((SEG)->pages_end - (SEG)->pages_base)
--- a/usr/src/uts/common/vm/vm_page.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/vm/vm_page.c Mon Jul 20 13:07:46 2009 -0400 @@ -1116,8 +1116,11 @@ VM_STAT_ADD(page_exphcontg[4]); return (1); } + /* + * Also check whether p_pagenum was modified by DR. + */ if (pp->p_szc != pszc || pp->p_vnode != vp || - pp->p_offset != off) { + pp->p_offset != off || pp->p_pagenum != pfn) { VM_STAT_ADD(page_exphcontg[5]); page_unlock(pp); off = save_off; @@ -1204,11 +1207,17 @@ */ for (i = 0; i < pages; i++, pp++, off += PAGESIZE, pfn++) { - ASSERT(pp->p_pagenum == pfn); if (!page_trylock(pp, SE_EXCL)) { VM_STAT_ADD(page_exphcontg[12]); break; } + /* + * Check whether p_pagenum was modified by DR. + */ + if (pp->p_pagenum != pfn) { + page_unlock(pp); + break; + } if (pp->p_vnode != vp || pp->p_offset != off) { VM_STAT_ADD(page_exphcontg[13]); @@ -5835,6 +5844,10 @@ * another cpu and trying to reference it after it has been freed. * This will keep us on cpu and prevent it from being removed while * we are still on it. + * + * We may be caching a memseg in vc_pnum_memseg/vc_pnext_memseg + * which is being resued by DR who will flush those references + * before modifying the reused memseg. See memseg_cpu_vm_flush(). */ kpreempt_disable(); vc = CPU->cpu_vm_data; @@ -5870,8 +5883,10 @@ if (pfnum >= seg->pages_base && pfnum < seg->pages_end) { vc->vc_pnum_memseg = seg; pp = seg->pages + (pfnum - seg->pages_base); - kpreempt_enable(); - return ((page_t *)pp); + if (pp->p_pagenum == pfnum) { + kpreempt_enable(); + return ((page_t *)pp); + } } } vc->vc_pnum_memseg = NULL; @@ -5887,20 +5902,33 @@ struct memseg *seg; page_t *pp; + /* + * We may be caching a memseg in vc_pnum_memseg/vc_pnext_memseg + * which is being resued by DR who will flush those references + * before modifying the reused memseg. See memseg_cpu_vm_flush(). + */ + kpreempt_disable(); /* Try hash */ if (((seg = memseg_hash[MEMSEG_PFN_HASH(pfnum)]) != NULL) && (pfnum >= seg->pages_base) && (pfnum < seg->pages_end)) { pp = seg->pages + (pfnum - seg->pages_base); - if (pp->p_pagenum == pfnum) + if (pp->p_pagenum == pfnum) { + kpreempt_enable(); return (seg); + } } /* Else Brute force */ for (seg = memsegs; seg != NULL; seg = seg->next) { if (pfnum >= seg->pages_base && pfnum < seg->pages_end) { - return (seg); - } - } + pp = seg->pages + (pfnum - seg->pages_base); + if (pp->p_pagenum == pfnum) { + kpreempt_enable(); + return (seg); + } + } + } + kpreempt_enable(); return ((struct memseg *)NULL); } @@ -5925,6 +5953,10 @@ * another cpu and trying to reference it after it has been freed. * This will keep us on cpu and prevent it from being removed while * we are still on it. + * + * We may be caching a memseg in vc_pnum_memseg/vc_pnext_memseg + * which is being resued by DR who will flush those references + * before modifying the reused memseg. See memseg_cpu_vm_flush(). */ kpreempt_disable(); vc = (vm_cpu_data_t *)CPU->cpu_vm_data; @@ -6008,12 +6040,12 @@ * Catch if we went past the end of the current memory segment. If so, * just move to the next segment with pages. */ - if (new_pp >= seg->epages) { + if (new_pp >= seg->epages || seg->pages_base == seg->pages_end) { do { seg = seg->next; if (seg == NULL) seg = memsegs; - } while (seg->pages == seg->epages); + } while (seg->pages_base == seg->pages_end); new_pp = seg->pages; *cookie = (void *)seg; }
--- a/usr/src/uts/common/vm/vm_pagelist.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/vm/vm_pagelist.c Mon Jul 20 13:07:46 2009 -0400 @@ -954,6 +954,7 @@ int cands_cache_nranges; int old_maxmrange, new_maxmrange; int rc = 0; + int oldmnode; cands_cache = kmem_zalloc(sizeof (pcc_info_t *) * NPC_MUTEX * MMU_PAGE_SIZES, KM_NOSLEEP); @@ -1048,6 +1049,21 @@ */ PAGE_CTRS_WRITE_LOCK(mnode); + /* + * For interleaved mnodes, find the first mnode + * with valid page counters since the current + * mnode may have just been added and not have + * valid page counters. + */ + if (interleaved_mnodes) { + for (i = 0; i < max_mem_nodes; i++) + if (PAGE_COUNTERS_COUNTERS(i, 1) != NULL) + break; + ASSERT(i < max_mem_nodes); + oldmnode = i; + } else + oldmnode = mnode; + old_nranges = mnode_nranges[mnode]; cands_cache_nranges = old_nranges; mnode_nranges[mnode] = nranges; @@ -1057,10 +1073,10 @@ for (r = 1; r < mmu_page_sizes; r++) { PAGE_COUNTERS_SHIFT(mnode, r) = PAGE_BSZS_SHIFT(r); - old_ctr = PAGE_COUNTERS_COUNTERS(mnode, r); - old_csz = PAGE_COUNTERS_ENTRIES(mnode, r); - oldbase = PAGE_COUNTERS_BASE(mnode, r); - old_npgs = old_csz << PAGE_COUNTERS_SHIFT(mnode, r); + old_ctr = PAGE_COUNTERS_COUNTERS(oldmnode, r); + old_csz = PAGE_COUNTERS_ENTRIES(oldmnode, r); + oldbase = PAGE_COUNTERS_BASE(oldmnode, r); + old_npgs = old_csz << PAGE_COUNTERS_SHIFT(oldmnode, r); for (mrange = 0; mrange < MAX_MNODE_MRANGES; mrange++) { old_color_array[mrange] = PAGE_COUNTERS_CURRENT_COLOR_ARRAY(mnode, @@ -1102,9 +1118,11 @@ for (i = 0; i < max_mem_nodes; i++) { if (i == mnode) continue; + ASSERT( + PAGE_COUNTERS_COUNTERS(i, r) == old_ctr || + PAGE_COUNTERS_COUNTERS(i, r) == NULL); if (mem_node_config[i].exists == 0) continue; - ASSERT(PAGE_COUNTERS_COUNTERS(i, r) == old_ctr); PAGE_COUNTERS_COUNTERS(i, r) = new_ctr; PAGE_COUNTERS_ENTRIES(i, r) = pcsz; PAGE_COUNTERS_BASE(i, r) = newbase; @@ -1126,13 +1144,14 @@ int mhi = interleaved_mnodes ? max_mem_nodes : (mnode + 1); int m; - pfn_t pfnum = newbase; + pfn_t pfnum; size_t idx; MEM_NODE_ITERATOR_DECL(it); for (m = mlo; m < mhi; m++) { if (mem_node_config[m].exists == 0) continue; + pfnum = newbase; MEM_NODE_ITERATOR_INIT(pfnum, m, r, &it); if (pfnum == (pfn_t)-1) { idx = 0; @@ -1143,8 +1162,10 @@ idx = (idx < pcsz) ? idx : 0; } for (mrange = 0; mrange < nranges; mrange++) { - PAGE_COUNTERS_CURRENT_COLOR(m, - r, i, mrange) = idx; + if (PAGE_COUNTERS_CURRENT_COLOR_ARRAY(m, + r, mrange) != NULL) + PAGE_COUNTERS_CURRENT_COLOR(m, + r, i, mrange) = idx; } } } @@ -2251,13 +2272,8 @@ /* get pfn range for mtype */ len = PAGE_COUNTERS_ENTRIES(mnode, r); -#if defined(__sparc) - lo = PAGE_COUNTERS_BASE(mnode, r); - hi = IDX_TO_PNUM(mnode, r, len); -#else MNODETYPE_2_PFN(mnode, mtype, lo, hi); hi++; -#endif /* use lower limit if given */ if (pfnhi != PFNNULL && pfnhi < hi)
--- a/usr/src/uts/common/vm/vm_usage.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/common/vm/vm_usage.c Mon Jul 20 13:07:46 2009 -0400 @@ -20,7 +20,7 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -111,11 +111,11 @@ * - visited page ranges for each collective. * - per vnode (entity->vme_vnode_hash) * - per shared amp (entity->vme_amp_hash) - * For accurate counting of map-shared and cow-shared pages. + * For accurate counting of map-shared and COW-shared pages. * * - visited private anons (refcnt > 1) for each collective. * (entity->vme_anon_hash) - * For accurate counting of cow-shared pages. + * For accurate counting of COW-shared pages. * * The common accounting structure is the vmu_entity_t, which represents * collectives: @@ -152,6 +152,7 @@ #include <sys/vm_usage.h> #include <sys/zone.h> #include <sys/sunddi.h> +#include <sys/avl.h> #include <vm/anon.h> #include <vm/as.h> #include <vm/seg_vn.h> @@ -167,13 +168,19 @@ #define VMUSAGE_BOUND_INCORE 1 #define VMUSAGE_BOUND_NOT_INCORE 2 +#define ISWITHIN(node, addr) ((node)->vmb_start <= addr && \ + (node)->vmb_end >= addr ? 1 : 0) + /* * bounds for vnodes and shared amps * Each bound is either entirely incore, entirely not in core, or - * entirely unknown. bounds are stored in order by offset. + * entirely unknown. bounds are stored in an avl tree sorted by start member + * when in use, otherwise (free or temporary lists) they're strung + * together off of vmb_next. */ typedef struct vmu_bound { - struct vmu_bound *vmb_next; + avl_node_t vmb_node; + struct vmu_bound *vmb_next; /* NULL in tree else on free or temp list */ pgcnt_t vmb_start; /* page offset in vnode/amp on which bound starts */ pgcnt_t vmb_end; /* page offset in vnode/amp on which bound ends */ char vmb_type; /* One of VMUSAGE_BOUND_* */ @@ -188,7 +195,7 @@ struct vmu_object *vmo_next; /* free list */ caddr_t vmo_key; short vmo_type; - vmu_bound_t *vmo_bounds; + avl_tree_t vmo_bounds; } vmu_object_t; /* @@ -214,7 +221,7 @@ struct vmu_entity *vme_next_calc; mod_hash_t *vme_vnode_hash; /* vnodes visited for entity */ mod_hash_t *vme_amp_hash; /* shared amps visited for entity */ - mod_hash_t *vme_anon_hash; /* cow anons visited for entity */ + mod_hash_t *vme_anon_hash; /* COW anons visited for entity */ vmusage_t vme_result; /* identifies entity and results */ } vmu_entity_t; @@ -298,12 +305,34 @@ static kmem_cache_t *vmu_object_cache; /* - * Save a bound on the free list + * Comparison routine for AVL tree. We base our comparison on vmb_start. + */ +static int +bounds_cmp(const void *bnd1, const void *bnd2) +{ + const vmu_bound_t *bound1 = bnd1; + const vmu_bound_t *bound2 = bnd2; + + if (bound1->vmb_start == bound2->vmb_start) { + return (0); + } + if (bound1->vmb_start < bound2->vmb_start) { + return (-1); + } + + return (1); +} + +/* + * Save a bound on the free list. */ static void vmu_free_bound(vmu_bound_t *bound) { bound->vmb_next = vmu_data.vmu_free_bounds; + bound->vmb_start = 0; + bound->vmb_end = 0; + bound->vmb_type = 0; vmu_data.vmu_free_bounds = bound; } @@ -314,14 +343,15 @@ vmu_free_object(mod_hash_val_t val) { vmu_object_t *obj = (vmu_object_t *)val; - vmu_bound_t *bound = obj->vmo_bounds; - vmu_bound_t *tmp; + avl_tree_t *tree = &(obj->vmo_bounds); + vmu_bound_t *bound; + void *cookie = NULL; - while (bound != NULL) { - tmp = bound; - bound = bound->vmb_next; - vmu_free_bound(tmp); - } + while ((bound = avl_destroy_nodes(tree, &cookie)) != NULL) + vmu_free_bound(bound); + avl_destroy(tree); + + obj->vmo_type = 0; obj->vmo_next = vmu_data.vmu_free_objects; vmu_data.vmu_free_objects = obj; } @@ -530,9 +560,10 @@ object = kmem_cache_alloc(vmu_object_cache, KM_SLEEP); } + object->vmo_next = NULL; object->vmo_key = key; object->vmo_type = type; - object->vmo_bounds = NULL; + avl_create(&(object->vmo_bounds), bounds_cmp, sizeof (vmu_bound_t), 0); return (object); } @@ -549,11 +580,14 @@ bound = vmu_data.vmu_free_bounds; vmu_data.vmu_free_bounds = vmu_data.vmu_free_bounds->vmb_next; - bzero(bound, sizeof (vmu_bound_t)); } else { bound = kmem_cache_alloc(vmu_bound_cache, KM_SLEEP); - bzero(bound, sizeof (vmu_bound_t)); } + + bound->vmb_next = NULL; + bound->vmb_start = 0; + bound->vmb_end = 0; + bound->vmb_type = 0; return (bound); } @@ -630,120 +664,117 @@ vmu_insert_lookup_object_bounds(vmu_object_t *ro, pgcnt_t start, pgcnt_t end, char type, vmu_bound_t **first, vmu_bound_t **last) { - vmu_bound_t *next; - vmu_bound_t *prev = NULL; - vmu_bound_t *tmp = NULL; - pgcnt_t ret = 0; + avl_tree_t *tree = &(ro->vmo_bounds); + avl_index_t where; + vmu_bound_t *walker, *tmp; + pgcnt_t ret = 0; + + ASSERT(start <= end); *first = *last = NULL; - for (next = ro->vmo_bounds; next != NULL; next = next->vmb_next) { - /* - * Find bounds overlapping or overlapped by range [start,end]. - */ - if (start > next->vmb_end) { - /* bound is before new bound */ - prev = next; - continue; + tmp = vmu_alloc_bound(); + tmp->vmb_start = start; + tmp->vmb_type = type; + + /* Hopelessly optimistic case. */ + if (walker = avl_find(tree, tmp, &where)) { + /* We got lucky. */ + vmu_free_bound(tmp); + *first = walker; + } + + if (walker == NULL) { + /* Is start in the previous node? */ + walker = avl_nearest(tree, where, AVL_BEFORE); + if (walker != NULL) { + if (ISWITHIN(walker, start)) { + /* We found start. */ + vmu_free_bound(tmp); + *first = walker; + } } - if (next->vmb_start > end) { - /* bound is after new bound */ - break; - } - if (*first == NULL) - *first = next; - *last = next; } + /* + * At this point, if *first is still NULL, then we + * didn't get a direct hit and start isn't covered + * by the previous node. We know that the next node + * must have a greater start value than we require + * because avl_find tells us where the AVL routines would + * insert our new node. We have some gap between the + * start we want and the next node. + */ if (*first == NULL) { - ASSERT(*last == NULL); - /* - * No bounds overlapping range [start,end], so create new - * bound - */ - tmp = vmu_alloc_bound(); - tmp->vmb_start = start; - tmp->vmb_end = end; - tmp->vmb_type = type; - if (prev == NULL) { - tmp->vmb_next = ro->vmo_bounds; - ro->vmo_bounds = tmp; + walker = avl_nearest(tree, where, AVL_AFTER); + if (walker != NULL && walker->vmb_start <= end) { + /* Fill the gap. */ + tmp->vmb_end = walker->vmb_start - 1; + *first = tmp; } else { - tmp->vmb_next = prev->vmb_next; - prev->vmb_next = tmp; + /* We have a gap over [start, end]. */ + tmp->vmb_end = end; + *first = *last = tmp; } - *first = tmp; - *last = tmp; - ASSERT(tmp->vmb_end >= tmp->vmb_start); - ret = tmp->vmb_end - tmp->vmb_start + 1; + ret += tmp->vmb_end - tmp->vmb_start + 1; + avl_insert(tree, tmp, where); + } + + ASSERT(*first != NULL); + + if (*last != NULL) { + /* We're done. */ return (ret); } - /* Check to see if start is before first known bound */ - ASSERT(first != NULL && last != NULL); - next = (*first); - if (start < (*first)->vmb_start) { - /* Create new bound before first bound */ - tmp = vmu_alloc_bound(); - tmp->vmb_start = start; - tmp->vmb_end = (*first)->vmb_start - 1; - tmp->vmb_type = type; - tmp->vmb_next = *first; - if (*first == ro->vmo_bounds) - ro->vmo_bounds = tmp; - if (prev != NULL) - prev->vmb_next = tmp; - ASSERT(tmp->vmb_end >= tmp->vmb_start); - ret += tmp->vmb_end - tmp->vmb_start + 1; - *first = tmp; - } /* - * Between start and end, search for gaps between and after existing - * bounds. Create new bounds to fill gaps if they exist. + * If we are here we still need to set *last and + * that may involve filling in some gaps. */ - while (end > next->vmb_end) { - /* - * Check for gap between bound and next bound. if no gap, - * continue. - */ - if ((next != *last) && - ((next->vmb_end + 1) == next->vmb_next->vmb_start)) { - next = next->vmb_next; - continue; + *last = *first; + for (;;) { + if (ISWITHIN(*last, end)) { + /* We're done. */ + break; } - /* - * Insert new bound in gap after bound, and before next - * bound if next bound exists. - */ - tmp = vmu_alloc_bound(); - tmp->vmb_type = type; - tmp->vmb_next = next->vmb_next; - tmp->vmb_start = next->vmb_end + 1; - - if (next != *last) { - tmp->vmb_end = next->vmb_next->vmb_start - 1; - ASSERT(tmp->vmb_end >= tmp->vmb_start); + walker = AVL_NEXT(tree, *last); + if (walker == NULL || walker->vmb_start > end) { + /* Bottom or mid tree with gap. */ + tmp = vmu_alloc_bound(); + tmp->vmb_start = (*last)->vmb_end + 1; + tmp->vmb_end = end; ret += tmp->vmb_end - tmp->vmb_start + 1; - next->vmb_next = tmp; - next = tmp->vmb_next; - } else { - tmp->vmb_end = end; - ASSERT(tmp->vmb_end >= tmp->vmb_start); - ret += tmp->vmb_end - tmp->vmb_start + 1; - next->vmb_next = tmp; + avl_insert_here(tree, tmp, *last, AVL_AFTER); *last = tmp; break; + } else { + if ((*last)->vmb_end + 1 != walker->vmb_start) { + /* Non-contiguous. */ + tmp = vmu_alloc_bound(); + tmp->vmb_start = (*last)->vmb_end + 1; + tmp->vmb_end = walker->vmb_start - 1; + ret += tmp->vmb_end - tmp->vmb_start + 1; + avl_insert_here(tree, tmp, *last, AVL_AFTER); + *last = tmp; + } else { + *last = walker; + } } } + return (ret); } /* * vmu_update_bounds() * + * tree: avl_tree in which first and last hang. + * * first, last: list of continuous bounds, of which zero or more are of * type VMUSAGE_BOUND_UNKNOWN. * + * new_tree: avl_tree in which new_first and new_last hang. + * * new_first, new_last: list of continuous bounds, of which none are of * type VMUSAGE_BOUND_UNKNOWN. These bounds are used to * update the types of bounds in (first,last) with @@ -763,8 +794,8 @@ * */ static pgcnt_t -vmu_update_bounds(vmu_bound_t **first, vmu_bound_t **last, - vmu_bound_t *new_first, vmu_bound_t *new_last) +vmu_update_bounds(avl_tree_t *tree, vmu_bound_t **first, vmu_bound_t **last, + avl_tree_t *new_tree, vmu_bound_t *new_first, vmu_bound_t *new_last) { vmu_bound_t *next, *new_next, *tmp; pgcnt_t rss = 0; @@ -777,19 +808,19 @@ * have unknown type. */ ASSERT((*first)->vmb_type != VMUSAGE_BOUND_UNKNOWN || - (*first)->vmb_start >= new_next->vmb_start); + (*first)->vmb_start >= new_first->vmb_start); ASSERT((*last)->vmb_type != VMUSAGE_BOUND_UNKNOWN || (*last)->vmb_end <= new_last->vmb_end); for (;;) { - /* If bound already has type, proceed to next bound */ + /* If bound already has type, proceed to next bound. */ if (next->vmb_type != VMUSAGE_BOUND_UNKNOWN) { if (next == *last) break; - next = next->vmb_next; + next = AVL_NEXT(tree, next); continue; } while (new_next->vmb_end < next->vmb_start) - new_next = new_next->vmb_next; + new_next = AVL_NEXT(new_tree, new_next); ASSERT(new_next->vmb_type != VMUSAGE_BOUND_UNKNOWN); next->vmb_type = new_next->vmb_type; if (new_next->vmb_end < next->vmb_end) { @@ -798,9 +829,8 @@ tmp->vmb_type = VMUSAGE_BOUND_UNKNOWN; tmp->vmb_start = new_next->vmb_end + 1; tmp->vmb_end = next->vmb_end; - tmp->vmb_next = next->vmb_next; + avl_insert_here(tree, tmp, next, AVL_AFTER); next->vmb_end = new_next->vmb_end; - next->vmb_next = tmp; if (*last == next) *last = tmp; if (next->vmb_type == VMUSAGE_BOUND_INCORE) @@ -811,41 +841,40 @@ rss += next->vmb_end - next->vmb_start + 1; if (next == *last) break; - next = next->vmb_next; + next = AVL_NEXT(tree, next); } } return (rss); } /* - * merges adjacent bounds with same type between first and last bound. + * Merges adjacent bounds with same type between first and last bound. * After merge, last pointer is no longer valid, as last bound may be * merged away. */ static void -vmu_merge_bounds(vmu_bound_t **first, vmu_bound_t **last) +vmu_merge_bounds(avl_tree_t *tree, vmu_bound_t **first, vmu_bound_t **last) { + vmu_bound_t *current; vmu_bound_t *next; - vmu_bound_t *tmp; + ASSERT(tree != NULL); ASSERT(*first != NULL); ASSERT(*last != NULL); - next = *first; - while (next != *last) { - - /* If bounds are adjacent and have same type, merge them */ - if (((next->vmb_end + 1) == next->vmb_next->vmb_start) && - (next->vmb_type == next->vmb_next->vmb_type)) { - tmp = next->vmb_next; - next->vmb_end = tmp->vmb_end; - next->vmb_next = tmp->vmb_next; - vmu_free_bound(tmp); - if (tmp == *last) - *last = next; - } else { - next = next->vmb_next; + current = *first; + while (current != *last) { + next = AVL_NEXT(tree, current); + if ((current->vmb_end + 1) == next->vmb_start && + current->vmb_type == next->vmb_type) { + current->vmb_end = next->vmb_end; + avl_remove(tree, next); + vmu_free_bound(next); + if (next == *last) { + break; + } } + current = AVL_NEXT(tree, current); } } @@ -855,14 +884,14 @@ * * If a bound is partially incore, it will be split into two bounds. * first and last may be modified, as bounds may be split into multiple - * bounds if the are partially incore/not-incore. + * bounds if they are partially incore/not-incore. * - * Set incore to non-zero if bounds are already known to be incore + * Set incore to non-zero if bounds are already known to be incore. * */ static void -vmu_amp_update_incore_bounds(struct anon_map *amp, vmu_bound_t **first, - vmu_bound_t **last, boolean_t incore) +vmu_amp_update_incore_bounds(avl_tree_t *tree, struct anon_map *amp, + vmu_bound_t **first, vmu_bound_t **last, boolean_t incore) { vmu_bound_t *next; vmu_bound_t *tmp; @@ -874,7 +903,7 @@ struct anon *ap; next = *first; - /* Shared anon slots don't change once set */ + /* Shared anon slots don't change once set. */ ANON_LOCK_ENTER(&->a_rwlock, RW_READER); for (;;) { if (incore == B_TRUE) @@ -883,7 +912,7 @@ if (next->vmb_type != VMUSAGE_BOUND_UNKNOWN) { if (next == *last) break; - next = next->vmb_next; + next = AVL_NEXT(tree, next); continue; } bound_type = next->vmb_type; @@ -919,16 +948,15 @@ next->vmb_type = page_type; } else if (next->vmb_type != page_type) { /* - * if current bound type does not match page + * If current bound type does not match page * type, need to split off new bound. */ tmp = vmu_alloc_bound(); tmp->vmb_type = page_type; tmp->vmb_start = index; tmp->vmb_end = next->vmb_end; - tmp->vmb_next = next->vmb_next; + avl_insert_here(tree, tmp, next, AVL_AFTER); next->vmb_end = index - 1; - next->vmb_next = tmp; if (*last == next) *last = tmp; next = tmp; @@ -947,7 +975,7 @@ ASSERT(next->vmb_type != VMUSAGE_BOUND_UNKNOWN); break; } else - next = next->vmb_next; + next = AVL_NEXT(tree, next); } ANON_LOCK_EXIT(&->a_rwlock); } @@ -957,8 +985,8 @@ * incore-/not-incore for vnodes. */ static void -vmu_vnode_update_incore_bounds(vnode_t *vnode, vmu_bound_t **first, - vmu_bound_t **last) +vmu_vnode_update_incore_bounds(avl_tree_t *tree, vnode_t *vnode, + vmu_bound_t **first, vmu_bound_t **last) { vmu_bound_t *next; vmu_bound_t *tmp; @@ -974,7 +1002,7 @@ if (next->vmb_type != VMUSAGE_BOUND_UNKNOWN) { if (next == *last) break; - next = next->vmb_next; + next = AVL_NEXT(tree, next); continue; } @@ -1007,16 +1035,15 @@ next->vmb_type = page_type; } else if (next->vmb_type != page_type) { /* - * if current bound type does not match page + * If current bound type does not match page * type, need to split off new bound. */ tmp = vmu_alloc_bound(); tmp->vmb_type = page_type; tmp->vmb_start = index; tmp->vmb_end = next->vmb_end; - tmp->vmb_next = next->vmb_next; + avl_insert_here(tree, tmp, next, AVL_AFTER); next->vmb_end = index - 1; - next->vmb_next = tmp; if (*last == next) *last = tmp; next = tmp; @@ -1035,15 +1062,15 @@ ASSERT(next->vmb_type != VMUSAGE_BOUND_UNKNOWN); break; } else - next = next->vmb_next; + next = AVL_NEXT(tree, next); } } /* * Calculate the rss and swap consumed by a segment. vmu_entities is the * list of entities to visit. For shared segments, the vnode or amp - * is looked up in each entity to see if has been already counted. Private - * anon pages are checked per entity to ensure that cow pages are not + * is looked up in each entity to see if it has been already counted. Private + * anon pages are checked per entity to ensure that COW pages are not * double counted. * * For private mapped files, first the amp is checked for private pages. @@ -1060,6 +1087,7 @@ vmu_object_t *entity_object = NULL; vmu_entity_t *entity; vmusage_t *result; + avl_tree_t *tree; vmu_bound_t *first = NULL; vmu_bound_t *last = NULL; vmu_bound_t *cur = NULL; @@ -1074,7 +1102,7 @@ pgcnt_t swresv = 0; pgcnt_t panon = 0; - /* Can zero-length segments exist? Not sure, so parenoia */ + /* Can zero-length segments exist? Not sure, so paranoia. */ if (seg->s_size <= 0) return; @@ -1085,11 +1113,31 @@ */ if (seg->s_ops == &segvn_ops) { svd = (struct segvn_data *)seg->s_data; - if (svd->type == MAP_SHARED) + if (svd->type == MAP_SHARED) { shared = B_TRUE; - else + } else { swresv = svd->swresv; + if (SEGVN_LOCK_TRYENTER(seg->s_as, &svd->lock, + RW_READER) != 0) { + /* + * Text replication anon maps can be shared + * across all zones. Space used for text + * replication is typically capped as a small % + * of memory. To keep it simple for now we + * don't account for swap and memory space used + * for text replication. + */ + if (svd->tr_state == SEGVN_TR_OFF && + svd->amp != NULL) { + private_amp = svd->amp; + p_start = svd->anon_index; + p_end = svd->anon_index + + btop(seg->s_size) - 1; + } + SEGVN_LOCK_EXIT(seg->s_as, &svd->lock); + } + } if (svd->vp != NULL) { file = 1; shared_object = vmu_find_insert_object( @@ -1109,20 +1157,6 @@ if (svd->amp->swresv == 0) incore = B_TRUE; } - SEGVN_LOCK_ENTER(seg->s_as, &svd->lock, RW_READER); - /* - * Text replication anon maps can be shared across all zones. - * Space used for text replication is typically capped as - * small % of memory. To keep it simple for now we don't - * account for swap and memory space used for text replication. - */ - if (svd->tr_state == SEGVN_TR_OFF && svd->amp != NULL && - svd->type == MAP_PRIVATE) { - private_amp = svd->amp; - p_start = svd->anon_index; - p_end = svd->anon_index + btop(seg->s_size) - 1; - } - SEGVN_LOCK_EXIT(seg->s_as, &svd->lock); } else if (seg->s_ops == &segspt_shmops) { shared = B_TRUE; shmd = (struct shm_data *)seg->s_data; @@ -1143,15 +1177,15 @@ /* * If there is a private amp, count anon pages that exist. If an - * anon has a refcnt > 1 (cow sharing), then save the anon in a + * anon has a refcnt > 1 (COW sharing), then save the anon in a * hash so that it is not double counted. * - * If there is also a shared object, they figure out the bounds + * If there is also a shared object, then figure out the bounds * which are not mapped by the private amp. */ if (private_amp != NULL) { - /* Enter as writer to prevent cow anons from being freed */ + /* Enter as writer to prevent COW anons from being freed */ ANON_LOCK_ENTER(&private_amp->a_rwlock, RW_WRITER); p_index = p_start; @@ -1185,7 +1219,7 @@ ap = NULL; } /* - * For cow segments, keep track of bounds not + * For COW segments, keep track of bounds not * backed by private amp so they can be looked * up in the backing vnode */ @@ -1199,7 +1233,6 @@ if (shared_object != NULL) { cur = vmu_alloc_bound(); - cur->vmb_next = NULL; cur->vmb_start = s_index; cur->vmb_end = s_index + p_bound_size; cur->vmb_type = VMUSAGE_BOUND_UNKNOWN; @@ -1270,7 +1303,7 @@ /* * Assume anon structs with a refcnt - * of 1 are not cow shared, so there + * of 1 are not COW shared, so there * is no reason to track them per entity. */ if (cnt == 1) { @@ -1282,7 +1315,7 @@ result = &entity->vme_result; /* - * Track cow anons per entity so + * Track COW anons per entity so * they are not double counted. */ if (vmu_find_insert_anon(entity->vme_anon_hash, @@ -1318,7 +1351,6 @@ * the shared object. */ first = vmu_alloc_bound(); - first->vmb_next = NULL; first->vmb_start = s_start; first->vmb_end = s_end; first->vmb_type = VMUSAGE_BOUND_UNKNOWN; @@ -1334,21 +1366,26 @@ cur->vmb_start, cur->vmb_end, VMUSAGE_BOUND_UNKNOWN, &first, &last) > 0) { /* new bounds, find incore/not-incore */ + tree = &(shared_object->vmo_bounds); if (shared_object->vmo_type == - VMUSAGE_TYPE_VNODE) + VMUSAGE_TYPE_VNODE) { vmu_vnode_update_incore_bounds( + tree, (vnode_t *) shared_object->vmo_key, &first, &last); - else + } else { vmu_amp_update_incore_bounds( + tree, (struct anon_map *) shared_object->vmo_key, &first, &last, incore); - vmu_merge_bounds(&first, &last); + } + vmu_merge_bounds(tree, &first, &last); } for (entity = vmu_entities; entity != NULL; entity = entity->vme_next_calc) { + avl_tree_t *e_tree; result = &entity->vme_result; @@ -1368,8 +1405,9 @@ /* * Range visited for this entity */ - rss = vmu_update_bounds(&e_first, - &e_last, first, last); + e_tree = &(entity_object->vmo_bounds); + rss = vmu_update_bounds(e_tree, &e_first, + &e_last, tree, first, last); result->vmu_rss_all += (rss << PAGESHIFT); if (shared == B_TRUE && file == B_FALSE) { /* shared anon mapping */ @@ -1389,7 +1427,7 @@ result->vmu_rss_private += (rss << PAGESHIFT); } - vmu_merge_bounds(&e_first, &e_last); + vmu_merge_bounds(e_tree, &e_first, &e_last); } tmp = cur; cur = cur->vmb_next;
--- a/usr/src/uts/i86pc/boot/boot_console.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/i86pc/boot/boot_console.c Mon Jul 20 13:07:46 2009 -0400 @@ -234,6 +234,7 @@ find_boot_line_prop(const char *name) { char *ptr; + char *ret = NULL; char end_char; size_t len; @@ -256,14 +257,14 @@ !ISSPACE(*ptr)) ptr++; if (*ptr == '\0') - return (NULL); + goto out; else if (*ptr != 'B') continue; } else { while ((*ptr != '\0') && !ISSPACE(*ptr)) ptr++; if (*ptr == '\0') - return (NULL); + goto out; continue; } @@ -274,10 +275,15 @@ if ((strncmp(ptr, name, len) == 0) && (ptr[len] == '=')) { ptr += len + 1; - if ((*ptr == '\'') || (*ptr == '"')) - return (ptr + 1); - else - return (ptr); + if ((*ptr == '\'') || (*ptr == '"')) { + ret = ptr + 1; + end_char = *ptr; + ptr++; + } else { + ret = ptr; + end_char = ','; + } + goto consume_property; } /* @@ -295,7 +301,7 @@ * name without a value, either continue or break. */ if (*ptr == '\0') - return (NULL); + goto out; else if (*ptr == ',') continue; else if (ISSPACE(*ptr)) @@ -307,6 +313,7 @@ */ if ((*ptr == '\'') || (*ptr == '"')) { end_char = *ptr; + ptr++; } else { /* * Not quoted, so the string ends at a comma @@ -320,15 +327,17 @@ * Now, we can ignore any characters until we find * end_char. */ +consume_property: for (; (*ptr != '\0') && (*ptr != end_char); ptr++) { if ((end_char == ',') && ISSPACE(*ptr)) break; } - if (*ptr && (*ptr != ',')) + if (*ptr && (*ptr != ',') && !ISSPACE(*ptr)) ptr++; } while (*ptr == ','); } - return (NULL); +out: + return (ret); } @@ -657,7 +666,7 @@ console_value_t *consolep; int i; - if (console != CONS_USBSER) { + if (console != CONS_USBSER && console != CONS_SCREEN_GRAPHICS) { if (console_set) { /* * If the console was set on the command line, @@ -705,13 +714,11 @@ serial_init(); return; } - } - - - /* - * USB serial -- we just collect data into a buffer - */ - if (console == CONS_USBSER || console == CONS_SCREEN_GRAPHICS) { + } else { + /* + * USB serial and GRAPHICS console + * we just collect data into a buffer + */ extern void *defcons_init(size_t); defcons_buf = defcons_cur = defcons_init(MMU_PAGESIZE); } @@ -748,7 +755,8 @@ static void defcons_putchar(int c) { - if (defcons_cur + 1 - defcons_buf < MMU_PAGESIZE) { + if (defcons_buf != NULL && + defcons_cur + 1 - defcons_buf < MMU_PAGESIZE) { *defcons_cur++ = c; *defcons_cur = 0; }
--- a/usr/src/uts/i86pc/i86hvm/io/hvm_bootstrap.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/i86pc/i86hvm/io/hvm_bootstrap.c Mon Jul 20 13:07:46 2009 -0400 @@ -20,12 +20,10 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/modctl.h> #include <sys/sunddi.h> #include <sys/sunndi.h> @@ -42,21 +40,29 @@ * these nodes (which usually happens when mounting the root disk device * in an hvm environment). See the block comments at the top of pv_cmdk.c * for more information about why this is necessary. + * + * hvmboot_rootconf() also force attaches xnf network driver nodes so + * that boot interface can be plumbed when booted via the network. */ int hvmboot_rootconf() { dev_info_t *xpvd_dip; - major_t xdf_major; + major_t dev_major; - xdf_major = ddi_name_to_major("xdf"); - if (xdf_major == (major_t)-1) + dev_major = ddi_name_to_major("xdf"); + if (dev_major == (major_t)-1) cmn_err(CE_PANIC, "unable to load xdf disk driver"); if (resolve_pathname("/xpvd", &xpvd_dip, NULL, NULL) != 0) cmn_err(CE_PANIC, "unable to configure /xpvd nexus"); - (void) ndi_devi_config_driver(xpvd_dip, 0, xdf_major); + (void) ndi_devi_config_driver(xpvd_dip, 0, dev_major); + + dev_major = ddi_name_to_major("xnf"); + if (dev_major == (major_t)-1) + cmn_err(CE_PANIC, "unable to load xnf network driver"); + (void) ndi_devi_config_driver(xpvd_dip, 0, dev_major); ndi_rele_devi(xpvd_dip); return (0);
--- a/usr/src/uts/i86pc/io/isa.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/i86pc/io/isa.c Mon Jul 20 13:07:46 2009 -0400 @@ -38,6 +38,7 @@ #include <sys/psm.h> #include <sys/ddidmareq.h> #include <sys/ddi_impldefs.h> +#include <sys/ddi_subrdefs.h> #include <sys/dma_engine.h> #include <sys/ddi.h> #include <sys/sunddi.h> @@ -57,10 +58,10 @@ psm_intr_op_t, int *); extern void pci_register_isa_resources(int, uint32_t, uint32_t); static char USED_RESOURCES[] = "used-resources"; -static void isa_alloc_nodes(dev_info_t *); +static void isa_enumerate(int); static void enumerate_BIOS_serial(dev_info_t *); static void adjust_prtsz(dev_info_t *isa_dip); -static void isa_postattach(dev_info_t *); +static void isa_create_ranges_prop(dev_info_t *); /* * The following typedef is used to represent an entry in the "ranges" @@ -228,13 +229,26 @@ int _init(void) { - return (mod_install(&modlinkage)); + int err; + + if ((err = mod_install(&modlinkage)) != 0) + return (err); + + impl_bus_add_probe(isa_enumerate); + return (0); } int _fini(void) { - return (mod_remove(&modlinkage)); + int err; + + impl_bus_delete_probe(isa_enumerate); + + if ((err = mod_remove(&modlinkage)) != 0) + return (err); + + return (0); } int @@ -268,19 +282,8 @@ return (DDI_FAILURE); } - bzero(isa_extra_resource, MAX_EXTRA_RESOURCE * sizeof (struct regspec)); - - if ((rval = i_dmae_init(devi)) == DDI_SUCCESS) { + if ((rval = i_dmae_init(devi)) == DDI_SUCCESS) ddi_report_dev(devi); - /* - * Enumerate children -- invoking ACPICA - * This is normally in bus_config(), but we need this - * to happen earlier to boot. - */ - isa_alloc_nodes(devi); - } - - isa_postattach(devi); return (rval); } @@ -329,7 +332,7 @@ } static void -isa_postattach(dev_info_t *dip) +isa_create_ranges_prop(dev_info_t *dip) { dev_info_t *used; int *ioarray, *memarray, status; @@ -1036,11 +1039,11 @@ } static void -isa_alloc_nodes(dev_info_t *isa_dip) +isa_enumerate(int reprogram) { - static int alloced = 0; int circ, i; dev_info_t *xdip; + dev_info_t *isa_dip = ddi_find_devinfo("isa", -1, 0); /* hard coded isa stuff */ struct regspec asy_regs[] = { @@ -1057,15 +1060,12 @@ char *acpi_prop; int acpi_enum = 1; /* ACPI is default to be on */ - if (alloced) + if (reprogram || !isa_dip) return; + bzero(isa_extra_resource, MAX_EXTRA_RESOURCE * sizeof (struct regspec)); + ndi_devi_enter(isa_dip, &circ); - if (alloced) { /* just in case we are multi-threaded */ - ndi_devi_exit(isa_dip, circ); - return; - } - alloced = 1; if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), DDI_PROP_DONTPASS, "acpi-enum", &acpi_prop) == DDI_PROP_SUCCESS) { @@ -1086,6 +1086,8 @@ /* adjust parallel port size */ adjust_prtsz(isa_dip); + + isa_create_ranges_prop(isa_dip); return; } cmn_err(CE_NOTE, "!Solaris did not detect ACPI BIOS"); @@ -1127,6 +1129,7 @@ ndi_devi_exit(isa_dip, circ); + isa_create_ranges_prop(isa_dip); } /*
--- a/usr/src/uts/i86pc/io/pcplusmp/apic.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/i86pc/io/pcplusmp/apic.c Mon Jul 20 13:07:46 2009 -0400 @@ -118,6 +118,7 @@ /* Now the ones for Dynamic Interrupt distribution */ int apic_enable_dynamic_migration = 0; +int apic_have_32bit_cr8 = 0; /* * These variables are frequently accessed in apic_intr_enter(), @@ -436,6 +437,9 @@ for (i = 0; i <= MAXIPL; i++) apic_cr8pri[i] = apic_ipltopri[i] >> APIC_IPL_SHIFT; CPU->cpu_pri_data = apic_cr8pri; +#else + if (cpuid_have_cr8access(CPU)) + apic_have_32bit_cr8 = 1; #endif /* __amd64 */ } @@ -953,8 +957,12 @@ setcr8((ulong_t)(apic_ipltopri[nipl] >> APIC_IPL_SHIFT)); #else - LOCAL_APIC_WRITE_REG(APIC_TASK_REG, - (uint32_t)apic_ipltopri[nipl]); + if (apic_have_32bit_cr8) + setcr8((ulong_t)(apic_ipltopri[nipl] >> + APIC_IPL_SHIFT)); + else + LOCAL_APIC_WRITE_REG(APIC_TASK_REG, + (uint32_t)apic_ipltopri[nipl]); #endif LOCAL_APIC_WRITE_REG(APIC_EOI_REG, 0); } else { @@ -995,8 +1003,12 @@ #if defined(__amd64) setcr8((ulong_t)(apic_ipltopri[nipl] >> APIC_IPL_SHIFT)); #else - LOCAL_APIC_WRITE_REG(APIC_TASK_REG, - (uint32_t)apic_ipltopri[nipl]); + if (apic_have_32bit_cr8) + setcr8((ulong_t)(apic_ipltopri[nipl] >> + APIC_IPL_SHIFT)); + else + LOCAL_APIC_WRITE_REG(APIC_TASK_REG, + (uint32_t)apic_ipltopri[nipl]); #endif } else { X2APIC_WRITE(APIC_TASK_REG, apic_ipltopri[nipl]); @@ -1059,7 +1071,10 @@ #if defined(__amd64) setcr8((ulong_t)apic_cr8pri[prev_ipl]); #else - apicadr[APIC_TASK_REG] = apic_ipltopri[prev_ipl]; + if (apic_have_32bit_cr8) + setcr8((ulong_t)(apic_ipltopri[prev_ipl] >> APIC_IPL_SHIFT)); + else + apicadr[APIC_TASK_REG] = apic_ipltopri[prev_ipl]; #endif APIC_INTR_EXIT(); @@ -1098,7 +1113,10 @@ #if defined(__amd64) setcr8((ulong_t)apic_cr8pri[ipl]); #else - apicadr[APIC_TASK_REG] = apic_ipltopri[ipl]; + if (apic_have_32bit_cr8) + setcr8((ulong_t)(apic_ipltopri[ipl] >> APIC_IPL_SHIFT)); + else + apicadr[APIC_TASK_REG] = apic_ipltopri[ipl]; #endif /* interrupts at ipl above this cannot be in progress */
--- a/usr/src/uts/i86pc/io/pcplusmp/apic_regops.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/i86pc/io/pcplusmp/apic_regops.c Mon Jul 20 13:07:46 2009 -0400 @@ -83,6 +83,7 @@ apic_send_EOI, }; +extern int apic_have_32bit_cr8; /* The default ops is local APIC (Memory Mapped IO) */ apic_reg_ops_t *apic_reg_ops = &local_apic_regs_ops; @@ -119,6 +120,8 @@ #if defined(__amd64) return ((int)getcr8()); #else + if (apic_have_32bit_cr8) + return ((int)getcr8()); return (apicadr[APIC_TASK_REG]); #endif } @@ -129,7 +132,10 @@ #if defined(__amd64) setcr8((ulong_t)(value >> APIC_IPL_SHIFT)); #else - apicadr[APIC_TASK_REG] = (uint32_t)value; + if (apic_have_32bit_cr8) + setcr8((ulong_t)(value >> APIC_IPL_SHIFT)); + else + apicadr[APIC_TASK_REG] = (uint32_t)value; #endif }
--- a/usr/src/uts/i86pc/io/ppm.conf Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/i86pc/io/ppm.conf Mon Jul 20 13:07:46 2009 -0400 @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -105,6 +105,7 @@ "Dell Inc.", "Latitude D630 ", "Dell Inc.", "Precision M4300 ", "Sun Microsystems", "Ultra 24", + "Sun Microsystems", "Ultra 27", "Sun Microsystems", "Sun Ultra 40 Workstation", "Sun Microsystems", "Sun Ultra 20 Workstation"; @@ -127,6 +128,7 @@ "Dell Inc.", "Latitude D630 ", "Dell Inc.", "Precision M4300 ", "Sun Microsystems", "Ultra 24", + "Sun Microsystems", "Ultra 27", "Sun Microsystems", "Sun Ultra 40 Workstation", "Sun Microsystems", "Sun Ultra 20 Workstation"; @@ -149,6 +151,7 @@ "Dell Inc.", "Latitude D630 ", "Dell Inc.", "Precision M4300 ", "Sun Microsystems", "Ultra 24", + "Sun Microsystems", "Ultra 27", "Sun Microsystems", "Sun Ultra 40 Workstation", "Sun Microsystems", "Sun Ultra 20 Workstation";
--- a/usr/src/uts/i86pc/os/cpuid.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/i86pc/os/cpuid.c Mon Jul 20 13:07:46 2009 -0400 @@ -364,6 +364,11 @@ break; case X86_VENDOR_AMD: switch (eax) { + + case 0x80000001: + cp->cp_ecx &= ~CPUID_AMD_ECX_CR8D; + break; + case 0x80000008: /* * Zero out the (ncores-per-chip - 1) field @@ -2535,6 +2540,24 @@ return (cpu->cpu_m.mcpu_cpi->cpi_clogid); } +/*ARGSUSED*/ +int +cpuid_have_cr8access(cpu_t *cpu) +{ +#if defined(__amd64) + return (1); +#else + struct cpuid_info *cpi; + + ASSERT(cpu != NULL); + cpi = cpu->cpu_m.mcpu_cpi; + if (cpi->cpi_vendor == X86_VENDOR_AMD && cpi->cpi_maxeax >= 1 && + (CPI_FEATURES_XTD_ECX(cpi) & CPUID_AMD_ECX_CR8D) != 0) + return (1); + return (0); +#endif +} + uint32_t cpuid_get_apicid(cpu_t *cpu) {
--- a/usr/src/uts/i86pc/os/ddi_impl.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/i86pc/os/ddi_impl.c Mon Jul 20 13:07:46 2009 -0400 @@ -200,6 +200,9 @@ check_driver_disable(); i_ddi_init_root(); + /* reprogram devices not set up by firmware (BIOS) */ + impl_bus_reprobe(); + /* * attach the isa nexus to get ACPI resource usage * isa is "kind of" a pseudo node @@ -218,8 +221,6 @@ (void) i_ddi_attach_hw_nodes("isa"); #endif - /* reprogram devices not set up by firmware (BIOS) */ - impl_bus_reprobe(); #endif /* !SAS && !MPSAS */ } @@ -2588,11 +2589,21 @@ impl_bus_add_probe(void (*func)(int)) { struct bus_probe *probe; + struct bus_probe *lastprobe = NULL; probe = kmem_alloc(sizeof (*probe), KM_SLEEP); - probe->next = bus_probes; probe->probe = func; - bus_probes = probe; + probe->next = NULL; + + if (!bus_probes) { + bus_probes = probe; + return; + } + + lastprobe = bus_probes; + while (lastprobe->next) + lastprobe = lastprobe->next; + lastprobe->next = probe; } /*ARGSUSED*/ @@ -2636,12 +2647,19 @@ if (modload("misc", "pci_autoconfig") < 0) { panic("failed to load misc/pci_autoconfig"); } + + if (modload("drv", "isa") < 0) + panic("failed to load drv/isa"); } + (void) modload("misc", "xpv_autoconfig"); #else if (modload("misc", "pci_autoconfig") < 0) { panic("failed to load misc/pci_autoconfig"); } + + if (modload("drv", "isa") < 0) + panic("failed to load drv/isa"); #endif probe = bus_probes;
--- a/usr/src/uts/i86pc/os/memnode.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/i86pc/os/memnode.c Mon Jul 20 13:07:46 2009 -0400 @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/systm.h> #include <sys/sysmacros.h> #include <sys/bootconf.h> @@ -85,9 +83,6 @@ end = roundup(end, btop(mem_node_physalign)) - 1; } - if (&plat_slice_add) - plat_slice_add(start, end); - mnode = PFN_2_MEM_NODE(start); ASSERT(mnode < max_mem_nodes); @@ -115,16 +110,6 @@ lgrp_config(LGRP_CONFIG_MEM_ADD, mnode, MEM_NODE_2_LGRPHAND(mnode)); } -/* ARGSUSED */ -void -mem_node_pre_del_slice(pfn_t start, pfn_t end) -{ - int mnode = PFN_2_MEM_NODE(start); - - ASSERT(mnode < max_mem_nodes); - ASSERT(mem_node_config[mnode].exists == 1); -} - /* * Remove a PFN range from a memnode. On some platforms, * the memnode will be created with physbase at the first @@ -133,7 +118,7 @@ * to assume physbase and up. */ void -mem_node_post_del_slice(pfn_t start, pfn_t end, int cancelled) +mem_node_del_slice(pfn_t start, pfn_t end) { int mnode; pgcnt_t delta_pgcnt, node_size; @@ -148,43 +133,56 @@ ASSERT(mnode < max_mem_nodes); ASSERT(mem_node_config[mnode].exists == 1); - if (!cancelled) { - delta_pgcnt = end - start; - node_size = mem_node_config[mnode].physmax - - mem_node_config[mnode].physbase; + delta_pgcnt = end - start; + node_size = mem_node_config[mnode].physmax - + mem_node_config[mnode].physbase; + + if (node_size > delta_pgcnt) { + /* + * Subtract the slice from the memnode. + */ + if (start <= mem_node_config[mnode].physbase) + mem_node_config[mnode].physbase = end + 1; + ASSERT(end <= mem_node_config[mnode].physmax); + if (end == mem_node_config[mnode].physmax) + mem_node_config[mnode].physmax = start - 1; + } else { + /* + * Let the common lgrp framework know this mnode is + * leaving + */ + lgrp_config(LGRP_CONFIG_MEM_DEL, + mnode, MEM_NODE_2_LGRPHAND(mnode)); - if (node_size > delta_pgcnt) { - /* - * Subtract the slice from the memnode. - */ - if (start <= mem_node_config[mnode].physbase) - mem_node_config[mnode].physbase = end + 1; - ASSERT(end <= mem_node_config[mnode].physmax); - if (end == mem_node_config[mnode].physmax) - mem_node_config[mnode].physmax = start - 1; - } else { - /* - * Let the common lgrp framework know this mnode is - * leaving - */ - lgrp_config(LGRP_CONFIG_MEM_DEL, - mnode, MEM_NODE_2_LGRPHAND(mnode)); + /* + * Delete the whole node. + */ + ASSERT(MNODE_PGCNT(mnode) == 0); + do { + omask = memnodes_mask; + nmask = omask & ~(1ull << mnode); + } while (cas64(&memnodes_mask, omask, nmask) != omask); + atomic_add_16(&num_memnodes, -1); + mem_node_config[mnode].exists = 0; + } +} - /* - * Delete the whole node. - */ - ASSERT(MNODE_PGCNT(mnode) == 0); - do { - omask = memnodes_mask; - nmask = omask & ~(1ull << mnode); - } while (cas64(&memnodes_mask, omask, nmask) != omask); - atomic_add_16(&num_memnodes, -1); - mem_node_config[mnode].exists = 0; - } +void +mem_node_add_range(pfn_t start, pfn_t end) +{ + if (&plat_slice_add) + plat_slice_add(start, end); + else + mem_node_add_slice(start, end); +} - if (&plat_slice_del) - plat_slice_del(start, end); - } +void +mem_node_del_range(pfn_t start, pfn_t end) +{ + if (&plat_slice_del) + plat_slice_del(start, end); + else + mem_node_del_slice(start, end); } void @@ -208,7 +206,7 @@ end = (list->address + list->size - 1) >> PAGESHIFT; if (end > physmax) end = physmax; - mem_node_add_slice(start, end); + mem_node_add_range(start, end); list = list->next; } mem_node_physalign = 0;
--- a/usr/src/uts/i86pc/sys/memnode.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/i86pc/sys/memnode.h Mon Jul 20 13:07:46 2009 -0400 @@ -19,15 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SYS_MEMNODE_H #define _SYS_MEMNODE_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -81,10 +79,11 @@ extern void startup_build_mem_nodes(struct memlist *); extern void mem_node_add_slice(pfn_t, pfn_t); -extern void mem_node_pre_del_slice(pfn_t, pfn_t); -extern void mem_node_post_del_slice(pfn_t, pfn_t, int); +extern void mem_node_del_slice(pfn_t, pfn_t); extern int mem_node_alloc(void); extern pgcnt_t mem_node_memlist_pages(int, struct memlist *); +extern void mem_node_add_range(pfn_t, pfn_t); +extern void mem_node_del_range(pfn_t, pfn_t); extern int plat_mnode_xcheck(pfn_t);
--- a/usr/src/uts/intel/Makefile.intel.shared Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/intel/Makefile.intel.shared Mon Jul 20 13:07:46 2009 -0400 @@ -334,6 +334,7 @@ DRV_KMODS += udp6 DRV_KMODS += ucode DRV_KMODS += ural +DRV_KMODS += uath DRV_KMODS += urtw DRV_KMODS += vgatext DRV_KMODS += heci @@ -631,6 +632,7 @@ MISC_KMODS += qlc_fw_6322 MISC_KMODS += qlc_fw_8100 MISC_KMODS += hwa1480_fw +MISC_KMODS += uathfw MISC_KMODS += uwba $(CLOSED_BUILD)CLOSED_MISC_KMODS += klmmod klmops @@ -710,11 +712,6 @@ MAC_KMODS += mac_ib # -# 'Devname' Modules (kernel/devname) -# -DEVNAME_KMODS += sdev_nsconfig_mod - -# # socketmod (kernel/socketmod) # SOCKET_KMODS += socksctp
--- a/usr/src/uts/intel/ia32/ml/i86_subr.s Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/intel/ia32/ml/i86_subr.s Mon Jul 20 13:07:46 2009 -0400 @@ -580,6 +580,24 @@ ret SET_SIZE(setcr0) + /* + * "lock mov %cr0" is used on processors which indicate it is + * supported via CPUID. Normally the 32 bit TPR is accessed via + * the local APIC. + */ + ENTRY(getcr8) + lock + movl %cr0, %eax + ret + SET_SIZE(getcr8) + + ENTRY(setcr8) + movl 4(%esp), %eax + lock + movl %eax, %cr0 + ret + SET_SIZE(setcr8) + ENTRY(getcr2) #if defined(__xpv) movl %gs:CPU_VCPU_INFO, %eax
--- a/usr/src/uts/intel/ia32/ml/modstubs.s Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/intel/ia32/ml/modstubs.s Mon Jul 20 13:07:46 2009 -0400 @@ -424,9 +424,7 @@ NO_UNLOAD_STUB(dev, sdev_modctl_readdir_free, nomod_minus_one); NO_UNLOAD_STUB(dev, devname_filename_register, nomod_minus_one); NO_UNLOAD_STUB(dev, sdev_modctl_devexists, nomod_minus_one); - NO_UNLOAD_STUB(dev, devname_nsmaps_register, nomod_minus_one); NO_UNLOAD_STUB(dev, devname_profile_update, nomod_minus_one); - NO_UNLOAD_STUB(dev, sdev_module_register, nomod_minus_one); NO_UNLOAD_STUB(dev, sdev_devstate_change, nomod_minus_one); NO_UNLOAD_STUB(dev, devvt_getvnodeops, nomod_minus_one); NO_UNLOAD_STUB(dev, devpts_getvnodeops, nomod_zero);
--- a/usr/src/uts/intel/os/minor_perm Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/intel/os/minor_perm Mon Jul 20 13:07:46 2009 -0400 @@ -144,6 +144,7 @@ clone:rwd 0666 root sys clone:rwn 0666 root sys clone:simnet 0666 root sys +clone:uath 0666 root sys clone:ural 0666 root sys clone:urtw 0666 root sys clone:wpi 0666 root sys @@ -177,6 +178,7 @@ rwd:* 0666 root sys rwn:* 0666 root sys simnet:* 0666 root sys +uath:* 0666 root sys ural:* 0666 root sys urtw:* 0666 root sys wpi:* 0666 root sys
--- a/usr/src/uts/intel/sdev_nsconfig_mod/Makefile Tue Jul 14 11:18:27 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (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 2006 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# uts/intel/sdev_nsconfig_mod/Makefile -# - -#pragma 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 = sdev_nsconfig_mod -OBJECTS = $(NSCONFIG_DEVNAME_OBJS:%=$(OBJS_DIR)/%) -LINTS = $(NSCONFIG_DEVNAME_OBJS:%.o=$(LINTS_DIR)/%.ln) -ROOTMODULE = $(ROOT_DEVNAME_DIR)/$(MODULE) - -# -# Include common rules. -# -include $(UTSBASE)/intel/Makefile.intel - -# -# Define targets -# -ALL_TARGET = $(BINARY) -LINT_TARGET = $(MODULE).lint -INSTALL_TARGET = $(BINARY) $(ROOTMODULE) - -# -# Override defaults to build a unique, local modstubs.o. -# -MODSTUBS_DIR = $(OBJS_DIR) -CLEANFILES += $(MODSTUBS_O) - -# -# depends on fs/dev module -# -LDFLAGS += -dy -Nfs/dev - -# -# 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 -
--- a/usr/src/uts/intel/sys/archsystm.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/intel/sys/archsystm.h Mon Jul 20 13:07:46 2009 -0400 @@ -45,6 +45,8 @@ extern ulong_t getcr0(void); extern void setcr0(ulong_t); +extern ulong_t getcr8(void); +extern void setcr8(ulong_t); extern ulong_t getcr2(void); extern void iommu_cpu_nop(void); extern void clflush_insn(caddr_t addr);
--- a/usr/src/uts/intel/sys/x86_archext.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/intel/sys/x86_archext.h Mon Jul 20 13:07:46 2009 -0400 @@ -629,6 +629,8 @@ extern uint32_t cpuid_getsockettype(struct cpu *); extern const char *cpuid_getsocketstr(struct cpu *); +extern int cpuid_have_cr8access(struct cpu *); + extern int cpuid_opteron_erratum(struct cpu *, uint_t); struct cpuid_info;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/intel/uath/Makefile Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,97 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This makefile drives the production of the uath driver kernel module. +# +# i86pc architecture dependent +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = uath +OBJECTS = $(UATH_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(UATH_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/intel/Makefile.intel + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +# +# Driver depends on GLDv3 & wifi kernel support module. +# +LDFLAGS += -dy -Nmisc/mac -Nmisc/net80211 -Nmisc/usba + +# +# Overrides +# +LINTTAGS += -erroff=E_BAD_PTR_CAST_ALIGN + +# +# 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 + +# +# If you have any special case that general +# Makefile rules don't serve for you, just do +# it yourself. +#
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/intel/uathfw/Makefile Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,112 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# +# This makefile drives the production of the hwa1480_fw kernel module. +# +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = uathfw +OBJECTS = $(UATHFW_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(UATHFW_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_MISC_DIR)/$(MODULE) + +FWOBJ = $(OBJS_DIR)/$(MODULE).o + +OBJECTS += $(FWOBJ) + +# +# Include common rules. +# +include $(UTSBASE)/intel/Makefile.intel + +LDFLAGS = +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +# +# For now, disable these lint checks; maintainers should endeavor +# to investigate and remove these for maximum lint coverage. +# Please do not carry these forward to new Makefiles. +# +LINTTAGS += -erroff=E_BAD_PTR_CAST_ALIGN +LINTTAGS += -erroff=E_PTRDIFF_OVERFLOW +LINTTAGS += -erroff=E_ASSIGN_NARROW_CONV +LINTTAGS += -erroff=E_STATIC_UNUSED + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) $(FWOBJ) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + $(RM) $(BINDEST)/$(BINCOPY) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + + +# customized section for transforming firmware binary +ELFWRAP = elfwrap +BINSRC = $(UTSBASE)/common/io/uath/uath_fw +BINDEST = $(UTSBASE)/intel/uathfw +BINCOPY = uathbin +ORIGIN_SRC = uathfw.bin + +#get build type, 32/64 +WRAPTYPE = $(CLASS:%=-%) + +#set elfwrap option +WRAPOPT = $(WRAPTYPE:-32=) + +$(FWOBJ): + cp $(BINSRC)/$(ORIGIN_SRC) $(BINDEST)/$(BINCOPY) + $(ELFWRAP) $(WRAPOPT) -o $@ $(BINDEST)/$(BINCOPY) + +# +# Include common targets. +# +include $(UTSBASE)/intel/Makefile.targ +
--- a/usr/src/uts/sparc/Makefile.sparc.shared Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/sparc/Makefile.sparc.shared Mon Jul 20 13:07:46 2009 -0400 @@ -493,11 +493,6 @@ MAC_KMODS += mac_ib # -# 'Devname' Modules (kernel/devname) -# -DEVNAME_KMODS += sdev_nsconfig_mod - -# # socketmod (kernel/socketmod) # SOCKET_KMODS += socksctp
--- a/usr/src/uts/sparc/ml/modstubs.s Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/sparc/ml/modstubs.s Mon Jul 20 13:07:46 2009 -0400 @@ -312,9 +312,7 @@ NO_UNLOAD_STUB(dev, sdev_modctl_readdir_free, nomod_minus_one); NO_UNLOAD_STUB(dev, devname_filename_register, nomod_minus_one); NO_UNLOAD_STUB(dev, sdev_modctl_devexists, nomod_minus_one); - NO_UNLOAD_STUB(dev, devname_nsmaps_register, nomod_minus_one); NO_UNLOAD_STUB(dev, devname_profile_update, nomod_minus_one); - NO_UNLOAD_STUB(dev, sdev_module_register, nomod_minus_one); NO_UNLOAD_STUB(dev, sdev_devstate_change, nomod_minus_one); NO_UNLOAD_STUB(dev, devvt_getvnodeops, nomod_minus_one); NO_UNLOAD_STUB(dev, devpts_getvnodeops, nomod_zero);
--- a/usr/src/uts/sparc/sdev_nsconfig_mod/Makefile Tue Jul 14 11:18:27 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (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 -# -# uts/sparc/sdev_nsconfig_mod/Makefile -# -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#pragma ident "%Z%%M% %I% %E% SMI" -# -# This makefile drives production of devname/sdev_nsconfig_mod module. -# -# -# Path to the base of the uts directory tree (usually /usr/src/uts). -# -UTSBASE = ../.. - -# -# Define the module and object file sets. -# -MODULE = sdev_nsconfig_mod -OBJECTS = $(NSCONFIG_DEVNAME_OBJS:%=$(OBJS_DIR)/%) -LINTS = $(NSCONFIG_DEVNAME_OBJS:%.o=$(LINTS_DIR)/%.ln) -ROOTMODULE = $(ROOT_DEVNAME_DIR)/$(MODULE) - -# -# Include common rules. -# -include $(UTSBASE)/sparc/Makefile.sparc - -# -# lint pass one enforcement -# -CFLAGS += $(CCVERBOSE) - -# -# Dependencies -# -LDFLAGS += -dy -Nfs/dev - -# -# Define targets -# -ALL_TARGET = $(BINARY) -LINT_TARGET = $(MODULE).lint -INSTALL_TARGET = $(BINARY) $(ROOTMODULE) - - -.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
--- a/usr/src/uts/sun4/cpu/cpu_module.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/sun4/cpu/cpu_module.c Mon Jul 20 13:07:46 2009 -0400 @@ -82,6 +82,11 @@ /*ARGSUSED*/ void +vtag_unmap_perm_tl1(uint64_t addr, uint64_t ctx) +{} + +/*ARGSUSED*/ +void vac_flushpage(pfn_t pf, int color) {}
--- a/usr/src/uts/sun4/io/px/px_intr.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/sun4/io/px/px_intr.c Mon Jul 20 13:07:46 2009 -0400 @@ -715,27 +715,27 @@ break; case DDI_INTROP_ENABLE: /* - * curr_nenables will be greater than 0 if rdip is using - * MSI-X and also, if it is using DUP interface. If this - * curr_enables is > 1, return after clearing the mask bit. + * For MSI, just clear the mask bit and return if curr_nenables + * is > 1. For MSI-X, program MSI address and data for every + * MSI-X vector including dup vectors irrespective of current + * curr_nenables value. */ - if ((pci_is_msi_enabled(rdip, hdlp->ih_type) == DDI_SUCCESS) && - (i_ddi_intr_get_current_nenables(rdip) > 0)) { - return (pci_msi_clr_mask(rdip, hdlp->ih_type, - hdlp->ih_inum)); - } + if ((pci_is_msi_enabled(rdip, hdlp->ih_type) != DDI_SUCCESS) || + (hdlp->ih_type == DDI_INTR_TYPE_MSIX)) { + nintrs = i_ddi_intr_get_current_nintrs(hdlp->ih_dip); - nintrs = i_ddi_intr_get_current_nintrs(hdlp->ih_dip); + if ((ret = pci_msi_configure(rdip, hdlp->ih_type, + nintrs, hdlp->ih_inum, msi_addr, + hdlp->ih_type == DDI_INTR_TYPE_MSIX ? + msi_num : msi_num & ~(nintrs - 1))) != DDI_SUCCESS) + return (ret); - if ((ret = pci_msi_configure(rdip, hdlp->ih_type, - nintrs, hdlp->ih_inum, msi_addr, - hdlp->ih_type == DDI_INTR_TYPE_MSIX ? msi_num : - msi_num & ~(nintrs - 1))) != DDI_SUCCESS) - return (ret); - - if ((ret = pci_msi_enable_mode(rdip, - hdlp->ih_type)) != DDI_SUCCESS) - return (ret); + if (i_ddi_intr_get_current_nenables(rdip) < 1) { + if ((ret = pci_msi_enable_mode(rdip, + hdlp->ih_type)) != DDI_SUCCESS) + return (ret); + } + } if ((ret = pci_msi_clr_mask(rdip, hdlp->ih_type, hdlp->ih_inum)) != DDI_SUCCESS)
--- a/usr/src/uts/sun4/os/memnode.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/sun4/os/memnode.c Mon Jul 20 13:07:46 2009 -0400 @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/systm.h> #include <sys/platform_module.h> #include <sys/sysmacros.h> @@ -82,9 +80,6 @@ end = roundup(end, btop(mem_node_physalign)) - 1; } - if (&plat_slice_add != NULL) - plat_slice_add(start, end); - mnode = PFN_2_MEM_NODE(start); ASSERT(mnode < max_mem_nodes); @@ -111,16 +106,6 @@ lgrp_config(LGRP_CONFIG_MEM_ADD, mnode, MEM_NODE_2_LGRPHAND(mnode)); } -/* ARGSUSED */ -void -mem_node_pre_del_slice(pfn_t start, pfn_t end) -{ - int mnode = PFN_2_MEM_NODE(start); - - ASSERT(mnode < max_mem_nodes); - ASSERT(mem_node_config[mnode].exists == 1); -} - /* * Remove a PFN range from a memnode. On some platforms, * the memnode will be created with physbase at the first @@ -129,7 +114,7 @@ * to assume physbase and up. */ void -mem_node_post_del_slice(pfn_t start, pfn_t end, int cancelled) +mem_node_del_slice(pfn_t start, pfn_t end) { int mnode; pgcnt_t delta_pgcnt, node_size; @@ -144,44 +129,57 @@ ASSERT(mnode < max_mem_nodes); ASSERT(mem_node_config[mnode].exists == 1); - if (!cancelled) { - delta_pgcnt = end - start; - node_size = mem_node_config[mnode].physmax - - mem_node_config[mnode].physbase; + delta_pgcnt = end - start; + node_size = mem_node_config[mnode].physmax - + mem_node_config[mnode].physbase; - if (node_size > delta_pgcnt) { - /* - * Subtract the slice from the memnode. - */ - if (start <= mem_node_config[mnode].physbase) - mem_node_config[mnode].physbase = end + 1; - ASSERT(end <= mem_node_config[mnode].physmax); - if (end == mem_node_config[mnode].physmax) - mem_node_config[mnode].physmax = start - 1; - } else { + if (node_size > delta_pgcnt) { + /* + * Subtract the slice from the memnode. + */ + if (start <= mem_node_config[mnode].physbase) + mem_node_config[mnode].physbase = end + 1; + ASSERT(end <= mem_node_config[mnode].physmax); + if (end == mem_node_config[mnode].physmax) + mem_node_config[mnode].physmax = start - 1; + } else { + + /* + * Let the common lgrp framework know the mnode is + * leaving + */ + lgrp_config(LGRP_CONFIG_MEM_DEL, mnode, + MEM_NODE_2_LGRPHAND(mnode)); - /* - * Let the common lgrp framework know the mnode is - * leaving - */ - lgrp_config(LGRP_CONFIG_MEM_DEL, mnode, - MEM_NODE_2_LGRPHAND(mnode)); + /* + * Delete the whole node. + */ + ASSERT(MNODE_PGCNT(mnode) == 0); + do { + omask = memnodes_mask; + nmask = omask & ~(1ull << mnode); + } while (cas64(&memnodes_mask, omask, nmask) != omask); + atomic_add_16(&num_memnodes, -1); + mem_node_config[mnode].exists = 0; + } +} - /* - * Delete the whole node. - */ - ASSERT(MNODE_PGCNT(mnode) == 0); - do { - omask = memnodes_mask; - nmask = omask & ~(1ull << mnode); - } while (cas64(&memnodes_mask, omask, nmask) != omask); - atomic_add_16(&num_memnodes, -1); - mem_node_config[mnode].exists = 0; - } +void +mem_node_add_range(pfn_t start, pfn_t end) +{ + if (&plat_slice_add != NULL) + plat_slice_add(start, end); + else + mem_node_add_slice(start, end); +} - if (&plat_slice_del != NULL) - plat_slice_del(start, end); - } +void +mem_node_del_range(pfn_t start, pfn_t end) +{ + if (&plat_slice_del != NULL) + plat_slice_del(start, end); + else + mem_node_del_slice(start, end); } void @@ -203,7 +201,7 @@ for (elem = 0; elem < nelems; list++, elem++) { basepfn = btop(list->addr); npgs = btop(list->size); - mem_node_add_slice(basepfn, basepfn + npgs - 1); + mem_node_add_range(basepfn, basepfn + npgs - 1); } } }
--- a/usr/src/uts/sun4/os/startup.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/sun4/os/startup.c Mon Jul 20 13:07:46 2009 -0400 @@ -202,6 +202,16 @@ pgcnt_t segziosize = 0; /* size of zio segment in pages */ /* + * A static DR page_t VA map is reserved that can map the page structures + * for a domain's entire RA space. The pages that backs this space are + * dynamically allocated and need not be physically contiguous. The DR + * map size is derived from KPM size. + */ +int ppvm_enable = 0; /* Static virtual map for page structs */ +page_t *ppvm_base; /* Base of page struct map */ +pgcnt_t ppvm_size = 0; /* Size of page struct map */ + +/* * debugger pages (if allocated) */ struct vnode kdebugvp; @@ -1987,6 +1997,8 @@ mach_kpm_init(); } + va = kpm_vbase + (kpm_size * vac_colors); + if (!segzio_fromheap) { size_t size; size_t physmem_b = mmu_ptob(physmem); @@ -2019,7 +2031,8 @@ } segziosize = mmu_btop(roundup(size, MMU_PAGESIZE)); /* put the base of the ZIO segment after the kpm segment */ - segzio_base = kpm_vbase + (kpm_size * vac_colors); + segzio_base = va; + va += mmu_ptob(segziosize); PRM_DEBUG(segziosize); PRM_DEBUG(segzio_base); @@ -2042,6 +2055,41 @@ rw_exit(&kas.a_lock); } + if (ppvm_enable) { + caddr_t ppvm_max; + + /* + * ppvm refers to the static VA space used to map + * the page_t's for dynamically added memory. + * + * ppvm_base should not cross a potential VA hole. + * + * ppvm_size should be large enough to map the + * page_t's needed to manage all of KPM range. + */ + ppvm_size = + roundup(mmu_btop(kpm_size * vac_colors) * sizeof (page_t), + MMU_PAGESIZE); + ppvm_max = (caddr_t)(0ull - ppvm_size); + ppvm_base = (page_t *)va; + + if ((caddr_t)ppvm_base <= hole_end) { + cmn_err(CE_WARN, + "Memory DR disabled: invalid DR map base: 0x%p\n", + (void *)ppvm_base); + ppvm_enable = 0; + } else if ((caddr_t)ppvm_base > ppvm_max) { + uint64_t diff = (caddr_t)ppvm_base - ppvm_max; + + cmn_err(CE_WARN, + "Memory DR disabled: insufficient DR map size:" + " 0x%lx (needed 0x%lx)\n", + ppvm_size - diff, ppvm_size); + ppvm_enable = 0; + } + PRM_DEBUG(ppvm_size); + PRM_DEBUG(ppvm_base); + } /* * Now create generic mapping segment. This mapping @@ -2541,10 +2589,15 @@ /* * init it, lock it, and hashin on prom_pages vp. * + * Mark it as NONRELOC to let DR know the page + * is locked long term, otherwise DR hangs when + * trying to remove those pages. + * * XXX vnode offsets on the prom_ppages vnode * are page numbers (gack) for >32 bit * physical memory machines. */ + PP_SETNORELOC(pp); add_physmem_cb(pp, base); if (page_trylock(pp, SE_EXCL) == 0) cmn_err(CE_PANIC, "prom page locked"); @@ -2614,7 +2667,7 @@ ASSERT(memseg_find( roundup(base + num, kpmpnpgs) - 1, NULL) == NULL); } - kpm_ppleft -= num; + kpm_ppleft -= kpnum; } memseg_list_add(seg); @@ -2645,6 +2698,8 @@ */ while (rpp < lpp) { ASSERT(PAGE_EXCL(rpp) && rpp->p_vnode == &prom_ppages); + ASSERT(PP_ISNORELOC(rpp)); + PP_CLRNORELOC(rpp); page_pp_unlock(rpp, 0, 1); page_hashout(rpp, NULL); page_unlock(rpp);
--- a/usr/src/uts/sun4/sys/memnode.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/sun4/sys/memnode.h Mon Jul 20 13:07:46 2009 -0400 @@ -19,15 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SYS_MEMNODE_H #define _SYS_MEMNODE_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -104,14 +102,19 @@ struct memlist; +/* + * Common layer calls the mem_node_*_range interfaces + * which in turn call the platmod hooks if they exist. + * The platmod layer then calls the mem_node_*slice interfaces. + */ extern void startup_build_mem_nodes(prom_memlist_t *, size_t); extern void mem_node_add_slice(pfn_t, pfn_t); -extern void mem_node_pre_del_slice(pfn_t, pfn_t); -extern void mem_node_post_del_slice(pfn_t, pfn_t, int); +extern void mem_node_del_slice(pfn_t, pfn_t); extern int mem_node_alloc(void); extern pgcnt_t mem_node_memlist_pages(int, struct memlist *); -extern void mem_node_add_slice(pfn_t start, pfn_t end); extern void mem_node_max_range(pfn_t *, pfn_t *); +extern void mem_node_add_range(pfn_t, pfn_t); +extern void mem_node_del_range(pfn_t, pfn_t); extern struct mem_node_conf mem_node_config[]; extern uint64_t mem_node_physalign;
--- a/usr/src/uts/sun4/vm/vm_dep.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/sun4/vm/vm_dep.h Mon Jul 20 13:07:46 2009 -0400 @@ -60,7 +60,6 @@ mtype = (flags & PG_NORELOC) ? MTYPE_NORELOC : MTYPE_RELOC; #define MNODETYPE_2_PFN(mnode, mtype, pfnlo, pfnhi) \ - ASSERT(mtype != MTYPE_NORELOC); \ pfnlo = mem_node_config[mnode].physbase; \ pfnhi = mem_node_config[mnode].physmax; @@ -115,12 +114,18 @@ * translations requiring initializer call if color or ceq_mask changes, * even if pfn doesn't. MEM_NODE_ITERATOR_INIT() must also be called before * PFN_2_COLOR() that uses a valid iterator argument. + * + * plat_mem_node_iterator_init() starts from last mblock in continuation + * case which may be invalid because memory DR. To detect this situation + * mi_genid is checked against mpo_genid which is incremented after a + * memory DR operation. See also plat_slice_add()/plat_slice_del(). */ #ifdef sun4v typedef struct mem_node_iterator { uint_t mi_mnode; /* mnode in which to iterate */ int mi_init; /* set to 1 when first init */ + int mi_genid; /* set/checked against mpo_genid */ int mi_last_mblock; /* last mblock visited */ uint_t mi_hash_ceq_mask; /* cached copy of ceq_mask */ uint_t mi_hash_color; /* cached copy of color */ @@ -460,6 +465,36 @@ } \ } +/* + * macro to call page_ctrs_adjust() when memory is added + * during a DR operation. + */ +#define PAGE_CTRS_ADJUST(pfn, cnt, rv) { \ + spgcnt_t _cnt = (spgcnt_t)(cnt); \ + int _mn; \ + pgcnt_t _np; \ + if (&plat_mem_node_intersect_range != NULL) { \ + for (_mn = 0; _mn < max_mem_nodes; _mn++) { \ + plat_mem_node_intersect_range((pfn), _cnt, _mn, &_np); \ + if (_np == 0) \ + continue; \ + if ((rv = page_ctrs_adjust(_mn)) != 0) \ + break; \ + } \ + } else { \ + pfn_t _pfn = (pfn); \ + pfn_t _endpfn = _pfn + _cnt; \ + while (_pfn < _endpfn) { \ + _mn = PFN_2_MEM_NODE(_pfn); \ + _np = MIN(_endpfn, mem_node_config[_mn].physmax + 1) - \ + _pfn; \ + _pfn += _np; \ + if ((rv = page_ctrs_adjust(_mn)) != 0) \ + break; \ + } \ + } \ +} + extern plcnt_t plcnt; #define MNODE_PGCNT(mn) \
--- a/usr/src/uts/sun4u/opl/os/opl.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/sun4u/opl/os/opl.c Mon Jul 20 13:07:46 2009 -0400 @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/cpuvar.h> #include <sys/systm.h> #include <sys/sysmacros.h> @@ -657,8 +655,7 @@ if (mem_node_config[mnode].exists) { start = mem_node_config[mnode].physbase; end = mem_node_config[mnode].physmax; - mem_node_pre_del_slice(start, end); - mem_node_post_del_slice(start, end, 0); + mem_node_del_slice(start, end); } } @@ -703,8 +700,7 @@ if (tnode != -1 && mem_node_config[tnode].exists) { start = mem_node_config[tnode].physbase; end = mem_node_config[tnode].physmax; - mem_node_pre_del_slice(start, end); - mem_node_post_del_slice(start, end, 0); + mem_node_del_slice(start, end); } plat_assign_lgrphand_to_mem_node(thand, snode);
--- a/usr/src/uts/sun4v/Makefile.files Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/sun4v/Makefile.files Mon Jul 20 13:07:46 2009 -0400 @@ -24,7 +24,7 @@ # Use is subject to license terms. # # This Makefile defines all file modules for the directory uts/sun4v -# and it's children. These are the source files which are sun4u +# and it's children. These are the source files which are sun4v # "implementation architecture" dependent. # @@ -60,6 +60,7 @@ CORE_OBJS += mem_cage.o CORE_OBJS += mem_config.o CORE_OBJS += memlist_new.o +CORE_OBJS += memseg.o CORE_OBJS += mpo.o CORE_OBJS += ppage.o CORE_OBJS += promif_asr.o @@ -161,6 +162,7 @@ BOOTDEV_OBJS += bootdev.o DR_CPU_OBJS += dr_cpu.o DR_IO_OBJS += dr_io.o +DR_MEM_OBJS += dr_mem.o DRCTL_OBJS = drctl.o drctl_impl.o dr_util.o DS_OBJS = ds_common.o ds_drv.o FAULT_ISO_OBJS = fault_iso.o
--- a/usr/src/uts/sun4v/Makefile.sun4v.shared Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/sun4v/Makefile.sun4v.shared Mon Jul 20 13:07:46 2009 -0400 @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # This makefile contains the common definitions for the sun4v unix @@ -390,6 +390,7 @@ MISC_KMODS += bootdev MISC_KMODS += dr_cpu MISC_KMODS += dr_io +MISC_KMODS += dr_mem MISC_KMODS += ds MISC_KMODS += fault_iso MISC_KMODS += ldc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/sun4v/dr_mem/Makefile Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,91 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = dr_mem +OBJECTS = $(DR_MEM_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(DR_MEM_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_PSM_MISC_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/sun4v/Makefile.sun4v + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +# +# lint pass one enforcement +# +CFLAGS += $(CCVERBOSE) + +# +# Turn on doubleword alignment for 64 bit registers +# +CFLAGS += -dalign + +# +# Module Dependencies +# +LDFLAGS += -dy -Nmisc/ds -Nmisc/platsvc -Ndrv/drctl + +# +# 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)/$(PLATFORM)/Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/sun4v/io/dr_mem.c Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,1252 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * sun4v Memory DR Module + */ + + +#include <sys/types.h> +#include <sys/cmn_err.h> +#include <sys/vmem.h> +#include <sys/kmem.h> +#include <sys/systm.h> +#include <sys/machsystm.h> /* for page_freelist_coalesce() */ +#include <sys/errno.h> +#include <sys/memnode.h> +#include <sys/memlist.h> +#include <sys/memlist_impl.h> +#include <sys/tuneable.h> +#include <sys/proc.h> +#include <sys/disp.h> +#include <sys/debug.h> +#include <sys/vm.h> +#include <sys/callb.h> +#include <sys/memlist_plat.h> /* for installed_top_size() */ +#include <sys/condvar_impl.h> /* for CV_HAS_WAITERS() */ +#include <sys/dumphdr.h> /* for dump_resize() */ +#include <sys/atomic.h> /* for use in stats collection */ +#include <sys/rwlock.h> +#include <vm/seg_kmem.h> +#include <vm/seg_kpm.h> +#include <vm/page.h> +#include <vm/vm_dep.h> +#define SUNDDI_IMPL /* so sunddi.h will not redefine splx() et al */ +#include <sys/sunddi.h> +#include <sys/mem_config.h> +#include <sys/mem_cage.h> +#include <sys/lgrp.h> +#include <sys/ddi.h> + +#include <sys/modctl.h> +#include <sys/sysevent/dr.h> +#include <sys/mach_descrip.h> +#include <sys/mdesc.h> +#include <sys/ds.h> +#include <sys/drctl.h> +#include <sys/dr_util.h> +#include <sys/dr_mem.h> + + +/* + * DR operations are subject to Memory Alignment restrictions + * for both address and the size of the request. + */ +#define MA_ADDR 0x10000000 /* addr alignment 256M */ +#define MA_SIZE 0x10000000 /* size alignment 256M */ + +#define MBLK_IS_VALID(m) \ + (IS_P2ALIGNED((m)->addr, MA_ADDR) && IS_P2ALIGNED((m)->size, MA_SIZE)) + +static memhandle_t dr_mh; /* memory handle for delete */ + +static struct modlmisc modlmisc = { + &mod_miscops, + "sun4v memory DR" +}; + +static struct modlinkage modlinkage = { + MODREV_1, + (void *)&modlmisc, + NULL +}; + +static int dr_mem_allow_unload = 0; + +typedef int (*fn_t)(dr_mem_blk_t *, int *); + +/* + * Global Domain Services (DS) Handle + */ +static ds_svc_hdl_t ds_handle; + +/* + * Supported DS Capability Versions + */ +static ds_ver_t dr_mem_vers[] = { { 1, 0 } }; +#define DR_MEM_NVERS (sizeof (dr_mem_vers) / sizeof (dr_mem_vers[0])) + +/* + * DS Capability Description + */ +static ds_capability_t dr_mem_cap = { + DR_MEM_DS_ID, /* svc_id */ + dr_mem_vers, /* vers */ + DR_MEM_NVERS /* nvers */ +}; + +/* + * DS Callbacks + */ +static void dr_mem_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t); +static void dr_mem_unreg_handler(ds_cb_arg_t arg); +static void dr_mem_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen); + +/* + * DS Client Ops Vector + */ +static ds_clnt_ops_t dr_mem_ops = { + dr_mem_reg_handler, /* ds_reg_cb */ + dr_mem_unreg_handler, /* ds_unreg_cb */ + dr_mem_data_handler, /* ds_data_cb */ + NULL /* cb_arg */ +}; + +/* + * Operation Results + * + * Used internally to gather results while an operation on a + * list of mblks is in progress. In particular, it is used to + * keep track of which mblks have already failed so that they are + * not processed further, and the manner in which they failed. + */ +typedef struct { + uint64_t addr; + uint64_t size; + uint32_t result; + uint32_t status; + char *string; +} dr_mem_res_t; + +static char * +dr_mem_estr[] = { + "operation succeeded", /* DR_MEM_RES_OK */ + "operation failed", /* DR_MEM_RES_FAILURE */ + "operation was blocked", /* DR_MEM_RES_BLOCKED */ + "memory not defined in MD", /* DR_MEM_RES_NOT_IN_MD */ + "memory already in use", /* DR_MEM_RES_ESPAN */ + "memory access test failed", /* DR_MEM_RES_EFAULT */ + "resource not available", /* DR_MEM_RES_ERESOURCE */ + "permanent pages in span", /* DR_MEM_RES_PERM */ + "memory span busy", /* DR_MEM_RES_EBUSY */ + "VM viability test failed", /* DR_MEM_RES_ENOTVIABLE */ + "no pages to unconfigure", /* DR_MEM_RES_ENOWORK */ + "operation cancelled", /* DR_MEM_RES_ECANCELLED */ + "operation refused", /* DR_MEM_RES_EREFUSED */ + "memory span duplicate", /* DR_MEM_RES_EDUP */ + "invalid argument" /* DR_MEM_RES_EINVAL */ +}; + +typedef struct { + kcondvar_t cond; + kmutex_t lock; + int error; + int done; +} mem_sync_t; + +/* + * Internal Functions + */ +static int dr_mem_init(void); +static int dr_mem_fini(void); + +static int dr_mem_list_wrk(dr_mem_hdr_t *, dr_mem_hdr_t **, int *); +static int dr_mem_list_query(dr_mem_hdr_t *, dr_mem_hdr_t **, int *); +static int dr_mem_del_stat(dr_mem_hdr_t *, dr_mem_hdr_t **, int *); +static int dr_mem_del_cancel(dr_mem_hdr_t *, dr_mem_hdr_t **, int *); + +static int dr_mem_unconfigure(dr_mem_blk_t *, int *); +static int dr_mem_configure(dr_mem_blk_t *, int *); +static void dr_mem_query(dr_mem_blk_t *, dr_mem_query_t *); + +static dr_mem_res_t *dr_mem_res_array_init(dr_mem_hdr_t *, drctl_rsrc_t *, int); +static void dr_mem_res_array_fini(dr_mem_res_t *res, int nres); +static size_t dr_mem_pack_response(dr_mem_hdr_t *req, dr_mem_res_t *res, + dr_mem_hdr_t **respp); + +static int dr_mem_find(dr_mem_blk_t *mbp); +static mde_cookie_t dr_mem_find_node_md(dr_mem_blk_t *, md_t *, mde_cookie_t *); + +static int mem_add(pfn_t, pgcnt_t); +static int mem_del(pfn_t, pgcnt_t); + +static size_t rsvaddsz; +extern void i_dr_mem_init(uint64_t *); +extern void i_dr_mem_fini(); +extern void i_dr_mem_update(); +extern int kphysm_add_memory_dynamic(pfn_t, pgcnt_t); + +int +_init(void) +{ + int status; + + /* check that Memory DR is enabled */ + if (dr_is_disabled(DR_TYPE_MEM)) + return (ENOTSUP); + + if ((status = dr_mem_init()) != 0) { + cmn_err(CE_NOTE, "Memory DR initialization failed"); + return (status); + } + + if ((status = mod_install(&modlinkage)) != 0) { + (void) dr_mem_fini(); + } + + return (status); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + +int +_fini(void) +{ + int status; + + if (dr_mem_allow_unload == 0) + return (EBUSY); + + if ((status = mod_remove(&modlinkage)) == 0) { + (void) dr_mem_fini(); + } + + return (status); +} + +static int +dr_mem_init(void) +{ + int rv; + + if ((rv = ds_cap_init(&dr_mem_cap, &dr_mem_ops)) != 0) { + cmn_err(CE_NOTE, "dr_mem: ds_cap_init failed: %d", rv); + return (rv); + } + + i_dr_mem_init(&rsvaddsz); + + return (0); +} + +static int +dr_mem_fini(void) +{ + int rv; + + i_dr_mem_fini(); + + if ((rv = ds_cap_fini(&dr_mem_cap)) != 0) { + cmn_err(CE_NOTE, "dr_mem: ds_cap_fini failed: %d", rv); + } + + return (rv); +} + +static void +dr_mem_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl) +{ + DR_DBG_MEM("reg_handler: arg=0x%p, ver=%d.%d, hdl=0x%lx\n", arg, + ver->major, ver->minor, hdl); + + ds_handle = hdl; +} + +static void +dr_mem_unreg_handler(ds_cb_arg_t arg) +{ + DR_DBG_MEM("unreg_handler: arg=0x%p\n", arg); + + ds_handle = DS_INVALID_HDL; +} + +/*ARGSUSED*/ +static void +dr_mem_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen) +{ + dr_mem_hdr_t *req = buf; + dr_mem_hdr_t err_resp; + dr_mem_hdr_t *resp = &err_resp; + int resp_len = 0; + int rv = EINVAL; + + /* + * Sanity check the message + */ + if (buflen < sizeof (dr_mem_hdr_t)) { + DR_DBG_MEM("incoming message short: expected at least %ld " + "bytes, received %ld\n", sizeof (dr_mem_hdr_t), buflen); + goto done; + } + + if (req == NULL) { + DR_DBG_MEM("empty message: expected at least %ld bytes\n", + sizeof (dr_mem_hdr_t)); + goto done; + } + + DR_DBG_MEM("incoming request:\n"); + DR_DBG_DUMP_MSG(buf, buflen); + + /* + * Process the command + */ + switch (req->msg_type) { + case DR_MEM_CONFIGURE: + case DR_MEM_UNCONFIGURE: + if (req->msg_arg == 0) { + DR_DBG_MEM("No mblks specified for operation\n"); + goto done; + } + if ((rv = dr_mem_list_wrk(req, &resp, &resp_len)) != 0) { + DR_DBG_MEM("%s failed (%d)\n", + (req->msg_type == DR_MEM_CONFIGURE) ? + "Memory configure" : "Memory unconfigure", rv); + } + break; + + case DR_MEM_UNCONF_STATUS: + if ((rv = dr_mem_del_stat(req, &resp, &resp_len)) != 0) + DR_DBG_MEM("Memory delete status failed (%d)\n", rv); + break; + + case DR_MEM_UNCONF_CANCEL: + if ((rv = dr_mem_del_cancel(req, &resp, &resp_len)) != 0) + DR_DBG_MEM("Memory delete cancel failed (%d)\n", rv); + break; + + case DR_MEM_QUERY: + if (req->msg_arg == 0) { + DR_DBG_MEM("No mblks specified for operation\n"); + goto done; + } + if ((rv = dr_mem_list_query(req, &resp, &resp_len)) != 0) + DR_DBG_MEM("Memory query failed (%d)\n", rv); + break; + + default: + cmn_err(CE_NOTE, "unsupported memory DR operation (%d)", + req->msg_type); + break; + } + +done: + /* check if an error occurred */ + if (resp == &err_resp) { + resp->req_num = (req) ? req->req_num : 0; + resp->msg_type = DR_MEM_ERROR; + resp->msg_arg = rv; + resp_len = sizeof (dr_mem_hdr_t); + } + + DR_DBG_MEM("outgoing response:\n"); + DR_DBG_DUMP_MSG(resp, resp_len); + + /* send back the response */ + if (ds_cap_send(ds_handle, resp, resp_len) != 0) { + DR_DBG_MEM("ds_send failed\n"); + } + + /* free any allocated memory */ + if (resp != &err_resp) { + kmem_free(resp, resp_len); + } +} + +/* + * Common routine to config or unconfig multiple mblks. + * + * Note: Do not modify result buffer or length on error. + */ +static int +dr_mem_list_wrk(dr_mem_hdr_t *req, dr_mem_hdr_t **resp, int *resp_len) +{ + int rv; + int idx; + int count; + int result; + int status; + fn_t dr_fn; + int se_hint; + dr_mem_blk_t *req_mblks; + dr_mem_res_t *res; + int drctl_cmd; + int drctl_flags = 0; + drctl_rsrc_t *drctl_req; + size_t drctl_req_len; + drctl_resp_t *drctl_resp; + drctl_rsrc_t *drctl_rsrc; + size_t drctl_resp_len = 0; + drctl_cookie_t drctl_res_ck; + + ASSERT((req != NULL) && (req->msg_arg != 0)); + + count = req->msg_arg; + + /* + * Extract all information that is specific + * to the various types of operations. + */ + switch (req->msg_type) { + case DR_MEM_CONFIGURE: + dr_fn = dr_mem_configure; + drctl_cmd = DRCTL_MEM_CONFIG_REQUEST; + se_hint = SE_HINT_INSERT; + break; + case DR_MEM_UNCONFIGURE: + dr_fn = dr_mem_unconfigure; + drctl_cmd = DRCTL_MEM_UNCONFIG_REQUEST; + se_hint = SE_HINT_REMOVE; + break; + default: + /* Programming error if we reach this. */ + cmn_err(CE_NOTE, "%s: bad msg_type %d\n", + __func__, req->msg_type); + ASSERT(0); + return (-1); + } + + /* the incoming array of mblks to operate on */ + req_mblks = DR_MEM_CMD_MBLKS(req); + + /* allocate drctl request msg based on incoming resource count */ + drctl_req_len = sizeof (drctl_rsrc_t) * count; + drctl_req = kmem_zalloc(drctl_req_len, KM_SLEEP); + + /* copy the size for the drctl call from the incoming request msg */ + for (idx = 0; idx < count; idx++) { + drctl_req[idx].res_mem_addr = req_mblks[idx].addr; + drctl_req[idx].res_mem_size = req_mblks[idx].size; + } + + rv = drctl_config_init(drctl_cmd, drctl_flags, drctl_req, + count, &drctl_resp, &drctl_resp_len, &drctl_res_ck); + + ASSERT((drctl_resp != NULL) && (drctl_resp_len != 0)); + + if (rv != 0) { + DR_DBG_MEM("%s: drctl_config_init returned: %d\n", + __func__, rv); + kmem_free(drctl_resp, drctl_resp_len); + kmem_free(drctl_req, drctl_req_len); + return (rv); + } + + ASSERT(drctl_resp->resp_type == DRCTL_RESP_OK); + + drctl_rsrc = drctl_resp->resp_resources; + + /* create the result scratch array */ + res = dr_mem_res_array_init(req, drctl_rsrc, count); + + /* perform the specified operation on each of the mblks */ + for (idx = 0; idx < count; idx++) { + /* + * If no action will be taken against the current + * mblk, update the drctl resource information to + * ensure that it gets recovered properly during + * the drctl fini() call. + */ + if (res[idx].result != DR_MEM_RES_OK) { + drctl_req[idx].status = DRCTL_STATUS_CONFIG_FAILURE; + continue; + } + + /* call the function to perform the actual operation */ + result = (*dr_fn)(&req_mblks[idx], &status); + + /* save off results of the operation */ + res[idx].result = result; + res[idx].status = status; + res[idx].addr = req_mblks[idx].addr; /* for partial case */ + res[idx].size = req_mblks[idx].size; /* for partial case */ + res[idx].string = i_ddi_strdup(dr_mem_estr[result], KM_SLEEP); + + /* save result for drctl fini() reusing init() msg memory */ + drctl_req[idx].status = (result != DR_MEM_RES_OK) ? + DRCTL_STATUS_CONFIG_FAILURE : DRCTL_STATUS_CONFIG_SUCCESS; + + DR_DBG_MEM("%s: mblk 0x%lx.0x%lx stat %d result %d off '%s'\n", + __func__, req_mblks[idx].addr, req_mblks[idx].size, + drctl_req[idx].status, result, + (res[idx].string) ? res[idx].string : ""); + } + + if ((rv = drctl_config_fini(&drctl_res_ck, drctl_req, count)) != 0) + DR_DBG_MEM("%s: drctl_config_fini returned: %d\n", + __func__, rv); + + /* + * Operation completed without any fatal errors. + * Pack the response for transmission. + */ + *resp_len = dr_mem_pack_response(req, res, resp); + + /* notify interested parties about the operation */ + dr_generate_event(DR_TYPE_MEM, se_hint); + + /* + * Deallocate any scratch memory. + */ + kmem_free(drctl_resp, drctl_resp_len); + kmem_free(drctl_req, drctl_req_len); + + dr_mem_res_array_fini(res, count); + + return (0); +} + +/* + * Allocate and initialize a result array based on the initial + * drctl operation. A valid result array is always returned. + */ +static dr_mem_res_t * +dr_mem_res_array_init(dr_mem_hdr_t *req, drctl_rsrc_t *rsrc, int nrsrc) +{ + int idx; + dr_mem_res_t *res; + char *err_str; + size_t err_len; + + /* allocate zero filled buffer to initialize fields */ + res = kmem_zalloc(nrsrc * sizeof (dr_mem_res_t), KM_SLEEP); + + /* + * Fill in the result information for each resource. + */ + for (idx = 0; idx < nrsrc; idx++) { + res[idx].addr = rsrc[idx].res_mem_addr; + res[idx].size = rsrc[idx].res_mem_size; + res[idx].result = DR_MEM_RES_OK; + + if (rsrc[idx].status == DRCTL_STATUS_ALLOW) + continue; + + /* + * Update the state information for this mblk. + */ + res[idx].result = DR_MEM_RES_BLOCKED; + res[idx].status = (req->msg_type == DR_MEM_CONFIGURE) ? + DR_MEM_STAT_UNCONFIGURED : DR_MEM_STAT_CONFIGURED; + + /* + * If an error string exists, copy it out of the + * message buffer. This eliminates any dependency + * on the memory allocated for the message buffer + * itself. + */ + if (rsrc[idx].offset != NULL) { + err_str = (char *)rsrc + rsrc[idx].offset; + err_len = strlen(err_str) + 1; + + res[idx].string = kmem_alloc(err_len, KM_SLEEP); + bcopy(err_str, res[idx].string, err_len); + } + } + + return (res); +} + +static void +dr_mem_res_array_fini(dr_mem_res_t *res, int nres) +{ + int idx; + size_t str_len; + + for (idx = 0; idx < nres; idx++) { + /* deallocate the error string if present */ + if (res[idx].string) { + str_len = strlen(res[idx].string) + 1; + kmem_free(res[idx].string, str_len); + } + } + + /* deallocate the result array itself */ + kmem_free(res, sizeof (dr_mem_res_t) * nres); +} + +/* + * Allocate and pack a response message for transmission based + * on the specified result array. A valid response message and + * valid size information is always returned. + */ +static size_t +dr_mem_pack_response(dr_mem_hdr_t *req, dr_mem_res_t *res, dr_mem_hdr_t **respp) +{ + int idx; + dr_mem_hdr_t *resp; + dr_mem_stat_t *resp_stat; + size_t resp_len; + uint32_t curr_off; + caddr_t curr_str; + size_t str_len; + size_t stat_len; + int nstat = req->msg_arg; + + /* + * Calculate the size of the response message + * and allocate an appropriately sized buffer. + */ + resp_len = sizeof (dr_mem_hdr_t); + + /* add the stat array size */ + stat_len = sizeof (dr_mem_stat_t) * nstat; + resp_len += stat_len; + + /* add the size of any error strings */ + for (idx = 0; idx < nstat; idx++) { + if (res[idx].string != NULL) { + resp_len += strlen(res[idx].string) + 1; + } + } + + /* allocate the message buffer */ + resp = kmem_zalloc(resp_len, KM_SLEEP); + + /* + * Fill in the header information. + */ + resp->req_num = req->req_num; + resp->msg_type = DR_MEM_OK; + resp->msg_arg = nstat; + + /* + * Fill in the stat information. + */ + resp_stat = DR_MEM_RESP_STATS(resp); + + /* string offsets start immediately after stat array */ + curr_off = sizeof (dr_mem_hdr_t) + stat_len; + curr_str = (char *)resp_stat + stat_len; + + for (idx = 0; idx < nstat; idx++) { + resp_stat[idx].addr = res[idx].addr; + resp_stat[idx].size = res[idx].size; + resp_stat[idx].result = res[idx].result; + resp_stat[idx].status = res[idx].status; + + if (res[idx].string != NULL) { + /* copy over the error string */ + str_len = strlen(res[idx].string) + 1; + bcopy(res[idx].string, curr_str, str_len); + resp_stat[idx].string_off = curr_off; + + curr_off += str_len; + curr_str += str_len; + } + } + + /* buffer should be exactly filled */ + ASSERT(curr_off == resp_len); + + *respp = resp; + return (resp_len); +} + +static void +dr_mem_query(dr_mem_blk_t *mbp, dr_mem_query_t *mqp) +{ + memquery_t mq; + + DR_DBG_MEM("dr_mem_query...\n"); + + + (void) kphysm_del_span_query(btop(mbp->addr), btop(mbp->size), &mq); + + if (!mq.phys_pages) + return; + + mqp->addr = mbp->addr; + mqp->mq.phys_pages = ptob(mq.phys_pages); + mqp->mq.managed = ptob(mq.managed); + mqp->mq.nonrelocatable = ptob(mq.nonrelocatable); + mqp->mq.first_nonrelocatable = ptob(mq.first_nonrelocatable); + mqp->mq.last_nonrelocatable = ptob(mq.last_nonrelocatable); + /* + * Set to the max byte offset within the page. + */ + if (mqp->mq.nonrelocatable) + mqp->mq.last_nonrelocatable += PAGESIZE - 1; +} + +/* + * Do not modify result buffer or length on error. + */ +static int +dr_mem_list_query(dr_mem_hdr_t *req, dr_mem_hdr_t **resp, int *resp_len) +{ + int idx; + int rlen; + int nml; + struct memlist *ml; + dr_mem_blk_t *req_mblks, mb; + dr_mem_hdr_t *rp; + dr_mem_query_t *stat; + + /* the incoming array of req_mblks to configure */ + req_mblks = DR_MEM_CMD_MBLKS(req); + + /* allocate a response message, should be freed by caller */ + nml = 0; + rlen = sizeof (dr_mem_hdr_t); + if (req_mblks->addr == NULL && req_mblks->size == 0) { + /* + * Request is for domain's full view of it's memory. + */ + memlist_read_lock(); + for (ml = phys_install; ml; ml = ml->next) + nml++; + + rlen += nml * sizeof (dr_mem_query_t); + } else { + rlen += req->msg_arg * sizeof (dr_mem_query_t); + } + rp = kmem_zalloc(rlen, KM_SLEEP); + + /* fill in the known data */ + rp->req_num = req->req_num; + rp->msg_type = DR_MEM_OK; + rp->msg_arg = nml ? nml : req->msg_arg; + + /* stat array for the response */ + stat = DR_MEM_RESP_QUERY(rp); + + /* get the status for each of the mblocks */ + if (nml) { + for (idx = 0, ml = phys_install; ml; ml = ml->next, idx++) { + mb.addr = ml->address; + mb.size = ml->size; + dr_mem_query(&mb, &stat[idx]); + } + memlist_read_unlock(); + } else { + for (idx = 0; idx < req->msg_arg; idx++) + dr_mem_query(&req_mblks[idx], &stat[idx]); + } + + *resp = rp; + *resp_len = rlen; + + return (0); +} + +static int +cvt_err(int err) +{ + int rv; + + switch (err) { + case KPHYSM_OK: + rv = DR_MEM_RES_OK; + break; + case KPHYSM_ESPAN: + rv = DR_MEM_RES_ESPAN; + break; + case KPHYSM_EFAULT: + rv = DR_MEM_RES_EFAULT; + break; + case KPHYSM_ERESOURCE: + rv = DR_MEM_RES_ERESOURCE; + break; + case KPHYSM_ENOTSUP: + case KPHYSM_ENOHANDLES: + rv = DR_MEM_RES_FAILURE; + break; + case KPHYSM_ENONRELOC: + rv = DR_MEM_RES_PERM; + break; + case KPHYSM_EHANDLE: + rv = DR_MEM_RES_FAILURE; + break; + case KPHYSM_EBUSY: + rv = DR_MEM_RES_EBUSY; + break; + case KPHYSM_ENOTVIABLE: + rv = DR_MEM_RES_ENOTVIABLE; + break; + case KPHYSM_ESEQUENCE: + rv = DR_MEM_RES_FAILURE; + break; + case KPHYSM_ENOWORK: + rv = DR_MEM_RES_ENOWORK; + break; + case KPHYSM_ECANCELLED: + rv = DR_MEM_RES_ECANCELLED; + break; + case KPHYSM_EREFUSED: + rv = DR_MEM_RES_EREFUSED; + break; + case KPHYSM_ENOTFINISHED: + case KPHYSM_ENOTRUNNING: + rv = DR_MEM_RES_FAILURE; + break; + case KPHYSM_EDUP: + rv = DR_MEM_RES_EDUP; + break; + default: + rv = DR_MEM_RES_FAILURE; + break; + } + + return (rv); +} + +static int +dr_mem_configure(dr_mem_blk_t *mbp, int *status) +{ + int rv; + uint64_t addr, size, addsz; + + rv = 0; + addr = mbp->addr; + size = mbp->size; + + DR_DBG_MEM("dr_mem_configure...\n"); + + if (!MBLK_IS_VALID(mbp)) { + DR_DBG_MEM("invalid mblk 0x%lx.0x%lx\n", addr, size); + *status = DR_MEM_STAT_UNCONFIGURED; + rv = DR_MEM_RES_EINVAL; + } else if (rv = dr_mem_find(mbp)) { + DR_DBG_MEM("failed to find mblk 0x%lx.0x%lx (%d)\n", + addr, size, rv); + if (rv == EINVAL) { + *status = DR_MEM_STAT_NOT_PRESENT; + rv = DR_MEM_RES_NOT_IN_MD; + } else { + *status = DR_MEM_STAT_UNCONFIGURED; + rv = DR_MEM_RES_FAILURE; + } + } else if (rsvaddsz) { + addr += size; + + /* + * Add up to the first <rsvaddsz> portion of mblock + * first since that portion has reserved meta pages. + * This will likely guarantee an additional amount of + * free pages from which we may have to allocate the + * rest of the meta pages. + * + * Break up the request in descending order (if needed) + * in order to ensure that cage grows from the high end + * of the original request. + */ + for (addsz = MIN(size, rsvaddsz); addsz > 0; addsz = size) { + ASSERT(addr >= mbp->addr); + DR_DBG_MEM("addsz=0x%lx size=0x%lx\n", addsz, size); + if (rv = mem_add(btop(addr - addsz), btop(addsz))) { + DR_DBG_MEM("failed to configure span" + " 0x%lx.0x%lx (%d)\n", addr, addsz, rv); + break; + } else { + size -= addsz; + addr -= addsz; + } + } + + /* + * Mark the mblock configured if any span + * in that mblock was successfully added. + * + * In case of partial success: + * + * rv != DR_MEM_RES_OK + * status == DR_MEM_STAT_CONFIGURED + * + * mark span actually configured. + */ + if (size == mbp->size && rv != KPHYSM_ESPAN) { + *status = DR_MEM_STAT_UNCONFIGURED; + } else { + DR_DBG_MEM("failed (partial) to configure span" + " 0x%lx.0x%lx (%d)\n", addr, addsz, rv); + *status = DR_MEM_STAT_CONFIGURED; + mbp->addr = addr; + mbp->size -= size; + } + + rv = cvt_err(rv); + i_dr_mem_update(); + } else { + /* + * The reserved feature is disabled, add whole mblock. + */ + rv = mem_add(btop(addr), btop(size)); + DR_DBG_MEM("addr=0x%lx size=0x%lx rv=%d\n", addr, size, rv); + if (rv) { + rv = cvt_err(rv); + *status = DR_MEM_STAT_UNCONFIGURED; + } else { + *status = DR_MEM_STAT_CONFIGURED; + } + } + + return (rv); +} + +static int +dr_mem_unconfigure(dr_mem_blk_t *mbp, int *status) +{ + int rv; + + DR_DBG_MEM("dr_mem_unconfigure...\n"); + + if (!MBLK_IS_VALID(mbp)) { + DR_DBG_MEM("invalid mblk 0x%lx.0x%lx\n", + mbp->addr, mbp->size); + *status = DR_MEM_STAT_CONFIGURED; + rv = DR_MEM_RES_EINVAL; + } else if (rv = mem_del(btop(mbp->addr), btop(mbp->size))) { + rv = cvt_err(rv); + *status = DR_MEM_STAT_CONFIGURED; + } else { + *status = DR_MEM_STAT_UNCONFIGURED; + rv = DR_MEM_RES_OK; + DR_DBG_MEM("mblk 0x%lx.0x%lx unconfigured\n", + mbp->addr, mbp->size); + } + return (rv); +} + +static int +dr_mem_del_stat(dr_mem_hdr_t *req, dr_mem_hdr_t **resp, int *resp_len) +{ + int status; + int rlen; + memdelstat_t del_stat, *stat; + dr_mem_hdr_t *rp; + + /* + * If a mem delete is in progress, get its status. + */ + status = (dr_mh && (kphysm_del_status(dr_mh, &del_stat) == KPHYSM_OK)); + + /* allocate a response message, should be freed by caller */ + rlen = sizeof (dr_mem_hdr_t); + rlen += status * sizeof (memdelstat_t); + rp = kmem_zalloc(rlen, KM_SLEEP); + + /* fill in the known data */ + rp->req_num = req->req_num; + rp->msg_type = DR_MEM_OK; + rp->msg_arg = status; + + if (status) { + /* stat struct for the response */ + stat = DR_MEM_RESP_DEL_STAT(rp); + stat->phys_pages = ptob(del_stat.phys_pages); + stat->managed = ptob(del_stat.managed); + stat->collected = ptob(del_stat.collected); + } + + *resp = rp; + *resp_len = rlen; + + return (0); +} + +static int +dr_mem_del_cancel(dr_mem_hdr_t *req, dr_mem_hdr_t **resp, int *resp_len) +{ + int rlen; + dr_mem_hdr_t *rp; + + /* allocate a response message, should be freed by caller */ + rlen = sizeof (dr_mem_hdr_t); + rp = kmem_zalloc(rlen, KM_SLEEP); + + /* fill in the known data */ + rp->req_num = req->req_num; + rp->msg_type = DR_MEM_OK; + rp->msg_arg = (dr_mh && kphysm_del_cancel(dr_mh) != KPHYSM_OK) ? + DR_MEM_RES_EINVAL : DR_MEM_RES_OK; + + *resp = rp; + *resp_len = rlen; + + return (0); +} + +static int +dr_mem_find(dr_mem_blk_t *mbp) +{ + md_t *mdp = NULL; + int num_nodes; + int rv = 0; + int listsz; + mde_cookie_t *listp = NULL; + mde_cookie_t memnode; + char *found = "found"; + + if ((mdp = md_get_handle()) == NULL) { + DR_DBG_MEM("unable to initialize machine description\n"); + return (-1); + } + + num_nodes = md_node_count(mdp); + ASSERT(num_nodes > 0); + + listsz = num_nodes * sizeof (mde_cookie_t); + listp = kmem_zalloc(listsz, KM_SLEEP); + + memnode = dr_mem_find_node_md(mbp, mdp, listp); + + if (memnode == MDE_INVAL_ELEM_COOKIE) { + rv = EINVAL; + found = "not found"; + } + + DR_DBG_MEM("mblk 0x%lx.0x%lx %s\n", mbp->addr, mbp->size, found); + + kmem_free(listp, listsz); + (void) md_fini_handle(mdp); + + return (rv); +} + +/* + * Look up a particular mblk in the MD. Returns the mde_cookie_t + * representing that mblk if present, and MDE_INVAL_ELEM_COOKIE + * otherwise. It is assumed the scratch array has already been + * allocated so that it can accommodate the worst case scenario, + * every node in the MD. + */ +static mde_cookie_t +dr_mem_find_node_md(dr_mem_blk_t *mbp, md_t *mdp, mde_cookie_t *listp) +{ + int idx; + int nnodes; + mde_cookie_t rootnode; + uint64_t base_prop; + uint64_t size_prop; + mde_cookie_t result = MDE_INVAL_ELEM_COOKIE; + + rootnode = md_root_node(mdp); + ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE); + + /* + * Scan the DAG for all the mem nodes + */ + nnodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "mblock"), + md_find_name(mdp, "fwd"), listp); + + if (nnodes < 0) { + DR_DBG_MEM("Scan for mblks failed\n"); + return (result); + } + + DR_DBG_MEM("dr_mem_find_node_md: found %d mblks in the MD\n", nnodes); + + /* + * Find the mblk of interest + */ + for (idx = 0; idx < nnodes; idx++) { + + if (md_get_prop_val(mdp, listp[idx], "base", &base_prop)) { + DR_DBG_MEM("Missing 'base' property for mblk node %d\n", + idx); + break; + } + + if (md_get_prop_val(mdp, listp[idx], "size", &size_prop)) { + DR_DBG_MEM("Missing 'size' property for mblk node %d\n", + idx); + break; + } + + if (base_prop <= mbp->addr && + (base_prop + size_prop) >= (mbp->addr + mbp->size)) { + /* found a match */ + DR_DBG_MEM("dr_mem_find_node_md: found mblk " + "0x%lx.0x%lx in MD\n", mbp->addr, mbp->size); + result = listp[idx]; + break; + } + } + + if (result == MDE_INVAL_ELEM_COOKIE) { + DR_DBG_MEM("mblk 0x%lx.0x%lx not in MD\n", + mbp->addr, mbp->size); + } + + return (result); +} + +static int +mem_add(pfn_t base, pgcnt_t npgs) +{ + int rv, rc; + + DR_DBG_MEM("%s: begin base=0x%lx npgs=0x%lx\n", __func__, base, npgs); + + if (npgs == 0) + return (0); + + rv = kphysm_add_memory_dynamic(base, npgs); + DR_DBG_MEM("%s: kphysm_add(0x%lx, 0x%lx) = %d", __func__, base, npgs, + rv); + if (!rv) { + if (rc = kcage_range_add(base, npgs, KCAGE_DOWN)) + cmn_err(CE_WARN, "kcage_range_add() = %d", rc); + } + return (rv); +} + +static void +del_done(void *arg, int error) +{ + mem_sync_t *ms = arg; + + mutex_enter(&ms->lock); + ms->error = error; + ms->done = 1; + cv_signal(&ms->cond); + mutex_exit(&ms->lock); +} + +static int +mem_del(pfn_t base, pgcnt_t npgs) +{ + int rv, err, del_range = 0; + mem_sync_t ms; + memquery_t mq; + memhandle_t mh; + struct memlist *ml; + struct memlist *d_ml = NULL; + + DR_DBG_MEM("%s: begin base=0x%lx npgs=0x%lx\n", __func__, base, npgs); + + if (npgs == 0) + return (0); + + if ((rv = kphysm_del_gethandle(&mh)) != KPHYSM_OK) { + cmn_err(CE_WARN, "%s: del_gethandle() = %d", __func__, rv); + return (rv); + } + if ((rv = kphysm_del_span_query(base, npgs, &mq)) + != KPHYSM_OK) { + cmn_err(CE_WARN, "%s: del_span_query() = %d", __func__, rv); + goto done; + } + if (mq.nonrelocatable) { + DR_DBG_MEM("%s: non-reloc pages = %ld", + __func__, mq.nonrelocatable); + rv = KPHYSM_ENONRELOC; + goto done; + } + if (rv = kcage_range_delete(base, npgs)) { + cmn_err(CE_WARN, "%s: del_range() = %d", __func__, rv); + goto done; + } else { + del_range++; + } + if ((rv = kphysm_del_span(mh, base, npgs)) != KPHYSM_OK) { + cmn_err(CE_WARN, "%s: del_span() = %d", __func__, rv); + goto done; + } + if ((rv = memlist_add_span(ptob(base), ptob(npgs), &d_ml)) + != MEML_SPANOP_OK) { + cmn_err(CE_WARN, "%s: add_span() = %d", __func__, rv); + goto done; + } + + DR_DBG_MEM("%s: reserved=0x%lx", __func__, npgs); + + bzero((void *) &ms, sizeof (ms)); + + mutex_init(&ms.lock, NULL, MUTEX_DRIVER, NULL); + cv_init(&ms.cond, NULL, CV_DRIVER, NULL); + mutex_enter(&ms.lock); + + if ((rv = kphysm_del_start(mh, del_done, (void *) &ms)) == KPHYSM_OK) { + /* + * Since we've called drctl_config_init, we are the only + * DR ctl operation in progress. Set dr_mh to the + * delete memhandle for use by stat and cancel. + */ + ASSERT(dr_mh == NULL); + dr_mh = mh; + + /* + * Wait for completion or interrupt. + */ + while (!ms.done) { + if (cv_wait_sig(&ms.cond, &ms.lock) == 0) { + /* + * There is a pending signal. + */ + (void) kphysm_del_cancel(mh); + DR_DBG_MEM("%s: cancel", __func__); + /* + * Wait for completion. + */ + while (!ms.done) + cv_wait(&ms.cond, &ms.lock); + } + } + dr_mh = NULL; + rv = ms.error; + } else { + DR_DBG_MEM("%s: del_start() = %d", __func__, rv); + } + + mutex_exit(&ms.lock); + cv_destroy(&ms.cond); + mutex_destroy(&ms.lock); + +done: + if (rv && del_range) { + /* + * Add back the spans to the kcage growth list. + */ + for (ml = d_ml; ml; ml = ml->next) + if (err = kcage_range_add(btop(ml->address), + btop(ml->size), KCAGE_DOWN)) + cmn_err(CE_WARN, "kcage_range_add() = %d", err); + } + memlist_free_list(d_ml); + + if ((err = kphysm_del_release(mh)) != KPHYSM_OK) + cmn_err(CE_WARN, "%s: del_release() = %d", __func__, err); + + DR_DBG_MEM("%s: rv=%d", __func__, rv); + + return (rv); +}
--- a/usr/src/uts/sun4v/io/dr_util.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/sun4v/io/dr_util.c Mon Jul 20 13:07:46 2009 -0400 @@ -20,12 +20,10 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * sun4v DR Utility functions */ @@ -41,6 +39,8 @@ #include <sys/dr_util.h> +extern int ppvm_enable; + boolean_t dr_is_disabled(dr_type_t type) { @@ -64,6 +64,11 @@ return (B_TRUE); } + if (type == DR_TYPE_MEM && ppvm_enable == 0) { + cmn_err(CE_NOTE, "!Memory DR is disabled\n"); + return (B_TRUE); + } + return (B_FALSE); }
--- a/usr/src/uts/sun4v/io/drctl.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/sun4v/io/drctl.c Mon Jul 20 13:07:46 2009 -0400 @@ -20,7 +20,7 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -354,6 +354,9 @@ if (count != 1) return (EIO); break; + case DRCTL_MEM_CONFIG_REQUEST: + case DRCTL_MEM_UNCONFIG_REQUEST: + break; default: return (EIO); } @@ -391,12 +394,13 @@ case DRCTL_IO_UNCONFIG_NOTIFY: case DRCTL_IO_CONFIG_REQUEST: case DRCTL_IO_CONFIG_NOTIFY: - rv = 0; - break; case DRCTL_MEM_CONFIG_REQUEST: case DRCTL_MEM_CONFIG_NOTIFY: case DRCTL_MEM_UNCONFIG_REQUEST: case DRCTL_MEM_UNCONFIG_NOTIFY: + rv = 0; + break; + default: rv = ENOTSUP; break; } @@ -555,9 +559,13 @@ break; case DRCTL_MEM_CONFIG_REQUEST: - case DRCTL_MEM_CONFIG_NOTIFY: + notify_cmd = DRCTL_MEM_CONFIG_NOTIFY; + break; + case DRCTL_MEM_UNCONFIG_REQUEST: - case DRCTL_MEM_UNCONFIG_NOTIFY: + notify_cmd = DRCTL_MEM_UNCONFIG_NOTIFY; + break; + default: /* none of the above should have been accepted in _init */ ASSERT(0); @@ -657,6 +665,12 @@ case DRCTL_CPU_UNCONFIG_NOTIFY: *data_size = count * sizeof (drctl_rsrc_t); break; + case DRCTL_MEM_CONFIG_REQUEST: + case DRCTL_MEM_CONFIG_NOTIFY: + case DRCTL_MEM_UNCONFIG_REQUEST: + case DRCTL_MEM_UNCONFIG_NOTIFY: + *data_size = count * sizeof (drctl_rsrc_t); + break; case DRCTL_IO_CONFIG_REQUEST: case DRCTL_IO_CONFIG_NOTIFY: case DRCTL_IO_UNCONFIG_REQUEST:
--- a/usr/src/uts/sun4v/io/mdeg.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/sun4v/io/mdeg.c Mon Jul 20 13:07:46 2009 -0400 @@ -20,12 +20,10 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * MD Event Generator (MDEG) Module */ @@ -885,18 +883,22 @@ static void mdeg_dump_clnt(mdeg_clnt_t *clnt) { - char str[MAX_FIELD_STR]; + char str[MAX_FIELD_STR] = ""; if (!clnt->valid) { MDEG_DBG(" valid=B_FALSE\n"); return; } - mdeg_spec_str(clnt->pspec, str, MAX_FIELD_STR); - MDEG_DBG(" pspecp=%s\n", str); + if (clnt->pspec) { + mdeg_spec_str(clnt->pspec, str, MAX_FIELD_STR); + MDEG_DBG(" pspecp=%s\n", str); + } - mdeg_match_str(clnt->nmatch, str, MAX_FIELD_STR); - MDEG_DBG(" nmatch=%s\n", str); + if (clnt->nmatch) { + mdeg_match_str(clnt->nmatch, str, MAX_FIELD_STR); + MDEG_DBG(" nmatch=%s\n", str); + } } static void
--- a/usr/src/uts/sun4v/os/fillsysinfo.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/sun4v/os/fillsysinfo.c Mon Jul 20 13:07:46 2009 -0400 @@ -75,7 +75,7 @@ static void get_weakest_mem_model(md_t *, mde_cookie_t); static void get_q_sizes(md_t *, mde_cookie_t); static void get_va_bits(md_t *, mde_cookie_t); -static size_t get_ra_limit(md_t *); +static size_t get_ra_limit(md_t *, mde_cookie_t); static int get_l2_cache_node_count(md_t *); static unsigned long names2bits(char *tokens, size_t tokenslen, char *bit_formatter, char *warning); @@ -495,7 +495,7 @@ /* * ra_limit is the highest real address in the machine. */ - ra_limit = get_ra_limit(mdp); + ra_limit = get_ra_limit(mdp, cpulist[0]); md_free_scan_dag(mdp, &cpulist); @@ -808,19 +808,38 @@ return (ul); } - uint64_t -get_ra_limit(md_t *mdp) +get_ra_limit(md_t *mdp, mde_cookie_t cpu_node_cookie) { + extern int ppvm_enable; + extern int meta_alloc_enable; mde_cookie_t *mem_list; mde_cookie_t *mblock_list; int i; int memnodes; int nmblock; + uint64_t r; uint64_t base; uint64_t size; uint64_t ra_limit = 0, new_limit = 0; + if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#ra-bits", &r) == 0) { + if (r == 0 || r > RA_ADDRESS_SPACE_BITS) + cmn_err(CE_PANIC, "Incorrect number of ra bits in MD"); + else { + /* + * Enable memory DR and metadata (page_t) + * allocation from existing memory. + */ + ppvm_enable = 1; + meta_alloc_enable = 1; + return (1ULL << r); + } + } + + cmn_err(CE_WARN, "mmu-#ra-bits property not found in MD"); + cmn_err(CE_WARN, "Memory DR disabled"); + memnodes = md_alloc_scan_dag(mdp, md_root_node(mdp), "memory", "fwd", &mem_list);
--- a/usr/src/uts/sun4v/os/mach_startup.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/sun4v/os/mach_startup.c Mon Jul 20 13:07:46 2009 -0400 @@ -506,6 +506,9 @@ if (modload("misc", "dr_io") == -1) cmn_err(CE_NOTE, "!'dr_io' module failed to load"); + if (modload("misc", "dr_mem") == -1) + cmn_err(CE_NOTE, "!'dr_mem' module failed to load"); + /* * Attempt to attach any virtual device servers. These * drivers must be loaded at start of day so that they
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/sun4v/os/memseg.c Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,410 @@ +/* + * + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <sys/types.h> +#include <sys/cmn_err.h> +#include <sys/vm.h> +#include <sys/mman.h> +#include <vm/vm_dep.h> +#include <vm/seg_kmem.h> +#include <vm/seg_kpm.h> +#include <sys/mem_config.h> +#include <sys/sysmacros.h> + +extern pgcnt_t pp_dummy_npages; +extern pfn_t *pp_dummy_pfn; /* Array of dummy pfns. */ + +extern kmutex_t memseg_lists_lock; +extern struct memseg *memseg_va_avail; +extern struct memseg *memseg_alloc(); + +extern page_t *ppvm_base; +extern pgcnt_t ppvm_size; + +static vnode_t pp_vn, rsv_vn; +static pgcnt_t rsv_metapgs; +static int meta_rsv_enable; +static int sun4v_memseg_debug; + +extern struct memseg *memseg_reuse(pgcnt_t); +extern void remap_to_dummy(caddr_t, pgcnt_t); + +/* + * The page_t memory for incoming pages is allocated from existing memory + * which can create a potential situation where memory addition fails + * because of shortage of existing memory. To mitigate this situation + * some memory is always reserved ahead of time for page_t allocation. + * Each 4MB of reserved page_t's guarantees a 256MB (x64) addition without + * page_t allocation. The added 256MB added memory could theoretically + * allow an addition of 16GB. + */ +#define RSV_SIZE 0x40000000 /* add size with rsrvd page_t's 1G */ + +#ifdef DEBUG +#define MEMSEG_DEBUG(args...) if (sun4v_memseg_debug) printf(args) +#else +#define MEMSEG_DEBUG(...) +#endif + +/* + * The page_t's for the incoming memory are allocated from + * existing pages. + */ +/*ARGSUSED*/ +int +memseg_alloc_meta(pfn_t base, pgcnt_t npgs, void **ptp, pgcnt_t *metap) +{ + page_t *pp, *opp, *epp, *pgpp; + pgcnt_t metapgs; + int i, rsv; + struct seg kseg; + caddr_t vaddr; + u_offset_t off; + + /* + * Verify incoming memory is within supported DR range. + */ + if ((base + npgs) * sizeof (page_t) > ppvm_size) + return (KPHYSM_ENOTSUP); + + opp = pp = ppvm_base + base; + epp = pp + npgs; + metapgs = btopr(npgs * sizeof (page_t)); + + if (!IS_P2ALIGNED((uint64_t)pp, PAGESIZE) && + page_find(&pp_vn, (u_offset_t)pp)) { + /* + * Another memseg has page_t's in the same + * page which 'pp' resides. This would happen + * if PAGESIZE is not an integral multiple of + * sizeof (page_t) and therefore 'pp' + * does not start on a page boundry. + * + * Since the other memseg's pages_t's still + * map valid pages, skip allocation of this page. + * Advance 'pp' to the next page which should + * belong only to the incoming memseg. + * + * If the last page_t in the current page + * crosses a page boundary, this should still + * work. The first part of the page_t is + * already allocated. The second part of + * the page_t will be allocated below. + */ + ASSERT(PAGESIZE % sizeof (page_t)); + pp = (page_t *)P2ROUNDUP((uint64_t)pp, PAGESIZE); + metapgs--; + } + + if (!IS_P2ALIGNED((uint64_t)epp, PAGESIZE) && + page_find(&pp_vn, (u_offset_t)epp)) { + /* + * Another memseg has page_t's in the same + * page which 'epp' resides. This would happen + * if PAGESIZE is not an integral multiple of + * sizeof (page_t) and therefore 'epp' + * does not start on a page boundry. + * + * Since the other memseg's pages_t's still + * map valid pages, skip allocation of this page. + */ + ASSERT(PAGESIZE % sizeof (page_t)); + metapgs--; + } + + ASSERT(IS_P2ALIGNED((uint64_t)pp, PAGESIZE)); + + /* + * Back metadata space with physical pages. + */ + kseg.s_as = &kas; + vaddr = (caddr_t)pp; + + for (i = 0; i < metapgs; i++) + if (page_find(&pp_vn, (u_offset_t)(vaddr + i * PAGESIZE))) + panic("page_find(0x%p, %p)\n", + (void *)&pp_vn, (void *)(vaddr + i * PAGESIZE)); + + /* + * Allocate the metadata pages; these are the pages that will + * contain the page_t's for the incoming memory. + * + * If a normal allocation fails, use the reserved metapgs for + * a small allocation; otherwise retry with PG_WAIT. + */ + rsv = off = 0; + if (metapgs <= rsv_metapgs) { + MEMSEG_DEBUG("memseg_get: use rsv 0x%lx metapgs", metapgs); + ASSERT(meta_rsv_enable); + rsv = 1; + } else if ((pgpp = page_create_va(&pp_vn, (u_offset_t)pp, ptob(metapgs), + PG_NORELOC | PG_EXCL, &kseg, vaddr)) == NULL) { + cmn_err(CE_WARN, "memseg_get: can't get 0x%ld metapgs", + metapgs); + return (KPHYSM_ERESOURCE); + } + if (rsv) { + /* + * The reseve pages must be hashed out of the reserve vnode + * and rehashed by <pp_vn,vaddr>. The resreved pages also + * must be replenished immedidately at the end of the add + * processing. + */ + for (i = 0; i < metapgs; i++) { + pgpp = page_find(&rsv_vn, off); + ASSERT(pgpp); + page_hashout(pgpp, 0); + hat_devload(kas.a_hat, vaddr, PAGESIZE, + page_pptonum(pgpp), PROT_READ | PROT_WRITE, + HAT_LOAD | HAT_LOAD_REMAP | HAT_LOAD_NOCONSIST); + ASSERT(!page_find(&pp_vn, (u_offset_t)vaddr)); + if (!page_hashin(pgpp, &pp_vn, (u_offset_t)vaddr, 0)) + panic("memseg_get: page_hashin(0x%p, 0x%p)", + (void *)pgpp, (void *)vaddr); + off += PAGESIZE; + vaddr += PAGESIZE; + rsv_metapgs--; + } + } else { + for (i = 0; i < metapgs; i++) { + hat_devload(kas.a_hat, vaddr, PAGESIZE, + page_pptonum(pgpp), PROT_READ | PROT_WRITE, + HAT_LOAD | HAT_LOAD_REMAP | HAT_LOAD_NOCONSIST); + pgpp = pgpp->p_next; + vaddr += PAGESIZE; + } + } + + ASSERT(ptp); + ASSERT(metap); + + *ptp = (void *)opp; + *metap = metapgs; + + return (KPHYSM_OK); +} + +void +memseg_free_meta(void *ptp, pgcnt_t metapgs) +{ + int i; + page_t *pp; + u_offset_t off; + + if (!metapgs) + return; + + off = (u_offset_t)ptp; + + ASSERT(off); + ASSERT(IS_P2ALIGNED((uint64_t)off, PAGESIZE)); + + MEMSEG_DEBUG("memseg_free_meta: off=0x%lx metapgs=0x%lx\n", + (uint64_t)off, metapgs); + /* + * Free pages allocated during add. + */ + for (i = 0; i < metapgs; i++) { + pp = page_find(&pp_vn, off); + ASSERT(pp); + ASSERT(pp->p_szc == 0); + page_io_unlock(pp); + page_destroy(pp, 0); + off += PAGESIZE; + } +} + +pfn_t +memseg_get_metapfn(void *ptp, pgcnt_t metapg) +{ + page_t *pp; + u_offset_t off; + + off = (u_offset_t)ptp + ptob(metapg); + + ASSERT(off); + ASSERT(IS_P2ALIGNED((uint64_t)off, PAGESIZE)); + + pp = page_find(&pp_vn, off); + ASSERT(pp); + ASSERT(pp->p_szc == 0); + ASSERT(pp->p_pagenum != PFN_INVALID); + + return (pp->p_pagenum); +} + +/* + * Remap a memseg's page_t's to dummy pages. Skip the low/high + * ends of the range if they are already in use. + */ +void +memseg_remap_meta(struct memseg *seg) +{ + int i; + u_offset_t off; + page_t *pp; +#if 0 + page_t *epp; +#endif + pgcnt_t metapgs; + + metapgs = btopr(MSEG_NPAGES(seg) * sizeof (page_t)); + ASSERT(metapgs); + pp = seg->pages; + seg->pages_end = seg->pages_base; +#if 0 + epp = seg->epages; + + /* + * This code cannot be tested as the kernel does not compile + * when page_t size is changed. It is left here as a starting + * point if the unaligned page_t size needs to be supported. + */ + + if (!IS_P2ALIGNED((uint64_t)pp, PAGESIZE) && + page_find(&pp_vn, (u_offset_t)(pp - 1)) && !page_deleted(pp - 1)) { + /* + * Another memseg has page_t's in the same + * page which 'pp' resides. This would happen + * if PAGESIZE is not an integral multiple of + * sizeof (page_t) and therefore 'seg->pages' + * does not start on a page boundry. + * + * Since the other memseg's pages_t's still + * map valid pages, skip remap of this page. + * Advance 'pp' to the next page which should + * belong only to the outgoing memseg. + * + * If the last page_t in the current page + * crosses a page boundary, this should still + * work. The first part of the page_t is + * valid since memseg_lock_delete_all() has + * been called. The second part of the page_t + * will be remapped to the corresponding + * dummy page below. + */ + ASSERT(PAGESIZE % sizeof (page_t)); + pp = (page_t *)P2ROUNDUP((uint64_t)pp, PAGESIZE); + metapgs--; + } + + if (!IS_P2ALIGNED((uint64_t)epp, PAGESIZE) && + page_find(&pp_vn, (u_offset_t)epp) && !page_deleted(epp)) { + /* + * Another memseg has page_t's in the same + * page which 'epp' resides. This would happen + * if PAGESIZE is not an integral multiple of + * sizeof (page_t) and therefore 'seg->epages' + * does not start on a page boundry. + * + * Since the other memseg's pages_t's still + * map valid pages, skip remap of this page. + */ + ASSERT(PAGESIZE % sizeof (page_t)); + metapgs--; + } +#endif + ASSERT(IS_P2ALIGNED((uint64_t)pp, PAGESIZE)); + + remap_to_dummy((caddr_t)pp, metapgs); + + off = (u_offset_t)pp; + + MEMSEG_DEBUG("memseg_remap: off=0x%lx metapgs=0x%lx\n", (uint64_t)off, + metapgs); + /* + * Free pages allocated during add. + */ + for (i = 0; i < metapgs; i++) { + pp = page_find(&pp_vn, off); + ASSERT(pp); + ASSERT(pp->p_szc == 0); + page_io_unlock(pp); + page_destroy(pp, 0); + off += PAGESIZE; + } +} + +static void +rsv_alloc() +{ + int i; + page_t *pp; + pgcnt_t metapgs; + u_offset_t off; + struct seg kseg; + + kseg.s_as = &kas; + + /* + * Reserve enough page_t pages for an add request of + * RSV_SIZE bytes. + */ + metapgs = btopr(btop(RSV_SIZE) * sizeof (page_t)) - rsv_metapgs; + + for (i = off = 0; i < metapgs; i++, off += PAGESIZE) { + (void) page_create_va(&rsv_vn, off, PAGESIZE, + PG_NORELOC | PG_WAIT, &kseg, 0); + pp = page_find(&rsv_vn, off); + ASSERT(pp); + ASSERT(PAGE_EXCL(pp)); + page_iolock_init(pp); + rsv_metapgs++; + } +} + +void +i_dr_mem_init(size_t *hint) +{ + if (meta_rsv_enable) { + rsv_alloc(); + if (hint) + *hint = RSV_SIZE; + } +} + +void +i_dr_mem_fini() +{ + int i; + page_t *pp; + u_offset_t off; + + for (i = off = 0; i < rsv_metapgs; i++, off += PAGESIZE) { + if (pp = page_find(&rsv_vn, off)) { + ASSERT(PAGE_EXCL(pp)); + page_destroy(pp, 0); + } + ASSERT(!page_find(&rsv_vn, off)); + } + rsv_metapgs = 0; +} + +void +i_dr_mem_update() +{ + rsv_alloc(); +}
--- a/usr/src/uts/sun4v/os/mpo.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/sun4v/os/mpo.c Mon Jul 20 13:07:46 2009 -0400 @@ -20,12 +20,10 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <sys/sysmacros.h> #include <sys/machsystm.h> @@ -36,6 +34,7 @@ #include <sys/memnode.h> #include <sys/mdesc.h> #include <sys/mpo.h> +#include <vm/page.h> #include <vm/vm_dep.h> #include <vm/hat_sfmmu.h> #include <sys/promif.h> @@ -91,6 +90,45 @@ * * plat_mem_node_intersect_range() * Find the intersection with a mem_node. + * + * plat_slice_add() + * plat_slice_del() + * Platform hooks to add/delete a pfn range. + * + * Internal Organization + * --------------------- + * + * A number of routines are used both boot/DR code which (re)build + * appropriate MPO structures. + * + * mblock_alloc() + * Allocate memory for mblocks and stripes as + * appropriate for boot or memory DR. + * + * mblock_free() + * Free memory allocated by mblock_alloc. + * + * mblock_update() + * Build mblocks based on mblock nodes read from the MD. + * + * mblock_update_add() + * Rebuild mblocks after a memory DR add operation. + * + * mblock_update_del() + * Rebuild mblocks after a memory DR delete operation. + * + * mblock_install() + * Install mblocks as the new configuration. + * + * mstripe_update() + * Build stripes based on mblocks. + * + * mnode_update() + * Call memnode layer to add/del a pfn range, based on stripes. + * + * The platform interfaces allocate all memory required for the + * particualar update first, block access to the MPO structures + * while they are updated, and free old structures after the update. */ int sun4v_mpo_enable = 1; @@ -106,6 +144,7 @@ static int n_lgrpnodes = 0; static int n_locality_groups = 0; static int max_locality_groups = 0; +static int szc_mask0 = 0; /* Save mblocks from the MD */ #define SMALL_MBLOCKS_COUNT 8 @@ -116,7 +155,6 @@ /* Save mem_node stripes calculate from mblocks and lgroups. */ static mem_stripe_t *mem_stripes; static mem_stripe_t small_mem_stripes[SMALL_MBLOCKS_COUNT * MAX_MEM_NODES]; -static int mstripesz = 0; static int n_mem_stripes = 0; static pfn_t mnode_stride; /* distance between stripes, start to start */ static int stripe_shift; /* stride/stripes expressed as a shift */ @@ -133,15 +171,33 @@ static int higher_latency = 0; static pfn_t base_ra_to_pa_pfn = 0; /* ra_to_pa for single mblock memory */ +static int mpo_genid; /* config gen; updated by mem DR */ +static mpo_config_t mpo_config; /* current mblocks and stripes */ + +typedef enum { U_ADD, U_ADD_ALL, U_DEL } update_t; static int valid_pages(md_t *md, mde_cookie_t cpu0); static int unique_home_mem_lg_count(uint64_t mem_lg_homeset); static int fix_interleave(void); +static int mblock_alloc(mpo_config_t *, update_t, int nmblocks); +static void mblock_install(mpo_config_t *); +static void mblock_free(mpo_config_t *); +static void mblock_update(mpo_config_t *, md_t, mde_cookie_t *mblocknodes); +static void mblock_update_add(mpo_config_t *); +static void mblock_update_del(mpo_config_t *, mpo_config_t *, pfn_t, pfn_t); +static void mstripe_update(mpo_config_t *); +static void mnode_update(mpo_config_t *, pfn_t, pfn_t, update_t); + /* Debug support */ #if defined(DEBUG) && !defined(lint) +#define VALIDATE_SLICE(base, end) { \ + ASSERT(IS_P2ALIGNED(ptob(base), TTEBYTES(TTE256M))); \ + ASSERT(IS_P2ALIGNED(ptob(end - base + 1), TTEBYTES(TTE256M))); \ +} #define MPO_DEBUG(args...) if (sun4v_mpo_debug) printf(args) #else +#define VALIDATE_SLICE(base, end) #define MPO_DEBUG(...) #endif /* DEBUG */ @@ -152,6 +208,31 @@ } /* + * The MPO locks are to protect the MPO metadata while that + * information is updated as a result of a memory DR operation. + * The read lock must be acquired to read the metadata and the + * write locks must be acquired to update it. + */ +#define mpo_rd_lock kpreempt_disable +#define mpo_rd_unlock kpreempt_enable + +static void +mpo_wr_lock() +{ + mutex_enter(&cpu_lock); + pause_cpus(NULL); + mutex_exit(&cpu_lock); +} + +static void +mpo_wr_unlock() +{ + mutex_enter(&cpu_lock); + start_cpus(); + mutex_exit(&cpu_lock); +} + +/* * Routine to read a uint64_t from a given md */ static int64_t @@ -350,204 +431,51 @@ mpo_update_tunables(); } -/* - * - * Traverse the MD to determine: - * - * Number of CPU nodes, lgrp_nodes, and mblocks - * Then for each lgrp_node, obtain the appropriate data. - * For each CPU, determine its home locality and store it. - * For each mblock, retrieve its data and store it. - */ -static int -lgrp_traverse(md_t *md) +static mde_cookie_t +md_get_root(md_t *md) { - mde_cookie_t root, *cpunodes, *lgrpnodes, *nodes, *mblocknodes; - uint64_t i, j, k, o, n_nodes; - uint64_t mem_lg_homeset = 0; - int ret_val = 0; - int result = 0; - int n_cpunodes = 0; - int sub_page_fix; - int mblocksz = 0; - size_t allocsz; + mde_cookie_t root = MDE_INVAL_ELEM_COOKIE; + int n_nodes; n_nodes = md_node_count(md); if (n_nodes <= 0) { - MPO_STATUS("lgrp_traverse: No nodes in node count\n"); - ret_val = -1; - goto fail; + MPO_STATUS("md_get_root: No nodes in node count\n"); + return (root); } root = md_root_node(md); if (root == MDE_INVAL_ELEM_COOKIE) { - MPO_STATUS("lgrp_traverse: Root node is missing\n"); - ret_val = -1; - goto fail; + MPO_STATUS("md_get_root: Root node is missing\n"); + return (root); } - /* - * Build the Memory Nodes. Do this before any possibility of - * bailing from this routine so we obtain ra_to_pa (needed for page - * coloring) even when there are no lgroups defined. - */ - - n_mblocks = md_alloc_scan_dag(md, root, PROP_LG_MBLOCK, - "fwd", &mblocknodes); - - if (n_mblocks <= 0) { - MPO_STATUS("lgrp_traverse: No mblock " - "nodes detected in Machine Descriptor\n"); - n_mblocks = 0; - ret_val = -1; - goto fail; - } - /* - * If we have a small number of mblocks we will use the space - * that we preallocated. Otherwise, we will dynamically - * allocate the space - */ - mblocksz = n_mblocks * sizeof (struct mblock_md); - mstripesz = MAX_MEM_NODES * n_mblocks * sizeof (mem_stripe_t); - - if (n_mblocks <= SMALL_MBLOCKS_COUNT) { - mpo_mblock = &small_mpo_mblocks[0]; - mem_stripes = &small_mem_stripes[0]; - } else { - allocsz = mmu_ptob(mmu_btopr(mblocksz + mstripesz)); - /* Ensure that we dont request more space than reserved */ - if (allocsz > MPOBUF_SIZE) { - MPO_STATUS("lgrp_traverse: Insufficient space " - "for mblock structures \n"); - ret_val = -1; - n_mblocks = 0; - goto fail; - } - mpo_mblock = (struct mblock_md *) - prom_alloc((caddr_t)MPOBUF_BASE, allocsz, PAGESIZE); - if (mpo_mblock != (struct mblock_md *)MPOBUF_BASE) { - MPO_STATUS("lgrp_traverse: Cannot allocate space " - "for mblocks \n"); - ret_val = -1; - n_mblocks = 0; - goto fail; - } - mpo_heap32_buf = (caddr_t)MPOBUF_BASE; - mpo_heap32_bufsz = MPOBUF_SIZE; - - mem_stripes = (mem_stripe_t *)(mpo_mblock + n_mblocks); - } - for (i = 0, j = 0; j < n_mblocks; j++) { - mpo_mblock[i].node = mblocknodes[j]; - - /* Without a base or size value we will fail */ - result = get_int(md, mblocknodes[j], PROP_LG_BASE, - &mpo_mblock[i].base); - if (result < 0) { - MPO_STATUS("lgrp_traverse: " - "PROP_LG_BASE is missing\n"); - n_mblocks = 0; - ret_val = -1; - goto fail; - } + MPO_DEBUG("md_get_root: Node Count: %d\n", n_nodes); + MPO_DEBUG("md_get_root: md: %p\n", md); + MPO_DEBUG("md_get_root: root: %lx\n", root); +done: + return (root); +} - result = get_int(md, mblocknodes[j], PROP_LG_SIZE, - &mpo_mblock[i].size); - if (result < 0) { - MPO_STATUS("lgrp_traverse: " - "PROP_LG_SIZE is missing\n"); - n_mblocks = 0; - ret_val = -1; - goto fail; - } - - result = get_int(md, mblocknodes[j], - PROP_LG_RA_PA_OFFSET, &mpo_mblock[i].ra_to_pa); - - /* If we don't have an ra_pa_offset, just set it to 0 */ - if (result < 0) - mpo_mblock[i].ra_to_pa = 0; - - MPO_DEBUG("mblock[%ld]: base = %lx, size = %lx, " - "ra_to_pa = %lx\n", i, - mpo_mblock[i].base, - mpo_mblock[i].size, - mpo_mblock[i].ra_to_pa); - - /* check for unsupportable values of base and size */ - if (mpo_mblock[i].base > - mpo_mblock[i].base + mpo_mblock[i].size) { - MPO_STATUS("lgrp_traverse: " - "PROP_LG_BASE+PROP_LG_SIZE is invalid: " - "base = %lx, size = %lx", - mpo_mblock[i].base, mpo_mblock[i].size); - n_mblocks = 0; - ret_val = -1; - goto fail; - } - - /* eliminate size==0 blocks */ - if (mpo_mblock[i].size != 0) { - i++; - } - } - - if (i == 0) { - MPO_STATUS("lgrp_traverse: " - "No non-empty mblock nodes were found " - "in the Machine Descriptor\n"); - n_mblocks = 0; - ret_val = -1; - goto fail; - } - ASSERT(i <= n_mblocks); - n_mblocks = i; - - /* Must sort mblocks by address for mem_node_iterator_init() */ - mblock_sort(mpo_mblock, n_mblocks); - - base_ra_to_pa_pfn = btop(mpo_mblock[0].ra_to_pa); - - /* Page coloring hook is required so we can iterate through mnodes */ - if (&page_next_pfn_for_color_cpu == NULL) { - MPO_STATUS("lgrp_traverse: No page coloring support\n"); - ret_val = -1; - goto fail; - } - - /* Global enable for mpo */ - if (sun4v_mpo_enable == 0) { - MPO_STATUS("lgrp_traverse: MPO feature is not enabled\n"); - ret_val = -1; - goto fail; - } +static int +lgrp_update(md_t *md, mde_cookie_t root) +{ + int i, j, result; + int ret_val = 0; + int sub_page_fix; + mde_cookie_t *nodes, *lgrpnodes; n_lgrpnodes = md_alloc_scan_dag(md, root, PROP_LG_MEM_LG, "fwd", &lgrpnodes); if (n_lgrpnodes <= 0 || n_lgrpnodes >= MAX_MD_LGROUPS) { - MPO_STATUS("lgrp_traverse: No Lgroups\n"); + MPO_STATUS("lgrp_update: No Lgroups\n"); ret_val = -1; goto fail; } - n_cpunodes = md_alloc_scan_dag(md, root, PROP_LG_CPU, "fwd", &cpunodes); - - if (n_cpunodes <= 0 || n_cpunodes > NCPU) { - MPO_STATUS("lgrp_traverse: No CPU nodes detected " - "in MD\n"); - ret_val = -1; - goto fail; - } - - MPO_DEBUG("lgrp_traverse: Node Count: %ld\n", n_nodes); - MPO_DEBUG("lgrp_traverse: md: %p\n", md); - MPO_DEBUG("lgrp_traverse: root: %lx\n", root); - MPO_DEBUG("lgrp_traverse: mem_lgs: %d\n", n_lgrpnodes); - MPO_DEBUG("lgrp_traverse: cpus: %d\n", n_cpunodes); - MPO_DEBUG("lgrp_traverse: mblocks: %d\n", n_mblocks); + MPO_DEBUG("lgrp_update: mem_lgs: %d\n", n_lgrpnodes); for (i = 0; i < n_lgrpnodes; i++) { mpo_lgroup[i].node = lgrpnodes[i]; @@ -590,7 +518,7 @@ for (i = 0; i < n_lgrpnodes; i++) { if (mpo_lgroup[0].addr_mask != mpo_lgroup[i].addr_mask) { - MPO_STATUS("lgrp_traverse: " + MPO_STATUS("lgrp_update: " "addr_mask values are not the same\n"); ret_val = -1; goto fail; @@ -609,13 +537,98 @@ PROP_LG_MBLOCK, "fwd", &nodes); md_free_scan_dag(md, &nodes); if (j != n_mblocks) { - MPO_STATUS("lgrp_traverse: " + MPO_STATUS("lgrp_update: " "sub-page interleave is being fixed\n"); ret_val = -1; goto fail; } } } +fail: + if (n_lgrpnodes > 0) { + md_free_scan_dag(md, &lgrpnodes); + for (i = 0; i < n_lgrpnodes; i++) + mpo_lgroup[i].node = MDE_INVAL_ELEM_COOKIE; + } + + return (ret_val); +} + +/* + * + * Traverse the MD to determine: + * + * Number of CPU nodes, lgrp_nodes, and mblocks + * Then for each lgrp_node, obtain the appropriate data. + * For each CPU, determine its home locality and store it. + * For each mblock, retrieve its data and store it. + */ +static int +lgrp_traverse(md_t *md) +{ + mde_cookie_t root, *cpunodes, *mblocknodes; + int o; + uint64_t i, k, stripe, stride; + uint64_t mem_lg_homeset = 0; + int ret_val = 0; + int result = 0; + int n_cpunodes = 0; + mpo_config_t new_config; + + if ((root = md_get_root(md)) == MDE_INVAL_ELEM_COOKIE) { + ret_val = -1; + goto fail; + } + + n_mblocks = md_alloc_scan_dag(md, root, PROP_LG_MBLOCK, "fwd", + &mblocknodes); + if (n_mblocks <= 0) { + MPO_STATUS("lgrp_traverse: No mblock nodes detected in Machine " + "Descriptor\n"); + ret_val = -1; + goto fail; + } + + /* + * Build the Memory Nodes. Do this before any possibility of + * bailing from this routine so we obtain ra_to_pa (needed for page + * coloring) even when there are no lgroups defined. + */ + if (mblock_alloc(&new_config, U_ADD_ALL, n_mblocks) < 0) { + ret_val = -1; + goto fail; + } + + mblock_update(&new_config, md, mblocknodes); + mblock_install(&new_config); + + /* Page coloring hook is required so we can iterate through mnodes */ + if (&page_next_pfn_for_color_cpu == NULL) { + MPO_STATUS("lgrp_traverse: No page coloring support\n"); + ret_val = -1; + goto fail; + } + + /* Global enable for mpo */ + if (sun4v_mpo_enable == 0) { + MPO_STATUS("lgrp_traverse: MPO feature is not enabled\n"); + ret_val = -1; + goto fail; + } + + n_cpunodes = md_alloc_scan_dag(md, root, PROP_LG_CPU, "fwd", &cpunodes); + + if (n_cpunodes <= 0 || n_cpunodes > NCPU) { + MPO_STATUS("lgrp_traverse: No CPU nodes detected " + "in MD\n"); + ret_val = -1; + goto fail; + } + + MPO_DEBUG("lgrp_traverse: cpus: %d\n", n_cpunodes); + + if ((ret_val = lgrp_update(md, root)) == -1) + goto fail; /* * Use the address mask from the first lgroup node @@ -634,6 +647,11 @@ max_locality_groups = 1 << highbit(home_mask_pfn >> home_mask_pfn_shift); + stripe_shift = highbit(max_locality_groups) - 1; + stripe = ptob(mnode_pages); + stride = max_locality_groups * stripe; + mnode_stride = btop(stride); + /* Now verify the home mask bits are contiguous */ if (max_locality_groups - 1 != home_mask_pfn >> home_mask_pfn_shift) { @@ -721,23 +739,17 @@ } fail: - /* MD cookies are no longer valid; ensure they are not used again. */ - for (i = 0; i < n_mblocks; i++) - mpo_mblock[i].node = MDE_INVAL_ELEM_COOKIE; - for (i = 0; i < n_lgrpnodes; i++) - mpo_lgroup[i].node = MDE_INVAL_ELEM_COOKIE; - if (n_cpunodes > 0) md_free_scan_dag(md, &cpunodes); - if (n_lgrpnodes > 0) - md_free_scan_dag(md, &lgrpnodes); if (n_mblocks > 0) md_free_scan_dag(md, &mblocknodes); else panic("lgrp_traverse: No memory blocks found"); - if (ret_val == 0) + if (ret_val == 0) { MPO_STATUS("MPO feature is enabled.\n"); + } else + sun4v_mpo_enable = 0; /* set this for DR */ return (ret_val); } @@ -843,13 +855,26 @@ mem_node_add_slice(basepfn, endpfn); } +static void +mpo_mem_node_del_slice(pfn_t basepfn, pfn_t endpfn) +{ +#if defined(DEBUG) && !defined(lint) + static int slice_count = 0; + + slice_count++; + MPO_DEBUG("mem_del_slice(%d): basepfn: %lx endpfn: %lx\n", + slice_count, basepfn, endpfn); +#endif + mem_node_del_slice(basepfn, endpfn); +} + /* * Helper routine for debugging calls to plat_assign_lgrphand_to_mem_node() */ static void mpo_plat_assign_lgrphand_to_mem_node(lgrp_handle_t plathand, int mnode) { - MPO_DEBUG("plat_assign_to_mem_nodes: lgroup home %ld," + MPO_DEBUG("plat_assign_to_mem_nodes: lgroup home %ld, " "mnode index: %d\n", plathand, mnode); plat_assign_lgrphand_to_mem_node(plathand, mnode); } @@ -901,22 +926,20 @@ * mblock 0 mblock 1 */ +/*ARGSUSED*/ void plat_build_mem_nodes(prom_memlist_t *list, size_t nelems) { - lgrp_handle_t lgrphand, lgrp_start; - int i, mnode, elem; - uint64_t offset, stripe_end, base, len, end, ra_to_pa, stride; - uint64_t stripe, frag, remove; - mem_stripe_t *ms; + int elem; + uint64_t base, len; /* Pre-reserve space for plat_assign_lgrphand_to_mem_node */ max_mem_nodes = max_locality_groups; + mstripe_update(&mpo_config); + /* Check for non-MPO sun4v platforms */ if (n_locality_groups <= 1) { - ASSERT(n_locality_groups == 1); - ASSERT(max_locality_groups == 1 && max_mem_nodes == 1); mpo_plat_assign_lgrphand_to_mem_node(LGRP_DEFAULT_HANDLE, 0); for (elem = 0; elem < nelems; list++, elem++) { base = list->addr; @@ -927,105 +950,8 @@ } mem_node_pfn_shift = 0; mem_node_physalign = 0; - - if (n_mblocks == 1) { - n_mem_stripes = 0; - } else { - n_mem_stripes = n_mblocks; - bzero(mem_stripes, mstripesz); - for (i = 0; i < n_mblocks; i++) { - base = mpo_mblock[i].base; - end = base + mpo_mblock[i].size; - ASSERT(end > base); - mem_stripes[i].exists = 1; - mpo_mblock[i].base_pfn = btop(base); - mpo_mblock[i].end_pfn = btop(end - 1); - mem_stripes[i].physbase = - mpo_mblock[i].base_pfn; - mem_stripes[i].physmax = mpo_mblock[i].end_pfn; - } - } - return; - } - - bzero(mem_stripes, mstripesz); - stripe = ptob(mnode_pages); - stride = max_locality_groups * stripe; - - /* Save commonly used values in globals */ - mnode_stride = btop(stride); - n_mem_stripes = max_locality_groups * n_mblocks; - stripe_shift = highbit(max_locality_groups) - 1; - - for (i = 0; i < n_mblocks; i++) { - base = mpo_mblock[i].base; - end = mpo_mblock[i].base + mpo_mblock[i].size; - ra_to_pa = mpo_mblock[i].ra_to_pa; - mpo_mblock[i].base_pfn = btop(base); - mpo_mblock[i].end_pfn = btop(end - 1); - - /* Find the offset from the prev stripe boundary in PA space. */ - offset = (base + ra_to_pa) & (stripe - 1); - - /* Set the next stripe boundary. */ - stripe_end = base - offset + stripe; - - lgrp_start = (((base + ra_to_pa) & home_mask) >> - home_mask_shift); - lgrphand = lgrp_start; - - /* - * Loop over all lgroups covered by the mblock, creating a - * stripe for each. Stop when lgrp_start is visited again. - */ - do { - /* mblock may not span all lgroups */ - if (base >= end) - break; - - mnode = lgrphand; - ASSERT(mnode < max_mem_nodes); - - /* - * Calculate the size of the fragment that does not - * belong to the mnode in the last partial stride. - */ - frag = (end - (base - offset)) & (stride - 1); - if (frag == 0) { - /* remove the gap */ - remove = stride - stripe; - } else if (frag < stripe) { - /* fragment fits in stripe; keep it all */ - remove = 0; - } else { - /* fragment is large; trim after whole stripe */ - remove = frag - stripe; - } - - ms = &mem_stripes[i * max_locality_groups + mnode]; - ms->physbase = btop(base); - ms->physmax = btop(end - 1 - remove); - ms->offset = btop(offset); - ms->exists = 1; - - /* - * If we have only 1 lgroup and multiple mblocks, - * then we have already established our lgrp handle - * to mem_node and mem_node_config values above. - */ - if (n_locality_groups > 1) { - mpo_plat_assign_lgrphand_to_mem_node(lgrphand, - mnode); - mpo_mem_node_add_slice(ms->physbase, - ms->physmax); - } - base = stripe_end; - stripe_end += stripe; - offset = 0; - lgrphand = (((base + ra_to_pa) & home_mask) >> - home_mask_shift); - } while (lgrphand != lgrp_start); - } + } else + mnode_update(&mpo_config, 0, 0, U_ADD_ALL); /* * Indicate to vm_pagelist that the hpm_counters array @@ -1042,11 +968,17 @@ lgrp_handle_t plat_lgrp_cpu_to_hand(processorid_t id) { + lgrp_handle_t lgrphand; + + mpo_rd_lock(); if (n_locality_groups > 1) { - return ((lgrp_handle_t)mpo_cpu[(int)id].home); + lgrphand = (lgrp_handle_t)mpo_cpu[(int)id].home; } else { - return ((lgrp_handle_t)LGRP_DEFAULT_HANDLE); /* Default */ + lgrphand = (lgrp_handle_t)LGRP_DEFAULT_HANDLE; /* Default */ } + mpo_rd_unlock(); + + return (lgrphand); } int @@ -1081,6 +1013,7 @@ * the pfn falls to get the ra_to_pa adjustment, and extract * the home bits. */ + mpo_rd_lock(); mb = &mpo_mblock[0]; for (i = 0; i < n_mblocks; i++) { if (pfn >= mb->base_pfn && pfn <= mb->end_pfn) { @@ -1088,6 +1021,7 @@ mnode = (((pfn + ra_to_pa_pfn) & home_mask_pfn) >> home_mask_pfn_shift); ASSERT(mnode < max_mem_nodes); + mpo_rd_unlock(); return (mnode); } mb++; @@ -1119,9 +1053,11 @@ * Find the mblock in which the pfn falls * in order to get the ra_to_pa adjustment. */ + mpo_rd_lock(); for (mb = &mpo_mblock[0], i = 0; i < n_mblocks; i++, mb++) { if (pfn <= mb->end_pfn && pfn >= mb->base_pfn) { ra_to_pa_pfn = btop(mb->ra_to_pa); + mpo_rd_unlock(); return (pfn + ra_to_pa_pfn); } } @@ -1160,6 +1096,11 @@ * When the caller calculates a pfn that is greater than the * returned value it->mi_mblock_end, the caller should again * call plat_mem_node_iterator_init, passing init=0. + * + * The last mblock in continuation case may be invalid because + * of memory DR. To detect this situation mi_genid is checked + * against mpo_genid which is incremented after a memory DR + * operation. See also plat_slice_add()/plat_slice_del(). */ pfn_t plat_mem_node_iterator_init(pfn_t pfn, int mnode, uchar_t szc, @@ -1177,15 +1118,20 @@ ASSERT(n_mblocks > 0); ASSERT(P2PHASE(pfn, szcpgcnt) == 0); - if (init) { + mpo_rd_lock(); + + if (init || (it->mi_genid != mpo_genid)) { + it->mi_genid = mpo_genid; it->mi_last_mblock = 0; it->mi_init = 1; } /* Check if mpo is not enabled and we only have one mblock */ if (n_locality_groups == 1 && n_mblocks == 1) { - if (P2PHASE(base_ra_to_pa_pfn, szcpgcnt)) - return ((pfn_t)-1); + if (P2PHASE(base_ra_to_pa_pfn, szcpgcnt)) { + pfn = (pfn_t)-1; + goto done; + } it->mi_mnode = mnode; it->mi_ra_to_pa = base_ra_to_pa_pfn; it->mi_mnode_pfn_mask = 0; @@ -1197,7 +1143,7 @@ pfn = P2ROUNDUP(it->mi_mblock_base, szcpgcnt); if ((pfn + szcpgcnt - 1) > it->mi_mblock_end) pfn = (pfn_t)-1; - return (pfn); + goto done; } /* init=1 means begin iterator, init=0 means continue */ @@ -1208,8 +1154,10 @@ i = it->mi_last_mblock; ASSERT(pfn > mem_stripes[i * max_locality_groups + mnode].physmax); - if (++i == n_mblocks) - return ((pfn_t)-1); + if (++i == n_mblocks) { + pfn = (pfn_t)-1; + goto done; + } } /* @@ -1229,7 +1177,8 @@ } if (i == n_mblocks) { it->mi_last_mblock = i - 1; - return ((pfn_t)-1); + pfn = (pfn_t)-1; + goto done; } it->mi_last_mblock = i; @@ -1250,6 +1199,8 @@ ASSERT(pfn + szcpgcnt - 1 <= end); } ASSERT((pfn + szcpgcnt - 1) <= mpo_mblock[i].end_pfn); +done: + mpo_rd_unlock(); return (pfn); } @@ -1300,6 +1251,7 @@ * multiply by stripe width, and add the start and end fragments. */ + mpo_rd_lock(); for (i = mnode; i < n_mem_stripes; i += max_locality_groups) { ms = &mem_stripes[i]; if (ms->exists && @@ -1357,6 +1309,7 @@ } *npages_out = npages; + mpo_rd_unlock(); } /* @@ -1384,9 +1337,15 @@ * to get a sane mask. */ - if (md_get_prop_val(md, cpu0, "mmu-page-size-list", &szc_mask)) - szc_mask = 0; - szc_mask |= (1 << TTE4M); /* largest in sun4v default support */ + if (cpu0 == NULL) + szc_mask = szc_mask0; + else { + if (md_get_prop_val(md, cpu0, "mmu-page-size-list", &szc_mask)) + szc_mask = 0; + /* largest in sun4v default support */ + szc_mask |= (1 << TTE4M); + szc_mask0 = szc_mask; + } max_szc = highbit(szc_mask) - 1; if (max_szc > TTE256M) max_szc = TTE256M; @@ -1494,3 +1453,592 @@ return (mask != 0); } + +/* + * mblock_alloc + * + * Allocate memory for mblock an stripe arrays from either static or + * dynamic space depending on utype, and return the result in mc. + * Returns 0 on success and -1 on error. + */ + +static int +mblock_alloc(mpo_config_t *mc, update_t utype, int nmblocks) +{ + mblock_md_t *mb = NULL; + mem_stripe_t *ms = NULL; + int nstripes = MAX_MEM_NODES * nmblocks; + size_t mblocksz = nmblocks * sizeof (struct mblock_md); + size_t mstripesz = nstripes * sizeof (mem_stripe_t); + size_t allocsz = mmu_ptob(mmu_btopr(mblocksz + mstripesz)); + + /* + * Allocate space for mblocks and mstripes. + * + * For DR allocations, just use kmem_alloc(), and set + * mc_alloc_sz to indicate it was used. + * + * For boot allocation: + * If we have a small number of mblocks we will use the space + * that we preallocated. Otherwise, we will dynamically + * allocate the space from the prom and map it to the + * reserved VA at MPOBUF_BASE. + */ + + if (utype == U_ADD || utype == U_DEL) { + mb = (struct mblock_md *)kmem_zalloc(allocsz, KM_SLEEP); + ms = (mem_stripe_t *)(mb + nmblocks); + mc->mc_alloc_sz = allocsz; + } else if (nmblocks <= SMALL_MBLOCKS_COUNT) { + mb = &small_mpo_mblocks[0]; + ms = &small_mem_stripes[0]; + mc->mc_alloc_sz = 0; + } else { + /* Ensure that we dont request more space than reserved */ + if (allocsz > MPOBUF_SIZE) { + MPO_STATUS("mblock_alloc: Insufficient space " + "for mblock structures \n"); + return (-1); + } + mb = (struct mblock_md *) + prom_alloc((caddr_t)MPOBUF_BASE, allocsz, PAGESIZE); + if (mb != (struct mblock_md *)MPOBUF_BASE) { + MPO_STATUS("mblock_alloc: Cannot allocate space " + "for mblocks \n"); + return (-1); + } + mpo_heap32_buf = (caddr_t)MPOBUF_BASE; + mpo_heap32_bufsz = MPOBUF_SIZE; + ms = (mem_stripe_t *)(mb + nmblocks); + mc->mc_alloc_sz = 0; + } + mc->mc_mblocks = mb; + mc->mc_stripes = ms; + mc->mc_nmblocks = nmblocks; + mc->mc_nstripes = nstripes; + MPO_DEBUG("mblock_alloc: mblocks: %d\n", nmblocks); + return (0); +} + +/* + * mblock_free + * + * Free memory in mc that was allocated by mblock_alloc. + */ + +static void +mblock_free(mpo_config_t *mc) +{ + if (mc->mc_alloc_sz > 0) { + ASSERT(mc->mc_mblocks != mpo_mblock); + kmem_free((caddr_t)mc->mc_mblocks, mc->mc_alloc_sz); + } + bzero(mc, sizeof (*mc)); +} + +/* + * mblock_install + * + * Install mblock config passed in mc as the global configuration. + * May only be called at boot or while holding mpo_wr_lock. + */ + +static void +mblock_install(mpo_config_t *mc) +{ + mpo_mblock = mc->mc_mblocks; + n_mblocks = mc->mc_nmblocks; + mem_stripes = mc->mc_stripes; + n_mem_stripes = mc->mc_nstripes; + base_ra_to_pa_pfn = btop(mc->mc_mblocks[0].ra_to_pa); + mpo_config = *mc; +} + +/* + * mblock_update + * + * Traverse mblocknodes, read the mblock properties from the MD, and + * save the mblocks in mc. + */ + +static void +mblock_update(mpo_config_t *mc, md_t md, mde_cookie_t *mblocknodes) +{ + uint64_t i, j; + int result = 0; + mblock_md_t *mblock = mc->mc_mblocks; + + for (i = 0, j = 0; j < mc->mc_nmblocks; j++) { + + /* Without a base or size value we will fail */ + result = get_int(md, mblocknodes[j], PROP_LG_BASE, + &mblock[i].base); + if (result < 0) { + MPO_STATUS("mblock_update: " + "PROP_LG_BASE is missing\n"); + mc->mc_nmblocks = 0; + return; + } + + result = get_int(md, mblocknodes[j], PROP_LG_SIZE, + &mblock[i].size); + if (result < 0) { + MPO_STATUS("mblock_update: " + "PROP_LG_SIZE is missing\n"); + mc->mc_nmblocks = 0; + return; + } + + result = get_int(md, mblocknodes[j], + PROP_LG_RA_PA_OFFSET, &mblock[i].ra_to_pa); + + /* If we don't have an ra_pa_offset, just set it to 0 */ + if (result < 0) + mblock[i].ra_to_pa = 0; + + MPO_DEBUG("mblock[%ld]: base = %lx, size = %lx, " + "ra_to_pa = %lx\n", i, + mblock[i].base, + mblock[i].size, + mblock[i].ra_to_pa); + + /* check for unsupportable values of base and size */ + if (mblock[i].base > mblock[i].base + mblock[i].size) { + MPO_STATUS("mblock_update: " + "PROP_LG_BASE+PROP_LG_SIZE is invalid: " + "base = %lx, size = %lx\n", + mblock[i].base, mblock[i].size); + mc->mc_nmblocks = 0; + return; + } + + /* eliminate size==0 blocks */ + if (mblock[i].size != 0) { + uint64_t base = mblock[i].base; + uint64_t end = base + mblock[i].size; + ASSERT(end > base); + mblock[i].base_pfn = btop(base); + mblock[i].end_pfn = btop(end - 1); + i++; + } + } + + if (i == 0) { + MPO_STATUS("mblock_update: " + "No non-empty mblock nodes were found " + "in the Machine Descriptor\n"); + mc->mc_nmblocks = 0; + return; + } + ASSERT(i <= mc->mc_nmblocks); + mc->mc_nmblocks = i; + + /* Must sort mblocks by address for mem_node_iterator_init() */ + mblock_sort(mblock, mc->mc_nmblocks); +} + +/* + * mblock_update_add + * + * Update mblock config after a memory DR add. The added range is not + * needed, as we read *all* mblock nodes from the MD. Save the mblocks + * in mc. + */ + +static void +mblock_update_add(mpo_config_t *mc) +{ + md_t *md; + mde_cookie_t root, *mblocknodes; + int nmblocks = 0; + + if ((md = md_get_handle()) == NULL) { + MPO_STATUS("Cannot access Machine Descriptor\n"); + goto error; + } + + if ((root = md_get_root(md)) == MDE_INVAL_ELEM_COOKIE) + goto error; + + nmblocks = md_alloc_scan_dag(md, root, PROP_LG_MBLOCK, "fwd", + &mblocknodes); + if (nmblocks <= 0) { + MPO_STATUS("No mblock nodes detected in Machine Descriptor\n"); + goto error; + } + + if (mblock_alloc(mc, U_ADD, nmblocks) < 0) + goto error; + + mblock_update(mc, md, mblocknodes); + md_free_scan_dag(md, &mblocknodes); + (void) md_fini_handle(md); + return; +error: + panic("mblock_update_add: cannot process mblocks from MD.\n"); +} + +/* + * mblock_update_del + * + * Update mblocks after a memory DR deletion of the range (ubase, uend). + * Allocate a new mblock config, copy old config to the new, modify the new + * mblocks to reflect the deletion. The new mblocks are returned in + * mc_new and are not yet installed as the active config. + */ + +static void +mblock_update_del(mpo_config_t *mc_new, mpo_config_t *mc_old, pfn_t ubase, + pfn_t uend) +{ + int i, j; + pfn_t base, end; + mblock_md_t *mblock; + int nmblocks = mc_old->mc_nmblocks; + + MPO_DEBUG("mblock_update_del(0x%lx, 0x%lx)\n", ubase, uend); + + /* + * Allocate mblocks in mc_new and copy the old to the new. + * Allocate one extra in case the deletion splits an mblock. + */ + if (mblock_alloc(mc_new, U_DEL, nmblocks + 1) < 0) + return; + mblock = mc_new->mc_mblocks; + bcopy(mc_old->mc_mblocks, mblock, nmblocks * sizeof (mblock_md_t)); + + /* + * Find the mblock containing the deleted range and adjust it in + * the new config. + */ + for (i = 0; i < nmblocks; i++) { + + base = btop(mblock[i].base); + end = base + btop(mblock[i].size) - 1; + + /* + * Adjust the mblock based on the subset that was deleted. + * + * If the entire mblk was deleted, compact the table. + * + * If the middle of the mblk was deleted, extend + * the table. Space for the new slot was already + * allocated. + * + * The memory to be deleted is a mblock or a subset of + * and does not span multiple mblocks. + */ + if (base == ubase && end == uend) { + for (j = i; j < nmblocks - 1; j++) + mblock[j] = mblock[j + 1]; + nmblocks--; + bzero(&mblock[nmblocks], sizeof (*mblock)); + break; + } else if (base < ubase && end > uend) { + for (j = nmblocks - 1; j >= i; j--) + mblock[j + 1] = mblock[j]; + mblock[i].size = ptob(ubase - base); + mblock[i].end_pfn = ubase - 1; + mblock[i + 1].base = ptob(uend + 1); + mblock[i + 1].size = ptob(end - uend); + mblock[i + 1].base_pfn = uend + 1; + nmblocks++; + break; + } else if (base == ubase) { + MPO_DEBUG("mblock_update_del: shrink>" + " i=%d base=0x%lx end=0x%lx", i, base, end); + mblock[i].base = ptob(uend + 1); + mblock[i].size -= ptob(uend - ubase + 1); + base = uend + 1; + mblock[i].base_pfn = base; + mblock[i].end_pfn = end; + MPO_DEBUG(" nbase=0x%lx nend=0x%lx\n", base, end); + break; + } else if (end == uend) { + MPO_DEBUG("mblock_update_del: shrink<" + " i=%d base=0x%lx end=0x%lx", i, base, end); + mblock[i].size -= ptob(uend - ubase + 1); + end = ubase - 1; + mblock[i].base_pfn = base; + mblock[i].end_pfn = end; + MPO_DEBUG(" nbase=0x%lx nend=0x%lx\n", base, end); + break; + } + } + mc_new->mc_nmblocks = nmblocks; + ASSERT(end > base); +} + +/* + * mstripe_update + * + * Read mblocks from mc and update mstripes in mc + */ + +static void +mstripe_update(mpo_config_t *mc) +{ + lgrp_handle_t lgrphand, lgrp_start; + int i, mnode; + uint64_t offset, stripe_end, base, end, ra_to_pa, stride; + uint64_t stripe, frag, remove; + mem_stripe_t *ms; + mblock_md_t *mblock = mc->mc_mblocks; + int nmblocks = mc->mc_nmblocks; + int mstripesz = MAX_MEM_NODES * nmblocks * sizeof (mem_stripe_t); + + /* Check for non-MPO sun4v platforms or memory DR removal */ + if (n_locality_groups <= 1) { + ASSERT(n_locality_groups == 1); + ASSERT(max_locality_groups == 1 && max_mem_nodes == 1); + + if (nmblocks == 1) { + mc->mc_nstripes = 0; + } else { + mc->mc_nstripes = nmblocks; + bzero(mc->mc_stripes, mstripesz); + for (i = 0; i < nmblocks; i++) { + mc->mc_stripes[i].exists = 1; + mc->mc_stripes[i].physbase = mblock[i].base_pfn; + mc->mc_stripes[i].physmax = mblock[i].end_pfn; + } + } + return; + } + + bzero(mc->mc_stripes, mstripesz); + mc->mc_nstripes = max_locality_groups * nmblocks; + stripe = ptob(mnode_pages); + stride = max_locality_groups * stripe; + + for (i = 0; i < nmblocks; i++) { + base = mblock[i].base; + end = base + mblock[i].size; + ra_to_pa = mblock[i].ra_to_pa; + + /* Find the offset from the prev stripe boundary in PA space. */ + offset = (base + ra_to_pa) & (stripe - 1); + + /* Set the next stripe boundary. */ + stripe_end = base - offset + stripe; + + lgrp_start = (((base + ra_to_pa) & home_mask) >> + home_mask_shift); + lgrphand = lgrp_start; + + /* + * Loop over all lgroups covered by the mblock, creating a + * stripe for each. Stop when lgrp_start is visited again. + */ + do { + /* mblock may not span all lgroups */ + if (base >= end) + break; + + mnode = lgrphand; + ASSERT(mnode < max_mem_nodes); + + /* + * Calculate the size of the fragment that does not + * belong to the mnode in the last partial stride. + */ + frag = (end - (base - offset)) & (stride - 1); + if (frag == 0) { + /* remove the gap */ + remove = stride - stripe; + } else if (frag < stripe) { + /* fragment fits in stripe; keep it all */ + remove = 0; + } else { + /* fragment is large; trim after whole stripe */ + remove = frag - stripe; + } + + ms = &mc->mc_stripes[i * max_locality_groups + mnode]; + ms->physbase = btop(base); + ms->physmax = btop(end - 1 - remove); + ms->offset = btop(offset); + ms->exists = 1; + + base = stripe_end; + stripe_end += stripe; + offset = 0; + lgrphand = (((base + ra_to_pa) & home_mask) >> + home_mask_shift); + } while (lgrphand != lgrp_start); + } +} + +#define INTERSECT(a, b, c, d) \ + if (((a) >= (c) && (a) <= (d)) || \ + ((c) >= (a) && (c) <= (b))) { \ + (c) = MAX((a), (c)); \ + (d) = MIN((b), (d)); \ + } else { \ + ASSERT((a) >= (d) || (b) <= (c)); \ + continue; \ + } \ + +/* + * mnode_update + * + * Read stripes from mc and update mnode extents. The mnode extents are + * part of the live configuration, so this can only be done at boot time + * or while holding the mpo_wr_lock. + */ + +static void +mnode_update(mpo_config_t *mc, pfn_t ubase, pfn_t uend, update_t utype) +{ + int i, j, mnode, found; + pfn_t base, end; + mem_stripe_t *ms; + + MPO_DEBUG("mnode_udpate: basepfn: %lx endpfn: %lx\n", ubase, uend); + + if (n_locality_groups <= 1 && mc->mc_nmblocks == 1) { + if (utype == U_ADD) + mpo_mem_node_add_slice(ubase, uend); + else if (utype == U_DEL) + mpo_mem_node_del_slice(ubase, uend); + else + panic("mnode update: %d: invalid\n", utype); + return; + } + + found = 0; + for (i = 0; i < mc->mc_nmblocks; i++) { + for (mnode = 0; mnode < max_locality_groups; mnode++) { + + j = i * max_locality_groups + mnode; + ms = &mc->mc_stripes[j]; + if (!ms->exists) + continue; + + base = ms->physbase; + end = ms->physmax; + + /* + * Look for the mstripes intersecting this slice. + * + * The mstripe and slice pairs may not be equal + * if a subset of a mblock is added/deleted. + */ + switch (utype) { + case U_ADD: + INTERSECT(ubase, uend, base, end); + /*FALLTHROUGH*/ + case U_ADD_ALL: + if (n_locality_groups > 1) + mpo_plat_assign_lgrphand_to_mem_node( + mnode, mnode); + mpo_mem_node_add_slice(base, end); + break; + case U_DEL: + INTERSECT(ubase, uend, base, end); + mpo_mem_node_del_slice(base, end); + break; + default: + panic("mnode_update: %d: invalid\n", utype); + break; + } + + found++; + } + } + + if (!found) + panic("mnode_update: mstripe not found"); + +#ifdef DEBUG + if (utype == U_ADD_ALL || utype == U_DEL) + return; + found = 0; + for (i = 0; i < max_mem_nodes; i++) { + if (!mem_node_config[i].exists) + continue; + if (ubase >= mem_node_config[i].physbase && + ubase <= mem_node_config[i].physmax) + found |= 1; + if (uend >= mem_node_config[i].physbase && + uend <= mem_node_config[i].physmax) + found |= 2; + } + ASSERT(found == 3); + { + pfn_t minpfn, maxpfn; + + mem_node_max_range(&minpfn, &maxpfn); + ASSERT(minpfn <= ubase); + ASSERT(maxpfn >= uend); + } +#endif +} + +/* + * Plat_slice_add()/plat_slice_del() are the platform hooks + * for adding/deleting a pfn range to/from the system. + * + * Platform_slice_add() is used for both boot/DR cases. + * + * - Zeus has already added the mblocks to the MD, so read the updated + * MD and allocate all data structures required to manage the new memory + * configuration. + * + * - Recompute the stripes which are derived from the mblocks. + * + * - Update (expand) the mnode extents and install the modified mblocks as + * the new mpo config. This must be done while holding the mpo_wr_lock + * to guarantee that no other threads access the mpo meta-data. + * + * - Unlock MPO data structures; the new config is live. Free the old config. + * + * Plat_slice_del() is used for DR only. + * + * - Zeus has not yet modified the MD to reflect the deletion, so copy + * the old mpo mblocks and delete the range from the copy. + * + * - Recompute the stripes which are derived from the mblocks. + * + * - Update (shrink) the mnode extents and install the modified mblocks as + * the new mpo config. This must be done while holding the mpo_wr_lock + * to guarantee that no other threads access the mpo meta-data. + * + * - Unlock MPO data structures; the new config is live. Free the old config. + */ + +void +plat_slice_add(pfn_t base, pfn_t end) +{ + mpo_config_t old_config = mpo_config; + mpo_config_t new_config; + + VALIDATE_SLICE(base, end); + mblock_update_add(&new_config); + mstripe_update(&new_config); + mpo_wr_lock(); + mblock_install(&new_config); + /* Use new config to add all ranges for mnode_update */ + mnode_update(&new_config, base, end, U_ADD); + mpo_genid++; + mpo_wr_unlock(); + mblock_free(&old_config); +} + +void +plat_slice_del(pfn_t base, pfn_t end) +{ + mpo_config_t old_config = mpo_config; + mpo_config_t new_config; + + VALIDATE_SLICE(base, end); + mblock_update_del(&new_config, &old_config, base, end); + mstripe_update(&new_config); + mpo_wr_lock(); + /* Use old config to find deleted range for mnode_update */ + mnode_update(&old_config, base, end, U_DEL); + mblock_install(&new_config); + mpo_genid++; + mpo_wr_unlock(); + mblock_free(&old_config); +}
--- a/usr/src/uts/sun4v/promif/promif_emul.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/sun4v/promif/promif_emul.c Mon Jul 20 13:07:46 2009 -0400 @@ -20,12 +20,10 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/promif_impl.h> #include <sys/machsystm.h> #include <sys/lpad.h> @@ -37,19 +35,39 @@ #include <sys/hypervisor_api.h> #include <sys/mdesc.h> #include <sys/mach_descrip.h> +#include <sys/cpu_module.h> #ifndef _KMDB +#include <sys/pte.h> +#include <vm/hat_sfmmu.h> +#include <sys/memlist_impl.h> + static processorid_t cif_cpu; static struct translation *cif_prom_trans; static size_t cif_prom_ntrans; int cif_cpu_mp_ready; int (*prom_cif_handler)(void *) = NULL; + +extern struct memlist *phys_avail; +extern struct vnode prom_ppages; +extern void kdi_tlb_page_unlock(caddr_t, int); + +#define COMBINE(hi, lo) (((uint64_t)(uint32_t)(hi) << 32) | (uint32_t)(lo)) +#define OFW_PT_START_ADDR 0xfffffffc00000000 /* OBP PT start */ +#define OFW_PT_END_ADDR 0xffffffffffffffff /* OBP PT end */ + +#define PROM_ADDR(a) (((a) >= OFW_START_ADDR && (a) <= OFW_END_ADDR) || \ + ((a) >= OFW_PT_START_ADDR && (a) <= OFW_PT_END_ADDR)) #endif #ifdef DEBUG uint_t cif_debug; -#endif /* DEBUG */ +int prom_free_debug; +#define PMFREE_DEBUG(args...) if (prom_free_debug) printf(args) +#else +#define PMFREE_DEBUG(args...) +#endif extern int (*cif_handler)(void *); @@ -171,6 +189,161 @@ #else +static struct translation * +read_prom_mappings(size_t *ntransp) +{ + char *prop = "translations"; + pnode_t node; + size_t translen; + ihandle_t immu; + struct translation *transroot; + + *ntransp = 0; + + /* + * the "translations" property is associated with the mmu node + */ + if ((immu = prom_mmu_ihandle()) == (ihandle_t)-1) { + PMFREE_DEBUG("no mmu ihandle"); + return (NULL); + } + node = (pnode_t)prom_getphandle(immu); + if (node == OBP_NONODE || node == OBP_BADNODE) { + PMFREE_DEBUG("no mmu node"); + return (NULL); + } + + if ((translen = prom_getproplen(node, prop)) == -1) { + PMFREE_DEBUG("no translations property"); + return (NULL); + } + transroot = (struct translation *)kmem_zalloc(translen, KM_SLEEP); + + if (prom_getprop(node, prop, (caddr_t)transroot) == -1) { + PMFREE_DEBUG("translations getprop failed"); + kmem_free(transroot, translen); + return (NULL); + } + *ntransp = translen / sizeof (*transroot); + + return (transroot); +} + +static void +unmap_prom_mappings(struct translation *transroot, size_t ntransroot) +{ + int i, j, rv; + int npgs, nunmapped, nfreed, nskipped; + char *p; + tte_t tte; + pfn_t pfn; + page_t *pp; + uint64_t vaddr; + struct translation *promt; + cpuset_t other_cpus; + + /* + * During startup isa_list is allocated in OBP address space + * so it needs to be re-allocated in kernel address space + * before OBP memory is unmapped. + * + * see cpu_setup_common(). + */ + p = kmem_zalloc(strlen(isa_list) + 1, KM_SLEEP); + (void) strcpy(p, isa_list); + isa_list = p; + + nfreed = 0; + nunmapped = 0; + nskipped = 0; + + for (i = 0, promt = transroot; i < ntransroot; i++, promt++) { + ASSERT(promt->tte_hi != 0); + ASSERT32(promt->virt_hi == 0 && promt->size_hi == 0); + + vaddr = COMBINE(promt->virt_hi, promt->virt_lo); + + if (!PROM_ADDR(vaddr)) { + nskipped++; + continue; + } + + npgs = mmu_btopr(COMBINE(promt->size_hi, promt->size_lo)); + + if (npgs > 1) { + PMFREE_DEBUG("large trans vaddr=0x%lx, npgs=%d\n", + vaddr, npgs); + } + for (j = 0; j < npgs; j++) { + + pfn = sfmmu_vatopfn((caddr_t)vaddr, KHATID, &tte); + + if (pfn == PFN_INVALID) { + tte.tte_inthi = promt->tte_hi; + tte.tte_intlo = promt->tte_lo; + pfn = TTE_TO_PFN((caddr_t)COMBINE( + promt->virt_hi, promt->virt_lo), &tte); + PMFREE_DEBUG( + "no mapping for vaddr=0x%lx (opfn=0x%lx)\n", + vaddr, pfn); + break; + } + ASSERT(!TTE_IS_LOCKED(&tte)); + ASSERT(TTE_IS_8K(&tte)); + + /* + * Unload the current mapping for the page and + * if it is the last mapping, free the page. + */ + pp = page_numtopp_nolock(pfn); + PMFREE_DEBUG("unmap vaddr=0x%lx pfn=0x%lx pp=0x%p", + vaddr, pfn, (void *)pp); + ASSERT(pp); + ASSERT(PAGE_EXCL(pp)); + ASSERT(PP_ISNORELOC(pp)); + ASSERT(!PP_ISFREE(pp)); + ASSERT(page_find(&prom_ppages, pfn)); + ASSERT(page_get_pagecnt(pp->p_szc) == 1); + + hat_unload(kas.a_hat, (caddr_t)vaddr, PAGESIZE, + HAT_UNLOAD_UNLOCK); + + if (pp->p_mapping) { + PMFREE_DEBUG(" skip\n"); + } else { + PP_CLRNORELOC(pp); + page_destroy(pp, 0); + memlist_write_lock(); + rv = memlist_add_span(pfn << PAGESHIFT, + PAGESIZE, &phys_avail); + ASSERT(rv == MEML_SPANOP_OK); + memlist_write_unlock(); + PMFREE_DEBUG(" free\n"); + nfreed++; + } + nunmapped++; + vaddr += PAGESIZE; + } + } + + if (transroot) { + PMFREE_DEBUG("nunmapped=%d nfreed=%d nskipped=%d\n", + nunmapped, nfreed, nskipped); + kmem_free(transroot, ntransroot * sizeof (*transroot)); + } + + /* + * Unload OBP permanent mappings. + */ + kdi_tlb_page_unlock((caddr_t)OFW_START_ADDR, 1); + kpreempt_disable(); + other_cpus = cpu_ready_set; + CPUSET_DEL(other_cpus, CPU->cpu_id); + xt_some(other_cpus, vtag_unmap_perm_tl1, (uint64_t)OFW_START_ADDR, + KCONTEXT); + kpreempt_enable(); +} + static void cache_prom_data(void); /* @@ -252,6 +425,8 @@ void (*kmdb_cb)(void); uint64_t rtba; uint64_t rv; + size_t ntransroot; + struct translation *transroot; /* * Check if domaining is enabled. If not, do not @@ -260,6 +435,8 @@ if (!domaining_enabled()) return; + transroot = read_prom_mappings(&ntransroot); + /* * Cache PROM data that is needed later, e.g. a shadow * copy of the device tree, IO mappings, etc. @@ -301,6 +478,9 @@ } cif_check_cpus(); + + if (transroot != NULL) + unmap_prom_mappings(transroot, ntransroot); } static void
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/sun4v/sys/dr_mem.h Mon Jul 20 13:07:46 2009 -0400 @@ -0,0 +1,123 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _DR_MEM_H +#define _DR_MEM_H + +/* + * Memory DR Control Protocol + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Memory DR Message Header + */ +typedef struct { + uint32_t msg_type; /* message type */ + uint32_t msg_arg; /* messages argument */ + uint64_t req_num; /* request number */ +} dr_mem_hdr_t; + +/* + * Memory command and response messages + */ + +#define DR_MEM_DS_ID "dr-mem" + +#define DR_MEM_CONFIGURE (0x4d43) /* 'MC' configure mem */ +#define DR_MEM_UNCONFIGURE (0x4d55) /* 'MU' unconfigure mem */ +#define DR_MEM_UNCONF_STATUS (0x4d53) /* 'MS' get mem unconf status */ +#define DR_MEM_UNCONF_CANCEL (0x4d4e) /* 'MN' cancel mem unconf */ +#define DR_MEM_QUERY (0x4d51) /* 'MQ' query mem info */ + +#define DR_MEM_OK ('o') +#define DR_MEM_ERROR ('e') + +typedef struct { + uint64_t addr; /* mblk base address */ + uint64_t size; /* mblk size */ +} dr_mem_blk_t; + +/* + * Response Message + */ +typedef struct { + uint64_t addr; /* mblk base address */ + uint64_t size; /* mblk size */ + uint32_t result; /* result of the operation */ + uint32_t status; /* status of the mblk */ + uint32_t string_off; /* informational string offset */ + uint32_t reserved; /* padding */ +} dr_mem_stat_t; + +typedef struct { + uint64_t addr; /* query address */ + memquery_t mq; /* query results */ +} dr_mem_query_t; + +/* + * Result Codes + */ +#define DR_MEM_RES_OK 0x0 /* operation succeeded */ +#define DR_MEM_RES_FAILURE 0x1 /* operation failed */ +#define DR_MEM_RES_BLOCKED 0x2 /* operation was blocked */ +#define DR_MEM_RES_NOT_IN_MD 0x3 /* memory not defined in MD */ +#define DR_MEM_RES_ESPAN 0x4 /* memory already in use */ +#define DR_MEM_RES_EFAULT 0x5 /* memory access test failed */ +#define DR_MEM_RES_ERESOURCE 0x6 /* resource not available */ +#define DR_MEM_RES_PERM 0x7 /* permanent pages in span */ +#define DR_MEM_RES_EBUSY 0x8 /* memory span busy */ +#define DR_MEM_RES_ENOTVIABLE 0x9 /* VM viability test failed */ +#define DR_MEM_RES_ENOWORK 0xA /* no pages to unconfigure */ +#define DR_MEM_RES_ECANCELLED 0xB /* operation cancelled */ +#define DR_MEM_RES_EREFUSED 0xC /* operation refused */ +#define DR_MEM_RES_EDUP 0xD /* memory span duplicate */ +#define DR_MEM_RES_EINVAL 0xE /* invalid argument */ + +/* + * Status Codes + */ +#define DR_MEM_STAT_NOT_PRESENT 0x0 /* mblk ID not in MD */ +#define DR_MEM_STAT_UNCONFIGURED 0x1 /* mblk unconfigured */ +#define DR_MEM_STAT_CONFIGURED 0x2 /* mblk configured */ + +/* + * Macros to access arrays that follow message header + */ +#define DR_MEM_HDR(h) ((dr_mem_hdr_t *)(h)) +#define DR_MEM_CMD_MBLKS(h) ((dr_mem_blk_t *)((DR_MEM_HDR(h)) + 1)) +#define DR_MEM_RESP_STATS(h) ((dr_mem_stat_t *)((DR_MEM_HDR(h)) + 1)) +#define DR_MEM_RESP_DEL_STAT(h) ((memdelstat_t *)(DR_MEM_HDR(h) + 1)) +#define DR_MEM_RESP_QUERY(h) ((dr_mem_query_t *)(DR_MEM_HDR(h) + 1)) + +#ifdef __cplusplus +} +#endif + +#endif /* _DR_MEM_H */
--- a/usr/src/uts/sun4v/sys/mpo.h Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/sun4v/sys/mpo.h Mon Jul 20 13:07:46 2009 -0400 @@ -1,4 +1,3 @@ - /* * CDDL HEADER START * @@ -21,15 +20,13 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SYS_MPO_H #define _SYS_MPO_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -80,14 +77,13 @@ /* Structure to store mblock information retrieved from the MD */ -struct mblock_md { +typedef struct mblock_md { uint64_t base; uint64_t size; uint64_t ra_to_pa; - mde_cookie_t node; pfn_t base_pfn; pfn_t end_pfn; -}; +} mblock_md_t; /* Structure for memnode information for use by plat_pfn_to_mem_node */ @@ -104,6 +100,17 @@ int exists; /* set to 1 if mblock has memory in this mnode stripe */ } mem_stripe_t; +/* Configuration including allocation state of mblocks and stripes */ + +typedef struct { + mblock_md_t *mc_mblocks; /* mblock array */ + int mc_nmblocks; /* number in array */ + mem_stripe_t *mc_stripes; /* stripe array */ + int mc_nstripes; /* number in array */ + int mc_alloc_sz; /* size in bytes of mc_mblocks if */ + /* it was kmem_alloc'd, else 0 */ +} mpo_config_t; + /* These are used when MPO requires preallocated kvseg32 space */ extern caddr_t mpo_heap32_buf; extern size_t mpo_heap32_bufsz;
--- a/usr/src/uts/sun4v/vm/mach_kpm.c Tue Jul 14 11:18:27 2009 -0400 +++ b/usr/src/uts/sun4v/vm/mach_kpm.c Mon Jul 20 13:07:46 2009 -0400 @@ -216,7 +216,32 @@ void hat_kpm_addmem_mseg_update(struct memseg *msp, pgcnt_t nkpmpgs, offset_t kpm_pages_off) -{} +{ + pfn_t base, end; + + /* + * kphysm_add_memory_dynamic() does not set nkpmpgs + * when page_t memory is externally allocated. That + * code must properly calculate nkpmpgs in all cases + * if nkpmpgs needs to be used at some point. + */ + + base = msp->pages_base; + end = msp->pages_end; + + hat_devload(kas.a_hat, kpm_vbase + mmu_ptob(base), + mmu_ptob(end - base), base, PROT_READ | PROT_WRITE, + HAT_LOAD | HAT_LOAD_LOCK | HAT_LOAD_NOCONSIST); +} + +/* + * Return end of metadata for an already setup memseg. + */ +caddr_t +hat_kpm_mseg_reuse(struct memseg *msp) +{ + return ((caddr_t)msp->epages); +} /*ARGSUSED*/ void @@ -229,16 +254,17 @@ {} /*ARGSUSED*/ -caddr_t -hat_kpm_mseg_reuse(struct memseg *msp) -{ - return (0); -} - -/*ARGSUSED*/ void hat_kpm_delmem_mseg_update(struct memseg *msp, struct memseg **mspp) -{} +{ + pfn_t base, end; + + base = msp->pages_base; + end = msp->pages_end; + + hat_unload(kas.a_hat, kpm_vbase + mmu_ptob(base), mmu_ptob(end - base), + HAT_UNLOAD | HAT_UNLOAD_UNLOCK | HAT_UNLOAD_UNMAP); +} /*ARGSUSED*/ void